diff --git a/circuits/cpp/src/aztec3/circuits/abis/packers.hpp b/circuits/cpp/src/aztec3/circuits/abis/packers.hpp index 63fd8cc20b0..3dd6f9591f5 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/packers.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/packers.hpp @@ -105,7 +105,7 @@ struct GeneratorIndexPacker { int COMMITMENT = GeneratorIndex::COMMITMENT; int COMMITMENT_NONCE = GeneratorIndex::COMMITMENT_NONCE; int UNIQUE_COMMITMENT = GeneratorIndex::UNIQUE_COMMITMENT; - int OUTER_COMMITMENT = GeneratorIndex::OUTER_COMMITMENT; + int SILOED_COMMITMENT = GeneratorIndex::SILOED_COMMITMENT; int NULLIFIER = GeneratorIndex::NULLIFIER; int INITIALISATION_NULLIFIER = GeneratorIndex::INITIALISATION_NULLIFIER; int OUTER_NULLIFIER = GeneratorIndex::OUTER_NULLIFIER; @@ -141,7 +141,7 @@ struct GeneratorIndexPacker { pack(NVP(COMMITMENT, COMMITMENT_NONCE, UNIQUE_COMMITMENT, - OUTER_COMMITMENT, + SILOED_COMMITMENT, NULLIFIER, INITIALISATION_NULLIFIER, OUTER_NULLIFIER, diff --git a/circuits/cpp/src/aztec3/circuits/hash.hpp b/circuits/cpp/src/aztec3/circuits/hash.hpp index 08531b1344d..bc2158cfd35 100644 --- a/circuits/cpp/src/aztec3/circuits/hash.hpp +++ b/circuits/cpp/src/aztec3/circuits/hash.hpp @@ -100,29 +100,29 @@ typename NCT::fr compute_commitment_nonce(typename NCT::fr first_nullifier, type } template -typename NCT::fr compute_unique_commitment(typename NCT::fr nonce, typename NCT::fr inner_commitment) +typename NCT::fr silo_commitment(typename NCT::address contract_address, typename NCT::fr inner_commitment) { using fr = typename NCT::fr; std::vector const inputs = { - nonce, + contract_address.to_field(), inner_commitment, }; - return NCT::hash(inputs, aztec3::GeneratorIndex::UNIQUE_COMMITMENT); + return NCT::hash(inputs, aztec3::GeneratorIndex::SILOED_COMMITMENT); } template -typename NCT::fr silo_commitment(typename NCT::address contract_address, typename NCT::fr commitment) +typename NCT::fr compute_unique_commitment(typename NCT::fr nonce, typename NCT::fr siloed_commitment) { using fr = typename NCT::fr; std::vector const inputs = { - contract_address.to_field(), - commitment, + nonce, + siloed_commitment, }; - return NCT::hash(inputs, aztec3::GeneratorIndex::OUTER_COMMITMENT); + return NCT::hash(inputs, aztec3::GeneratorIndex::UNIQUE_COMMITMENT); } template diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/c_bind.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/c_bind.cpp index 43e45c2e240..7b503ddb509 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/c_bind.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/c_bind.cpp @@ -14,7 +14,7 @@ namespace { using Builder = UltraCircuitBuilder; using NT = aztec3::utils::types::NativeTypes; -using DummyBuilder = aztec3::utils::DummyCircuitBuilder; +using DummyCircuitBuilder = aztec3::utils::DummyCircuitBuilder; using aztec3::circuits::abis::PreviousKernelData; using aztec3::circuits::abis::TxRequest; using aztec3::circuits::abis::private_kernel::PrivateCallData; @@ -67,7 +67,7 @@ WASM_EXPORT uint8_t* private_kernel__sim_init(uint8_t const* tx_request_buf, size_t* private_kernel_public_inputs_size_out, uint8_t const** private_kernel_public_inputs_buf) { - DummyBuilder builder = DummyBuilder("private_kernel__sim_init"); + DummyCircuitBuilder builder = DummyCircuitBuilder("private_kernel__sim_init"); PrivateCallData private_call_data; read(private_call_buf, private_call_data); @@ -98,7 +98,7 @@ WASM_EXPORT uint8_t* private_kernel__sim_inner(uint8_t const* previous_kernel_bu size_t* private_kernel_public_inputs_size_out, uint8_t const** private_kernel_public_inputs_buf) { - DummyBuilder builder = DummyBuilder("private_kernel__sim_inner"); + DummyCircuitBuilder builder = DummyCircuitBuilder("private_kernel__sim_inner"); PrivateCallData private_call_data; read(private_call_buf, private_call_data); @@ -124,7 +124,7 @@ WASM_EXPORT uint8_t* private_kernel__sim_inner(uint8_t const* previous_kernel_bu } CBIND(private_kernel__sim_ordering, [](PreviousKernelData previous_kernel) { - DummyBuilder builder = DummyBuilder("private_kernel__sim_ordering"); + DummyCircuitBuilder builder = DummyCircuitBuilder("private_kernel__sim_ordering"); auto const& public_inputs = native_private_kernel_circuit_ordering(builder, previous_kernel); return builder.result_or_error(public_inputs); }); diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/common.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/common.cpp index f46ff859373..09ca200535d 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/common.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/common.cpp @@ -6,7 +6,6 @@ #include "aztec3/circuits/abis/function_data.hpp" #include "aztec3/circuits/abis/kernel_circuit_public_inputs.hpp" #include "aztec3/circuits/abis/new_contract_data.hpp" -#include "aztec3/circuits/abis/previous_kernel_data.hpp" #include "aztec3/circuits/abis/private_kernel/private_call_data.hpp" #include "aztec3/circuits/abis/read_request_membership_witness.hpp" #include "aztec3/circuits/hash.hpp" @@ -21,7 +20,6 @@ using aztec3::circuits::abis::ContractLeafPreimage; using aztec3::circuits::abis::FunctionData; using aztec3::circuits::abis::KernelCircuitPublicInputs; using aztec3::circuits::abis::NewContractData; -using aztec3::circuits::abis::PreviousKernelData; using aztec3::circuits::abis::ReadRequestMembershipWitness; using aztec3::utils::array_length; @@ -61,15 +59,14 @@ void common_validate_call_stack(DummyBuilder& builder, PrivateCallData const * - https://discourse.aztec.network/t/spending-notes-which-havent-yet-been-inserted/180 * * @param builder - * @param storage_contract_address Contract address to use when siloing read requests * @param historic_private_data_tree_root This is a reference to the historic root which all * read requests are checked against here. - * @param read_requests the commitments being read by this private call + * @param read_requests the commitments being read by this private call - 'pending note reads' here are + * `inner_note_hashes` (not yet siloed, not unique), but 'pre-existing note reads' are `unique_siloed_note_hashes` * @param read_request_membership_witnesses used to compute the private data root * for a given request which is essentially a membership check */ void common_validate_read_requests(DummyBuilder& builder, - NT::fr const& storage_contract_address, NT::fr const& historic_private_data_tree_root, std::array const& read_requests, std::array, @@ -89,41 +86,40 @@ void common_validate_read_requests(DummyBuilder& builder, // for every request in all kernel iterations for (size_t rr_idx = 0; rr_idx < aztec3::MAX_READ_REQUESTS_PER_CALL; rr_idx++) { const auto& read_request = read_requests[rr_idx]; - // the read request comes un-siloed from the app circuit so we must silo it here - // so that it matches the private data tree leaf that we are membership checking - const auto leaf = silo_commitment(storage_contract_address, read_request); const auto& witness = read_request_membership_witnesses[rr_idx]; // A pending commitment is the one that is not yet added to private data tree // A transient read is when we try to "read" a pending commitment // We determine if it is a transient read depending on the leaf index from the membership witness // Note that the Merkle membership proof would be null and void in case of an transient read - // but we use the leaf index as a placeholder to detect a transient read. + // but we use the leaf index as a placeholder to detect a 'pending note read'. if (read_request != 0 && !witness.is_transient) { const auto& root_for_read_request = - root_from_sibling_path(leaf, witness.leaf_index, witness.sibling_path); - builder.do_assert(root_for_read_request == historic_private_data_tree_root, - format("private data tree root mismatch at read_request[", - rr_idx, - "]", - "\n\texpected root: ", - historic_private_data_tree_root, - "\n\tbut got root*: ", - root_for_read_request, - "\n\tread_request: ", - read_request, - "\n\tsiloed-rr (leaf): ", - leaf, - "\n\tleaf_index: ", - witness.leaf_index, - "\n\tis_transient: ", - witness.is_transient, - "\n\thint_to_commitment: ", - witness.hint_to_commitment, - "\n\t* got root by siloing read_request (compressing with " - "storage_contract_address to get leaf) " - "and merkle-hashing to a root using membership witness"), - CircuitErrorCode::PRIVATE_KERNEL__READ_REQUEST_PRIVATE_DATA_ROOT_MISMATCH); + root_from_sibling_path(read_request, witness.leaf_index, witness.sibling_path); + builder.do_assert( + root_for_read_request == historic_private_data_tree_root, + format("private data tree root mismatch at read_request[", + rr_idx, + "]", + "\n\texpected root: ", + historic_private_data_tree_root, + "\n\tbut got root*: ", + root_for_read_request, + "\n\tread_request**: ", + read_request, + "\n\tleaf_index: ", + witness.leaf_index, + "\n\tis_transient: ", + witness.is_transient, + "\n\thint_to_commitment: ", + witness.hint_to_commitment, + "\n\t* got root by treating the read_request as a leaf in the private data tree " + "and merkle-hashing to a root using the membership witness" + "\n\t** for 'pre-existing note reads', the read_request is the unique_siloed_note_hash " + "(it has been hashed with contract address and then a nonce)"), + CircuitErrorCode::PRIVATE_KERNEL__READ_REQUEST_PRIVATE_DATA_ROOT_MISMATCH); + // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1354): do we need to enforce + // that a non-transient read_request was derived from the proper/current contract address? } } } @@ -226,13 +222,9 @@ void common_update_end_values(DummyBuilder& builder, // commitments std::array siloed_new_commitments{}; - const auto& first_nullifier = public_inputs.end.new_nullifiers[0]; - const auto index_start = array_length(public_inputs.end.new_commitments); for (size_t i = 0; i < new_commitments.size(); ++i) { - const auto nonce = compute_commitment_nonce(first_nullifier, index_start + i); - const auto unique_commitment = compute_unique_commitment(nonce, new_commitments[i]); siloed_new_commitments[i] = - new_commitments[i] == 0 ? 0 : silo_commitment(storage_contract_address, unique_commitment); + new_commitments[i] == 0 ? 0 : silo_commitment(storage_contract_address, new_commitments[i]); } push_array_to_array( builder, @@ -406,30 +398,4 @@ void common_contract_logic(DummyBuilder& builder, } } -void common_inner_ordering_initialise_end_values(PreviousKernelData const& previous_kernel, - KernelCircuitPublicInputs& public_inputs) -{ - public_inputs.constants = previous_kernel.public_inputs.constants; - - // Ensure the arrays are the same as previously, before we start pushing more data onto them in other - // functions within this circuit: - auto& end = public_inputs.end; - const auto& start = previous_kernel.public_inputs.end; - - end.new_commitments = start.new_commitments; - end.new_nullifiers = start.new_nullifiers; - - end.private_call_stack = start.private_call_stack; - end.public_call_stack = start.public_call_stack; - end.new_l2_to_l1_msgs = start.new_l2_to_l1_msgs; - - end.encrypted_logs_hash = start.encrypted_logs_hash; - end.unencrypted_logs_hash = start.unencrypted_logs_hash; - - end.encrypted_log_preimages_length = start.encrypted_log_preimages_length; - end.unencrypted_log_preimages_length = start.unencrypted_log_preimages_length; - - end.optionally_revealed_data = start.optionally_revealed_data; -} - } // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/common.hpp b/circuits/cpp/src/aztec3/circuits/kernel/private/common.hpp index 57256896e19..8226b41c338 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/common.hpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/common.hpp @@ -5,7 +5,6 @@ #include "aztec3/circuits/abis/contract_deployment_data.hpp" #include "aztec3/circuits/abis/function_data.hpp" #include "aztec3/circuits/abis/kernel_circuit_public_inputs.hpp" -#include "aztec3/circuits/abis/previous_kernel_data.hpp" #include "aztec3/circuits/abis/private_kernel/private_call_data.hpp" #include "aztec3/circuits/abis/read_request_membership_witness.hpp" #include "aztec3/utils/dummy_circuit_builder.hpp" @@ -17,7 +16,6 @@ using aztec3::circuits::abis::ContractDeploymentData; using DummyBuilder = aztec3::utils::DummyCircuitBuilder; using aztec3::circuits::abis::FunctionData; using aztec3::circuits::abis::KernelCircuitPublicInputs; -using aztec3::circuits::abis::PreviousKernelData; using aztec3::circuits::abis::ReadRequestMembershipWitness; using aztec3::circuits::abis::private_kernel::PrivateCallData; @@ -26,7 +24,6 @@ using aztec3::circuits::abis::private_kernel::PrivateCallData; void common_validate_call_stack(DummyBuilder& builder, PrivateCallData const& private_call); void common_validate_read_requests(DummyBuilder& builder, - NT::fr const& storage_contract_address, NT::fr const& historic_private_data_tree_root, std::array const& read_requests, std::array, @@ -48,7 +45,4 @@ void common_contract_logic(DummyBuilder& builder, ContractDeploymentData const& contract_dep_data, FunctionData const& function_data); -void common_inner_ordering_initialise_end_values(PreviousKernelData const& previous_kernel, - KernelCircuitPublicInputs& public_inputs); - } // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit.test.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit.test.cpp index 0c42c5c442e..74aa9cc0ec1 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit.test.cpp @@ -45,11 +45,8 @@ TEST_F(native_private_kernel_tests, native_accumulate_transient_read_requests) { auto private_inputs_init = do_private_call_get_kernel_inputs_init(false, deposit, standard_test_args()); - auto first_nullifier = private_inputs_init.tx_request.hash(); - private_inputs_init.private_call.call_stack_item.public_inputs.new_commitments[0] = fr(12); - private_inputs_init.private_call.call_stack_item.public_inputs.read_requests[0] = - compute_unique_commitment(compute_commitment_nonce(first_nullifier, 1), fr(23)); + private_inputs_init.private_call.call_stack_item.public_inputs.read_requests[0] = fr(23); private_inputs_init.private_call.read_request_membership_witnesses[0].is_transient = true; DummyBuilder builder = DummyBuilder("native_private_kernel_tests__native_accumulate_transient_read_requests"); @@ -64,8 +61,7 @@ TEST_F(native_private_kernel_tests, native_accumulate_transient_read_requests) auto private_inputs_inner = do_private_call_get_kernel_inputs_inner(false, deposit, standard_test_args()); private_inputs_inner.private_call.call_stack_item.public_inputs.new_commitments[0] = fr(23); - private_inputs_inner.private_call.call_stack_item.public_inputs.read_requests[0] = - compute_unique_commitment(compute_commitment_nonce(first_nullifier, 0), fr(12)); + private_inputs_inner.private_call.call_stack_item.public_inputs.read_requests[0] = fr(12); private_inputs_inner.private_call.read_request_membership_witnesses[0].is_transient = true; // The original call is not multi-iterative (call stack depth == 1) and we re-feed the same private call stack @@ -101,11 +97,8 @@ TEST_F(native_private_kernel_tests, native_transient_read_requests_no_match) { auto private_inputs_init = do_private_call_get_kernel_inputs_init(false, deposit, standard_test_args()); - auto first_nullifier = private_inputs_init.tx_request.hash(); - private_inputs_init.private_call.call_stack_item.public_inputs.new_commitments[0] = fr(10); - private_inputs_init.private_call.call_stack_item.public_inputs.read_requests[0] = - compute_unique_commitment(compute_commitment_nonce(first_nullifier, 1), fr(23)); + private_inputs_init.private_call.call_stack_item.public_inputs.read_requests[0] = fr(23); private_inputs_init.private_call.read_request_membership_witnesses[0].is_transient = true; DummyBuilder builder = DummyBuilder("native_private_kernel_tests__native_transient_read_requests_no_match"); @@ -120,8 +113,7 @@ TEST_F(native_private_kernel_tests, native_transient_read_requests_no_match) auto private_inputs_inner = do_private_call_get_kernel_inputs_inner(false, deposit, standard_test_args()); private_inputs_inner.private_call.call_stack_item.public_inputs.new_commitments[0] = fr(23); - private_inputs_inner.private_call.call_stack_item.public_inputs.read_requests[0] = - compute_unique_commitment(compute_commitment_nonce(first_nullifier, 0), fr(12)); + private_inputs_inner.private_call.call_stack_item.public_inputs.read_requests[0] = fr(12); private_inputs_inner.private_call.read_request_membership_witnesses[0].is_transient = true; // The original call is not multi-iterative (call stack depth == 1) and we re-feed the same private call stack diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_init.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_init.cpp index 4f4867cceb2..440022dd920 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_init.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_init.cpp @@ -5,40 +5,22 @@ #include "aztec3/circuits/abis/combined_historic_tree_roots.hpp" #include "aztec3/circuits/abis/private_historic_tree_roots.hpp" #include "aztec3/circuits/abis/private_kernel/private_kernel_inputs_init.hpp" -#include "aztec3/constants.hpp" #include "aztec3/utils/array.hpp" + +namespace { +using NT = aztec3::utils::types::NativeTypes; + using aztec3::circuits::abis::CombinedConstantData; using aztec3::circuits::abis::CombinedHistoricTreeRoots; +using aztec3::circuits::abis::KernelCircuitPublicInputs; using aztec3::circuits::abis::PrivateHistoricTreeRoots; using aztec3::circuits::abis::private_kernel::PrivateKernelInputsInit; using aztec3::utils::array_push; +using aztec3::utils::CircuitErrorCode; +using aztec3::utils::DummyCircuitBuilder; using aztec3::utils::is_array_empty; -using CircuitErrorCode = aztec3::utils::CircuitErrorCode; - -namespace aztec3::circuits::kernel::private_kernel { -// using plonk::stdlib::merkle_tree:: - -// // TODO: NEED TO RECONCILE THE `proof`'s public inputs (which are uint8's) with the -// // private_call.call_stack_item.public_inputs! -// CT::AggregationObject verify_proofs(Builder& builder, -// PrivateKernelInputsInit const& private_inputs, -// size_t const& num_private_call_public_inputs, -// size_t const& num_private_kernel_public_inputs) -// { -// CT::AggregationObject aggregation_object = Aggregator::aggregate( -// &builder, private_inputs.private_call.vk, private_inputs.private_call.proof, -// num_private_call_public_inputs); - -// Aggregator::aggregate(&builder, -// private_inputs.previous_kernel.vk, -// private_inputs.previous_kernel.proof, -// num_private_kernel_public_inputs, -// aggregation_object); - -// return aggregation_object; -// } void initialise_end_values(PrivateKernelInputsInit const& private_inputs, KernelCircuitPublicInputs& public_inputs) @@ -66,8 +48,33 @@ void initialise_end_values(PrivateKernelInputsInit const& private_inputs, // Set the constants in public_inputs. public_inputs.constants = constants; } +} // namespace + +namespace aztec3::circuits::kernel::private_kernel { + +// using plonk::stdlib::merkle_tree:: + +// // TODO: NEED TO RECONCILE THE `proof`'s public inputs (which are uint8's) with the +// // private_call.call_stack_item.public_inputs! +// CT::AggregationObject verify_proofs(Builder& builder, +// PrivateKernelInputsInit const& private_inputs, +// size_t const& num_private_call_public_inputs, +// size_t const& num_private_kernel_public_inputs) +// { +// CT::AggregationObject aggregation_object = Aggregator::aggregate( +// &builder, private_inputs.private_call.vk, private_inputs.private_call.proof, +// num_private_call_public_inputs); + +// Aggregator::aggregate(&builder, +// private_inputs.previous_kernel.vk, +// private_inputs.previous_kernel.proof, +// num_private_kernel_public_inputs, +// aggregation_object); + +// return aggregation_object; +// } -void validate_this_private_call_against_tx_request(DummyBuilder& builder, +void validate_this_private_call_against_tx_request(DummyCircuitBuilder& builder, PrivateKernelInputsInit const& private_inputs) { // TODO(mike): this logic might need to change to accommodate the weird edge 3 initial txs (the 'main' tx, the 'fee' @@ -94,7 +101,7 @@ void validate_this_private_call_against_tx_request(DummyBuilder& builder, CircuitErrorCode::PRIVATE_KERNEL__USER_INTENT_MISMATCH_BETWEEN_TX_REQUEST_AND_CALL_STACK_ITEM); }; -void validate_inputs(DummyBuilder& builder, PrivateKernelInputsInit const& private_inputs) +void validate_inputs(DummyCircuitBuilder& builder, PrivateKernelInputsInit const& private_inputs) { const auto& this_call_stack_item = private_inputs.private_call.call_stack_item; @@ -124,7 +131,7 @@ void validate_inputs(DummyBuilder& builder, PrivateKernelInputsInit const& p CircuitErrorCode::PRIVATE_KERNEL__CONTRACT_ADDRESS_MISMATCH); } -void update_end_values(DummyBuilder& builder, +void update_end_values(DummyCircuitBuilder& builder, PrivateKernelInputsInit const& private_inputs, KernelCircuitPublicInputs& public_inputs) { @@ -169,7 +176,7 @@ void update_end_values(DummyBuilder& builder, // NOTE: THIS IS A VERY UNFINISHED WORK IN PROGRESS. // TODO(mike): is there a way to identify whether an input has not been used by ths circuit? This would help us // more-safely ensure we're constraining everything. -KernelCircuitPublicInputs native_private_kernel_circuit_initial(DummyBuilder& builder, +KernelCircuitPublicInputs native_private_kernel_circuit_initial(DummyCircuitBuilder& builder, PrivateKernelInputsInit const& private_inputs) { // We'll be pushing data to this during execution of this circuit. @@ -190,7 +197,6 @@ KernelCircuitPublicInputs native_private_kernel_circuit_initial(DummyBuilder common_validate_read_requests( builder, - private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address, public_inputs.constants.historic_tree_roots.private_historic_tree_roots.private_data_tree_root, private_inputs.private_call.call_stack_item.public_inputs.read_requests, // read requests from private call private_inputs.private_call.read_request_membership_witnesses); diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_init.test.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_init.test.cpp index 8b4c0369be3..c861737da88 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_init.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_init.test.cpp @@ -3,6 +3,7 @@ #include "aztec3/circuits/abis/read_request_membership_witness.hpp" #include "aztec3/circuits/apps/test_apps/basic_contract_deployment/basic_contract_deployment.hpp" #include "aztec3/circuits/apps/test_apps/escrow/deposit.hpp" +#include "aztec3/circuits/hash.hpp" #include "aztec3/circuits/kernel/private/init.hpp" #include "aztec3/constants.hpp" #include "aztec3/utils/circuit_errors.hpp" @@ -16,9 +17,9 @@ namespace aztec3::circuits::kernel::private_kernel { +using aztec3::circuits::silo_nullifier; using aztec3::circuits::apps::test_apps::basic_contract_deployment::constructor; using aztec3::circuits::apps::test_apps::escrow::deposit; - using aztec3::circuits::kernel::private_kernel::testing_harness::do_private_call_get_kernel_inputs_init; using aztec3::circuits::kernel::private_kernel::testing_harness::get_random_reads; using aztec3::circuits::kernel::private_kernel::testing_harness::validate_deployed_contract_address; @@ -307,7 +308,12 @@ TEST_F(native_private_kernel_init_tests, native_read_request_bad_request) auto const& contract_address = private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; - auto [read_requests, read_request_membership_witnesses, root] = get_random_reads(contract_address, 2); + auto const first_nullifier = silo_nullifier(contract_address, private_inputs.tx_request.hash()); + auto [read_requests, + read_request_membership_witnesses, + _transient_read_requests, + _transient_read_request_membership_witnesses, + root] = get_random_reads(first_nullifier, contract_address, 2); private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; // tweak read_request so it gives wrong root when paired with its sibling path @@ -336,7 +342,12 @@ TEST_F(native_private_kernel_init_tests, native_read_request_bad_leaf_index) auto const& contract_address = private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; - auto [read_requests, read_request_membership_witnesses, root] = get_random_reads(contract_address, 2); + auto const first_nullifier = silo_nullifier(contract_address, private_inputs.tx_request.hash()); + auto [read_requests, + read_request_membership_witnesses, + _transient_read_requests, + _transient_read_request_membership_witnesses, + root] = get_random_reads(first_nullifier, contract_address, 2); private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; // tweak leaf index so it gives wrong root when paired with its request and sibling path @@ -364,7 +375,12 @@ TEST_F(native_private_kernel_init_tests, native_read_request_bad_sibling_path) auto const& contract_address = private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; - auto [read_requests, read_request_membership_witnesses, root] = get_random_reads(contract_address, 2); + auto const first_nullifier = silo_nullifier(contract_address, private_inputs.tx_request.hash()); + auto [read_requests, + read_request_membership_witnesses, + _transient_read_requests, + _transient_read_request_membership_witnesses, + root] = get_random_reads(first_nullifier, contract_address, 2); private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; // tweak sibling path so it gives wrong root when paired with its request @@ -393,9 +409,18 @@ TEST_F(native_private_kernel_init_tests, native_read_request_root_mismatch) private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; // generate two random sets of read requests and mix them so their roots don't match - auto [read_requests0, read_request_membership_witnesses0, root] = get_random_reads(contract_address, 2); + auto const first_nullifier = silo_nullifier(contract_address, private_inputs.tx_request.hash()); + auto [read_requests0, + read_request_membership_witnesses0, + _transient_read_requests0, + _transient_read_request_membership_witnesses0, + root] = get_random_reads(first_nullifier, contract_address, 2); private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; - auto [read_requests1, read_request_membership_witnesses1, _root] = get_random_reads(contract_address, 2); + auto [read_requests1, + read_request_membership_witnesses1, + _transient_read_requests1, + _transient_read_request_membership_witnesses1, + _root] = get_random_reads(first_nullifier, contract_address, 2); std::array bad_requests{}; std::array, MAX_READ_REQUESTS_PER_CALL> bad_witnesses; // note we are using read_requests0 for some and read_requests1 for others @@ -463,7 +488,12 @@ TEST_F(native_private_kernel_init_tests, native_one_read_requests_works) auto const& contract_address = private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; - auto [read_requests, read_request_membership_witnesses, root] = get_random_reads(contract_address, 1); + auto const first_nullifier = silo_nullifier(contract_address, private_inputs.tx_request.hash()); + auto [read_requests, + read_request_membership_witnesses, + _transient_read_requests, + _transient_read_request_membership_witnesses, + root] = get_random_reads(first_nullifier, contract_address, 1); private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.read_requests = read_requests; private_inputs.private_call.read_request_membership_witnesses = read_request_membership_witnesses; @@ -495,7 +525,12 @@ TEST_F(native_private_kernel_init_tests, native_two_read_requests_works) auto const& contract_address = private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; - auto [read_requests, read_request_membership_witnesses, root] = get_random_reads(contract_address, 2); + auto const first_nullifier = silo_nullifier(contract_address, private_inputs.tx_request.hash()); + auto [read_requests, + read_request_membership_witnesses, + _transient_read_requests, + _transient_read_request_membership_witnesses, + root] = get_random_reads(first_nullifier, contract_address, 2); private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.read_requests = read_requests; private_inputs.private_call.read_request_membership_witnesses = read_request_membership_witnesses; @@ -527,8 +562,12 @@ TEST_F(native_private_kernel_init_tests, native_max_read_requests_works) auto const& contract_address = private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; - auto [read_requests, read_request_membership_witnesses, root] = - get_random_reads(contract_address, MAX_READ_REQUESTS_PER_CALL); + auto const first_nullifier = silo_nullifier(contract_address, private_inputs.tx_request.hash()); + auto [read_requests, + read_request_membership_witnesses, + _transient_read_requests, + _transient_read_request_membership_witnesses, + root] = get_random_reads(first_nullifier, contract_address, MAX_READ_REQUESTS_PER_CALL); private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.read_requests = read_requests; private_inputs.private_call.read_request_membership_witnesses = read_request_membership_witnesses; @@ -562,8 +601,12 @@ TEST_F(native_private_kernel_init_tests, native_read_requests_less_than_witnesse auto const& contract_address = private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; - auto [read_requests, read_request_membership_witnesses, root] = - get_random_reads(contract_address, MAX_READ_REQUESTS_PER_CALL); + auto const first_nullifier = silo_nullifier(contract_address, private_inputs.tx_request.hash()); + auto [read_requests, + read_request_membership_witnesses, + _transient_read_requests, + _transient_read_request_membership_witnesses, + root] = get_random_reads(first_nullifier, contract_address, MAX_READ_REQUESTS_PER_CALL); read_requests[MAX_READ_REQUESTS_PER_CALL - 1] = fr(0); private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; @@ -585,8 +628,12 @@ TEST_F(native_private_kernel_init_tests, native_read_requests_more_than_witnesse auto const& contract_address = private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; - auto [read_requests, read_request_membership_witnesses, root] = - get_random_reads(contract_address, MAX_READ_REQUESTS_PER_CALL); + auto const first_nullifier = silo_nullifier(contract_address, private_inputs.tx_request.hash()); + auto [read_requests, + read_request_membership_witnesses, + _transient_read_requests, + _transient_read_request_membership_witnesses, + root] = get_random_reads(first_nullifier, contract_address, MAX_READ_REQUESTS_PER_CALL); read_request_membership_witnesses[MAX_READ_REQUESTS_PER_CALL - 1] = ReadRequestMembershipWitness{}; @@ -612,14 +659,18 @@ TEST_F(native_private_kernel_init_tests, native_one_transient_read_requests_work auto const& contract_address = private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; - auto [read_requests, read_request_membership_witnesses, root] = get_random_reads(contract_address, 1); + auto const first_nullifier = silo_nullifier(contract_address, private_inputs.tx_request.hash()); + auto [read_requests, + read_request_membership_witnesses, + transient_read_requests, + transient_read_request_membership_witnesses, + root] = get_random_reads(first_nullifier, contract_address, 1); private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; - private_inputs.private_call.call_stack_item.public_inputs.read_requests = read_requests; // Make the read request transient - read_request_membership_witnesses[0].leaf_index = NT::fr(0); - read_request_membership_witnesses[0].sibling_path = std::array{}; - read_request_membership_witnesses[0].is_transient = true; + read_requests[0] = transient_read_requests[0]; + read_request_membership_witnesses[0] = transient_read_request_membership_witnesses[0]; + private_inputs.private_call.call_stack_item.public_inputs.read_requests = read_requests; private_inputs.private_call.read_request_membership_witnesses = read_request_membership_witnesses; DummyBuilder builder = DummyBuilder("native_private_kernel_init_tests__native_one_transient_read_requests_works"); @@ -646,15 +697,18 @@ TEST_F(native_private_kernel_init_tests, native_max_read_requests_one_transient_ auto const& contract_address = private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; - auto [read_requests, read_request_membership_witnesses, root] = - get_random_reads(contract_address, MAX_READ_REQUESTS_PER_CALL); + auto const first_nullifier = silo_nullifier(contract_address, private_inputs.tx_request.hash()); + auto [read_requests, + read_request_membership_witnesses, + transient_read_requests, + transient_read_request_membership_witnesses, + root] = get_random_reads(first_nullifier, contract_address, MAX_READ_REQUESTS_PER_CALL); private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.read_requests = read_requests; // Make the read request at position 1 transient - read_request_membership_witnesses[1].leaf_index = NT::fr(0); - read_request_membership_witnesses[1].sibling_path = std::array{}; - read_request_membership_witnesses[1].is_transient = true; + read_requests[1] = transient_read_requests[1]; + read_request_membership_witnesses[1] = transient_read_request_membership_witnesses[1]; private_inputs.private_call.read_request_membership_witnesses = read_request_membership_witnesses; DummyBuilder builder = @@ -681,19 +735,15 @@ TEST_F(native_private_kernel_init_tests, native_max_read_requests_all_transient_ auto const& contract_address = private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; - auto [read_requests, read_request_membership_witnesses, root] = - get_random_reads(contract_address, MAX_READ_REQUESTS_PER_CALL); + auto const first_nullifier = silo_nullifier(contract_address, private_inputs.tx_request.hash()); + auto [read_requests, + read_request_membership_witnesses, + transient_read_requests, + transient_read_request_membership_witnesses, + root] = get_random_reads(first_nullifier, contract_address, MAX_READ_REQUESTS_PER_CALL); private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; - private_inputs.private_call.call_stack_item.public_inputs.read_requests = read_requests; - - - // Make the read request at position 1 transient - for (size_t rr_idx = 0; rr_idx < MAX_READ_REQUESTS_PER_CALL; ++rr_idx) { - read_request_membership_witnesses[rr_idx].leaf_index = NT::fr(0); - read_request_membership_witnesses[rr_idx].sibling_path = std::array{}; - read_request_membership_witnesses[rr_idx].is_transient = true; - } - private_inputs.private_call.read_request_membership_witnesses = read_request_membership_witnesses; + private_inputs.private_call.call_stack_item.public_inputs.read_requests = transient_read_requests; + private_inputs.private_call.read_request_membership_witnesses = transient_read_request_membership_witnesses; DummyBuilder builder = DummyBuilder("native_private_kernel_init_tests__native_max_read_requests_all_transient_works"); diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_inner.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_inner.cpp index 38de771f1c6..12c6e707e98 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_inner.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_inner.cpp @@ -5,20 +5,52 @@ #include "aztec3/circuits/abis/new_contract_data.hpp" #include "aztec3/circuits/abis/previous_kernel_data.hpp" #include "aztec3/circuits/abis/private_kernel/private_kernel_inputs_inner.hpp" -#include "aztec3/constants.hpp" #include "aztec3/utils/array.hpp" #include "aztec3/utils/dummy_circuit_builder.hpp" -namespace aztec3::circuits::kernel::private_kernel { +namespace { +using NT = aztec3::utils::types::NativeTypes; using aztec3::circuits::abis::ContractLeafPreimage; using aztec3::circuits::abis::KernelCircuitPublicInputs; +using aztec3::circuits::abis::PreviousKernelData; using aztec3::circuits::abis::private_kernel::PrivateKernelInputsInner; - using aztec3::utils::array_length; using aztec3::utils::array_pop; -using DummyBuilder = aztec3::utils::DummyCircuitBuilder; -using CircuitErrorCode = aztec3::utils::CircuitErrorCode; +using aztec3::utils::CircuitErrorCode; +using aztec3::utils::DummyCircuitBuilder; + + +void initialise_end_values(PreviousKernelData const& previous_kernel, KernelCircuitPublicInputs& public_inputs) +{ + public_inputs.constants = previous_kernel.public_inputs.constants; + + // Ensure the arrays are the same as previously, before we start pushing more data onto them in other + // functions within this circuit: + auto& end = public_inputs.end; + const auto& start = previous_kernel.public_inputs.end; + + end.new_commitments = start.new_commitments; + end.new_nullifiers = start.new_nullifiers; + + end.private_call_stack = start.private_call_stack; + end.public_call_stack = start.public_call_stack; + end.new_l2_to_l1_msgs = start.new_l2_to_l1_msgs; + + end.encrypted_logs_hash = start.encrypted_logs_hash; + end.unencrypted_logs_hash = start.unencrypted_logs_hash; + + end.encrypted_log_preimages_length = start.encrypted_log_preimages_length; + end.unencrypted_log_preimages_length = start.unencrypted_log_preimages_length; + + end.optionally_revealed_data = start.optionally_revealed_data; + + end.read_requests = start.read_requests; + end.read_request_membership_witnesses = start.read_request_membership_witnesses; +} +} // namespace + +namespace aztec3::circuits::kernel::private_kernel { // using plonk::stdlib::merkle_tree:: @@ -41,21 +73,8 @@ using CircuitErrorCode = aztec3::utils::CircuitErrorCode; // return aggregation_object; // } -void initialise_end_values(PreviousKernelData const& previous_kernel, KernelCircuitPublicInputs& public_inputs) -{ - common_inner_ordering_initialise_end_values(previous_kernel, public_inputs); - // Ensure the arrays are the same as previously, before we start pushing more data onto them in other - // functions within this circuit: - auto& end = public_inputs.end; - const auto& start = previous_kernel.public_inputs.end; - - end.read_requests = start.read_requests; - end.read_request_membership_witnesses = start.read_request_membership_witnesses; -} - - -void validate_this_private_call_hash(DummyBuilder& builder, +void validate_this_private_call_hash(DummyCircuitBuilder& builder, PrivateKernelInputsInner const& private_inputs, KernelCircuitPublicInputs& public_inputs) { @@ -74,7 +93,7 @@ void validate_this_private_call_hash(DummyBuilder& builder, CircuitErrorCode::PRIVATE_KERNEL__CALCULATED_PRIVATE_CALL_HASH_AND_PROVIDED_PRIVATE_CALL_HASH_MISMATCH); }; -void validate_contract_tree_root(DummyBuilder& builder, PrivateKernelInputsInner const& private_inputs) +void validate_contract_tree_root(DummyCircuitBuilder& builder, PrivateKernelInputsInner const& private_inputs) { auto const& purported_contract_tree_root = private_inputs.private_call.call_stack_item.public_inputs.historic_contract_tree_root; @@ -87,7 +106,7 @@ void validate_contract_tree_root(DummyBuilder& builder, PrivateKernelInputsInner CircuitErrorCode::PRIVATE_KERNEL__PURPORTED_CONTRACT_TREE_ROOT_AND_PREVIOUS_KERNEL_CONTRACT_TREE_ROOT_MISMATCH); } -void validate_inputs(DummyBuilder& builder, PrivateKernelInputsInner const& private_inputs) +void validate_inputs(DummyCircuitBuilder& builder, PrivateKernelInputsInner const& private_inputs) { const auto& this_call_stack_item = private_inputs.private_call.call_stack_item; @@ -114,12 +133,14 @@ void validate_inputs(DummyBuilder& builder, PrivateKernelInputsInner const& common_validate_previous_kernel_read_requests( builder, start.read_requests, start.read_request_membership_witnesses); + + // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1329): validate that 0th nullifier is nonzero } // NOTE: THIS IS A VERY UNFINISHED WORK IN PROGRESS. // TODO(mike): is there a way to identify whether an input has not been used by ths circuit? This would help us // more-safely ensure we're constraining everything. -KernelCircuitPublicInputs native_private_kernel_circuit_inner(DummyBuilder& builder, +KernelCircuitPublicInputs native_private_kernel_circuit_inner(DummyCircuitBuilder& builder, PrivateKernelInputsInner const& private_inputs) { // We'll be pushing data to this during execution of this circuit. @@ -141,7 +162,6 @@ KernelCircuitPublicInputs native_private_kernel_circuit_inner(DummyBuilder& common_validate_read_requests( builder, - private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address, public_inputs.constants.historic_tree_roots.private_historic_tree_roots.private_data_tree_root, private_inputs.private_call.call_stack_item.public_inputs.read_requests, // read requests from private call private_inputs.private_call.read_request_membership_witnesses); diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_inner.test.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_inner.test.cpp index 3d737fa455e..03dcacd71e8 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_inner.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_inner.test.cpp @@ -247,7 +247,13 @@ TEST_F(native_private_kernel_inner_tests, native_read_request_bad_request) auto const& contract_address = private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; - auto [read_requests, read_request_membership_witnesses, root] = get_random_reads(contract_address, 2); + auto const first_nullifier = + silo_nullifier(contract_address, private_inputs.previous_kernel.public_inputs.end.new_nullifiers[0]); + auto [read_requests, + read_request_membership_witnesses, + _transient_read_requests, + _transient_read_request_membership_witnesses, + root] = get_random_reads(first_nullifier, contract_address, 2); private_inputs.previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots .private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; @@ -275,7 +281,13 @@ TEST_F(native_private_kernel_inner_tests, native_read_request_bad_leaf_index) auto const& contract_address = private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; - auto [read_requests, read_request_membership_witnesses, root] = get_random_reads(contract_address, 2); + auto const first_nullifier = + silo_nullifier(contract_address, private_inputs.previous_kernel.public_inputs.end.new_nullifiers[0]); + auto [read_requests, + read_request_membership_witnesses, + _transient_read_requests, + _transient_read_request_membership_witnesses, + root] = get_random_reads(first_nullifier, contract_address, 2); private_inputs.previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots .private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; @@ -302,7 +314,13 @@ TEST_F(native_private_kernel_inner_tests, native_read_request_bad_sibling_path) auto const& contract_address = private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; - auto [read_requests, read_request_membership_witnesses, root] = get_random_reads(contract_address, 2); + auto const first_nullifier = + silo_nullifier(contract_address, private_inputs.previous_kernel.public_inputs.end.new_nullifiers[0]); + auto [read_requests, + read_request_membership_witnesses, + _transient_read_requests, + _transient_read_request_membership_witnesses, + root] = get_random_reads(first_nullifier, contract_address, 2); private_inputs.previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots .private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; @@ -330,11 +348,21 @@ TEST_F(native_private_kernel_inner_tests, native_read_request_root_mismatch) private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; // generate two random sets of read requests and mix them so their roots don't match - auto [read_requests0, read_request_membership_witnesses0, root] = get_random_reads(contract_address, 2); + auto const first_nullifier = + silo_nullifier(contract_address, private_inputs.previous_kernel.public_inputs.end.new_nullifiers[0]); + auto [read_requests0, + read_request_membership_witnesses0, + _transient_read_requests0, + _transient_read_request_membership_witnesses0, + root] = get_random_reads(first_nullifier, contract_address, 2); private_inputs.previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots .private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; - auto [read_requests1, read_request_membership_witnesses1, _root] = get_random_reads(contract_address, 2); + auto [read_requests1, + read_request_membership_witnesses1, + _transient_read_requests1, + _transient_read_request_membership_witnesses1, + _root] = get_random_reads(first_nullifier, contract_address, 2); std::array bad_requests{}; std::array, MAX_READ_REQUESTS_PER_CALL> bad_witnesses; // note we are using read_requests0 for some and read_requests1 for others @@ -396,7 +424,13 @@ TEST_F(native_private_kernel_inner_tests, native_one_read_requests_works) auto const& contract_address = private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; - auto [read_requests, read_request_membership_witnesses, root] = get_random_reads(contract_address, 1); + auto const first_nullifier = + silo_nullifier(contract_address, private_inputs.previous_kernel.public_inputs.end.new_nullifiers[0]); + auto [read_requests, + read_request_membership_witnesses, + _transient_read_requests, + _transient_read_request_membership_witnesses, + root] = get_random_reads(first_nullifier, contract_address, 1); private_inputs.previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots .private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; @@ -427,7 +461,13 @@ TEST_F(native_private_kernel_inner_tests, native_two_read_requests_works) auto const& contract_address = private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; - auto [read_requests, read_request_membership_witnesses, root] = get_random_reads(contract_address, 2); + auto const first_nullifier = + silo_nullifier(contract_address, private_inputs.previous_kernel.public_inputs.end.new_nullifiers[0]); + auto [read_requests, + read_request_membership_witnesses, + _transient_read_requests, + _transient_read_request_membership_witnesses, + root] = get_random_reads(first_nullifier, contract_address, 2); private_inputs.previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots .private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; @@ -458,8 +498,13 @@ TEST_F(native_private_kernel_inner_tests, native_max_read_requests_works) auto const& contract_address = private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; - auto [read_requests, read_request_membership_witnesses, root] = - get_random_reads(contract_address, MAX_READ_REQUESTS_PER_CALL); + auto const first_nullifier = + silo_nullifier(contract_address, private_inputs.previous_kernel.public_inputs.end.new_nullifiers[0]); + auto [read_requests, + read_request_membership_witnesses, + _transient_read_requests, + _transient_read_request_membership_witnesses, + root] = get_random_reads(first_nullifier, contract_address, MAX_READ_REQUESTS_PER_CALL); private_inputs.previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots .private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; @@ -488,8 +533,13 @@ TEST_F(native_private_kernel_inner_tests, native_read_requests_less_than_witness auto const& contract_address = private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; - auto [read_requests, read_request_membership_witnesses, root] = - get_random_reads(contract_address, MAX_READ_REQUESTS_PER_CALL); + auto const first_nullifier = + silo_nullifier(contract_address, private_inputs.previous_kernel.public_inputs.end.new_nullifiers[0]); + auto [read_requests, + read_request_membership_witnesses, + _transient_read_requests, + _transient_read_request_membership_witnesses, + root] = get_random_reads(first_nullifier, contract_address, MAX_READ_REQUESTS_PER_CALL); read_requests[MAX_READ_REQUESTS_PER_CALL - 1] = fr(0); private_inputs.previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots @@ -513,8 +563,13 @@ TEST_F(native_private_kernel_inner_tests, native_read_requests_more_than_witness auto const& contract_address = private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; - auto [read_requests, read_request_membership_witnesses, root] = - get_random_reads(contract_address, MAX_READ_REQUESTS_PER_CALL); + auto const first_nullifier = + silo_nullifier(contract_address, private_inputs.previous_kernel.public_inputs.end.new_nullifiers[0]); + auto [read_requests, + read_request_membership_witnesses, + _transient_read_requests, + _transient_read_request_membership_witnesses, + root] = get_random_reads(first_nullifier, contract_address, MAX_READ_REQUESTS_PER_CALL); read_request_membership_witnesses[MAX_READ_REQUESTS_PER_CALL - 1] = ReadRequestMembershipWitness{}; @@ -542,14 +597,19 @@ TEST_F(native_private_kernel_inner_tests, native_one_transient_read_requests_wor auto const& contract_address = private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; - auto [read_requests, read_request_membership_witnesses, root] = get_random_reads(contract_address, 1); + auto const first_nullifier = + silo_nullifier(contract_address, private_inputs.previous_kernel.public_inputs.end.new_nullifiers[0]); + auto [read_requests, + read_request_membership_witnesses, + transient_read_requests, + transient_read_request_membership_witnesses, + root] = get_random_reads(first_nullifier, contract_address, 1); private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; - private_inputs.private_call.call_stack_item.public_inputs.read_requests = read_requests; // Make the read request transient - read_request_membership_witnesses[0].leaf_index = NT::fr(0); - read_request_membership_witnesses[0].sibling_path = std::array{}; - read_request_membership_witnesses[0].is_transient = true; + read_requests[0] = transient_read_requests[0]; + read_request_membership_witnesses[0] = transient_read_request_membership_witnesses[0]; + private_inputs.private_call.call_stack_item.public_inputs.read_requests = read_requests; private_inputs.private_call.read_request_membership_witnesses = read_request_membership_witnesses; DummyBuilder builder = DummyBuilder("native_private_kernel_inner_tests__native_one_transient_read_requests_works"); @@ -575,17 +635,21 @@ TEST_F(native_private_kernel_inner_tests, native_max_read_requests_one_transient auto const& contract_address = private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; - auto [read_requests, read_request_membership_witnesses, root] = - get_random_reads(contract_address, MAX_READ_REQUESTS_PER_CALL); + auto const first_nullifier = + silo_nullifier(contract_address, private_inputs.previous_kernel.public_inputs.end.new_nullifiers[0]); + auto [read_requests, + read_request_membership_witnesses, + transient_read_requests, + transient_read_request_membership_witnesses, + root] = get_random_reads(first_nullifier, contract_address, MAX_READ_REQUESTS_PER_CALL); private_inputs.previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots .private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; - private_inputs.private_call.call_stack_item.public_inputs.read_requests = read_requests; // Make the read request at position 1 transient - read_request_membership_witnesses[1].leaf_index = NT::fr(0); - read_request_membership_witnesses[1].sibling_path = std::array{}; - read_request_membership_witnesses[1].is_transient = true; + read_requests[1] = transient_read_requests[1]; + read_request_membership_witnesses[1] = transient_read_request_membership_witnesses[1]; + private_inputs.private_call.call_stack_item.public_inputs.read_requests = read_requests; private_inputs.private_call.read_request_membership_witnesses = read_request_membership_witnesses; DummyBuilder builder = @@ -613,20 +677,18 @@ TEST_F(native_private_kernel_inner_tests, native_max_read_requests_all_transient auto const& contract_address = private_inputs.private_call.call_stack_item.public_inputs.call_context.storage_contract_address; - auto [read_requests, read_request_membership_witnesses, root] = - get_random_reads(contract_address, MAX_READ_REQUESTS_PER_CALL); + auto const first_nullifier = + silo_nullifier(contract_address, private_inputs.previous_kernel.public_inputs.end.new_nullifiers[0]); + auto [read_requests, + read_request_membership_witnesses, + transient_read_requests, + transient_read_request_membership_witnesses, + root] = get_random_reads(first_nullifier, contract_address, MAX_READ_REQUESTS_PER_CALL); private_inputs.previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots .private_data_tree_root = root; private_inputs.private_call.call_stack_item.public_inputs.historic_private_data_tree_root = root; - private_inputs.private_call.call_stack_item.public_inputs.read_requests = read_requests; - - // Make the read request at position 1 transient - for (size_t rr_idx = 0; rr_idx < MAX_READ_REQUESTS_PER_CALL; ++rr_idx) { - read_request_membership_witnesses[rr_idx].leaf_index = NT::fr(0); - read_request_membership_witnesses[rr_idx].sibling_path = std::array{}; - read_request_membership_witnesses[rr_idx].is_transient = true; - } - private_inputs.private_call.read_request_membership_witnesses = read_request_membership_witnesses; + private_inputs.private_call.call_stack_item.public_inputs.read_requests = transient_read_requests; + private_inputs.private_call.read_request_membership_witnesses = transient_read_request_membership_witnesses; DummyBuilder builder = DummyBuilder("native_private_kernel_inner_tests__native_max_read_requests_one_transient_works"); diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_ordering.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_ordering.cpp index 1e65a349b31..cd4a0d37c24 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_ordering.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_ordering.cpp @@ -3,6 +3,7 @@ #include "aztec3/circuits/abis/kernel_circuit_public_inputs.hpp" #include "aztec3/circuits/abis/previous_kernel_data.hpp" +#include "aztec3/circuits/hash.hpp" #include "aztec3/constants.hpp" #include "aztec3/utils/array.hpp" #include "aztec3/utils/circuit_errors.hpp" @@ -10,24 +11,54 @@ #include -namespace aztec3::circuits::kernel::private_kernel { +namespace { +using NT = aztec3::utils::types::NativeTypes; using aztec3::circuits::abis::KernelCircuitPublicInputs; using aztec3::circuits::abis::PreviousKernelData; - using aztec3::utils::array_length; -using DummyBuilder = aztec3::utils::DummyCircuitBuilder; -using CircuitErrorCode = aztec3::utils::CircuitErrorCode; +using aztec3::utils::CircuitErrorCode; +using aztec3::utils::DummyCircuitBuilder; + +void initialise_end_values(PreviousKernelData const& previous_kernel, KernelCircuitPublicInputs& public_inputs) +{ + public_inputs.constants = previous_kernel.public_inputs.constants; + + // Ensure the arrays are the same as previously, before we start pushing more data onto them in other + // functions within this circuit: + auto& end = public_inputs.end; + const auto& start = previous_kernel.public_inputs.end; + + // NOTE: don't forward new_commitments as the nonce must be applied + // end.new_commitments = start.new_commitments; + end.new_nullifiers = start.new_nullifiers; + + end.private_call_stack = start.private_call_stack; + end.public_call_stack = start.public_call_stack; + end.new_l2_to_l1_msgs = start.new_l2_to_l1_msgs; + + end.encrypted_logs_hash = start.encrypted_logs_hash; + end.unencrypted_logs_hash = start.unencrypted_logs_hash; + + end.encrypted_log_preimages_length = start.encrypted_log_preimages_length; + end.unencrypted_log_preimages_length = start.unencrypted_log_preimages_length; + + end.optionally_revealed_data = start.optionally_revealed_data; +} +} // namespace + + +namespace aztec3::circuits::kernel::private_kernel { // TODO(https://github.com/AztecProtocol/aztec-packages/issues/892): optimized based on hints // regarding matching a read request to a commitment // i.e., we get pairs i,j such that read_requests[i] == new_commitments[j] -void match_reads_to_commitments(DummyBuilder& builder, +void match_reads_to_commitments(DummyCircuitBuilder& builder, std::array const& read_requests, std::array, MAX_READ_REQUESTS_PER_TX> const& read_request_membership_witnesses, - std::array& new_commitments) + std::array const& new_commitments) { // Arrays read_request and read_request_membership_witnesses must be of the same length. Otherwise, // we might get into trouble when accumulating them in public_inputs.end @@ -103,7 +134,7 @@ void match_reads_to_commitments(DummyBuilder& builder, // regarding matching a nullifier to a commitment // i.e., we get pairs i,j such that new_nullifiers[i] == new_commitments[j] // void match_nullifiers_to_commitments_and_squash( -// DummyBuilder& builder, +// DummyCircuitBuilder& builder, // std::array& new_nullifiers, // // std::array const& nullifier_hints, // ??? // std::array& new_commitments) @@ -148,14 +179,29 @@ void match_reads_to_commitments(DummyBuilder& builder, // array_rearrange(new_nullifiers); //} -KernelCircuitPublicInputs native_private_kernel_circuit_ordering(DummyBuilder& builder, +void apply_commitment_nonces(NT::fr const& first_nullifier, + std::array const& siloed_commitments, + std::array& unique_siloed_commitments) +{ + for (size_t c_idx = 0; c_idx < MAX_NEW_COMMITMENTS_PER_TX; c_idx++) { + // Apply nonce to all non-zero/non-empty commitments + // Nonce is the hash of the first (0th) nullifier and the commitment's index into new_commitments array + const auto nonce = compute_commitment_nonce(first_nullifier, c_idx); + unique_siloed_commitments[c_idx] = + siloed_commitments[c_idx] == 0 ? 0 : compute_unique_commitment(nonce, siloed_commitments[c_idx]); + } +} + +KernelCircuitPublicInputs native_private_kernel_circuit_ordering(DummyCircuitBuilder& builder, PreviousKernelData const& previous_kernel) { // We'll be pushing data to this during execution of this circuit. KernelCircuitPublicInputs public_inputs{}; // Do this before any functions can modify the inputs. - common_inner_ordering_initialise_end_values(previous_kernel, public_inputs); + initialise_end_values(previous_kernel, public_inputs); + + // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1329): validate that 0th nullifier is nonzero common_validate_previous_kernel_read_requests(builder, previous_kernel.public_inputs.end.read_requests, @@ -168,7 +214,7 @@ KernelCircuitPublicInputs native_private_kernel_circuit_ordering(DummyBuilde match_reads_to_commitments(builder, previous_kernel.public_inputs.end.read_requests, previous_kernel.public_inputs.end.read_request_membership_witnesses, - public_inputs.end.new_commitments); + previous_kernel.public_inputs.end.new_commitments); // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1074): ideally final public_inputs // shouldn't even include read_requests and read_request_membership_witnesses as they should be empty. @@ -182,6 +228,10 @@ KernelCircuitPublicInputs native_private_kernel_circuit_ordering(DummyBuilde // // public_inputs.end.nullifier_hints, // public_inputs.end.new_commitments); + apply_commitment_nonces(previous_kernel.public_inputs.end.new_nullifiers[0], + previous_kernel.public_inputs.end.new_commitments, + public_inputs.end.new_commitments); + return public_inputs; }; diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_ordering.test.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_ordering.test.cpp index 651ce656994..b66249b00c3 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_ordering.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_ordering.test.cpp @@ -2,6 +2,7 @@ #include "aztec3/circuits/apps/test_apps/escrow/deposit.hpp" #include "aztec3/constants.hpp" +#include "aztec3/utils/array.hpp" #include "aztec3/utils/circuit_errors.hpp" #include "barretenberg/ecc/curves/bn254/fr.hpp" @@ -33,16 +34,26 @@ TEST_F(native_private_kernel_ordering_tests, native_matching_one_read_request_to { auto private_inputs = do_private_call_get_kernel_inputs_inner(false, deposit, standard_test_args()); - std::array new_commitments{}; + std::array new_nullifiers{}; + std::array siloed_commitments{}; + std::array unique_siloed_commitments{}; std::array read_requests{}; std::array, MAX_READ_REQUESTS_PER_TX> read_request_membership_witnesses{}; - new_commitments[0] = fr(1282); - read_requests[0] = fr(1282); + new_nullifiers[0] = NT::fr::random_element(); + siloed_commitments[0] = NT::fr::random_element(); // create random commitment + // ordering circuit applies nonces to commitments + const auto nonce = compute_commitment_nonce(new_nullifiers[0], 0); + unique_siloed_commitments[0] = + siloed_commitments[0] == 0 ? 0 : compute_unique_commitment(nonce, siloed_commitments[0]); + + read_requests[0] = siloed_commitments[0]; read_request_membership_witnesses[0].is_transient = true; - private_inputs.previous_kernel.public_inputs.end.new_commitments = new_commitments; + + private_inputs.previous_kernel.public_inputs.end.new_nullifiers = new_nullifiers; + private_inputs.previous_kernel.public_inputs.end.new_commitments = siloed_commitments; private_inputs.previous_kernel.public_inputs.end.read_requests = read_requests; private_inputs.previous_kernel.public_inputs.end.read_request_membership_witnesses = read_request_membership_witnesses; @@ -58,7 +69,7 @@ TEST_F(native_private_kernel_ordering_tests, native_matching_one_read_request_to } ASSERT_FALSE(builder.failed()); ASSERT_TRUE(array_length(public_inputs.end.new_commitments) == 1); - ASSERT_TRUE(public_inputs.end.new_commitments[0] == fr(1282)); + ASSERT_TRUE(public_inputs.end.new_commitments[0] == unique_siloed_commitments[0]); // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1074): read_request*s // can be removed from final public inputs ASSERT_TRUE(array_length(public_inputs.end.read_requests) == 0); @@ -69,23 +80,32 @@ TEST_F(native_private_kernel_ordering_tests, native_matching_some_read_requests_ { auto private_inputs = do_private_call_get_kernel_inputs_inner(false, deposit, standard_test_args()); - std::array new_commitments{}; + std::array new_nullifiers{}; + std::array siloed_commitments{}; + std::array unique_siloed_commitments{}; std::array read_requests{}; std::array, MAX_READ_REQUESTS_PER_TX> read_request_membership_witnesses{}; - new_commitments[0] = fr(1285); - new_commitments[1] = fr(1283); - new_commitments[2] = fr(1282); - new_commitments[3] = fr(1284); - + new_nullifiers[0] = NT::fr::random_element(); + const auto& first_nullifier = new_nullifiers[0]; + // create random commitments to input to ordering circuit, and compute their "unique" versions + // to be expected at the output + for (size_t c_idx = 0; c_idx < MAX_NEW_COMMITMENTS_PER_TX; c_idx++) { + siloed_commitments[c_idx] = NT::fr::random_element(); // create random commitment + // ordering circuit applies nonces to commitments + const auto nonce = compute_commitment_nonce(first_nullifier, c_idx); + unique_siloed_commitments[c_idx] = + siloed_commitments[c_idx] == 0 ? 0 : compute_unique_commitment(nonce, siloed_commitments[c_idx]); + } - read_requests[0] = fr(1283); - read_requests[1] = fr(1284); + read_requests[0] = siloed_commitments[1]; + read_requests[1] = siloed_commitments[3]; read_request_membership_witnesses[0].is_transient = true; read_request_membership_witnesses[1].is_transient = true; - private_inputs.previous_kernel.public_inputs.end.new_commitments = new_commitments; + private_inputs.previous_kernel.public_inputs.end.new_nullifiers = new_nullifiers; + private_inputs.previous_kernel.public_inputs.end.new_commitments = siloed_commitments; private_inputs.previous_kernel.public_inputs.end.read_requests = read_requests; private_inputs.previous_kernel.public_inputs.end.read_request_membership_witnesses = read_request_membership_witnesses; @@ -99,11 +119,11 @@ TEST_F(native_private_kernel_ordering_tests, native_matching_some_read_requests_ info("failure: ", failure); } ASSERT_FALSE(builder.failed()); - ASSERT_TRUE(array_length(public_inputs.end.new_commitments) == 4); - ASSERT_TRUE(public_inputs.end.new_commitments[0] == fr(1285)); - ASSERT_TRUE(public_inputs.end.new_commitments[1] == fr(1283)); - ASSERT_TRUE(public_inputs.end.new_commitments[2] == fr(1282)); - ASSERT_TRUE(public_inputs.end.new_commitments[3] == fr(1284)); + ASSERT_TRUE(array_length(public_inputs.end.new_commitments) == MAX_NEW_COMMITMENTS_PER_TX); + // ensure that commitments had nonce applied properly and all appear at output + for (size_t c_idx = 0; c_idx < MAX_NEW_COMMITMENTS_PER_TX; c_idx++) { + ASSERT_TRUE(public_inputs.end.new_commitments[c_idx] == unique_siloed_commitments[c_idx]); + } // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1074): read_request*s // can be removed from final public inputs ASSERT_TRUE(array_length(public_inputs.end.read_requests) == 0); @@ -114,32 +134,24 @@ TEST_F(native_private_kernel_ordering_tests, native_read_request_unknown_fails) { auto private_inputs = do_private_call_get_kernel_inputs_inner(false, deposit, standard_test_args()); - std::array new_commitments{}; + std::array siloed_commitments{}; std::array read_requests{}; std::array, MAX_READ_REQUESTS_PER_TX> read_request_membership_witnesses{}; - new_commitments[0] = fr(1285); - new_commitments[1] = fr(1283); - new_commitments[2] = fr(1282); - new_commitments[3] = fr(1284); - - - read_requests[0] = fr(1284); - read_requests[1] = fr(1282); - read_requests[2] = fr(1283); - read_requests[3] = fr(1286); - read_request_membership_witnesses[0].is_transient = true; - read_request_membership_witnesses[1].is_transient = true; - read_request_membership_witnesses[2].is_transient = true; - read_request_membership_witnesses[3].is_transient = true; + for (size_t c_idx = 0; c_idx < MAX_NEW_COMMITMENTS_PER_TX; c_idx++) { + siloed_commitments[c_idx] = NT::fr::random_element(); // create random commitment + read_requests[c_idx] = siloed_commitments[c_idx]; // create random read requests + // ^ will match each other! + read_request_membership_witnesses[c_idx].is_transient = true; // ordering circuit only allows transient reads + } + read_requests[3] = NT::fr::random_element(); // force one read request not to match - private_inputs.previous_kernel.public_inputs.end.new_commitments = new_commitments; + private_inputs.previous_kernel.public_inputs.end.new_commitments = siloed_commitments; private_inputs.previous_kernel.public_inputs.end.read_requests = read_requests; private_inputs.previous_kernel.public_inputs.end.read_request_membership_witnesses = read_request_membership_witnesses; - DummyBuilder builder = DummyBuilder("native_private_kernel_ordering_tests__native_read_request_unknown_fails"); native_private_kernel_circuit_ordering(builder, private_inputs.previous_kernel); @@ -151,18 +163,18 @@ TEST_F(native_private_kernel_ordering_tests, native_unresolved_non_transient_rea { auto private_inputs = do_private_call_get_kernel_inputs_inner(false, deposit, standard_test_args()); - std::array new_commitments{}; + std::array siloed_commitments{}; std::array read_requests{}; std::array, MAX_READ_REQUESTS_PER_TX> read_request_membership_witnesses{}; - new_commitments[0] = fr(1285); + siloed_commitments[0] = NT::fr::random_element(); - read_requests[0] = fr(1285); + read_requests[0] = siloed_commitments[0]; read_request_membership_witnesses[0].is_transient = false; // ordering circuit only allows transient reads - private_inputs.previous_kernel.public_inputs.end.new_commitments = new_commitments; + private_inputs.previous_kernel.public_inputs.end.new_commitments = siloed_commitments; private_inputs.previous_kernel.public_inputs.end.read_requests = read_requests; private_inputs.previous_kernel.public_inputs.end.read_request_membership_witnesses = read_request_membership_witnesses; diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/testing_harness.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/testing_harness.cpp index dc5d281d1bd..6889cdf6c9b 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/testing_harness.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/testing_harness.cpp @@ -47,18 +47,22 @@ using aztec3::utils::array_length; /** * @brief Get the random read requests and their membership requests * - * @details read requests are siloed by contract address before being + * @details read requests are siloed by contract address and nonce before being * inserted into mock private data tree * + * @param first_nullifier used when computing nonce for unique_siloed_commitments (private data tree leaves) * @param contract_address address to use when siloing read requests * @param num_read_requests if negative, use random num. Must be < MAX_READ_REQUESTS_PER_CALL * @return std::tuple */ std::tuple, + std::array, MAX_READ_REQUESTS_PER_CALL>, + std::array, std::array, MAX_READ_REQUESTS_PER_CALL>, NT::fr> -get_random_reads(NT::fr const& contract_address, int const num_read_requests) +get_random_reads(NT::fr const& first_nullifier, NT::fr const& contract_address, int const num_read_requests) { + std::array transient_read_requests{}; std::array read_requests{}; std::array leaves{}; @@ -69,8 +73,16 @@ get_random_reads(NT::fr const& contract_address, int const num_read_requests) // randomize private app circuit's read requests for (size_t rr = 0; rr < final_num_rr; rr++) { // randomize commitment and its leaf index - read_requests[rr] = NT::fr::random_element(); - leaves[rr] = silo_commitment(contract_address, read_requests[rr]); + // transient read requests are raw (not siloed and not unique at input to kernel circuit) + transient_read_requests[rr] = NT::fr::random_element(); + + const auto siloed_commitment = silo_commitment(contract_address, read_requests[rr]); + const auto nonce = compute_commitment_nonce(first_nullifier, rr); + const auto unique_siloed_commitment = + siloed_commitment == 0 ? 0 : compute_unique_commitment(nonce, siloed_commitment); + + leaves[rr] = unique_siloed_commitment; + read_requests[rr] = unique_siloed_commitment; } // this set and the following loop lets us generate totally random leaf indices @@ -94,18 +106,31 @@ get_random_reads(NT::fr const& contract_address, int const num_read_requests) } // compute the merkle sibling paths for each request + std::array, MAX_READ_REQUESTS_PER_CALL> + transient_read_request_membership_witnesses{}; std::array, MAX_READ_REQUESTS_PER_CALL> read_request_membership_witnesses{}; for (size_t i = 0; i < array_length(read_requests); i++) { read_request_membership_witnesses[i] = { .leaf_index = NT::fr(rr_leaf_indices[i]), .sibling_path = get_sibling_path( private_data_tree, rr_leaf_indices[i], 0), + .is_transient = false, .hint_to_commitment = 0 }; + transient_read_request_membership_witnesses[i] = { + .leaf_index = NT::fr(0), + .sibling_path = compute_empty_sibling_path(0), + .is_transient = true, + .hint_to_commitment = 0 + }; } - return { read_requests, read_request_membership_witnesses, private_data_tree.root() }; -} + return { read_requests, + read_request_membership_witnesses, + transient_read_requests, + transient_read_request_membership_witnesses, + private_data_tree.root() }; +} // namespace aztec3::circuits::kernel::private_kernel::testing_harness std::pair, ContractDeploymentData> create_private_call_deploy_data( bool const is_constructor, diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/testing_harness.hpp b/circuits/cpp/src/aztec3/circuits/kernel/private/testing_harness.hpp index 3efa81b6757..37618d7571b 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/testing_harness.hpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/testing_harness.hpp @@ -9,6 +9,7 @@ #include "aztec3/circuits/abis/private_kernel/private_kernel_inputs_init.hpp" #include "aztec3/circuits/abis/private_kernel/private_kernel_inputs_inner.hpp" #include "aztec3/circuits/abis/read_request_membership_witness.hpp" +#include "aztec3/circuits/abis/tx_request.hpp" #include "aztec3/circuits/hash.hpp" #include "aztec3/circuits/kernel/private/common.hpp" #include "aztec3/circuits/kernel/private/utils.hpp" @@ -27,6 +28,7 @@ using aztec3::circuits::abis::KernelCircuitPublicInputs; using aztec3::circuits::abis::NewContractData; using aztec3::circuits::abis::OptionalPrivateCircuitPublicInputs; using aztec3::circuits::abis::ReadRequestMembershipWitness; +using aztec3::circuits::abis::TxRequest; using aztec3::circuits::abis::private_kernel::PrivateCallData; using aztec3::circuits::abis::private_kernel::PrivateKernelInputsInit; using aztec3::circuits::abis::private_kernel::PrivateKernelInputsInner; @@ -74,17 +76,27 @@ inline const auto& get_empty_contract_siblings() /** * @brief Get the random read requests and their membership requests * - * @details read requests are siloed by contract address before being + * @details read requests are siloed by contract address and nonce before being * inserted into mock private data tree * + * @param first_nullifier used when computing nonce for unique_siloed_commitments (private data tree leaves) * @param contract_address address to use when siloing read requests * @param num_read_requests if negative, use random num - * @return std::tuple + * @return tuple including read requests, their membership witnesses, their transient versions, and the + * private data tree root that contains all of these randomly created commitments at random leaf indices + * std::tuple< + * read_requests, + * read_request_memberships_witnesses, + * transient_read_requests, + * transient_read_request_memberships_witnesses, + * historic_private_data_tree_root> */ std::tuple, + std::array, MAX_READ_REQUESTS_PER_CALL>, + std::array, std::array, MAX_READ_REQUESTS_PER_CALL>, NT::fr> -get_random_reads(NT::fr const& contract_address, int num_read_requests); +get_random_reads(NT::fr const& first_nullifier, NT::fr const& contract_address, int num_read_requests); /** * @brief Create a private call deploy data object diff --git a/circuits/cpp/src/aztec3/circuits/kernel/public/.test.cpp b/circuits/cpp/src/aztec3/circuits/kernel/public/.test.cpp index 79189514a82..42aec0b1f35 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/public/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/public/.test.cpp @@ -28,7 +28,7 @@ #include namespace { -using DummyBuilder = aztec3::utils::DummyCircuitBuilder; +using DummyCircuitBuilder = aztec3::utils::DummyCircuitBuilder; using aztec3::circuits::abis::public_kernel::PublicKernelInputs; using NT = aztec3::utils::types::NativeTypes; using aztec3::circuits::abis::CallContext; diff --git a/circuits/cpp/src/aztec3/circuits/kernel/public/c_bind.cpp b/circuits/cpp/src/aztec3/circuits/kernel/public/c_bind.cpp index b15896d162d..ad9209f065b 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/public/c_bind.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/public/c_bind.cpp @@ -14,7 +14,7 @@ namespace { using Builder = UltraCircuitBuilder; using NT = aztec3::utils::types::NativeTypes; -using DummyBuilder = aztec3::utils::DummyCircuitBuilder; +using DummyCircuitBuilder = aztec3::utils::DummyCircuitBuilder; using aztec3::circuits::abis::KernelCircuitPublicInputs; using aztec3::circuits::abis::public_kernel::PublicKernelInputs; using aztec3::circuits::kernel::public_kernel::native_public_kernel_circuit_private_previous_kernel; diff --git a/circuits/cpp/src/aztec3/circuits/rollup/base/.test.cpp b/circuits/cpp/src/aztec3/circuits/rollup/base/.test.cpp index 32d59de3fa6..0df32971e66 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/.test.cpp @@ -52,7 +52,7 @@ using aztec3::circuits::abis::NewContractData; using aztec3::circuits::rollup::test_utils::utils::make_public_data_update_request; using aztec3::circuits::rollup::test_utils::utils::make_public_read; -using DummyBuilder = aztec3::utils::DummyCircuitBuilder; +using DummyCircuitBuilder = aztec3::utils::DummyCircuitBuilder; using aztec3::utils::CircuitErrorCode; } // namespace @@ -128,7 +128,7 @@ class base_rollup_tests : public ::testing::Test { TEST_F(base_rollup_tests, native_no_new_contract_leafs) { - DummyBuilder builder = DummyBuilder("base_rollup_tests__native_no_new_contract_leafs"); + DummyCircuitBuilder builder = DummyCircuitBuilder("base_rollup_tests__native_no_new_contract_leafs"); // When there are no contract deployments. The contract tree should be inserting 0 leafs, (not empty leafs); // Initially, the start_contract_tree_snapshot is empty (leaf is 0. hash it up). // Get sibling path of index 0 leaf (for circuit to check membership via sibling path) @@ -158,7 +158,7 @@ TEST_F(base_rollup_tests, native_no_new_contract_leafs) TEST_F(base_rollup_tests, native_contract_leaf_inserted) { - DummyBuilder builder = DummyBuilder("base_rollup_tests__native_contract_leaf_inserted"); + DummyCircuitBuilder builder = DummyCircuitBuilder("base_rollup_tests__native_contract_leaf_inserted"); // When there is a contract deployment, the contract tree should be inserting 1 leaf. // The remaining leafs should be 0 leafs, (not empty leafs); @@ -203,7 +203,8 @@ TEST_F(base_rollup_tests, native_contract_leaf_inserted) TEST_F(base_rollup_tests, native_contract_leaf_inserted_in_non_empty_snapshot_tree) { - DummyBuilder builder = DummyBuilder("base_rollup_tests__native_contract_leaf_inserted_in_non_empty_snapshot_tree"); + DummyCircuitBuilder builder = + DummyCircuitBuilder("base_rollup_tests__native_contract_leaf_inserted_in_non_empty_snapshot_tree"); // Same as before except our start_contract_snapshot_tree is not empty std::array, 2> kernel_data = { get_empty_kernel(), get_empty_kernel() }; @@ -258,7 +259,7 @@ TEST_F(base_rollup_tests, native_contract_leaf_inserted_in_non_empty_snapshot_tr TEST_F(base_rollup_tests, native_new_commitments_tree) { - DummyBuilder builder = DummyBuilder("base_rollup_tests__native_new_commitments_tree"); + DummyCircuitBuilder builder = DummyCircuitBuilder("base_rollup_tests__native_new_commitments_tree"); // Create 4 new mock commitments. Add them to kernel data. // Then get sibling path so we can verify insert them into the tree. @@ -338,7 +339,7 @@ TEST_F(base_rollup_tests, native_new_nullifier_tree_empty) /** * RUN */ - DummyBuilder builder = DummyBuilder("base_rollup_tests__native_new_nullifier_tree_empty"); + DummyCircuitBuilder builder = DummyCircuitBuilder("base_rollup_tests__native_new_nullifier_tree_empty"); std::array, 2> const kernel_data = { get_empty_kernel(), get_empty_kernel() }; BaseRollupInputs const empty_inputs = base_rollup_inputs_from_kernels(kernel_data); @@ -376,7 +377,7 @@ void nullifier_insertion_test(std::array new_ } auto end_nullifier_tree_snapshot = nullifier_tree.get_snapshot(); - DummyBuilder builder = DummyBuilder("base_rollup_tests__nullifier_insertion_test"); + DummyCircuitBuilder builder = DummyCircuitBuilder("base_rollup_tests__nullifier_insertion_test"); std::array, 2> kernel_data = { get_empty_kernel(), get_empty_kernel() }; for (uint8_t i = 0; i < 2; i++) { std::array kernel_nullifiers; @@ -441,7 +442,7 @@ TEST_F(base_rollup_tests, native_new_nullifier_tree_sparse) } auto expected_end_nullifier_tree_snapshot = nullifier_tree.get_snapshot(); - DummyBuilder builder = DummyBuilder("base_rollup_tests__native_new_nullifier_tree_sparse"); + DummyCircuitBuilder builder = DummyCircuitBuilder("base_rollup_tests__native_new_nullifier_tree_sparse"); BaseRollupInputs const empty_inputs = base_rollup_inputs_from_kernels({ get_empty_kernel(), get_empty_kernel() }); std::tuple, AppendOnlyTreeSnapshot> inputs_and_snapshots = test_utils::utils::generate_nullifier_tree_testing_values_explicit(empty_inputs, nullifiers, initial_values); @@ -470,7 +471,7 @@ TEST_F(base_rollup_tests, native_new_nullifier_tree_sparse) TEST_F(base_rollup_tests, native_nullifier_tree_regression) { // Regression test caught when testing the typescript nullifier tree implementation - DummyBuilder builder = DummyBuilder("base_rollup_tests__native_nullifier_tree_regression"); + DummyCircuitBuilder builder = DummyCircuitBuilder("base_rollup_tests__native_nullifier_tree_regression"); // This test runs after some data has already been inserted into the tree // This test will pre-populate the tree with 6 * KERNEL_NEW_NULLILFIERS_LENGTH values (0 item + 6 * @@ -549,7 +550,7 @@ TEST_F(base_rollup_tests, native_new_nullifier_tree_double_spend) * DESCRIPTION */ - DummyBuilder builder = DummyBuilder("base_rollup_tests__native_new_nullifier_tree_double_spend"); + DummyCircuitBuilder builder = DummyCircuitBuilder("base_rollup_tests__native_new_nullifier_tree_double_spend"); BaseRollupInputs const empty_inputs = base_rollup_inputs_from_kernels({ get_empty_kernel(), get_empty_kernel() }); fr const nullifier_to_insert = @@ -572,7 +573,7 @@ TEST_F(base_rollup_tests, native_new_nullifier_tree_double_spend) TEST_F(base_rollup_tests, native_empty_block_calldata_hash) { - DummyBuilder builder = DummyBuilder("base_rollup_tests__native_empty_block_calldata_hash"); + DummyCircuitBuilder builder = DummyCircuitBuilder("base_rollup_tests__native_empty_block_calldata_hash"); std::vector const zero_bytes_vec = test_utils::utils::get_empty_calldata_leaf(); auto expected_calldata_hash = sha256::sha256(zero_bytes_vec); BaseRollupInputs inputs = base_rollup_inputs_from_kernels({ get_empty_kernel(), get_empty_kernel() }); @@ -618,7 +619,7 @@ TEST_F(base_rollup_tests, native_calldata_hash) std::array const expected_calldata_hash = components::compute_kernels_calldata_hash(kernel_data); - DummyBuilder builder = DummyBuilder("base_rollup_tests__native_calldata_hash"); + DummyCircuitBuilder builder = DummyCircuitBuilder("base_rollup_tests__native_calldata_hash"); BaseRollupInputs inputs = base_rollup_inputs_from_kernels(kernel_data); BaseOrMergeRollupPublicInputs outputs = aztec3::circuits::rollup::native_base_rollup::base_rollup_circuit(builder, inputs); @@ -636,7 +637,8 @@ TEST_F(base_rollup_tests, native_compute_membership_historic_private_data_negati // WRITE a negative test that will fail the inclusion proof // Test membership works for empty trees - DummyBuilder builder = DummyBuilder("base_rollup_tests__native_compute_membership_historic_private_data_negative"); + DummyCircuitBuilder builder = + DummyCircuitBuilder("base_rollup_tests__native_compute_membership_historic_private_data_negative"); std::array, 2> const kernel_data = { get_empty_kernel(), get_empty_kernel() }; BaseRollupInputs inputs = base_rollup_inputs_from_kernels(kernel_data); @@ -667,7 +669,8 @@ TEST_F(base_rollup_tests, native_compute_membership_historic_private_data_negati TEST_F(base_rollup_tests, native_compute_membership_historic_contract_tree_negative) { // Test membership works for empty trees - DummyBuilder builder = DummyBuilder("base_rollup_tests__native_compute_membership_historic_contract_tree_negative"); + DummyCircuitBuilder builder = + DummyCircuitBuilder("base_rollup_tests__native_compute_membership_historic_contract_tree_negative"); std::array, 2> const kernel_data = { get_empty_kernel(), get_empty_kernel() }; BaseRollupInputs inputs = base_rollup_inputs_from_kernels(kernel_data); @@ -698,7 +701,7 @@ TEST_F(base_rollup_tests, native_compute_membership_historic_contract_tree_negat TEST_F(base_rollup_tests, native_constants_dont_change) { - DummyBuilder builder = DummyBuilder("base_rollup_tests__native_constants_dont_change"); + DummyCircuitBuilder builder = DummyCircuitBuilder("base_rollup_tests__native_constants_dont_change"); BaseRollupInputs inputs = base_rollup_inputs_from_kernels({ get_empty_kernel(), get_empty_kernel() }); BaseOrMergeRollupPublicInputs outputs = aztec3::circuits::rollup::native_base_rollup::base_rollup_circuit(builder, inputs); @@ -709,7 +712,7 @@ TEST_F(base_rollup_tests, native_constants_dont_change) TEST_F(base_rollup_tests, native_constants_dont_match_kernels_chain_id) { - DummyBuilder builder = DummyBuilder("base_rollup_tests__native_constants_dont_change"); + DummyCircuitBuilder builder = DummyCircuitBuilder("base_rollup_tests__native_constants_dont_change"); BaseRollupInputs inputs = base_rollup_inputs_from_kernels({ get_empty_kernel(), get_empty_kernel() }); inputs.constants.global_variables.chain_id = 3; BaseOrMergeRollupPublicInputs const outputs = @@ -721,7 +724,7 @@ TEST_F(base_rollup_tests, native_constants_dont_match_kernels_chain_id) TEST_F(base_rollup_tests, native_constants_dont_match_kernels_version) { - DummyBuilder builder = DummyBuilder("base_rollup_tests__native_constants_dont_change"); + DummyCircuitBuilder builder = DummyCircuitBuilder("base_rollup_tests__native_constants_dont_change"); BaseRollupInputs inputs = base_rollup_inputs_from_kernels({ get_empty_kernel(), get_empty_kernel() }); inputs.constants.global_variables.version = 3; BaseOrMergeRollupPublicInputs const outputs = @@ -734,7 +737,7 @@ TEST_F(base_rollup_tests, native_constants_dont_match_kernels_version) TEST_F(base_rollup_tests, native_aggregate) { // TODO(rahul): Fix this when aggregation works - DummyBuilder builder = DummyBuilder("base_rollup_tests__native_aggregate"); + DummyCircuitBuilder builder = DummyCircuitBuilder("base_rollup_tests__native_aggregate"); BaseRollupInputs inputs = base_rollup_inputs_from_kernels({ get_empty_kernel(), get_empty_kernel() }); BaseOrMergeRollupPublicInputs const outputs = aztec3::circuits::rollup::native_base_rollup::base_rollup_circuit(builder, inputs); @@ -745,7 +748,7 @@ TEST_F(base_rollup_tests, native_aggregate) TEST_F(base_rollup_tests, native_subtree_height_is_0) { - DummyBuilder builder = DummyBuilder("base_rollup_tests__native_subtree_height_is_0"); + DummyCircuitBuilder builder = DummyCircuitBuilder("base_rollup_tests__native_subtree_height_is_0"); BaseRollupInputs const inputs = base_rollup_inputs_from_kernels({ get_empty_kernel(), get_empty_kernel() }); BaseOrMergeRollupPublicInputs const outputs = aztec3::circuits::rollup::native_base_rollup::base_rollup_circuit(builder, inputs); @@ -763,7 +766,7 @@ TEST_F(base_rollup_tests, native_cbind_0) TEST_F(base_rollup_tests, native_single_public_state_read) { - DummyBuilder builder = DummyBuilder("base_rollup_tests__native_single_public_state_read"); + DummyCircuitBuilder builder = DummyCircuitBuilder("base_rollup_tests__native_single_public_state_read"); MemoryStore private_data_tree_store; MerkleTree private_data_tree(private_data_tree_store, PRIVATE_DATA_TREE_HEIGHT); @@ -798,7 +801,7 @@ TEST_F(base_rollup_tests, native_single_public_state_read) TEST_F(base_rollup_tests, native_single_public_state_write) { - DummyBuilder builder = DummyBuilder("base_rollup_tests__native_single_public_state_write"); + DummyCircuitBuilder builder = DummyCircuitBuilder("base_rollup_tests__native_single_public_state_write"); MemoryStore private_data_tree_store; MerkleTree private_data_tree(private_data_tree_store, PRIVATE_DATA_TREE_HEIGHT); @@ -836,7 +839,7 @@ TEST_F(base_rollup_tests, native_single_public_state_write) TEST_F(base_rollup_tests, native_multiple_public_state_read_writes) { - DummyBuilder builder = DummyBuilder("base_rollup_tests__native_multiple_public_state_read_writes"); + DummyCircuitBuilder builder = DummyCircuitBuilder("base_rollup_tests__native_multiple_public_state_read_writes"); MemoryStore private_data_tree_store; MerkleTree private_data_tree(private_data_tree_store, PRIVATE_DATA_TREE_HEIGHT); @@ -883,7 +886,7 @@ TEST_F(base_rollup_tests, native_multiple_public_state_read_writes) TEST_F(base_rollup_tests, native_invalid_public_state_read) { - DummyBuilder builder = DummyBuilder("base_rollup_tests__native_invalid_public_state_read"); + DummyCircuitBuilder builder = DummyCircuitBuilder("base_rollup_tests__native_invalid_public_state_read"); MemoryStore private_data_tree_store; MerkleTree private_data_tree(private_data_tree_store, PRIVATE_DATA_TREE_HEIGHT); diff --git a/circuits/cpp/src/aztec3/circuits/rollup/base/c_bind.cpp b/circuits/cpp/src/aztec3/circuits/rollup/base/c_bind.cpp index 0b20a881e40..21ee3283ccf 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/c_bind.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/c_bind.cpp @@ -13,7 +13,7 @@ namespace { using Builder = UltraCircuitBuilder; using NT = aztec3::utils::types::NativeTypes; -using DummyBuilder = aztec3::utils::DummyCircuitBuilder; +using DummyCircuitBuilder = aztec3::utils::DummyCircuitBuilder; using aztec3::circuits::abis::BaseOrMergeRollupPublicInputs; using aztec3::circuits::abis::BaseRollupInputs; using aztec3::circuits::rollup::native_base_rollup::base_rollup_circuit; @@ -51,7 +51,7 @@ WASM_EXPORT uint8_t* base_rollup__sim(uint8_t const* base_rollup_inputs_buf, size_t* base_rollup_public_inputs_size_out, uint8_t const** base_or_merge_rollup_public_inputs_buf) { - DummyBuilder builder = DummyBuilder("base_rollup__sim"); + DummyCircuitBuilder builder = DummyCircuitBuilder("base_rollup__sim"); // TODO accept proving key and use that to initialize builders // this info is just to prevent error for unused pk_buf // TODO do we want to accept it or just get it from our factory? diff --git a/circuits/cpp/src/aztec3/circuits/rollup/merge/.test.cpp b/circuits/cpp/src/aztec3/circuits/rollup/merge/.test.cpp index 2b5d04ada96..6a7bebc58b9 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/merge/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/merge/.test.cpp @@ -11,7 +11,7 @@ namespace { using aztec3::circuits::rollup::merge::MergeRollupInputs; -using DummyBuilder = aztec3::utils::DummyCircuitBuilder; +using DummyCircuitBuilder = aztec3::utils::DummyCircuitBuilder; using aztec3::circuits::rollup::test_utils::utils::compare_field_hash_to_expected; using aztec3::circuits::rollup::test_utils::utils::get_empty_kernel; diff --git a/circuits/cpp/src/aztec3/circuits/rollup/merge/c_bind.cpp b/circuits/cpp/src/aztec3/circuits/rollup/merge/c_bind.cpp index 9c1fd16a787..6f39a044c4b 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/merge/c_bind.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/merge/c_bind.cpp @@ -8,7 +8,7 @@ namespace { using NT = aztec3::utils::types::NativeTypes; -using DummyBuilder = aztec3::utils::DummyCircuitBuilder; +using DummyCircuitBuilder = aztec3::utils::DummyCircuitBuilder; using aztec3::circuits::abis::BaseOrMergeRollupPublicInputs; using aztec3::circuits::abis::MergeRollupInputs; using aztec3::circuits::rollup::merge::merge_rollup_circuit; @@ -21,7 +21,7 @@ WASM_EXPORT uint8_t* merge_rollup__sim(uint8_t const* merge_rollup_inputs_buf, size_t* merge_rollup_public_inputs_size_out, uint8_t const** merge_rollup_public_inputs_buf) { - DummyBuilder builder = DummyBuilder("merge_rollup__sim"); + DummyCircuitBuilder builder = DummyCircuitBuilder("merge_rollup__sim"); MergeRollupInputs merge_rollup_inputs; read(merge_rollup_inputs_buf, merge_rollup_inputs); diff --git a/circuits/cpp/src/aztec3/circuits/rollup/root/c_bind.cpp b/circuits/cpp/src/aztec3/circuits/rollup/root/c_bind.cpp index 9bc1e7b66f7..4ac89d01143 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/root/c_bind.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/root/c_bind.cpp @@ -11,7 +11,7 @@ namespace { using Builder = UltraCircuitBuilder; using NT = aztec3::utils::types::NativeTypes; -using DummyBuilder = aztec3::utils::DummyCircuitBuilder; +using DummyCircuitBuilder = aztec3::utils::DummyCircuitBuilder; using aztec3::circuits::rollup::native_root_rollup::root_rollup_circuit; using aztec3::circuits::rollup::native_root_rollup::RootRollupInputs; using aztec3::circuits::rollup::native_root_rollup::RootRollupPublicInputs; @@ -52,7 +52,7 @@ WASM_EXPORT uint8_t* root_rollup__sim(uint8_t const* root_rollup_inputs_buf, RootRollupInputs root_rollup_inputs; read(root_rollup_inputs_buf, root_rollup_inputs); - DummyBuilder builder = DummyBuilder("root_rollup__sim"); + DummyCircuitBuilder builder = DummyCircuitBuilder("root_rollup__sim"); RootRollupPublicInputs const public_inputs = root_rollup_circuit(builder, root_rollup_inputs); // serialize public inputs to bytes vec diff --git a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp index 13a7a58768f..e7ed21be531 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp @@ -22,7 +22,7 @@ using ConstantRollupData = aztec3::circuits::abis::ConstantRollupData; using BaseRollupInputs = aztec3::circuits::abis::BaseRollupInputs; using RootRollupInputs = aztec3::circuits::abis::RootRollupInputs; using RootRollupPublicInputs = aztec3::circuits::abis::RootRollupPublicInputs; -using DummyBuilder = aztec3::utils::DummyCircuitBuilder; +using DummyCircuitBuilder = aztec3::utils::DummyCircuitBuilder; using Aggregator = aztec3::circuits::recursion::Aggregator; using AppendOnlyTreeSnapshot = aztec3::circuits::abis::AppendOnlyTreeSnapshot; diff --git a/circuits/cpp/src/aztec3/constants.hpp b/circuits/cpp/src/aztec3/constants.hpp index 08ba3785f45..901cb4eb9fb 100644 --- a/circuits/cpp/src/aztec3/constants.hpp +++ b/circuits/cpp/src/aztec3/constants.hpp @@ -141,7 +141,7 @@ enum GeneratorIndex { COMMITMENT = 1, // Size = 7 (unused) COMMITMENT_NONCE, // Size = 2 UNIQUE_COMMITMENT, // Size = 2 - OUTER_COMMITMENT, // Size = 2 + SILOED_COMMITMENT, // Size = 2 NULLIFIER, // Size = 4 (unused) INITIALISATION_NULLIFIER, // Size = 2 (unused) OUTER_NULLIFIER, // Size = 2 diff --git a/docs/docs/aztec/protocol/trees/trees.mdx b/docs/docs/aztec/protocol/trees/trees.mdx index a4b675ea472..5264a72c6b0 100644 --- a/docs/docs/aztec/protocol/trees/trees.mdx +++ b/docs/docs/aztec/protocol/trees/trees.mdx @@ -51,10 +51,10 @@ note_hash: Field = pedersen::compress( The Private Kernel circuit will modify this `note_hash` further, before it is inserted into the tree. It will: -- Ensure uniqueness of the commitment, by hashing it with some new nullifier: - `unique_note_hash: Field = hash(note_hash, new_nullifier);` - Silo the commitment, to prevent cross-contamination of this contract's state variables with other contracts' state variables: - `siloed_note_hash: Field = hash(unique_note_hash, contract_address);` + `siloed_note_hash: Field = hash(note_hash, contract_address);` +- Ensure uniqueness of the commitment, by hashing it with a nonce + `unique_siloed_note_hash: Field = hash(siloed_note_hash, nonce);`, where `nonce: Field = hash(new_nullifiers[0], index)`, where `index` is the position of the new note hash in all new note hashes. > Note, all hashes will be appropriately domain-separated. diff --git a/yarn-project/acir-simulator/src/client/client_execution_context.ts b/yarn-project/acir-simulator/src/client/client_execution_context.ts index 2b7c150efc4..d2de01d5124 100644 --- a/yarn-project/acir-simulator/src/client/client_execution_context.ts +++ b/yarn-project/acir-simulator/src/client/client_execution_context.ts @@ -1,5 +1,4 @@ -import { CircuitsWasm, PrivateHistoricTreeRoots, ReadRequestMembershipWitness, TxContext } from '@aztec/circuits.js'; -import { computeCommitmentNonce } from '@aztec/circuits.js/abis'; +import { PrivateHistoricTreeRoots, ReadRequestMembershipWitness, TxContext } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr, Point } from '@aztec/foundation/fields'; import { createDebugLogger } from '@aztec/foundation/log'; @@ -132,7 +131,7 @@ export class ClientTxExecutionContext { const dbNotes = await this.db.getNotes(contractAddress, storageSlotField); // Remove notes which were already nullified during this transaction. - const dbNotesFiltered = dbNotes.filter(n => !this.pendingNullifiers.has(n.nullifier as Fr)); + const dbNotesFiltered = dbNotes.filter(n => !this.pendingNullifiers.has(n.siloedNullifier as Fr)); // Nullified pending notes are already removed from the list. const notes = pickNotes([...dbNotesFiltered, ...pendingNotes], { @@ -220,16 +219,13 @@ export class ClientTxExecutionContext { * @param contractAddress - The contract address. * @param storageSlot - The storage slot. * @param preimage - new note preimage. - * @param nullifier - note nullifier * @param innerNoteHash - inner note hash */ - public async pushNewNote(contractAddress: AztecAddress, storageSlot: Fr, preimage: Fr[], innerNoteHash: Fr) { - const wasm = await CircuitsWasm.get(); - const nonce = computeCommitmentNonce(wasm, this.txNullifier, this.pendingNotes.length); + public pushNewNote(contractAddress: AztecAddress, storageSlot: Fr, preimage: Fr[], innerNoteHash: Fr) { this.pendingNotes.push({ contractAddress, storageSlot: storageSlot, - nonce, + nonce: Fr.ZERO, // nonce is cannot be known during private execution preimage, innerNoteHash, }); @@ -238,10 +234,10 @@ export class ClientTxExecutionContext { /** * Adding a nullifier into the current set of all pending nullifiers created * within the current transaction/execution. - * @param nullifier - The pending nullifier to add in the list. + * @param innerNullifier - The pending nullifier to add in the list (not yet siloed by contract address). */ - public pushPendingNullifier(nullifier: Fr) { - this.pendingNullifiers.add(nullifier); + public pushNewNullifier(innerNullifier: Fr) { + this.pendingNullifiers.add(innerNullifier); } /** diff --git a/yarn-project/acir-simulator/src/client/db_oracle.ts b/yarn-project/acir-simulator/src/client/db_oracle.ts index 37a6270f579..73ef78d004f 100644 --- a/yarn-project/acir-simulator/src/client/db_oracle.ts +++ b/yarn-project/acir-simulator/src/client/db_oracle.ts @@ -19,7 +19,7 @@ export interface NoteData { /** The preimage of the note */ preimage: Fr[]; /** The corresponding nullifier of the note */ - nullifier?: Fr; + siloedNullifier?: Fr; /** The note's leaf index in the private data tree. Undefined for pending notes. */ index?: bigint; } diff --git a/yarn-project/acir-simulator/src/client/private_execution.test.ts b/yarn-project/acir-simulator/src/client/private_execution.test.ts index e61915b7a5a..0479739d780 100644 --- a/yarn-project/acir-simulator/src/client/private_execution.test.ts +++ b/yarn-project/acir-simulator/src/client/private_execution.test.ts @@ -17,7 +17,6 @@ import { computeCommitmentNonce, computeContractAddressFromPartial, computeSecretMessageHash, - computeTxHash, computeUniqueCommitment, siloCommitment, } from '@aztec/circuits.js/abis'; @@ -59,7 +58,6 @@ describe('Private Execution test suite', () => { let circuitsWasm: CircuitsWasm; let oracle: MockProxy; let acirSimulator: AcirSimulator; - let txNullifier: Fr; let historicRoots = PrivateHistoricTreeRoots.empty(); let logger: DebugLogger; @@ -104,8 +102,6 @@ describe('Private Execution test suite', () => { packedArguments: [packedArguments], }); - txNullifier = computeTxHash(circuitsWasm, txRequest.toTxRequest()); - return acirSimulator.run( txRequest, abi, @@ -166,14 +162,31 @@ describe('Private Execution test suite', () => { describe('zk token contract', () => { const contractAddress = defaultContractAddress; const recipientPk = PrivateKey.fromString('0c9ed344548e8f9ba8aa3c9f8651eaa2853130f6c1e9c050ccf198f7ea18a7ec'); + const mockFirstNullifier = new Fr(1111); let owner: AztecAddress; let recipient: AztecAddress; let currentNoteIndex = 0n; const buildNote = (amount: bigint, owner: AztecAddress, storageSlot = Fr.random()) => { - const nonce = new Fr(currentNoteIndex); + // WARNING: this is not actually how nonces are computed! + // For the purpose of this test we use a mocked firstNullifier and and a random number + // to compute the nonce. Proper nonces are only enforced later by the kernel/later circuits + // which are not relevant to this test. In practice, the kernel first squashes all transient + // noteHashes with their matching nullifiers. It then reorders the remaining "persistable" + // noteHashes. A TX's real first nullifier (generated by the initial kernel) and a noteHash's + // array index at the output of the final kernel/ordering circuit are used to derive nonce via: + // `hash(firstNullifier, noteHashIndex)` + const noteHashIndex = Math.floor(Math.random()); // mock index in TX's final newNoteHashes array + const nonce = computeCommitmentNonce(circuitsWasm, mockFirstNullifier, noteHashIndex); const preimage = [new Fr(amount), owner.toField(), Fr.random()]; - return { contractAddress, storageSlot, index: currentNoteIndex++, nonce, nullifier: new Fr(0), preimage }; + return { + contractAddress, + storageSlot, + nonce, + preimage, + siloedNullifier: new Fr(0), + index: currentNoteIndex++, + }; }; beforeEach(async () => { @@ -217,10 +230,10 @@ describe('Private Execution test suite', () => { const innerNoteHash = Fr.fromBuffer( pedersenPlookupCommitInputs(circuitsWasm, [storageSlot.toBuffer(), valueNoteHash]), ); - const uniqueNoteHash = computeUniqueCommitment(circuitsWasm, note.nonce, innerNoteHash); - const siloedNoteHash = siloCommitment(circuitsWasm, contractAddress, uniqueNoteHash); - const nullifier = Fr.fromBuffer( - pedersenPlookupCommitInputs(circuitsWasm, [siloedNoteHash.toBuffer(), ownerPk.value]), + const siloedNoteHash = siloCommitment(circuitsWasm, contractAddress, innerNoteHash); + const uniqueSiloedNoteHash = computeUniqueCommitment(circuitsWasm, note.nonce, siloedNoteHash); + const innerNullifier = Fr.fromBuffer( + pedersenPlookupCommitInputs(circuitsWasm, [uniqueSiloedNoteHash.toBuffer(), ownerPk.value]), ); const result = await acirSimulator.computeNoteHashAndNullifier( @@ -232,9 +245,9 @@ describe('Private Execution test suite', () => { expect(result).toEqual({ innerNoteHash, - uniqueNoteHash, siloedNoteHash, - nullifier, + uniqueSiloedNoteHash, + innerNullifier, }); }); @@ -294,7 +307,7 @@ describe('Private Execution test suite', () => { // The two notes were nullified const newNullifiers = result.callStackItem.publicInputs.newNullifiers.filter(field => !field.equals(Fr.ZERO)); - expect(newNullifiers).toEqual(consumedNotes.map(n => n.nullifier)); + expect(newNullifiers).toEqual(consumedNotes.map(n => n.innerNullifier)); expect(result.preimages.newNotes).toHaveLength(2); const [changeNote, recipientNote] = result.preimages.newNotes; @@ -315,7 +328,7 @@ describe('Private Execution test suite', () => { expect(changeNote.preimage[0]).toEqual(new Fr(40n)); const readRequests = result.callStackItem.publicInputs.readRequests.filter(field => !field.equals(Fr.ZERO)); - expect(readRequests).toEqual(consumedNotes.map(n => n.uniqueNoteHash)); + expect(readRequests).toEqual(consumedNotes.map(n => n.uniqueSiloedNoteHash)); }); it('should be able to transfer with dummy notes', async () => { @@ -337,7 +350,7 @@ describe('Private Execution test suite', () => { const result = await runSimulator({ args, abi }); const newNullifiers = result.callStackItem.publicInputs.newNullifiers.filter(field => !field.equals(Fr.ZERO)); - expect(newNullifiers).toEqual(consumedNotes.map(n => n.nullifier)); + expect(newNullifiers).toEqual(consumedNotes.map(n => n.innerNullifier)); expect(result.preimages.newNotes).toHaveLength(2); const [changeNote, recipientNote] = result.preimages.newNotes; @@ -350,7 +363,8 @@ describe('Private Execution test suite', () => { const secret = Fr.random(); const abi = ZkTokenContractAbi.functions.find(f => f.name === 'claim')!; const storageSlot = new Fr(2n); - const nonce = Fr.ZERO; + // choose nonzero nonce otherwise reads will be interpreted as transient (inner note hash instead of unique+siloed) + const nonce = new Fr(1n); oracle.getNotes.mockResolvedValue([ { @@ -358,7 +372,7 @@ describe('Private Execution test suite', () => { storageSlot, nonce, preimage: [new Fr(amount), secret], - nullifier: new Fr(0), + siloedNullifier: new Fr(0), index: 1n, }, ]); @@ -376,8 +390,9 @@ describe('Private Execution test suite', () => { const readRequests = result.callStackItem.publicInputs.readRequests.filter(field => !field.equals(Fr.ZERO)); const customNoteHash = hash([toBufferBE(amount, 32), secret.toBuffer()]); const innerNoteHash = Fr.fromBuffer(hash([storageSlot.toBuffer(), customNoteHash])); - const uniqueNoteHash = computeUniqueCommitment(circuitsWasm, nonce, innerNoteHash); - expect(readRequests).toEqual([uniqueNoteHash]); + const siloedNoteHash = siloCommitment(circuitsWasm, contractAddress, innerNoteHash); + const uniqueSiloedNoteHash = computeUniqueCommitment(circuitsWasm, nonce, siloedNoteHash); + expect(readRequests).toEqual([uniqueSiloedNoteHash]); }); }); @@ -504,7 +519,7 @@ describe('Private Execution test suite', () => { // Check the commitment read request was created successfully. const readRequests = result.callStackItem.publicInputs.readRequests.filter(field => !field.equals(Fr.ZERO)); expect(readRequests).toHaveLength(1); - expect(readRequests[0]).toEqual(commitment); + expect(readRequests[0]).toEqual(siloedCommitment); }); }); @@ -608,19 +623,19 @@ describe('Private Execution test suite', () => { const commitment = newCommitments[0]; const storageSlot = computeSlotForMapping(new Fr(1n), owner.toField(), circuitsWasm); - expect(commitment).toEqual(await acirSimulator.computeInnerNoteHash(contractAddress, storageSlot, note.preimage)); + const innerNoteHash = await acirSimulator.computeInnerNoteHash(contractAddress, storageSlot, note.preimage); + expect(commitment).toEqual(innerNoteHash); - // read request should match commitment - const nonce = computeCommitmentNonce(circuitsWasm, txNullifier, 0); + // read request should match innerNoteHash for pending notes (there is no nonce, so can't compute "unique" hash) const readRequest = result.callStackItem.publicInputs.readRequests[0]; - expect(readRequest).toEqual(computeUniqueCommitment(circuitsWasm, nonce, commitment)); + expect(readRequest).toEqual(innerNoteHash); const gotNoteValue = result.callStackItem.publicInputs.returnValues[0].value; expect(gotNoteValue).toEqual(amountToTransfer); const nullifier = result.callStackItem.publicInputs.newNullifiers[0]; expect(nullifier).toEqual( - await acirSimulator.computeNullifier(contractAddress, nonce, note.storageSlot, note.preimage), + await acirSimulator.computeInnerNullifier(contractAddress, Fr.ZERO, note.storageSlot, note.preimage), ); }); @@ -674,19 +689,20 @@ describe('Private Execution test suite', () => { const commitment = newCommitments[0]; const storageSlot = computeSlotForMapping(new Fr(1n), owner.toField(), circuitsWasm); - expect(commitment).toEqual(await acirSimulator.computeInnerNoteHash(contractAddress, storageSlot, note.preimage)); + const innerNoteHash = await acirSimulator.computeInnerNoteHash(contractAddress, storageSlot, note.preimage); + expect(commitment).toEqual(innerNoteHash); - // read request should match commitment - const nonce = computeCommitmentNonce(circuitsWasm, txNullifier, 0); + // read request should match innerNoteHash for pending notes (there is no nonce, so can't compute "unique" hash) const readRequest = execGetThenNullify.callStackItem.publicInputs.readRequests[0]; - expect(readRequest).toEqual(computeUniqueCommitment(circuitsWasm, nonce, commitment)); + expect(readRequest).toEqual(innerNoteHash); const gotNoteValue = execGetThenNullify.callStackItem.publicInputs.returnValues[0].value; expect(gotNoteValue).toEqual(amountToTransfer); + const nonce = Fr.ZERO; const nullifier = execGetThenNullify.callStackItem.publicInputs.newNullifiers[0]; expect(nullifier).toEqual( - await acirSimulator.computeNullifier(contractAddress, nonce, note.storageSlot, note.preimage), + await acirSimulator.computeInnerNullifier(contractAddress, nonce, note.storageSlot, note.preimage), ); // check that the last get_notes call return no note diff --git a/yarn-project/acir-simulator/src/client/private_execution.ts b/yarn-project/acir-simulator/src/client/private_execution.ts index 57fb3c34bc3..a0d26662409 100644 --- a/yarn-project/acir-simulator/src/client/private_execution.ts +++ b/yarn-project/acir-simulator/src/client/private_execution.ts @@ -76,8 +76,8 @@ export class PrivateFunctionExecution { getNotes: ([slot], sortBy, sortOrder, [limit], [offset], [returnSize]) => this.context.getNotes(this.contractAddress, slot, sortBy, sortOrder, +limit, +offset, +returnSize), getRandomField: () => Promise.resolve(toACVMField(Fr.random())), - notifyCreatedNote: async ([storageSlot], preimage, [innerNoteHash]) => { - await this.context.pushNewNote( + notifyCreatedNote: ([storageSlot], preimage, [innerNoteHash]) => { + this.context.pushNewNote( this.contractAddress, fromACVMField(storageSlot), preimage.map(f => fromACVMField(f)), @@ -90,7 +90,7 @@ export class PrivateFunctionExecution { storageSlot: fromACVMField(storageSlot), preimage: preimage.map(f => fromACVMField(f)), }); - return ZERO_ACVM_FIELD; + return Promise.resolve(ZERO_ACVM_FIELD); }, notifyNullifiedNote: ([slot], [nullifier], acvmPreimage, [innerNoteHash]) => { newNullifiers.push({ @@ -98,7 +98,7 @@ export class PrivateFunctionExecution { storageSlot: fromACVMField(slot), nullifier: fromACVMField(nullifier), }); - this.context.pushPendingNullifier(fromACVMField(nullifier)); + this.context.pushNewNullifier(fromACVMField(nullifier)); this.context.nullifyPendingNotes(fromACVMField(innerNoteHash), this.contractAddress, fromACVMField(slot)); return Promise.resolve(ZERO_ACVM_FIELD); }, diff --git a/yarn-project/acir-simulator/src/client/simulator.ts b/yarn-project/acir-simulator/src/client/simulator.ts index 425d1caf27b..13280358fd0 100644 --- a/yarn-project/acir-simulator/src/client/simulator.ts +++ b/yarn-project/acir-simulator/src/client/simulator.ts @@ -157,7 +157,7 @@ export class AcirSimulator { args: encodeArguments(abi, [contractAddress, nonce, storageSlot, extendedPreimage]), }; - const [[innerNoteHash, uniqueNoteHash, siloedNoteHash, innerNullifier]] = await this.runUnconstrained( + const [[innerNoteHash, siloedNoteHash, uniqueSiloedNoteHash, innerNullifier]] = await this.runUnconstrained( execRequest, abi, AztecAddress.ZERO, @@ -167,9 +167,9 @@ export class AcirSimulator { return { innerNoteHash: new Fr(innerNoteHash), - uniqueNoteHash: new Fr(uniqueNoteHash), siloedNoteHash: new Fr(siloedNoteHash), - nullifier: new Fr(innerNullifier), + uniqueSiloedNoteHash: new Fr(uniqueSiloedNoteHash), + innerNullifier: new Fr(innerNullifier), }; } catch (e) { throw new Error( @@ -205,14 +205,19 @@ export class AcirSimulator { * @param abi - The ABI of the function `compute_note_hash`. * @returns The note hash. */ - public async computeUniqueNoteHash(contractAddress: AztecAddress, nonce: Fr, storageSlot: Fr, notePreimage: Fr[]) { - const { uniqueNoteHash } = await this.computeNoteHashAndNullifier( + public async computeUniqueSiloedNoteHash( + contractAddress: AztecAddress, + nonce: Fr, + storageSlot: Fr, + notePreimage: Fr[], + ) { + const { uniqueSiloedNoteHash } = await this.computeNoteHashAndNullifier( contractAddress, nonce, storageSlot, notePreimage, ); - return uniqueNoteHash; + return uniqueSiloedNoteHash; } /** @@ -243,8 +248,13 @@ export class AcirSimulator { * @param abi - The ABI of the function `compute_note_hash`. * @returns The note hash. */ - public async computeNullifier(contractAddress: AztecAddress, nonce: Fr, storageSlot: Fr, notePreimage: Fr[]) { - const { nullifier } = await this.computeNoteHashAndNullifier(contractAddress, nonce, storageSlot, notePreimage); - return nullifier; + public async computeInnerNullifier(contractAddress: AztecAddress, nonce: Fr, storageSlot: Fr, notePreimage: Fr[]) { + const { innerNullifier } = await this.computeNoteHashAndNullifier( + contractAddress, + nonce, + storageSlot, + notePreimage, + ); + return innerNullifier; } } diff --git a/yarn-project/acir-simulator/src/client/unconstrained_execution.test.ts b/yarn-project/acir-simulator/src/client/unconstrained_execution.test.ts index bb93bb3cfe1..c411c6e2264 100644 --- a/yarn-project/acir-simulator/src/client/unconstrained_execution.test.ts +++ b/yarn-project/acir-simulator/src/client/unconstrained_execution.test.ts @@ -69,7 +69,7 @@ describe('Unconstrained Execution test suite', () => { nonce: Fr.random(), isSome: new Fr(1), preimage, - nullifier: Fr.random(), + siloedNullifier: Fr.random(), index: BigInt(index), })), ); diff --git a/yarn-project/aztec-rpc/src/database/memory_db.ts b/yarn-project/aztec-rpc/src/database/memory_db.ts index 756e7b6c8a0..a6a4eeb2a39 100644 --- a/yarn-project/aztec-rpc/src/database/memory_db.ts +++ b/yarn-project/aztec-rpc/src/database/memory_db.ts @@ -70,7 +70,7 @@ export class MemoryDB extends MemoryContractDatabase implements Database { const nullifierSet = new Set(nullifiers.map(nullifier => nullifier.toString())); const [remaining, removed] = this.noteSpendingInfoTable.reduce( (acc: [NoteSpendingInfoDao[], NoteSpendingInfoDao[]], noteSpendingInfo) => { - const nullifier = noteSpendingInfo.nullifier.toString(); + const nullifier = noteSpendingInfo.siloedNullifier.toString(); if (noteSpendingInfo.publicKey.equals(account) && nullifierSet.has(nullifier)) { acc[1].push(noteSpendingInfo); } else { diff --git a/yarn-project/aztec-rpc/src/database/note_spending_info_dao.ts b/yarn-project/aztec-rpc/src/database/note_spending_info_dao.ts index 81b6f168721..33e87ccf5a7 100644 --- a/yarn-project/aztec-rpc/src/database/note_spending_info_dao.ts +++ b/yarn-project/aztec-rpc/src/database/note_spending_info_dao.ts @@ -29,9 +29,9 @@ export interface NoteSpendingInfoDao { */ notePreimage: NotePreimage; /** - * The nullifier of the note. + * The nullifier of the note (siloed by contract address). */ - nullifier: Fr; + siloedNullifier: Fr; /** * The location of the relevant note in the private data tree. */ @@ -48,7 +48,7 @@ export const createRandomNoteSpendingInfoDao = ({ ownerAddress = AztecAddress.random(), storageSlot = Fr.random(), notePreimage = NotePreimage.random(), - nullifier = Fr.random(), + siloedNullifier = Fr.random(), index = Fr.random().value, publicKey = Point.random(), }: Partial = {}): NoteSpendingInfoDao => ({ @@ -57,7 +57,7 @@ export const createRandomNoteSpendingInfoDao = ({ ownerAddress, storageSlot, notePreimage, - nullifier, + siloedNullifier, index, publicKey, }); diff --git a/yarn-project/aztec-rpc/src/note_processor/note_processor.test.ts b/yarn-project/aztec-rpc/src/note_processor/note_processor.test.ts index 736d96bae30..390a981c08d 100644 --- a/yarn-project/aztec-rpc/src/note_processor/note_processor.test.ts +++ b/yarn-project/aztec-rpc/src/note_processor/note_processor.test.ts @@ -128,9 +128,9 @@ describe('Note Processor', () => { simulator.computeNoteHashAndNullifier.mockImplementation((...args) => Promise.resolve({ innerNoteHash: Fr.random(), - uniqueNoteHash: Fr.random(), - siloedNoteHash: computeMockNoteHash(args[3]), - nullifier: Fr.random(), + siloedNoteHash: Fr.random(), + uniqueSiloedNoteHash: computeMockNoteHash(args[3]), + innerNullifier: Fr.random(), }), ); }); diff --git a/yarn-project/aztec-rpc/src/note_processor/note_processor.ts b/yarn-project/aztec-rpc/src/note_processor/note_processor.ts index fc8d5470df2..4353b3f55a7 100644 --- a/yarn-project/aztec-rpc/src/note_processor/note_processor.ts +++ b/yarn-project/aztec-rpc/src/note_processor/note_processor.ts @@ -122,7 +122,7 @@ export class NoteProcessor { (indexOfTxInABlock + 1) * MAX_NEW_NULLIFIERS_PER_TX, ); try { - const { index, nonce, nullifier } = await this.findNoteIndexAndNullifier( + const { index, nonce, siloedNullifier } = await this.findNoteIndexAndNullifier( dataStartIndexForTx, newCommitments, newNullifiers[0], @@ -130,9 +130,9 @@ export class NoteProcessor { ); noteSpendingInfoDaos.push({ ...noteSpendingInfo, - index, nonce, - nullifier, + siloedNullifier, + index, publicKey: this.publicKey, }); userPertainingTxIndices.add(indexOfTxInABlock); @@ -179,21 +179,29 @@ export class NoteProcessor { const wasm = await CircuitsWasm.get(); let commitmentIndex = 0; let nonce: Fr | undefined; + let innerNoteHash: Fr | undefined; + let uniqueSiloedNoteHash: Fr | undefined; let innerNullifier: Fr | undefined; for (; commitmentIndex < commitments.length; ++commitmentIndex) { const commitment = commitments[commitmentIndex]; if (commitment.equals(Fr.ZERO)) break; const expectedNonce = computeCommitmentNonce(wasm, firstNullifier, commitmentIndex); - const { siloedNoteHash, nullifier } = await this.simulator.computeNoteHashAndNullifier( + const { + innerNoteHash: innerNoteHashTmp, + uniqueSiloedNoteHash: uniqueSiloedNoteHashTmp, + innerNullifier: innerNullifierTmp, + } = await this.simulator.computeNoteHashAndNullifier( contractAddress, expectedNonce, storageSlot, notePreimage.items, ); - if (commitment.equals(siloedNoteHash)) { + if (commitment.equals(uniqueSiloedNoteHashTmp)) { nonce = expectedNonce; - innerNullifier = nullifier; + innerNoteHash = innerNoteHashTmp; + uniqueSiloedNoteHash = uniqueSiloedNoteHashTmp; + innerNullifier = innerNullifierTmp; break; } } @@ -205,7 +213,9 @@ export class NoteProcessor { return { index: BigInt(dataStartIndex + commitmentIndex), nonce, - nullifier: siloNullifier(wasm, contractAddress, innerNullifier!), + innerNoteHash: innerNoteHash!, + uniqueSiloedNoteHash: uniqueSiloedNoteHash!, + siloedNullifier: siloNullifier(wasm, contractAddress, innerNullifier!), }; } @@ -253,7 +263,7 @@ export class NoteProcessor { this.log( `Added note spending info for contract ${noteSpendingInfo.contractAddress} at slot ${ noteSpendingInfo.storageSlot - } with nullifier ${noteSpendingInfo.nullifier.toString()}`, + } with nullifier ${noteSpendingInfo.siloedNullifier.toString()}`, ); }); } @@ -263,7 +273,7 @@ export class NoteProcessor { this.log( `Removed note spending info for contract ${noteSpendingInfo.contractAddress} at slot ${ noteSpendingInfo.storageSlot - } with nullifier ${noteSpendingInfo.nullifier.toString()}`, + } with nullifier ${noteSpendingInfo.siloedNullifier.toString()}`, ); }); } diff --git a/yarn-project/aztec-rpc/src/simulator_oracle/index.ts b/yarn-project/aztec-rpc/src/simulator_oracle/index.ts index 267ea532c16..813e4a8f5e6 100644 --- a/yarn-project/aztec-rpc/src/simulator_oracle/index.ts +++ b/yarn-project/aztec-rpc/src/simulator_oracle/index.ts @@ -43,12 +43,12 @@ export class SimulatorOracle implements DBOracle { async getNotes(contractAddress: AztecAddress, storageSlot: Fr) { const noteDaos = await this.db.getNoteSpendingInfo(contractAddress, storageSlot); - return noteDaos.map(({ contractAddress, storageSlot, nonce, notePreimage, nullifier, index }) => ({ + return noteDaos.map(({ contractAddress, storageSlot, nonce, notePreimage, siloedNullifier, index }) => ({ contractAddress, storageSlot, nonce, preimage: notePreimage.items, - nullifier, + siloedNullifier, // RPC Client can use this index to get full MembershipWitness index, })); @@ -85,12 +85,12 @@ export class SimulatorOracle implements DBOracle { /** * Retrieves the noir oracle data required to prove existence of a given commitment. * @param contractAddress - The contract Address. - * @param commitment - The key of the message being fetched. + * @param innerCommitment - The key of the message being fetched. * @returns - A promise that resolves to the commitment data, a sibling path and the * index of the message in the private data tree. */ - async getCommitmentOracle(contractAddress: AztecAddress, commitment: Fr): Promise { - const siloedCommitment = siloCommitment(await CircuitsWasm.get(), contractAddress, commitment); + async getCommitmentOracle(contractAddress: AztecAddress, innerCommitment: Fr): Promise { + const siloedCommitment = siloCommitment(await CircuitsWasm.get(), contractAddress, innerCommitment); const index = await this.dataTreeProvider.findCommitmentIndex(siloedCommitment.toBuffer()); if (!index) throw new Error('Commitment not found'); diff --git a/yarn-project/circuits.js/src/abis/abis.ts b/yarn-project/circuits.js/src/abis/abis.ts index 18a6b2b27f4..c458ffb8ca2 100644 --- a/yarn-project/circuits.js/src/abis/abis.ts +++ b/yarn-project/circuits.js/src/abis/abis.ts @@ -262,18 +262,6 @@ export function computeCommitmentNonce(wasm: IWasmModule, nullifierZero: Fr, com return abisComputeCommitmentNonce(wasm, nullifierZero, new Fr(commitmentIndex)); } -/** - * Computes a unique commitment. It includes a nonce which contains data that guarantees the commiment will be unique. - * @param wasm - A module providing low-level wasm access. - * @param nonce - The contract address. - * @param innerCommitment - An inner commitment. - * @returns A siloed commitment. - */ -export function computeUniqueCommitment(wasm: IWasmModule, nonce: Fr, innerCommitment: Fr): Fr { - wasm.call('pedersen__init'); - return abisComputeUniqueCommitment(wasm, nonce, innerCommitment); -} - /** * Computes a siloed commitment, given the contract address and the commitment itself. * A siloed commitment effectively namespaces a commitment to a specific contract. @@ -287,6 +275,18 @@ export function siloCommitment(wasm: IWasmModule, contract: AztecAddress, unique return abisSiloCommitment(wasm, contract, uniqueCommitment); } +/** + * Computes a unique commitment. It includes a nonce which contains data that guarantees the commiment will be unique. + * @param wasm - A module providing low-level wasm access. + * @param nonce - The contract address. + * @param siloedCommitment - An siloed commitment. + * @returns A unique commitment. + */ +export function computeUniqueCommitment(wasm: IWasmModule, nonce: Fr, siloedCommitment: Fr): Fr { + wasm.call('pedersen__init'); + return abisComputeUniqueCommitment(wasm, nonce, siloedCommitment); +} + /** * Computes a siloed nullifier, given the contract address and the inner nullifier. * A siloed nullifier effectively namespaces a nullifier to a specific contract. diff --git a/yarn-project/circuits.js/src/cbind/constants.gen.ts b/yarn-project/circuits.js/src/cbind/constants.gen.ts index ae742de789f..9d4cd273f20 100644 --- a/yarn-project/circuits.js/src/cbind/constants.gen.ts +++ b/yarn-project/circuits.js/src/cbind/constants.gen.ts @@ -78,7 +78,7 @@ export enum GeneratorIndex { COMMITMENT = 1, COMMITMENT_NONCE = 2, UNIQUE_COMMITMENT = 3, - OUTER_COMMITMENT = 4, + SILOED_COMMITMENT = 4, NULLIFIER = 5, INITIALISATION_NULLIFIER = 6, OUTER_NULLIFIER = 7, diff --git a/yarn-project/noir-contracts/src/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr b/yarn-project/noir-contracts/src/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr index 18bdc91e711..4890312af1c 100644 --- a/yarn-project/noir-contracts/src/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr +++ b/yarn-project/noir-contracts/src/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr @@ -1,7 +1,7 @@ use dep::std::hash::pedersen; use dep::aztec::note::note_interface::NoteInterface; use dep::aztec::note::note_header::NoteHeader; -use dep::aztec::note::utils::compute_siloed_note_hash; +use dep::aztec::note::utils::compute_unique_siloed_note_hash; use dep::aztec::oracle::get_secret_key::get_secret_key; use dep::aztec::oracle::get_public_key::get_public_key; @@ -53,11 +53,11 @@ impl EcdsaPublicKeyNote { } fn compute_nullifier(self) -> Field { - let siloed_note_hash = compute_siloed_note_hash(EcdsaPublicKeyNoteInterface, self); + let unique_siloed_note_hash = compute_unique_siloed_note_hash(EcdsaPublicKeyNoteInterface, self); let owner_nullifying_public_key = get_public_key(self.owner); let secret = get_secret_key(owner_nullifying_public_key); dep::std::hash::pedersen([ - siloed_note_hash, + unique_siloed_note_hash, secret, ])[0] } diff --git a/yarn-project/noir-contracts/src/contracts/non_native_token_contract/src/transparent_note.nr b/yarn-project/noir-contracts/src/contracts/non_native_token_contract/src/transparent_note.nr index 93b6a5ce307..9da37a4d38d 100644 --- a/yarn-project/noir-contracts/src/contracts/non_native_token_contract/src/transparent_note.nr +++ b/yarn-project/noir-contracts/src/contracts/non_native_token_contract/src/transparent_note.nr @@ -38,19 +38,21 @@ impl TransparentNote { fn consume_in_secret(self: Self, context: &mut Context, root: Field, secret: Field) { // Get the commitment value (before silo) - let commitment = self.get_commitment(); - - // Let the kernel perform the read. - context.push_read_request(commitment); + let innerCommitment = self.get_commitment(); // Get the commitment data, (where it is in the db) - let commitment_oracle_call = get_commitment(commitment); + let commitment_oracle_call = get_commitment(innerCommitment); let commitment_data = make_commitment_getter_data(commitment_oracle_call, 0); + let siloed_commitment = commitment_data.message; // oracle call returns siloed commitment + + // Let the kernel perform the read. + context.push_read_request(siloed_commitment); + // Do we still need to do this with read requests? assert(root == commitment_data.root); // Calculate the nullifier - self.emit_nullifier(context, secret, commitment, commitment_data.leaf_index); + self.emit_nullifier(context, secret, siloed_commitment, commitment_data.leaf_index); } fn compute_secret_hash(secret: Field) -> Field { diff --git a/yarn-project/noir-contracts/src/contracts/pokeable_token_contract/src/address_note.nr b/yarn-project/noir-contracts/src/contracts/pokeable_token_contract/src/address_note.nr index b77e3130465..50bfe8cc8b5 100644 --- a/yarn-project/noir-contracts/src/contracts/pokeable_token_contract/src/address_note.nr +++ b/yarn-project/noir-contracts/src/contracts/pokeable_token_contract/src/address_note.nr @@ -1,7 +1,7 @@ use dep::std::hash::pedersen; use dep::aztec::note::note_interface::NoteInterface; use dep::aztec::note::note_header::NoteHeader; -use dep::aztec::note::utils::compute_siloed_note_hash; +use dep::aztec::note::utils::compute_unique_siloed_note_hash; use dep::aztec::oracle::get_secret_key::get_secret_key; use dep::aztec::oracle::get_public_key::get_public_key; @@ -27,11 +27,11 @@ impl AddressNote { } fn compute_nullifier(self) -> Field { - let siloed_note_hash = compute_siloed_note_hash(AddressNoteMethods, self); + let unique_siloed_note_hash = compute_unique_siloed_note_hash(AddressNoteMethods, self); let owner_nullifying_public_key = get_public_key(self.address); let secret = get_secret_key(owner_nullifying_public_key); dep::std::hash::pedersen([ - siloed_note_hash, + unique_siloed_note_hash, secret, ])[0] } diff --git a/yarn-project/noir-contracts/src/contracts/schnorr_multi_key_account_contract/src/public_key_note.nr b/yarn-project/noir-contracts/src/contracts/schnorr_multi_key_account_contract/src/public_key_note.nr index 5e7f774c603..f52772b7c9c 100644 --- a/yarn-project/noir-contracts/src/contracts/schnorr_multi_key_account_contract/src/public_key_note.nr +++ b/yarn-project/noir-contracts/src/contracts/schnorr_multi_key_account_contract/src/public_key_note.nr @@ -3,7 +3,7 @@ use dep::aztec::note::note_interface::NoteInterface; use dep::aztec::note::note_header::NoteHeader; use dep::aztec::oracle::get_secret_key::get_secret_key; use dep::aztec::oracle::get_public_key::get_public_key; -use dep::aztec::note::utils::compute_siloed_note_hash; +use dep::aztec::note::utils::compute_unique_siloed_note_hash; global PUBLIC_KEY_NOTE_LEN: Field = 3; @@ -32,11 +32,11 @@ impl PublicKeyNote { } fn compute_nullifier(self) -> Field { - let siloed_note_hash = compute_siloed_note_hash(PublicKeyNoteMethods, self); + let unique_siloed_note_hash = compute_unique_siloed_note_hash(PublicKeyNoteMethods, self); let owner_nullifying_public_key = get_public_key(self.owner); let secret = get_secret_key(owner_nullifying_public_key); dep::std::hash::pedersen([ - siloed_note_hash, + unique_siloed_note_hash, secret, ])[0] } diff --git a/yarn-project/noir-contracts/src/contracts/zk_token_contract/src/claim_note.nr b/yarn-project/noir-contracts/src/contracts/zk_token_contract/src/claim_note.nr index 8b90f451747..3f7aa743a3d 100644 --- a/yarn-project/noir-contracts/src/contracts/zk_token_contract/src/claim_note.nr +++ b/yarn-project/noir-contracts/src/contracts/zk_token_contract/src/claim_note.nr @@ -2,7 +2,7 @@ use dep::std::hash::pedersen; use dep::aztec::note::{ note_header::NoteHeader, note_interface::NoteInterface, - utils::compute_siloed_note_hash, + utils::compute_note_hash_for_read_or_nullify, }; global CLAIM_NOTE_LEN: Field = 2; @@ -42,9 +42,9 @@ impl ClaimNote { } fn compute_nullifier(self) -> Field { - let siloed_note_hash = compute_siloed_note_hash(ClaimNoteMethods, self); + let note_hash_for_nullify = compute_note_hash_for_read_or_nullify(ClaimNoteMethods, self); dep::std::hash::pedersen([ - siloed_note_hash, + note_hash_for_nullify, self.secret_hash, // Include the secret_hash again so that the public won't know the note has been claimed. ])[0] } diff --git a/yarn-project/noir-libs/noir-aztec/src/constants_gen.nr b/yarn-project/noir-libs/noir-aztec/src/constants_gen.nr index 8e20b4c95a2..94f9920ad39 100644 --- a/yarn-project/noir-libs/noir-aztec/src/constants_gen.nr +++ b/yarn-project/noir-libs/noir-aztec/src/constants_gen.nr @@ -76,7 +76,7 @@ global LOGS_HASHES_NUM_BYTES_PER_BASE_ROLLUP: comptime Field = 128; global GENERATOR_INDEX__COMMITMENT = 1; global GENERATOR_INDEX__COMMITMENT_NONCE = 2; global GENERATOR_INDEX__UNIQUE_COMMITMENT = 3; -global GENERATOR_INDEX__OUTER_COMMITMENT = 4; +global GENERATOR_INDEX__SILOED_COMMITMENT = 4; global GENERATOR_INDEX__NULLIFIER = 5; global GENERATOR_INDEX__INITIALISATION_NULLIFIER = 6; global GENERATOR_INDEX__OUTER_NULLIFIER = 7; diff --git a/yarn-project/noir-libs/noir-aztec/src/note/note_getter.nr b/yarn-project/noir-libs/noir-aztec/src/note/note_getter.nr index 33088b0af86..3a6c243c4d0 100644 --- a/yarn-project/noir-libs/noir-aztec/src/note/note_getter.nr +++ b/yarn-project/noir-libs/noir-aztec/src/note/note_getter.nr @@ -9,7 +9,8 @@ use crate::context::Context; use crate::note::{ note_getter_options::NoteGetterOptions, note_interface::NoteInterface, - utils::compute_unique_note_hash, + utils::compute_note_hash_for_read_or_nullify, + utils::compute_unique_siloed_note_hash, }; use crate::oracle; use crate::types::option::Option; @@ -43,9 +44,8 @@ fn ensure_note_exists( check_note_header(*context, storage_slot, note_interface, *note); - let unique_note_hash = compute_unique_note_hash(note_interface, *note); - - context.push_read_request(unique_note_hash); + let note_hash_for_read_request = compute_note_hash_for_read_or_nullify(note_interface, *note); + context.push_read_request(note_hash_for_read_request); } fn get_note( @@ -56,10 +56,10 @@ fn get_note( let note = get_note_internal(storage_slot, note_interface); check_note_header(*context, storage_slot, note_interface, note); - - let unique_note_hash = compute_unique_note_hash(note_interface, note); - context.push_read_request(unique_note_hash); + let note_hash_for_read_request = compute_note_hash_for_read_or_nullify(note_interface, note); + + context.push_read_request(note_hash_for_read_request); note } @@ -72,13 +72,15 @@ fn get_notes( let opt_notes = get_notes_internal(storage_slot, note_interface, options); for i in 0..opt_notes.len() { let opt_note = opt_notes[i]; - let mut unique_note_hash = 0; + let mut note_hash_for_read_request = 0; if opt_note.is_some() { let note = opt_note.unwrap_unchecked(); check_note_header(*context, storage_slot, note_interface, note); - unique_note_hash = compute_unique_note_hash(note_interface, note); + note_hash_for_read_request = compute_note_hash_for_read_or_nullify(note_interface, note); }; - context.push_read_request(unique_note_hash); + // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1410): test to ensure + // failure if malicious oracle injects 0 nonce here for a "pre-existing" note. + context.push_read_request(note_hash_for_read_request); }; opt_notes } diff --git a/yarn-project/noir-libs/noir-aztec/src/note/note_hash.nr b/yarn-project/noir-libs/noir-aztec/src/note/note_hash.nr index 69b2e6d0f19..8b507a404f9 100644 --- a/yarn-project/noir-libs/noir-aztec/src/note/note_hash.nr +++ b/yarn-project/noir-libs/noir-aztec/src/note/note_hash.nr @@ -1,17 +1,17 @@ use dep::std::hash::{pedersen, pedersen_with_separator}; -use crate::constants_gen::{GENERATOR_INDEX__UNIQUE_COMMITMENT, GENERATOR_INDEX__OUTER_COMMITMENT}; +use crate::constants_gen::{GENERATOR_INDEX__UNIQUE_COMMITMENT, GENERATOR_INDEX__SILOED_COMMITMENT}; fn compute_inner_hash(storage_slot: Field, note_hash: Field) -> Field { // TODO(#1205) Do we need a generator index here? pedersen([storage_slot, note_hash])[0] } -fn compute_unique_hash(nonce: Field, inner_note_hash: Field) -> Field { - let inputs = [nonce, inner_note_hash]; - pedersen_with_separator(inputs, GENERATOR_INDEX__UNIQUE_COMMITMENT)[0] +fn compute_siloed_hash(contract_address: Field, inner_note_hash: Field) -> Field { + let inputs = [contract_address, inner_note_hash]; + pedersen_with_separator(inputs, GENERATOR_INDEX__SILOED_COMMITMENT)[0] } -fn compute_siloed_hash(contract_address: Field, unique_note_hash: Field) -> Field { - let inputs = [contract_address, unique_note_hash]; - pedersen_with_separator(inputs, GENERATOR_INDEX__OUTER_COMMITMENT)[0] -} \ No newline at end of file +fn compute_unique_hash(nonce: Field, siloed_note_hash: Field) -> Field { + let inputs = [nonce, siloed_note_hash]; + pedersen_with_separator(inputs, GENERATOR_INDEX__UNIQUE_COMMITMENT)[0] +} diff --git a/yarn-project/noir-libs/noir-aztec/src/note/utils.nr b/yarn-project/noir-libs/noir-aztec/src/note/utils.nr index 44c236ae6a0..d8a459286f2 100644 --- a/yarn-project/noir-libs/noir-aztec/src/note/utils.nr +++ b/yarn-project/noir-libs/noir-aztec/src/note/utils.nr @@ -1,5 +1,5 @@ use crate::note::{ - note_hash::{compute_inner_hash, compute_unique_hash, compute_siloed_hash}, + note_hash::{compute_inner_hash, compute_siloed_hash, compute_unique_hash}, note_header::NoteHeader, note_interface::NoteInterface, }; @@ -18,28 +18,49 @@ fn compute_inner_note_hash( compute_inner_hash(header.storage_slot, note_hash) } -fn compute_unique_note_hash( +fn compute_siloed_note_hash( note_interface: NoteInterface, - note: Note, + note_with_header: Note, ) -> Field { let get_header = note_interface.get_header; - let header = get_header(note); + let header = get_header(note_with_header); - let inner_note_hash = compute_inner_note_hash(note_interface, note); + let inner_note_hash = compute_inner_note_hash(note_interface, note_with_header); - compute_unique_hash(header.nonce, inner_note_hash) + compute_siloed_hash(header.contract_address, inner_note_hash) } -fn compute_siloed_note_hash( +fn compute_unique_siloed_note_hash( note_interface: NoteInterface, - note: Note, + note_with_header: Note, ) -> Field { let get_header = note_interface.get_header; - let header = get_header(note); + let header = get_header(note_with_header); + + let siloed_note_hash = compute_siloed_note_hash(note_interface, note_with_header); - let unique_note_hash = compute_unique_note_hash(note_interface, note); + compute_unique_hash(header.nonce, siloed_note_hash) +} + +fn compute_note_hash_for_read_or_nullify( + note_interface: NoteInterface, + note_with_header: Note, +) -> Field { + let get_header = note_interface.get_header; + let header = get_header(note_with_header); + + if (header.nonce == 0) { + // when nonce is zero, that means we are reading a pending note (doesn't have a nonce yet), + // so we just read the inner_note_hash (kernel will silo by contract address) + compute_inner_note_hash(note_interface, note_with_header) + } else { + // When nonce is nonzero, that means we are reading a settled note (from tree) created in a + // previous TX. So we need the unique_siloed_note_hash which has already been hashed with + // contract address and then nonce. This hash will match the existing leaf in the private + // data tree, so the kernel can just perform a membership check directly on this hash/leaf. + compute_unique_siloed_note_hash(note_interface, note_with_header) + } - compute_siloed_hash(header.contract_address, unique_note_hash) } fn compute_note_hash_and_nullifier( @@ -56,12 +77,12 @@ fn compute_note_hash_and_nullifier( let note_hash = compute_note_hash(note); let inner_note_hash = compute_inner_hash(note_header.storage_slot, note_hash); - let unique_note_hash = compute_unique_hash(note_header.nonce, inner_note_hash); + let siloed_note_hash = compute_siloed_hash(note_header.contract_address, inner_note_hash); + + let unique_siloed_note_hash = compute_unique_hash(note_header.nonce, siloed_note_hash); - let siloed_note_hash = compute_siloed_hash(note_header.contract_address, unique_note_hash); - let compute_nullifier = note_interface.compute_nullifier; let inner_nullifier = compute_nullifier(note); - [inner_note_hash, unique_note_hash, siloed_note_hash, inner_nullifier] + [inner_note_hash, siloed_note_hash, unique_siloed_note_hash, inner_nullifier] } diff --git a/yarn-project/noir-libs/value-note/src/value_note.nr b/yarn-project/noir-libs/value-note/src/value_note.nr index da2fc7b5015..4df998ac255 100644 --- a/yarn-project/noir-libs/value-note/src/value_note.nr +++ b/yarn-project/noir-libs/value-note/src/value_note.nr @@ -1,7 +1,7 @@ use dep::aztec::note::{ note_header::NoteHeader, note_interface::NoteInterface, - utils::compute_siloed_note_hash, + utils::compute_note_hash_for_read_or_nullify, }; use dep::aztec::oracle::{ rand::rand, @@ -53,14 +53,14 @@ impl ValueNote { } fn compute_nullifier(self) -> Field { - let siloed_note_hash = compute_siloed_note_hash(ValueNoteMethods, self); + let note_hash_for_nullify = compute_note_hash_for_read_or_nullify(ValueNoteMethods, self); let owner_nullifying_public_key = get_public_key(self.owner); // TODO: get_secret_key should just accept an address // TODO! let secret = get_secret_key(owner_nullifying_public_key); dep::std::hash::pedersen([ - siloed_note_hash, - secret, + note_hash_for_nullify, + secret, ])[0] }