diff --git a/circuits/cpp/src/aztec3/circuits/abis/.test.cpp b/circuits/cpp/src/aztec3/circuits/abis/.test.cpp index 8709a54327a..edccf86f5fe 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/.test.cpp @@ -1,6 +1,5 @@ #include "index.hpp" #include "previous_kernel_data.hpp" -#include "private_kernel/private_inputs.hpp" #include "aztec3/circuits/abis/combined_accumulated_data.hpp" diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp index e26d2f71ca2..1323eec894d 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp @@ -8,7 +8,7 @@ #include "private_circuit_public_inputs.hpp" #include "tx_context.hpp" #include "tx_request.hpp" -#include "private_kernel/private_inputs.hpp" +#include "private_kernel/private_kernel_inputs_inner.hpp" #include "public_kernel/public_kernel_inputs.hpp" #include "public_kernel/public_kernel_inputs_no_previous_kernel.hpp" #include "rollup/base/base_or_merge_rollup_public_inputs.hpp" @@ -18,6 +18,7 @@ #include "aztec3/circuits/abis/combined_accumulated_data.hpp" #include "aztec3/circuits/abis/new_contract_data.hpp" +#include "aztec3/circuits/abis/private_kernel/private_kernel_inputs_init.hpp" #include "aztec3/circuits/abis/signed_tx_request.hpp" #include "aztec3/circuits/abis/types.hpp" #include @@ -441,9 +442,14 @@ WASM_EXPORT const char* abis__test_roundtrip_serialize_signed_tx_request(uint8_t return as_string_output>(input, size); } -WASM_EXPORT const char* abis__test_roundtrip_serialize_private_kernel_inputs(uint8_t const* input, uint32_t* size) +WASM_EXPORT const char* abis__test_roundtrip_serialize_private_kernel_inputs_inner(uint8_t const* input, uint32_t* size) { - return as_string_output>(input, size); + return as_string_output>(input, size); +} + +WASM_EXPORT const char* abis__test_roundtrip_serialize_private_kernel_inputs_init(uint8_t const* input, uint32_t* size) +{ + return as_string_output>(input, size); } WASM_EXPORT const char* abis__test_roundtrip_serialize_kernel_circuit_public_inputs(uint8_t const* input, diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp index c1865b39554..590c88a0f54 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp @@ -1,5 +1,4 @@ #include "c_bind.h" - #include "function_leaf_preimage.hpp" #include "tx_request.hpp" diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/private_kernel_inputs_init.hpp similarity index 55% rename from circuits/cpp/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp rename to circuits/cpp/src/aztec3/circuits/abis/private_kernel/private_kernel_inputs_init.hpp index 607b397a8b3..c7e90cadd56 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/private_inputs.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/private_kernel_inputs_init.hpp @@ -1,15 +1,10 @@ #pragma once #include "private_call_data.hpp" -#include "../combined_accumulated_data.hpp" -#include "../previous_kernel_data.hpp" #include "../signed_tx_request.hpp" -#include -#include -#include - -#include +#include "aztec3/utils/types/circuit_types.hpp" +#include "aztec3/utils/types/native_types.hpp" namespace aztec3::circuits::abis::private_kernel { @@ -17,28 +12,26 @@ using aztec3::utils::types::CircuitTypes; using aztec3::utils::types::NativeTypes; using std::is_same; -template struct PrivateInputs { +template struct PrivateKernelInputsInit { using fr = typename NCT::fr; using boolean = typename NCT::boolean; SignedTxRequest signed_tx_request{}; - PreviousKernelData previous_kernel{}; PrivateCallData private_call{}; - boolean operator==(PrivateInputs const& other) const + boolean operator==(PrivateKernelInputsInit const& other) const { - return signed_tx_request == other.signed_tx_request && previous_kernel == other.previous_kernel && - private_call == other.private_call; + return signed_tx_request == other.signed_tx_request && private_call == other.private_call; }; - template PrivateInputs> to_circuit_type(Composer& composer) const + template + PrivateKernelInputsInit> to_circuit_type(Composer& composer) const { static_assert((std::is_same::value)); - PrivateInputs> private_inputs = { + PrivateKernelInputsInit> private_inputs = { // TODO to_ct(signature), signed_tx_request.to_circuit_type(composer), - previous_kernel.to_circuit_type(composer), private_call.to_circuit_type(composer), }; @@ -46,30 +39,26 @@ template struct PrivateInputs { }; }; -template void read(uint8_t const*& it, PrivateInputs& private_inputs) +template void read(uint8_t const*& it, PrivateKernelInputsInit& private_inputs) { using serialize::read; read(it, private_inputs.signed_tx_request); - read(it, private_inputs.previous_kernel); read(it, private_inputs.private_call); }; -template void write(std::vector& buf, PrivateInputs const& private_inputs) +template void write(std::vector& buf, PrivateKernelInputsInit const& private_inputs) { using serialize::write; write(buf, private_inputs.signed_tx_request); - write(buf, private_inputs.previous_kernel); write(buf, private_inputs.private_call); }; -template std::ostream& operator<<(std::ostream& os, PrivateInputs const& private_inputs) +template std::ostream& operator<<(std::ostream& os, PrivateKernelInputsInit const& private_inputs) { return os << "signed_tx_request:\n" << private_inputs.signed_tx_request << "\n" - << "previous_kernel:\n" - << private_inputs.previous_kernel << "\n" << "private_call:\n" << private_inputs.private_call << "\n"; } diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_kernel/private_kernel_inputs_inner.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/private_kernel_inputs_inner.hpp new file mode 100644 index 00000000000..79c0d9235cc --- /dev/null +++ b/circuits/cpp/src/aztec3/circuits/abis/private_kernel/private_kernel_inputs_inner.hpp @@ -0,0 +1,68 @@ +#pragma once + +#include "private_call_data.hpp" +#include "../previous_kernel_data.hpp" + +#include "aztec3/utils/types/circuit_types.hpp" +#include "aztec3/utils/types/convert.hpp" +#include "aztec3/utils/types/native_types.hpp" + +#include + +namespace aztec3::circuits::abis::private_kernel { + +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; +using std::is_same; + +template struct PrivateKernelInputsInner { + using fr = typename NCT::fr; + using boolean = typename NCT::boolean; + + PreviousKernelData previous_kernel{}; + PrivateCallData private_call{}; + + boolean operator==(PrivateKernelInputsInner const& other) const + { + return previous_kernel == other.previous_kernel && private_call == other.private_call; + }; + + template + PrivateKernelInputsInner> to_circuit_type(Composer& composer) const + { + static_assert((std::is_same::value)); + + PrivateKernelInputsInner> private_inputs = { + previous_kernel.to_circuit_type(composer), + private_call.to_circuit_type(composer), + }; + + return private_inputs; + }; +}; + +template void read(uint8_t const*& it, PrivateKernelInputsInner& private_inputs) +{ + using serialize::read; + + read(it, private_inputs.previous_kernel); + read(it, private_inputs.private_call); +}; + +template void write(std::vector& buf, PrivateKernelInputsInner const& private_inputs) +{ + using serialize::write; + + write(buf, private_inputs.previous_kernel); + write(buf, private_inputs.private_call); +}; + +template std::ostream& operator<<(std::ostream& os, PrivateKernelInputsInner const& private_inputs) +{ + return os << "previous_kernel:\n" + << private_inputs.previous_kernel << "\n" + << "private_call:\n" + << private_inputs.private_call << "\n"; +} + +} // namespace aztec3::circuits::abis::private_kernel \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/.test.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/.test.cpp index f4701a0cc40..8677ed2f34d 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/.test.cpp @@ -1,30 +1,29 @@ #include "c_bind.h" #include "index.hpp" -#include "init.hpp" +#include "aztec3/circuits/abis/call_context.hpp" +#include "aztec3/circuits/abis/call_stack_item.hpp" +#include "aztec3/circuits/abis/combined_accumulated_data.hpp" +#include "aztec3/circuits/abis/combined_constant_data.hpp" +#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/private_circuit_public_inputs.hpp" +#include "aztec3/circuits/abis/private_historic_tree_roots.hpp" +#include "aztec3/circuits/abis/private_kernel/private_call_data.hpp" +#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/signed_tx_request.hpp" +#include "aztec3/circuits/abis/tx_context.hpp" +#include "aztec3/circuits/abis/tx_request.hpp" +#include "aztec3/circuits/abis/types.hpp" +#include "aztec3/circuits/apps/function_execution_context.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/utils.hpp" #include "aztec3/constants.hpp" #include "aztec3/utils/circuit_errors.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include @@ -54,14 +53,13 @@ using aztec3::circuits::abis::CombinedHistoricTreeRoots; using aztec3::circuits::abis::KernelCircuitPublicInputs; using aztec3::circuits::abis::PrivateHistoricTreeRoots; using aztec3::circuits::abis::private_kernel::PrivateCallData; -using aztec3::circuits::abis::private_kernel::PrivateInputs; +using aztec3::circuits::abis::private_kernel::PrivateKernelInputsInner; using aztec3::circuits::apps::test_apps::basic_contract_deployment::constructor; using aztec3::circuits::apps::test_apps::escrow::deposit; using DummyComposer = aztec3::utils::DummyComposer; -using aztec3::utils::array_push; using CircuitErrorCode = aztec3::utils::CircuitErrorCode; // A type representing any private circuit function @@ -164,18 +162,11 @@ std::shared_ptr gen_func_vk(bool is_constructor, private_function const& return dummy_composer.compute_verification_key(); } -/** - * @brief Perform a private circuit call and generate the inputs to private kernel - * - * @param is_constructor whether this private circuit call is a constructor - * @param func the private circuit call being validated by this kernel iteration - * @param args_vec the private call's args - * @return PrivateInputs - the inputs to the private call circuit - */ -PrivateInputs do_private_call_get_kernel_inputs(bool const is_constructor, - private_function const& func, - std::vector const& args_vec, - bool real_kernel_circuit = false) +std::pair, ContractDeploymentData> create_private_call_deploy_data( + bool const is_constructor, + private_function const& func, + std::vector const& args_vec, + NT::address const& msg_sender) { //*************************************************************************** // Initialize some inputs to private call and kernel circuits @@ -189,9 +180,6 @@ PrivateInputs do_private_call_get_kernel_inputs(bool const is_constructor, const NT::fr acir_hash = 12341234; const NT::fr msg_sender_private_key = 123456789; - const NT::address msg_sender = - NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); - const NT::address& tx_origin = msg_sender; FunctionData const function_data{ .function_selector = 1, // TODO: deduce this from the contract, somehow. @@ -304,15 +292,77 @@ PrivateInputs do_private_call_get_kernel_inputs(bool const is_constructor, NT::Proof const private_circuit_proof = private_circuit_prover.construct_proof(); // info("\nproof: ", private_circuit_proof.proof_data); + + //*************************************************************************** + // We mock a kernel circuit proof for the base case of kernel recursion (because even the first iteration of the + // kernel circuit expects to verify some previous kernel circuit). + //*************************************************************************** + // TODO: we have a choice to make: + // Either the `end` state of the mock kernel's public inputs can be set equal to the public call we _want_ to + // verify in the first round of recursion, OR, we have some fiddly conditional logic in the circuit to ignore + // certain checks if we're handling the 'base case' of the recursion. + // I've chosen the former, for now. + const CallStackItem call_stack_item{ + .contract_address = contract_address, + .function_data = function_data, + .public_inputs = private_circuit_public_inputs, + }; + + //*************************************************************************** + // Now we can construct the full private inputs to the kernel circuit + //*************************************************************************** + + return std::pair, ContractDeploymentData>( + PrivateCallData{ + .call_stack_item = call_stack_item, + .private_call_stack_preimages = ctx.get_private_call_stack_items(), + + .proof = private_circuit_proof, + .vk = private_circuit_vk, + + .function_leaf_membership_witness = { + .leaf_index = function_leaf_index, + .sibling_path = get_empty_function_siblings(), + }, + + .contract_leaf_membership_witness = { + .leaf_index = contract_leaf_index, + .sibling_path = get_empty_contract_siblings(), + }, + + .portal_contract_address = portal_contract_address, + + .acir_hash = acir_hash + }, + contract_deployment_data); +} + +// JEAMON: Most of the current tests should call this variant (init case) +PrivateKernelInputsInit do_private_call_get_kernel_inputs_init(bool const is_constructor, + private_function const& func, + std::vector const& args_vec) +{ + //*************************************************************************** + // Initialize some inputs to private call and kernel circuits + //*************************************************************************** + // TODO randomize inputs + + const NT::address msg_sender = + NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); + const NT::address& tx_origin = msg_sender; + + auto const& [private_call_data, contract_deployment_data] = + create_private_call_deploy_data(is_constructor, func, args_vec, msg_sender); + //*************************************************************************** // We can create a TxRequest from some of the above data. Users must sign a TxRequest in order to give permission // for a tx to take place - creating a SignedTxRequest. //*************************************************************************** auto const tx_request = TxRequest{ .from = tx_origin, - .to = contract_address, - .function_data = function_data, - .args = private_circuit_public_inputs.args, + .to = private_call_data.call_stack_item.contract_address, + .function_data = private_call_data.call_stack_item.function_data, + .args = private_call_data.call_stack_item.public_inputs.args, .nonce = 0, .tx_context = TxContext{ @@ -330,6 +380,49 @@ PrivateInputs do_private_call_get_kernel_inputs(bool const is_constructor, //.signature = TODO: need a method for signing a TxRequest. }; + //*************************************************************************** + // Now we can construct the full private inputs to the kernel circuit + //*************************************************************************** + PrivateKernelInputsInit kernel_private_inputs = PrivateKernelInputsInit{ + .signed_tx_request = signed_tx_request, + .private_call = private_call_data, + }; + + return kernel_private_inputs; +} + + +/** + * @brief Perform a private circuit call and generate the inputs to private kernel + * + * @param is_constructor whether this private circuit call is a constructor + * @param func the private circuit call being validated by this kernel iteration + * @param args_vec the private call's args + * @return PrivateInputs - the inputs to the private call circuit + */ +PrivateKernelInputsInner do_private_call_get_kernel_inputs_inner(bool const is_constructor, + private_function const& func, + std::vector const& args_vec, + bool real_kernel_circuit = false) +{ + //*************************************************************************** + // Initialize some inputs to private call and kernel circuits + //*************************************************************************** + // TODO randomize inputs + + const NT::address msg_sender = + NT::fr(uint256_t(0x01071e9a23e0f7edULL, 0x5d77b35d1830fa3eULL, 0xc6ba3660bb1f0c0bULL, 0x2ef9f7f09867fd6eULL)); + + auto const& private_call_deploy = create_private_call_deploy_data(is_constructor, func, args_vec, msg_sender); + + auto const& private_call_data = private_call_deploy.first; + const TxContext tx_context = TxContext{ + .is_fee_payment_tx = false, + .is_rebate_payment_tx = false, + .is_contract_deployment_tx = is_constructor, + .contract_deployment_data = private_call_deploy.second, + }; + //*************************************************************************** // We mock a kernel circuit proof for the base case of kernel recursion (because even the first iteration of the // kernel circuit expects to verify some previous kernel circuit). @@ -339,15 +432,11 @@ PrivateInputs do_private_call_get_kernel_inputs(bool const is_constructor, // verify in the first round of recursion, OR, we have some fiddly conditional logic in the circuit to ignore // certain checks if we're handling the 'base case' of the recursion. // I've chosen the former, for now. - const CallStackItem call_stack_item{ - .contract_address = tx_request.to, - .function_data = tx_request.function_data, - .public_inputs = private_circuit_public_inputs, - }; std::array initial_kernel_private_call_stack{}; - initial_kernel_private_call_stack[0] = call_stack_item.hash(); + initial_kernel_private_call_stack[0] = private_call_data.call_stack_item.hash(); + auto const& private_circuit_public_inputs = private_call_data.call_stack_item.public_inputs; // Get dummy previous kernel auto mock_previous_kernel = utils::dummy_previous_kernel(real_kernel_circuit); // Fill in some important fields in public inputs @@ -361,39 +450,16 @@ PrivateInputs do_private_call_get_kernel_inputs(bool const is_constructor, .contract_tree_root = private_circuit_public_inputs.historic_contract_tree_root, }, }, - .tx_context = tx_request.tx_context, + .tx_context = tx_context, }; mock_previous_kernel.public_inputs.is_private = true; //*************************************************************************** // Now we can construct the full private inputs to the kernel circuit //*************************************************************************** - PrivateInputs kernel_private_inputs = PrivateInputs{ - .signed_tx_request = signed_tx_request, - + PrivateKernelInputsInner kernel_private_inputs = PrivateKernelInputsInner{ .previous_kernel = mock_previous_kernel, - - .private_call = - PrivateCallData{ - .call_stack_item = call_stack_item, - .private_call_stack_preimages = ctx.get_private_call_stack_items(), - - .proof = private_circuit_proof, - .vk = private_circuit_vk, - - .function_leaf_membership_witness = { - .leaf_index = function_leaf_index, - .sibling_path = get_empty_function_siblings(), - }, - .contract_leaf_membership_witness = { - .leaf_index = contract_leaf_index, - .sibling_path = get_empty_contract_siblings(), - }, - - .portal_contract_address = portal_contract_address, - - .acir_hash = acir_hash, - }, + .private_call = private_call_data, }; return kernel_private_inputs; @@ -407,7 +473,7 @@ PrivateInputs do_private_call_get_kernel_inputs(bool const is_constructor, * @param private_inputs to be used in manual computation * @param public_inputs that contain the expected new contract address */ -void validate_deployed_contract_address(PrivateInputs const& private_inputs, +void validate_deployed_contract_address(PrivateKernelInputsInit const& private_inputs, KernelCircuitPublicInputs const& public_inputs) { auto tx_request = private_inputs.signed_tx_request.tx_request; @@ -434,14 +500,21 @@ TEST(private_kernel_tests, circuit_deposit) NT::fr const& asset_id = 1; NT::fr const& memo = 999; - auto const& private_inputs = do_private_call_get_kernel_inputs(false, deposit, { amount, asset_id, memo }, true); + auto const& private_inputs = + do_private_call_get_kernel_inputs_inner(false, deposit, { amount, asset_id, memo }, true); // Execute and prove the first kernel iteration Composer private_kernel_composer("../barretenberg/cpp/srs_db/ignition"); auto const& public_inputs = private_kernel_circuit(private_kernel_composer, private_inputs, true); + // TODO(jeanmon): this is a temporary hack until we have private_kernel_circuit init and inner + // variant. Once this is supported, we will be able to generate public_inputs with + // a call to private_kernel_circuit_init(private_inputs_init, ...) + auto const& private_inputs_init = + do_private_call_get_kernel_inputs_init(false, deposit, { amount, asset_id, memo }); + // Check contract address was correctly computed by the circuit - validate_deployed_contract_address(private_inputs, public_inputs); + validate_deployed_contract_address(private_inputs_init, public_inputs); // Create the final kernel proof and verify it natively. auto final_kernel_prover = private_kernel_composer.create_prover(); @@ -463,9 +536,9 @@ TEST(private_kernel_tests, native_deposit) NT::fr const& asset_id = 1; NT::fr const& memo = 999; - auto const& private_inputs = do_private_call_get_kernel_inputs(false, deposit, { amount, asset_id, memo }); + auto const& private_inputs = do_private_call_get_kernel_inputs_init(false, deposit, { amount, asset_id, memo }); DummyComposer composer = DummyComposer("private_kernel_tests__native_deposit"); - auto const& public_inputs = native_private_kernel_circuit(composer, private_inputs, true); + auto const& public_inputs = native_private_kernel_circuit_initial(composer, private_inputs); validate_deployed_contract_address(private_inputs, public_inputs); @@ -482,14 +555,19 @@ TEST(private_kernel_tests, circuit_basic_contract_deployment) NT::fr const& arg1 = 1; NT::fr const& arg2 = 999; - auto const& private_inputs = do_private_call_get_kernel_inputs(true, constructor, { arg0, arg1, arg2 }, true); + auto const& private_inputs = do_private_call_get_kernel_inputs_inner(true, constructor, { arg0, arg1, arg2 }, true); // Execute and prove the first kernel iteration Composer private_kernel_composer("../barretenberg/cpp/srs_db/ignition"); auto const& public_inputs = private_kernel_circuit(private_kernel_composer, private_inputs, true); + // TODO(jeanmon): this is a temporary hack until we have private_kernel_circuit init and inner + // variant. Once this is supported, we will be able to generate public_inputs with + // a call to private_kernel_circuit_init(private_inputs_init, ...) + auto const& private_inputs_init = do_private_call_get_kernel_inputs_init(true, constructor, { arg0, arg1, arg2 }); + // Check contract address was correctly computed by the circuit - validate_deployed_contract_address(private_inputs, public_inputs); + validate_deployed_contract_address(private_inputs_init, public_inputs); // Create the final kernel proof and verify it natively. auto final_kernel_prover = private_kernel_composer.create_prover(); @@ -511,9 +589,9 @@ TEST(private_kernel_tests, native_basic_contract_deployment) NT::fr const& arg1 = 1; NT::fr const& arg2 = 999; - auto const& private_inputs = do_private_call_get_kernel_inputs(true, constructor, { arg0, arg1, arg2 }); + auto const& private_inputs = do_private_call_get_kernel_inputs_init(true, constructor, { arg0, arg1, arg2 }); DummyComposer composer = DummyComposer("private_kernel_tests__native_basic_contract_deployment"); - auto const& public_inputs = native_private_kernel_circuit(composer, private_inputs, true); + auto const& public_inputs = native_private_kernel_circuit_initial(composer, private_inputs); validate_deployed_contract_address(private_inputs, public_inputs); @@ -531,9 +609,9 @@ TEST(private_kernel_tests, circuit_create_proof_cbinds) NT::fr const& arg2 = 999; // first run actual simulation to get public inputs - auto const& private_inputs = do_private_call_get_kernel_inputs(true, constructor, { arg0, arg1, arg2 }, true); + auto const& private_inputs = do_private_call_get_kernel_inputs_init(true, constructor, { arg0, arg1, arg2 }); DummyComposer composer = DummyComposer("private_kernel_tests__circuit_create_proof_cbinds"); - auto const& public_inputs = native_private_kernel_circuit(composer, private_inputs, true); + auto const& public_inputs = native_private_kernel_circuit_initial(composer, private_inputs); // serialize expected public inputs for later comparison std::vector expected_public_inputs_vec; @@ -608,23 +686,4 @@ TEST(private_kernel_tests, cbind_private_kernel__dummy_previous_kernel) EXPECT_EQ(actual_ss.str(), expected_ss.str()); } -/** - * @brief Test error is registered when `new_nullifiers` are not empty in first iteration - */ -TEST(private_kernel_tests, native_registers_error_when_no_space_for_nullifier) -{ - NT::fr const& amount = 5; - NT::fr const& asset_id = 1; - NT::fr const& memo = 999; - - auto private_inputs = do_private_call_get_kernel_inputs(false, deposit, { amount, asset_id, memo }); - array_push(private_inputs.previous_kernel.public_inputs.end.new_nullifiers, NT::fr::random_element()); - - DummyComposer composer = DummyComposer("private_kernel_tests__native_registers_error_when_no_space_for_nullifier"); - native_private_kernel_circuit(composer, private_inputs, true); - - ASSERT_EQ(composer.get_first_failure().code, - CircuitErrorCode::PRIVATE_KERNEL__NEW_NULLIFIERS_NOT_EMPTY_IN_FIRST_ITERATION); -} - } // namespace aztec3::circuits::kernel::private_kernel 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 96ff1fddde6..51b467872c4 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/c_bind.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/c_bind.cpp @@ -3,6 +3,9 @@ #include "index.hpp" #include "utils.hpp" +#include "aztec3/circuits/abis/combined_constant_data.hpp" +#include "aztec3/circuits/abis/kernel_circuit_public_inputs.hpp" + #include "barretenberg/srs/reference_string/env_reference_string.hpp" #include @@ -14,8 +17,10 @@ using aztec3::circuits::abis::KernelCircuitPublicInputs; using aztec3::circuits::abis::PreviousKernelData; using aztec3::circuits::abis::SignedTxRequest; using aztec3::circuits::abis::private_kernel::PrivateCallData; -using aztec3::circuits::abis::private_kernel::PrivateInputs; -using aztec3::circuits::kernel::private_kernel::native_private_kernel_circuit; +using aztec3::circuits::abis::private_kernel::PrivateKernelInputsInit; +using aztec3::circuits::abis::private_kernel::PrivateKernelInputsInner; +using aztec3::circuits::kernel::private_kernel::native_private_kernel_circuit_initial; +using aztec3::circuits::kernel::private_kernel::native_private_kernel_circuit_inner; using aztec3::circuits::kernel::private_kernel::private_kernel_circuit; using aztec3::circuits::kernel::private_kernel::utils::dummy_previous_kernel; @@ -54,6 +59,10 @@ WASM_EXPORT size_t private_kernel__init_verification_key(uint8_t const* pk_buf, CBIND(private_kernel__dummy_previous_kernel, []() { return dummy_previous_kernel(); }); + +// TODO(jeanmon) We will need two versions of this one to expose to ts. +// First let us try to get it compiled with one function (the inner one). + // TODO(dbanks12): comment about how public_inputs is a confusing name // returns size of public inputs WASM_EXPORT uint8_t* private_kernel__sim(uint8_t const* signed_tx_request_buf, @@ -64,41 +73,35 @@ WASM_EXPORT uint8_t* private_kernel__sim(uint8_t const* signed_tx_request_buf, uint8_t const** private_kernel_public_inputs_buf) { DummyComposer composer = DummyComposer("private_kernel__sim"); - SignedTxRequest signed_tx_request; - read(signed_tx_request_buf, signed_tx_request); - PrivateCallData private_call_data; read(private_call_buf, private_call_data); - PreviousKernelData previous_kernel; + KernelCircuitPublicInputs public_inputs = KernelCircuitPublicInputs{}; + if (first_iteration) { - previous_kernel = dummy_previous_kernel(); + SignedTxRequest signed_tx_request; + read(signed_tx_request_buf, signed_tx_request); - previous_kernel.public_inputs.end.private_call_stack[0] = private_call_data.call_stack_item.hash(); - previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots.private_data_tree_root = - private_call_data.call_stack_item.public_inputs.historic_private_data_tree_root; - previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots.nullifier_tree_root = - private_call_data.call_stack_item.public_inputs.historic_nullifier_tree_root; - previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots.contract_tree_root = - private_call_data.call_stack_item.public_inputs.historic_contract_tree_root; - previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots - .l1_to_l2_messages_tree_root = - private_call_data.call_stack_item.public_inputs.historic_l1_to_l2_messages_tree_root; - // previous_kernel.public_inputs.constants.historic_tree_roots.private_kernel_vk_tree_root = - previous_kernel.public_inputs.constants.tx_context = signed_tx_request.tx_request.tx_context; - previous_kernel.public_inputs.is_private = true; + // Assert that previous_kernel_buf is empty (i.e. nullptr) + ASSERT(previous_kernel_buf == nullptr); + + PrivateKernelInputsInit const private_inputs = PrivateKernelInputsInit{ + .signed_tx_request = signed_tx_request, + .private_call = private_call_data, + }; + + public_inputs = native_private_kernel_circuit_initial(composer, private_inputs); } else { + PreviousKernelData previous_kernel; read(previous_kernel_buf, previous_kernel); - } - PrivateInputs const private_inputs = PrivateInputs{ - .signed_tx_request = signed_tx_request, - .previous_kernel = previous_kernel, - .private_call = private_call_data, - }; + PrivateKernelInputsInner const private_inputs = PrivateKernelInputsInner{ + .previous_kernel = previous_kernel, + .private_call = private_call_data, + }; - KernelCircuitPublicInputs const public_inputs = - native_private_kernel_circuit(composer, private_inputs, first_iteration); + public_inputs = native_private_kernel_circuit_inner(composer, private_inputs); + } // serialize public inputs to bytes vec std::vector public_inputs_vec; @@ -111,6 +114,9 @@ WASM_EXPORT uint8_t* private_kernel__sim(uint8_t const* signed_tx_request_buf, return composer.alloc_and_serialize_first_failure(); } +// TODO(jeanmon): We currently only support inner variant because the circuit version +// was not splitted into inner/init counterparts. Once this is done, we have to modify +// the below method to dispatch over the two variants based on first_iteration boolean. // returns size of proof data WASM_EXPORT size_t private_kernel__prove(uint8_t const* signed_tx_request_buf, uint8_t const* previous_kernel_buf, @@ -147,8 +153,7 @@ WASM_EXPORT size_t private_kernel__prove(uint8_t const* signed_tx_request_buf, } else { read(previous_kernel_buf, previous_kernel); } - PrivateInputs const private_inputs = PrivateInputs{ - .signed_tx_request = signed_tx_request, + PrivateKernelInputsInner const private_inputs = PrivateKernelInputsInner{ .previous_kernel = previous_kernel, .private_call = private_call_data, }; diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/common.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/common.cpp new file mode 100644 index 00000000000..0306a6476e5 --- /dev/null +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/common.cpp @@ -0,0 +1,208 @@ +#include "init.hpp" + +#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/new_contract_data.hpp" +#include "aztec3/circuits/abis/private_kernel/private_call_data.hpp" +#include "aztec3/circuits/hash.hpp" +#include "aztec3/constants.hpp" +#include "aztec3/utils/array.hpp" +#include "aztec3/utils/dummy_composer.hpp" + +using DummyComposer = aztec3::utils::DummyComposer; + +using aztec3::circuits::abis::ContractDeploymentData; +using aztec3::circuits::abis::ContractLeafPreimage; +using aztec3::circuits::abis::FunctionData; +using aztec3::circuits::abis::KernelCircuitPublicInputs; +using aztec3::circuits::abis::NewContractData; + +using aztec3::utils::array_push; +using aztec3::utils::is_array_empty; +using aztec3::utils::push_array_to_array; +using DummyComposer = aztec3::utils::DummyComposer; +using CircuitErrorCode = aztec3::utils::CircuitErrorCode; +using aztec3::circuits::abis::private_kernel::PrivateCallData; + +namespace aztec3::circuits::kernel::private_kernel { + +void common_validate_call_stack(DummyComposer& composer, PrivateCallData const& private_call) +{ + const auto& stack = private_call.call_stack_item.public_inputs.private_call_stack; + const auto& preimages = private_call.private_call_stack_preimages; + for (size_t i = 0; i < stack.size(); ++i) { + const auto& hash = stack[i]; + const auto& preimage = preimages[i]; + + // Note: this assumes it's computationally infeasible to have `0` as a valid call_stack_item_hash. + // Assumes `hash == 0` means "this stack item is empty". + const auto calculated_hash = hash == 0 ? 0 : preimage.hash(); + composer.do_assert(hash == calculated_hash, + format("private_call_stack[", i, "] = ", hash, "; does not reconcile"), + CircuitErrorCode::PRIVATE_KERNEL__PRIVATE_CALL_STACK_ITEM_HASH_MISMATCH); + } +} + +void common_update_end_values(DummyComposer& composer, + PrivateCallData const& private_call, + KernelCircuitPublicInputs& public_inputs) +{ + const auto private_call_public_inputs = private_call.call_stack_item.public_inputs; + + const auto& new_commitments = private_call_public_inputs.new_commitments; + const auto& new_nullifiers = private_call_public_inputs.new_nullifiers; + + const auto& is_static_call = private_call_public_inputs.call_context.is_static_call; + + if (is_static_call) { + // No state changes are allowed for static calls: + composer.do_assert(is_array_empty(new_commitments) == true, + "new_commitments must be empty for static calls", + CircuitErrorCode::PRIVATE_KERNEL__NEW_COMMITMENTS_NOT_EMPTY_FOR_STATIC_CALL); + composer.do_assert(is_array_empty(new_nullifiers) == true, + "new_nullifiers must be empty for static calls", + CircuitErrorCode::PRIVATE_KERNEL__NEW_NULLIFIERS_NOT_EMPTY_FOR_STATIC_CALL); + } + + const auto& storage_contract_address = private_call_public_inputs.call_context.storage_contract_address; + + // Enhance commitments and nullifiers with domain separation whereby domain is the contract. + { // commitments & nullifiers + std::array siloed_new_commitments; + for (size_t i = 0; i < new_commitments.size(); ++i) { + siloed_new_commitments[i] = new_commitments[i] == 0 ? 0 + : add_contract_address_to_commitment( + storage_contract_address, new_commitments[i]); + } + + std::array siloed_new_nullifiers; + for (size_t i = 0; i < new_nullifiers.size(); ++i) { + siloed_new_nullifiers[i] = new_nullifiers[i] == 0 ? 0 + : add_contract_address_to_nullifier( + storage_contract_address, new_nullifiers[i]); + } + + push_array_to_array(siloed_new_commitments, public_inputs.end.new_commitments); + push_array_to_array(siloed_new_nullifiers, public_inputs.end.new_nullifiers); + } + + { // call stacks + const auto& this_private_call_stack = private_call_public_inputs.private_call_stack; + push_array_to_array(this_private_call_stack, public_inputs.end.private_call_stack); + + const auto& this_public_call_stack = private_call_public_inputs.public_call_stack; + push_array_to_array(this_public_call_stack, public_inputs.end.public_call_stack); + } + + { // new l2 to l1 messages + const auto& portal_contract_address = private_call.portal_contract_address; + const auto& new_l2_to_l1_msgs = private_call_public_inputs.new_l2_to_l1_msgs; + std::array new_l2_to_l1_msgs_to_insert; + for (size_t i = 0; i < new_l2_to_l1_msgs.size(); ++i) { + if (!new_l2_to_l1_msgs[i].is_zero()) { + // @todo @LHerskind chain-ids and rollup version id should be added here. Right now, just hard coded. + // @todo @LHerskind chain-id is hardcoded for foundry + const auto chain_id = fr(31337); + new_l2_to_l1_msgs_to_insert[i] = compute_l2_to_l1_hash(storage_contract_address, + fr(1), // rollup version id + portal_contract_address, + chain_id, + new_l2_to_l1_msgs[i]); + } + } + push_array_to_array(new_l2_to_l1_msgs_to_insert, public_inputs.end.new_l2_to_l1_msgs); + } +} + +void common_contract_logic(DummyComposer& composer, + PrivateCallData const& private_call, + KernelCircuitPublicInputs& public_inputs, + ContractDeploymentData const& contract_dep_data, + FunctionData const& function_data) +{ + const auto private_call_public_inputs = private_call.call_stack_item.public_inputs; + const auto& storage_contract_address = private_call_public_inputs.call_context.storage_contract_address; + const auto& portal_contract_address = private_call.portal_contract_address; + const auto& deployer_address = private_call_public_inputs.call_context.msg_sender; + + auto private_call_vk_hash = + stdlib::recursion::verification_key::compress_native(private_call.vk, GeneratorIndex::VK); + + auto constructor_hash = + compute_constructor_hash(function_data, private_call_public_inputs.args, private_call_vk_hash); + + auto const new_contract_address = compute_contract_address(deployer_address, + contract_dep_data.contract_address_salt, + contract_dep_data.function_tree_root, + constructor_hash); + + // Add new contract data if its a contract deployment function + NewContractData const native_new_contract_data{ new_contract_address, + portal_contract_address, + contract_dep_data.function_tree_root }; + + array_push, KERNEL_NEW_CONTRACTS_LENGTH>(public_inputs.end.new_contracts, + native_new_contract_data); + + auto is_contract_deployment = public_inputs.constants.tx_context.is_contract_deployment_tx; + + // input storage contract address must be 0 if its a constructor call and non-zero otherwise + if (is_contract_deployment) { + composer.do_assert(contract_dep_data.constructor_vk_hash == private_call_vk_hash, + "constructor_vk_hash doesn't match private_call_vk_hash", + CircuitErrorCode::PRIVATE_KERNEL__INVALID_CONSTRUCTOR_VK_HASH); + + // must imply == derived address + composer.do_assert(storage_contract_address == new_contract_address, + "contract address supplied doesn't match derived address", + CircuitErrorCode::PRIVATE_KERNEL__INVALID_CONTRACT_ADDRESS); + + // compute contract address nullifier + auto const blake_input = new_contract_address.to_field().to_buffer(); + auto const new_contract_address_nullifier = NT::fr::serialize_from_buffer(NT::blake3s(blake_input).data()); + + // push the contract address nullifier to nullifier vector + array_push(public_inputs.end.new_nullifiers, new_contract_address_nullifier); + } else { + // non-contract deployments must specify contract address being interacted with + composer.do_assert(storage_contract_address != 0, + "contract address can't be 0 for non-contract deployment related transactions", + CircuitErrorCode::PRIVATE_KERNEL__INVALID_CONTRACT_ADDRESS); + + /* We need to compute the root of the contract tree, starting from the function's VK: + * - Compute the vk_hash (done above) + * - Compute the function_leaf: hash(function_selector, is_private, vk_hash, acir_hash) + * - Hash the function_leaf with the function_leaf's sibling_path to get the function_tree_root + * - Compute the contract_leaf: hash(contract_address, portal_contract_address, function_tree_root) + * - Hash the contract_leaf with the contract_leaf's sibling_path to get the contract_tree_root + */ + + // The logic below ensures that the contract exists in the contracts tree + + auto const& computed_function_tree_root = + function_tree_root_from_siblings(private_call.call_stack_item.function_data.function_selector, + true, // is_private + private_call_vk_hash, + private_call.acir_hash, + private_call.function_leaf_membership_witness.leaf_index, + private_call.function_leaf_membership_witness.sibling_path); + + auto const& computed_contract_tree_root = + contract_tree_root_from_siblings(computed_function_tree_root, + storage_contract_address, + portal_contract_address, + private_call.contract_leaf_membership_witness.leaf_index, + private_call.contract_leaf_membership_witness.sibling_path); + + auto const& purported_contract_tree_root = + private_call.call_stack_item.public_inputs.historic_contract_tree_root; + + composer.do_assert( + computed_contract_tree_root == purported_contract_tree_root, + "computed_contract_tree_root doesn't match purported_contract_tree_root", + CircuitErrorCode::PRIVATE_KERNEL__COMPUTED_CONTRACT_TREE_ROOT_AND_PURPORTED_CONTRACT_TREE_ROOT_MISMATCH); + } +} + +} // 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 new file mode 100644 index 00000000000..502929e134e --- /dev/null +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/common.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include "init.hpp" + +#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/private_kernel/private_call_data.hpp" +#include "aztec3/utils/dummy_composer.hpp" + +namespace aztec3::circuits::kernel::private_kernel { + +using aztec3::circuits::abis::ContractDeploymentData; +using DummyComposer = aztec3::utils::DummyComposer; +using aztec3::circuits::abis::FunctionData; +using aztec3::circuits::abis::KernelCircuitPublicInputs; +using aztec3::circuits::abis::private_kernel::PrivateCallData; + +// TODO(suyash): Add comments to these as well as other functions in PKC-init. +void common_validate_call_stack(DummyComposer& composer, PrivateCallData const& private_call); + +void common_update_end_values(DummyComposer& composer, + PrivateCallData const& private_call, + KernelCircuitPublicInputs& public_inputs); + +void common_contract_logic(DummyComposer& composer, + PrivateCallData const& private_call, + KernelCircuitPublicInputs& public_inputs, + ContractDeploymentData const& contract_dep_data, + FunctionData const& function_data); +} // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/index.hpp b/circuits/cpp/src/aztec3/circuits/kernel/private/index.hpp index 60f0e23967e..7195cb64ed0 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/index.hpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/index.hpp @@ -1,3 +1,4 @@ #include "init.hpp" -#include "native_private_kernel_circuit.hpp" +#include "native_private_kernel_circuit_init.hpp" +#include "native_private_kernel_circuit_inner.hpp" #include "private_kernel_circuit.hpp" \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/init.hpp b/circuits/cpp/src/aztec3/circuits/kernel/private/init.hpp index 6da9911174d..991ba4ed6bd 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/init.hpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/init.hpp @@ -1,12 +1,11 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include -#include +#include "aztec3/circuits/apps/function_execution_context.hpp" +#include "aztec3/circuits/apps/oracle_wrapper.hpp" +#include "aztec3/circuits/recursion/aggregator.hpp" +#include "aztec3/oracle/oracle.hpp" +#include "aztec3/utils/types/circuit_types.hpp" +#include "aztec3/utils/types/convert.hpp" +#include "aztec3/utils/types/native_types.hpp" namespace aztec3::circuits::kernel::private_kernel { diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit.cpp deleted file mode 100644 index 7a4f068db46..00000000000 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit.cpp +++ /dev/null @@ -1,415 +0,0 @@ -#include "init.hpp" - -#include "aztec3/circuits/abis/function_leaf_preimage.hpp" -#include "aztec3/constants.hpp" -#include -#include -#include -#include -#include -#include - -#include - -namespace aztec3::circuits::kernel::private_kernel { - -using aztec3::circuits::abis::ContractLeafPreimage; -using aztec3::circuits::abis::KernelCircuitPublicInputs; -using aztec3::circuits::abis::NewContractData; -using aztec3::circuits::abis::private_kernel::PrivateInputs; - -using aztec3::utils::array_length; -using aztec3::utils::array_pop; -using aztec3::utils::array_push; -using aztec3::utils::is_array_empty; -using aztec3::utils::push_array_to_array; -using DummyComposer = aztec3::utils::DummyComposer; -using CircuitErrorCode = aztec3::utils::CircuitErrorCode; - -using aztec3::circuits::compute_constructor_hash; -using aztec3::circuits::compute_contract_address; -using aztec3::circuits::compute_l2_to_l1_hash; -using aztec3::circuits::contract_tree_root_from_siblings; -using aztec3::circuits::function_tree_root_from_siblings; - -// 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(Composer& composer, -// PrivateInputs 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( -// &composer, private_inputs.private_call.vk, private_inputs.private_call.proof, -// num_private_call_public_inputs); - -// Aggregator::aggregate(&composer, -// private_inputs.previous_kernel.vk, -// private_inputs.previous_kernel.proof, -// num_private_kernel_public_inputs, -// aggregation_object); - -// return aggregation_object; -// } - -void initialise_end_values(PrivateInputs const& private_inputs, KernelCircuitPublicInputs& public_inputs) -{ - public_inputs.constants = private_inputs.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 = private_inputs.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.optionally_revealed_data = start.optionally_revealed_data; -} - -void contract_logic(DummyComposer& composer, - PrivateInputs const& private_inputs, - KernelCircuitPublicInputs& public_inputs) -{ - const auto private_call_public_inputs = private_inputs.private_call.call_stack_item.public_inputs; - const auto& storage_contract_address = private_call_public_inputs.call_context.storage_contract_address; - const auto& portal_contract_address = private_inputs.private_call.portal_contract_address; - const auto& deployer_address = private_call_public_inputs.call_context.msg_sender; - const auto& contract_deployment_data = - private_inputs.signed_tx_request.tx_request.tx_context.contract_deployment_data; - - // contract deployment - - // input storage contract address must be 0 if its a constructor call and non-zero otherwise - auto is_contract_deployment = public_inputs.constants.tx_context.is_contract_deployment_tx; - - auto private_call_vk_hash = stdlib::recursion::verification_key::compress_native( - private_inputs.private_call.vk, GeneratorIndex::VK); - - auto constructor_hash = compute_constructor_hash(private_inputs.signed_tx_request.tx_request.function_data, - private_call_public_inputs.args, - private_call_vk_hash); - - if (is_contract_deployment) { - composer.do_assert(contract_deployment_data.constructor_vk_hash == private_call_vk_hash, - "constructor_vk_hash doesn't match private_call_vk_hash", - CircuitErrorCode::PRIVATE_KERNEL__INVALID_CONSTRUCTOR_VK_HASH); - } - - auto const new_contract_address = compute_contract_address(deployer_address, - contract_deployment_data.contract_address_salt, - contract_deployment_data.function_tree_root, - constructor_hash); - - if (is_contract_deployment) { - // must imply == derived address - composer.do_assert(storage_contract_address == new_contract_address, - "contract address supplied doesn't match derived address", - CircuitErrorCode::PRIVATE_KERNEL__INVALID_CONTRACT_ADDRESS); - } else { - // non-contract deployments must specify contract address being interacted with - composer.do_assert(storage_contract_address != 0, - "contract address can't be 0 for non-contract deployment related transactions", - CircuitErrorCode::PRIVATE_KERNEL__INVALID_CONTRACT_ADDRESS); - } - - // compute contract address nullifier - auto const blake_input = new_contract_address.to_field().to_buffer(); - auto const new_contract_address_nullifier = NT::fr::serialize_from_buffer(NT::blake3s(blake_input).data()); - - // push the contract address nullifier to nullifier vector - if (is_contract_deployment) { - array_push(public_inputs.end.new_nullifiers, new_contract_address_nullifier); - } - - // Add new contract data if its a contract deployment function - NewContractData const native_new_contract_data{ new_contract_address, - portal_contract_address, - contract_deployment_data.function_tree_root }; - - array_push, KERNEL_NEW_CONTRACTS_LENGTH>(public_inputs.end.new_contracts, - native_new_contract_data); - - /* We need to compute the root of the contract tree, starting from the function's VK: - * - Compute the vk_hash (done above) - * - Compute the function_leaf: hash(function_selector, is_private, vk_hash, acir_hash) - * - Hash the function_leaf with the function_leaf's sibling_path to get the function_tree_root - * - Compute the contract_leaf: hash(contract_address, portal_contract_address, function_tree_root) - * - Hash the contract_leaf with the contract_leaf's sibling_path to get the contract_tree_root - */ - - // ensure that historic/purported contract tree root matches the one in previous kernel - auto const& purported_contract_tree_root = - private_inputs.private_call.call_stack_item.public_inputs.historic_contract_tree_root; - auto const& previous_kernel_contract_tree_root = - private_inputs.previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots - .contract_tree_root; - composer.do_assert( - purported_contract_tree_root == previous_kernel_contract_tree_root, - "purported_contract_tree_root doesn't match previous_kernel_contract_tree_root", - CircuitErrorCode::PRIVATE_KERNEL__PURPORTED_CONTRACT_TREE_ROOT_AND_PREVIOUS_KERNEL_CONTRACT_TREE_ROOT_MISMATCH); - - // The logic below ensures that the contract exists in the contracts tree - if (!is_contract_deployment) { - auto const& computed_function_tree_root = function_tree_root_from_siblings( - private_inputs.private_call.call_stack_item.function_data.function_selector, - true, // is_private - private_call_vk_hash, - private_inputs.private_call.acir_hash, - private_inputs.private_call.function_leaf_membership_witness.leaf_index, - private_inputs.private_call.function_leaf_membership_witness.sibling_path); - - auto const& computed_contract_tree_root = contract_tree_root_from_siblings( - computed_function_tree_root, - storage_contract_address, - portal_contract_address, - private_inputs.private_call.contract_leaf_membership_witness.leaf_index, - private_inputs.private_call.contract_leaf_membership_witness.sibling_path); - - composer.do_assert( - computed_contract_tree_root == purported_contract_tree_root, - "computed_contract_tree_root doesn't match purported_contract_tree_root", - CircuitErrorCode::PRIVATE_KERNEL__COMPUTED_CONTRACT_TREE_ROOT_AND_PURPORTED_CONTRACT_TREE_ROOT_MISMATCH); - } -} - -void update_end_values(DummyComposer& composer, - PrivateInputs const& private_inputs, - KernelCircuitPublicInputs& public_inputs, - bool first_iteration) -{ - const auto private_call_public_inputs = private_inputs.private_call.call_stack_item.public_inputs; - - const auto& new_commitments = private_call_public_inputs.new_commitments; - const auto& new_nullifiers = private_call_public_inputs.new_nullifiers; - - const auto& is_static_call = private_call_public_inputs.call_context.is_static_call; - - if (is_static_call) { - // No state changes are allowed for static calls: - composer.do_assert(is_array_empty(new_commitments) == true, - "new_commitments must be empty for static calls", - CircuitErrorCode::PRIVATE_KERNEL__NEW_COMMITMENTS_NOT_EMPTY_FOR_STATIC_CALL); - composer.do_assert(is_array_empty(new_nullifiers) == true, - "new_nullifiers must be empty for static calls", - CircuitErrorCode::PRIVATE_KERNEL__NEW_NULLIFIERS_NOT_EMPTY_FOR_STATIC_CALL); - } - - const auto& storage_contract_address = private_call_public_inputs.call_context.storage_contract_address; - - if (first_iteration) { - // Since it's the first iteration, we need to push the the tx hash nullifier into the `new_nullifiers` array - - // If the nullifiers array is not empty a change was made and we need to rework this - composer.do_assert(is_array_empty(public_inputs.end.new_nullifiers), - "new_nullifiers array must be empty in a first iteration of private kernel", - CircuitErrorCode::PRIVATE_KERNEL__NEW_NULLIFIERS_NOT_EMPTY_IN_FIRST_ITERATION); - - array_push(public_inputs.end.new_nullifiers, private_inputs.signed_tx_request.hash()); - } - - { - // Nonce nullifier - // DANGER: This is terrible. This should not be part of the protocol. This is an intentional bodge to reach a - // milestone. This must not be the way we derive nonce nullifiers in production. It can be front-run by other - // users. It is not domain separated. Naughty. - array_push(public_inputs.end.new_nullifiers, private_inputs.signed_tx_request.tx_request.nonce); - } - - { // commitments & nullifiers - std::array siloed_new_commitments; - for (size_t i = 0; i < new_commitments.size(); ++i) { - siloed_new_commitments[i] = new_commitments[i] == 0 ? 0 - : add_contract_address_to_commitment( - storage_contract_address, new_commitments[i]); - } - - std::array siloed_new_nullifiers; - for (size_t i = 0; i < new_nullifiers.size(); ++i) { - siloed_new_nullifiers[i] = new_nullifiers[i] == 0 ? 0 - : add_contract_address_to_nullifier( - storage_contract_address, new_nullifiers[i]); - } - - push_array_to_array(siloed_new_commitments, public_inputs.end.new_commitments); - push_array_to_array(siloed_new_nullifiers, public_inputs.end.new_nullifiers); - } - - { // private call stack - const auto& this_private_call_stack = private_call_public_inputs.private_call_stack; - push_array_to_array(this_private_call_stack, public_inputs.end.private_call_stack); - } - - { // public call stack - const auto& this_public_call_stack = private_call_public_inputs.public_call_stack; - push_array_to_array(this_public_call_stack, public_inputs.end.public_call_stack); - } - - { // new l2 to l1 messages - const auto& portal_contract_address = private_inputs.private_call.portal_contract_address; - const auto& new_l2_to_l1_msgs = private_call_public_inputs.new_l2_to_l1_msgs; - std::array new_l2_to_l1_msgs_to_insert; - for (size_t i = 0; i < new_l2_to_l1_msgs.size(); ++i) { - if (!new_l2_to_l1_msgs[i].is_zero()) { - // @todo @LHerskind chain-ids and rollup version id should be added here. Right now, just hard coded. - // @todo @LHerskind chain-id is hardcoded for foundry - const auto chain_id = fr(31337); - new_l2_to_l1_msgs_to_insert[i] = compute_l2_to_l1_hash(storage_contract_address, - fr(1), // rollup version id - portal_contract_address, - chain_id, - new_l2_to_l1_msgs[i]); - } - } - push_array_to_array(new_l2_to_l1_msgs_to_insert, public_inputs.end.new_l2_to_l1_msgs); - } -} - -void validate_this_private_call_hash(DummyComposer& composer, - PrivateInputs const& private_inputs, - KernelCircuitPublicInputs& public_inputs) -{ - // TODO: this logic might need to change to accommodate the weird edge 3 initial txs (the 'main' tx, the 'fee' tx, - // and the 'gas rebate' tx). - const auto popped_private_call_hash = array_pop(public_inputs.end.private_call_stack); - const auto calculated_this_private_call_hash = private_inputs.private_call.call_stack_item.hash(); - - composer.do_assert( - popped_private_call_hash == calculated_this_private_call_hash, - "calculated private_call_hash does not match provided private_call_hash at the top of the call stack", - CircuitErrorCode::PRIVATE_KERNEL__CALCULATED_PRIVATE_CALL_HASH_AND_PROVIDED_PRIVATE_CALL_HASH_MISMATCH); -}; - -void validate_this_private_call_stack(DummyComposer& composer, PrivateInputs const& private_inputs) -{ - const auto& stack = private_inputs.private_call.call_stack_item.public_inputs.private_call_stack; - const auto& preimages = private_inputs.private_call.private_call_stack_preimages; - for (size_t i = 0; i < stack.size(); ++i) { - const auto& hash = stack[i]; - const auto& preimage = preimages[i]; - - // Note: this assumes it's computationally infeasible to have `0` as a valid call_stack_item_hash. - // Assumes `hash == 0` means "this stack item is empty". - const auto calculated_hash = hash == 0 ? 0 : preimage.hash(); - composer.do_assert(hash == calculated_hash, - format("private_call_stack[", i, "] = ", hash, "; does not reconcile"), - CircuitErrorCode::PRIVATE_KERNEL__PRIVATE_CALL_STACK_ITEM_HASH_MISMATCH); - } -}; - -void validate_inputs(DummyComposer& composer, PrivateInputs const& private_inputs, bool is_base_case) -{ - const auto& this_call_stack_item = private_inputs.private_call.call_stack_item; - - composer.do_assert(this_call_stack_item.function_data.is_private == true, - "Cannot execute a non-private function with the private kernel circuit", - CircuitErrorCode::PRIVATE_KERNEL__NON_PRIVATE_FUNCTION_EXECUTED_WITH_PRIVATE_KERNEL); - - const auto& start = private_inputs.previous_kernel.public_inputs.end; - - // TODO: we might want to range-constrain the call_count to prevent some kind of overflow errors. Having said that, - // iterating 2^254 times isn't feasible. - - NT::fr const start_private_call_stack_length = array_length(start.private_call_stack); - NT::fr const start_public_call_stack_length = array_length(start.public_call_stack); - NT::fr const start_new_l2_to_l1_msgs_length = array_length(start.new_l2_to_l1_msgs); - - // Base Case - if (is_base_case) { - // TODO: change to allow 3 initial calls on the private call stack, so a fee can be paid and a gas - // rebate can be paid. - - composer.do_assert(start_private_call_stack_length == 1, - "Private call stack must be length 1", - CircuitErrorCode::PRIVATE_KERNEL__PRIVATE_CALL_STACK_LENGTH_MISMATCH); - - composer.do_assert(start_public_call_stack_length == 0, - "Public call stack must be empty", - CircuitErrorCode::PRIVATE_KERNEL__UNSUPPORTED_OP); - composer.do_assert(start_new_l2_to_l1_msgs_length == 0, - "L2 to L1 msgs must be empty", - CircuitErrorCode::PRIVATE_KERNEL__UNSUPPORTED_OP); - - composer.do_assert(this_call_stack_item.public_inputs.call_context.is_delegate_call == false, - "Users cannot make a delegatecall", - CircuitErrorCode::PRIVATE_KERNEL__UNSUPPORTED_OP); - composer.do_assert(this_call_stack_item.public_inputs.call_context.is_static_call == false, - "Users cannot make a static call", - CircuitErrorCode::PRIVATE_KERNEL__UNSUPPORTED_OP); - - // The below also prevents delegatecall/staticcall in the base case - composer.do_assert(this_call_stack_item.public_inputs.call_context.storage_contract_address == - this_call_stack_item.contract_address, - "Storage contract address must be that of the called contract", - CircuitErrorCode::PRIVATE_KERNEL__CONTRACT_ADDRESS_MISMATCH); - - composer.do_assert(private_inputs.previous_kernel.vk->contains_recursive_proof == false, - "Mock kernel proof must not contain a recursive proof", - CircuitErrorCode::PRIVATE_KERNEL__KERNEL_PROOF_CONTAINS_RECURSIVE_PROOF); - - // TODO: Assert that the previous kernel data is empty. (Or rather, the verify_proof() function needs a valid - // dummy proof and vk to complete execution, so actually what we want is for that mockvk to be - // hard-coded into the circuit and assert that that is the one which has been used in the base case). - } else { - // is_recursive_case - - composer.do_assert(private_inputs.previous_kernel.public_inputs.is_private == true, - "Cannot verify a non-private kernel snark in the private kernel circuit", - CircuitErrorCode::PRIVATE_KERNEL__NON_PRIVATE_KERNEL_VERIFIED_WITH_PRIVATE_KERNEL); - composer.do_assert(this_call_stack_item.function_data.is_constructor == false, - "A constructor must be executed as the first tx in the recursion", - CircuitErrorCode::PRIVATE_KERNEL__CONSTRUCTOR_EXECUTED_IN_RECURSION); - composer.do_assert(start_private_call_stack_length != 0, - "Cannot execute private kernel circuit with an empty private call stack", - CircuitErrorCode::PRIVATE_KERNEL__PRIVATE_CALL_STACK_EMPTY); - } -} - -// NOTE: THIS IS A VERY UNFINISHED WORK IN PROGRESS. -// TODO: decide what to return. -// TODO: 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(DummyComposer& composer, - PrivateInputs const& private_inputs, - bool first_iteration) -{ - // We'll be pushing data to this during execution of this circuit. - KernelCircuitPublicInputs public_inputs{}; - - // Do this before any functions can modify the inputs. - initialise_end_values(private_inputs, public_inputs); - - validate_inputs(composer, private_inputs, first_iteration); - - validate_this_private_call_hash(composer, private_inputs, public_inputs); - - // TODO(rahul) FIXME - https://github.com/AztecProtocol/aztec-packages/issues/499 - // Noir doesn't have hash index so it can't hash private call stack item correctly - // validate_this_private_call_stack(composer, private_inputs); - - update_end_values(composer, private_inputs, public_inputs, first_iteration); - - contract_logic(composer, private_inputs, public_inputs); - - // We'll skip any verification in this native implementation, because for a Local Developer Testnet, there won't - // _be_ a valid proof to verify!!! auto aggregation_object = verify_proofs(composer, - // private_inputs, - // _private_inputs.private_call.vk->num_public_inputs, - // _private_inputs.previous_kernel.vk->num_public_inputs); - - // TODO(dbanks12): kernel vk membership check! - - // Note: given that we skipped the verify_proof function, the aggregation object we get at the end will just be the - // same as we had at the start. public_inputs.end.aggregation_object = aggregation_object; - public_inputs.end.aggregation_object = private_inputs.previous_kernel.public_inputs.end.aggregation_object; - - return 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.hpp b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit.hpp deleted file mode 100644 index 71a111db940..00000000000 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include "init.hpp" - -#include -#include -#include - -namespace aztec3::circuits::kernel::private_kernel { - -using aztec3::circuits::abis::KernelCircuitPublicInputs; -using aztec3::circuits::abis::private_kernel::PrivateInputs; -// using abis::private_kernel::PublicInputs; -using DummyComposer = aztec3::utils::DummyComposer; - -// TODO: decide what to return. -KernelCircuitPublicInputs native_private_kernel_circuit(DummyComposer& composer, - PrivateInputs const& _private_inputs, - bool first_iteration); - -} // 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_init.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_init.cpp new file mode 100644 index 00000000000..2a1e6ef5bf1 --- /dev/null +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_init.cpp @@ -0,0 +1,194 @@ +#include "common.hpp" + +#include "aztec3/circuits/abis/combined_constant_data.hpp" +#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/circuits/kernel/private/init.hpp" +#include "aztec3/constants.hpp" +#include "aztec3/utils/array.hpp" + +using aztec3::circuits::abis::CombinedConstantData; +using aztec3::circuits::abis::CombinedHistoricTreeRoots; +using aztec3::circuits::abis::PrivateHistoricTreeRoots; +using aztec3::circuits::abis::private_kernel::PrivateKernelInputsInit; +using aztec3::utils::array_push; +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(Composer& composer, +// 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( +// &composer, private_inputs.private_call.vk, private_inputs.private_call.proof, +// num_private_call_public_inputs); + +// Aggregator::aggregate(&composer, +// 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) +{ + // Define the constants data. + auto const& private_call_public_inputs = private_inputs.private_call.call_stack_item.public_inputs; + auto const constants = CombinedConstantData{ + .historic_tree_roots = + CombinedHistoricTreeRoots{ + .private_historic_tree_roots = + PrivateHistoricTreeRoots{ + .private_data_tree_root = private_call_public_inputs.historic_private_data_tree_root, + .nullifier_tree_root = private_call_public_inputs.historic_nullifier_tree_root, + .contract_tree_root = private_call_public_inputs.historic_contract_tree_root, + .l1_to_l2_messages_tree_root = private_call_public_inputs.historic_l1_to_l2_messages_tree_root, + }, + }, + .tx_context = private_inputs.signed_tx_request.tx_request.tx_context, + }; + + // Set the constants in public_inputs. + public_inputs.constants = constants; +} + +void validate_this_private_call_against_tx_request(DummyComposer& composer, + PrivateKernelInputsInit const& private_inputs) +{ + // TODO: this logic might need to change to accommodate the weird edge 3 initial txs (the 'main' tx, the 'fee' tx, + // and the 'gas rebate' tx). + + // Confirm that the SignedTxRequest (user's intent) matches the private call being executed + const auto& tx_request = private_inputs.signed_tx_request.tx_request; + const auto& call_stack_item = private_inputs.private_call.call_stack_item; + + const auto tx_request_args_hash = NT::compress(tx_request.args, FUNCTION_ARGS); + const auto call_args_hash = NT::compress(call_stack_item.public_inputs.args, FUNCTION_ARGS); + + composer.do_assert( + tx_request.to == call_stack_item.contract_address, + "user's intent does not match initial private call (tx_request.to must match call_stack_item.contract_address)", + CircuitErrorCode::PRIVATE_KERNEL__USER_INTENT_MISMATCH_BETWEEN_TX_REQUEST_AND_CALL_STACK_ITEM); + + composer.do_assert(tx_request.function_data.hash() == call_stack_item.function_data.hash(), + "user's intent does not match initial private call (tx_request.function_data must match " + "call_stack_item.function_data)", + CircuitErrorCode::PRIVATE_KERNEL__USER_INTENT_MISMATCH_BETWEEN_TX_REQUEST_AND_CALL_STACK_ITEM); + + composer.do_assert(tx_request_args_hash == call_args_hash, + "user's intent does not match initial private call (tx_request.args must match " + "call_stack_item.public_inputs.args)", + CircuitErrorCode::PRIVATE_KERNEL__USER_INTENT_MISMATCH_BETWEEN_TX_REQUEST_AND_CALL_STACK_ITEM); +}; + +void validate_inputs(DummyComposer& composer, PrivateKernelInputsInit const& private_inputs) +{ + const auto& this_call_stack_item = private_inputs.private_call.call_stack_item; + + composer.do_assert(this_call_stack_item.function_data.is_private == true, + "Cannot execute a non-private function with the private kernel circuit", + CircuitErrorCode::PRIVATE_KERNEL__NON_PRIVATE_FUNCTION_EXECUTED_WITH_PRIVATE_KERNEL); + + // TODO: change to allow 3 initial calls on the private call stack, so a fee can be paid and a gas + // rebate can be paid. + + /* If we are going to have 3 initial calls on the private call stack, + * then do we still need the `private_call_stack` + * despite no longer needing a full `previous_kernel` + */ + + composer.do_assert(this_call_stack_item.public_inputs.call_context.is_delegate_call == false, + "Users cannot make a delegatecall", + CircuitErrorCode::PRIVATE_KERNEL__UNSUPPORTED_OP); + composer.do_assert(this_call_stack_item.public_inputs.call_context.is_static_call == false, + "Users cannot make a static call", + CircuitErrorCode::PRIVATE_KERNEL__UNSUPPORTED_OP); + + // The below also prevents delegatecall/staticcall in the base case + composer.do_assert(this_call_stack_item.public_inputs.call_context.storage_contract_address == + this_call_stack_item.contract_address, + "Storage contract address must be that of the called contract", + CircuitErrorCode::PRIVATE_KERNEL__CONTRACT_ADDRESS_MISMATCH); + + // TODO: Assert that the previous kernel data is empty. (Or rather, the verify_proof() function needs a valid + // dummy proof and vk to complete execution, so actually what we want is for that mockvk to be + // hard-coded into the circuit and assert that that is the one which has been used in the base case). +} + +void update_end_values(PrivateKernelInputsInit const& private_inputs, KernelCircuitPublicInputs& public_inputs) +{ + // We only initialzed constants member of public_inputs so far. Therefore, there must not be any + // new nullifiers as part of public_inputs. + ASSERT(is_array_empty(public_inputs.end.new_nullifiers)); + + // Since it's the first iteration, we need to push the the tx hash nullifier into the `new_nullifiers` array + array_push(public_inputs.end.new_nullifiers, private_inputs.signed_tx_request.hash()); + + // Nonce nullifier + // DANGER: This is terrible. This should not be part of the protocol. This is an intentional bodge to reach a + // milestone. This must not be the way we derive nonce nullifiers in production. It can be front-run by other + // users. It is not domain separated. Naughty. + array_push(public_inputs.end.new_nullifiers, private_inputs.signed_tx_request.tx_request.nonce); +} + +// NOTE: THIS IS A VERY UNFINISHED WORK IN PROGRESS. +// TODO: 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(DummyComposer& composer, + PrivateKernelInputsInit const& private_inputs) +{ + // We'll be pushing data to this during execution of this circuit. + KernelCircuitPublicInputs public_inputs{}; + + // Do this before any functions can modify the inputs. + initialise_end_values(private_inputs, public_inputs); + + validate_inputs(composer, private_inputs); + + // TODO(rahul) FIXME - https://github.com/AztecProtocol/aztec-packages/issues/499 + // Noir doesn't have hash index so it can't hash private call stack item correctly + // TODO(jeanmon) FIXME - https://github.com/AztecProtocol/aztec-packages/issues/672 + // validate_this_private_call_against_tx_request(composer, private_inputs); + + // TODO(dbanks12): may need to comment out hash check in here according to TODO above + // TODO(jeanmon) FIXME - https://github.com/AztecProtocol/aztec-packages/issues/671 + // common_validate_call_stack(composer, private_inputs.private_call); + + update_end_values(private_inputs, public_inputs); + + common_update_end_values(composer, private_inputs.private_call, public_inputs); + + common_contract_logic(composer, + private_inputs.private_call, + public_inputs, + private_inputs.signed_tx_request.tx_request.tx_context.contract_deployment_data, + private_inputs.signed_tx_request.tx_request.function_data); + + // We'll skip any verification in this native implementation, because for a Local Developer Testnet, there won't + // _be_ a valid proof to verify!!! auto aggregation_object = verify_proofs(composer, + // private_inputs, + // _private_inputs.private_call.vk->num_public_inputs, + // _private_inputs.previous_kernel.vk->num_public_inputs); + + // TODO: kernel vk membership check! + + // In the native version, as there is no verify_proofs call, we can initialize aggregation object with the default + // constructor. + NT::AggregationObject const empty_aggregation_object{}; + public_inputs.end.aggregation_object = empty_aggregation_object; + + return 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_init.hpp b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_init.hpp new file mode 100644 index 00000000000..c9d86e0a397 --- /dev/null +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_init.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include "init.hpp" + +#include "aztec3/circuits/abis/kernel_circuit_public_inputs.hpp" +#include "aztec3/circuits/abis/private_kernel/private_kernel_inputs_init.hpp" +#include "aztec3/utils/dummy_composer.hpp" + +namespace aztec3::circuits::kernel::private_kernel { + +using aztec3::circuits::abis::KernelCircuitPublicInputs; +using aztec3::circuits::abis::private_kernel::PrivateKernelInputsInit; +// using abis::private_kernel::PublicInputs; +using DummyComposer = aztec3::utils::DummyComposer; + +KernelCircuitPublicInputs native_private_kernel_circuit_initial(DummyComposer& composer, + PrivateKernelInputsInit const& private_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_inner.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_inner.cpp new file mode 100644 index 00000000000..9ffa1974ee4 --- /dev/null +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_inner.cpp @@ -0,0 +1,188 @@ +#include "common.hpp" +#include "init.hpp" + +#include "aztec3/circuits/abis/kernel_circuit_public_inputs.hpp" +#include "aztec3/circuits/abis/new_contract_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_composer.hpp" + +namespace aztec3::circuits::kernel::private_kernel { + +using aztec3::circuits::abis::ContractLeafPreimage; +using aztec3::circuits::abis::KernelCircuitPublicInputs; +using aztec3::circuits::abis::private_kernel::PrivateKernelInputsInner; + +using aztec3::utils::array_length; +using aztec3::utils::array_pop; +using DummyComposer = aztec3::utils::DummyComposer; +using CircuitErrorCode = aztec3::utils::CircuitErrorCode; + +// 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(Composer& composer, +// PrivateInputs 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( +// &composer, private_inputs.private_call.vk, private_inputs.private_call.proof, +// num_private_call_public_inputs); + +// Aggregator::aggregate(&composer, +// private_inputs.previous_kernel.vk, +// private_inputs.previous_kernel.proof, +// num_private_kernel_public_inputs, +// aggregation_object); + +// return aggregation_object; +// } + +void initialise_end_values(PrivateKernelInputsInner const& private_inputs, + KernelCircuitPublicInputs& public_inputs) +{ + public_inputs.constants = private_inputs.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 = private_inputs.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.optionally_revealed_data = start.optionally_revealed_data; +} + +void validate_this_private_call_hash(DummyComposer& composer, + PrivateKernelInputsInner const& private_inputs, + KernelCircuitPublicInputs& public_inputs) +{ + // TODO: this logic might need to change to accommodate the weird edge 3 initial txs (the 'main' tx, the 'fee' tx, + // and the 'gas rebate' tx). + const auto popped_private_call_hash = array_pop(public_inputs.end.private_call_stack); + const auto calculated_this_private_call_hash = private_inputs.private_call.call_stack_item.hash(); + + composer.do_assert( + popped_private_call_hash == calculated_this_private_call_hash, + "calculated private_call_hash does not match provided private_call_hash at the top of the call stack", + CircuitErrorCode::PRIVATE_KERNEL__CALCULATED_PRIVATE_CALL_HASH_AND_PROVIDED_PRIVATE_CALL_HASH_MISMATCH); +}; + +void validate_this_private_call_stack(DummyComposer& composer, PrivateKernelInputsInner const& private_inputs) +{ + const auto& stack = private_inputs.private_call.call_stack_item.public_inputs.private_call_stack; + const auto& preimages = private_inputs.private_call.private_call_stack_preimages; + for (size_t i = 0; i < stack.size(); ++i) { + const auto& hash = stack[i]; + const auto& preimage = preimages[i]; + + // Note: this assumes it's computationally infeasible to have `0` as a valid call_stack_item_hash. + // Assumes `hash == 0` means "this stack item is empty". + const auto calculated_hash = hash == 0 ? 0 : preimage.hash(); + composer.do_assert(hash == calculated_hash, + format("private_call_stack[", i, "] = ", hash, "; does not reconcile"), + CircuitErrorCode::PRIVATE_KERNEL__PRIVATE_CALL_STACK_ITEM_HASH_MISMATCH); + } +}; + +void validate_contract_tree_root(DummyComposer& composer, PrivateKernelInputsInner const& private_inputs) +{ + auto const& purported_contract_tree_root = + private_inputs.private_call.call_stack_item.public_inputs.historic_contract_tree_root; + auto const& previous_kernel_contract_tree_root = + private_inputs.previous_kernel.public_inputs.constants.historic_tree_roots.private_historic_tree_roots + .contract_tree_root; + composer.do_assert( + purported_contract_tree_root == previous_kernel_contract_tree_root, + "purported_contract_tree_root doesn't match previous_kernel_contract_tree_root", + CircuitErrorCode::PRIVATE_KERNEL__PURPORTED_CONTRACT_TREE_ROOT_AND_PREVIOUS_KERNEL_CONTRACT_TREE_ROOT_MISMATCH); +} + +void validate_inputs(DummyComposer& composer, PrivateKernelInputsInner const& private_inputs) +{ + const auto& this_call_stack_item = private_inputs.private_call.call_stack_item; + + composer.do_assert(this_call_stack_item.function_data.is_private == true, + "Cannot execute a non-private function with the private kernel circuit", + CircuitErrorCode::PRIVATE_KERNEL__NON_PRIVATE_FUNCTION_EXECUTED_WITH_PRIVATE_KERNEL); + + const auto& start = private_inputs.previous_kernel.public_inputs.end; + + // TODO: we might want to range-constrain the call_count to prevent some kind of overflow errors. Having said that, + // iterating 2^254 times isn't feasible. + + NT::fr const start_private_call_stack_length = array_length(start.private_call_stack); + + // is_recursive_case + + composer.do_assert(private_inputs.previous_kernel.public_inputs.is_private == true, + "Cannot verify a non-private kernel snark in the private kernel circuit", + CircuitErrorCode::PRIVATE_KERNEL__NON_PRIVATE_KERNEL_VERIFIED_WITH_PRIVATE_KERNEL); + composer.do_assert(this_call_stack_item.function_data.is_constructor == false, + "A constructor must be executed as the first tx in the recursion", + CircuitErrorCode::PRIVATE_KERNEL__CONSTRUCTOR_EXECUTED_IN_RECURSION); + composer.do_assert(start_private_call_stack_length != 0, + "Cannot execute private kernel circuit with an empty private call stack", + CircuitErrorCode::PRIVATE_KERNEL__PRIVATE_CALL_STACK_EMPTY); +} + +// NOTE: THIS IS A VERY UNFINISHED WORK IN PROGRESS. +// TODO: 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(DummyComposer& composer, + PrivateKernelInputsInner const& private_inputs) +{ + // We'll be pushing data to this during execution of this circuit. + KernelCircuitPublicInputs public_inputs{}; + + // Do this before any functions can modify the inputs. + initialise_end_values(private_inputs, public_inputs); + + validate_inputs(composer, private_inputs); + + validate_this_private_call_hash(composer, private_inputs, public_inputs); + + // TODO(rahul) FIXME - https://github.com/AztecProtocol/aztec-packages/issues/499 + // Noir doesn't have hash index so it can't hash private call stack item correctly + // validate_this_private_call_stack(composer, private_inputs); + + // TODO(dbanks12): may need to comment out hash check in here according to TODO above + // TODO(jeanmon) FIXME - https://github.com/AztecProtocol/aztec-packages/issues/671 + // common_validate_call_stack(composer, private_inputs.private_call); + + common_update_end_values(composer, private_inputs.private_call, public_inputs); + + // ensure that historic/purported contract tree root matches the one in previous kernel + validate_contract_tree_root(composer, private_inputs); + + const auto private_call_stack_item = private_inputs.private_call.call_stack_item; + common_contract_logic(composer, + private_inputs.private_call, + public_inputs, + private_call_stack_item.public_inputs.contract_deployment_data, + private_call_stack_item.function_data); + + // We'll skip any verification in this native implementation, because for a Local Developer Testnet, there won't + // _be_ a valid proof to verify!!! auto aggregation_object = verify_proofs(composer, + // private_inputs, + // _private_inputs.private_call.vk->num_public_inputs, + // _private_inputs.previous_kernel.vk->num_public_inputs); + + // TODO(dbanks12): kernel vk membership check! + + // Note: given that we skipped the verify_proof function, the aggregation object we get at the end will just be the + // same as we had at the start. public_inputs.end.aggregation_object = aggregation_object; + public_inputs.end.aggregation_object = private_inputs.previous_kernel.public_inputs.end.aggregation_object; + + return 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_inner.hpp b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_inner.hpp new file mode 100644 index 00000000000..3aff9613450 --- /dev/null +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_inner.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include "init.hpp" + +#include "aztec3/circuits/abis/kernel_circuit_public_inputs.hpp" +#include "aztec3/circuits/abis/private_kernel/private_kernel_inputs_inner.hpp" +#include "aztec3/utils/dummy_composer.hpp" + +namespace aztec3::circuits::kernel::private_kernel { + +using aztec3::circuits::abis::KernelCircuitPublicInputs; +using aztec3::circuits::abis::private_kernel::PrivateKernelInputsInner; +using DummyComposer = aztec3::utils::DummyComposer; + +KernelCircuitPublicInputs native_private_kernel_circuit_inner(DummyComposer& composer, + PrivateKernelInputsInner const& _private_inputs); + +} // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp index 6b5cec6102c..ce407e449e5 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp @@ -1,18 +1,18 @@ #include "init.hpp" +#include "aztec3/circuits/abis/kernel_circuit_public_inputs.hpp" +#include "aztec3/circuits/abis/new_contract_data.hpp" +#include "aztec3/circuits/abis/private_kernel/private_kernel_inputs_inner.hpp" +#include "aztec3/circuits/hash.hpp" #include "aztec3/constants.hpp" -#include -#include -#include -#include -#include +#include "barretenberg/stdlib/primitives/field/array.hpp" namespace aztec3::circuits::kernel::private_kernel { using aztec3::circuits::abis::KernelCircuitPublicInputs; using aztec3::circuits::abis::NewContractData; -using aztec3::circuits::abis::private_kernel::PrivateInputs; +using aztec3::circuits::abis::private_kernel::PrivateKernelInputsInner; using plonk::stdlib::array_length; using plonk::stdlib::array_pop; @@ -28,7 +28,7 @@ using aztec3::circuits::compute_contract_address; // 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(Composer& composer, - PrivateInputs const& private_inputs, + PrivateKernelInputsInner const& private_inputs, size_t const& num_private_call_public_inputs, size_t const& num_private_kernel_public_inputs) { @@ -55,7 +55,8 @@ CT::AggregationObject verify_proofs(Composer& composer, * as well as signed TX request and the private call information * @param public_inputs should be empty here since it is being initialized in this call */ -void initialise_end_values(PrivateInputs const& private_inputs, KernelCircuitPublicInputs& public_inputs) +void initialise_end_values(PrivateKernelInputsInner const& private_inputs, + KernelCircuitPublicInputs& public_inputs) { // TODO: Ensure public inputs is empty here public_inputs.constants = private_inputs.previous_kernel.public_inputs.constants; @@ -86,7 +87,7 @@ void initialise_end_values(PrivateInputs const& private_inputs, KernelCircui * and update its running callstack with all items in the current private-circuit/function's * callstack. */ -void update_end_values(PrivateInputs const& private_inputs, KernelCircuitPublicInputs& public_inputs) +void update_end_values(PrivateKernelInputsInner const& private_inputs, KernelCircuitPublicInputs& public_inputs) { const auto private_call_public_inputs = private_inputs.private_call.call_stack_item.public_inputs; @@ -104,15 +105,14 @@ void update_end_values(PrivateInputs const& private_inputs, KernelCircuitPub const auto& storage_contract_address = private_call_public_inputs.call_context.storage_contract_address; const auto& portal_contract_address = private_inputs.private_call.portal_contract_address; const auto& deployer_address = private_call_public_inputs.call_context.msg_sender; - const auto& contract_deployment_data = - private_inputs.signed_tx_request.tx_request.tx_context.contract_deployment_data; + const auto& contract_deployment_data = private_call_public_inputs.contract_deployment_data; { // contract deployment // input storage contract address must be 0 if its a constructor call and non-zero otherwise auto is_contract_deployment = public_inputs.constants.tx_context.is_contract_deployment_tx; auto private_call_vk_hash = private_inputs.private_call.vk->compress(GeneratorIndex::VK); - auto constructor_hash = compute_constructor_hash(private_inputs.signed_tx_request.tx_request.function_data, + auto constructor_hash = compute_constructor_hash(private_inputs.private_call.call_stack_item.function_data, private_call_public_inputs.args, private_call_vk_hash); @@ -199,7 +199,7 @@ void update_end_values(PrivateInputs const& private_inputs, KernelCircuitPub * @brief Ensure that the function/call-stack-item currently being processed by the kernel * matches the one that the previous kernel iteration said should come next. */ -void validate_this_private_call_hash(PrivateInputs const& private_inputs) +void validate_this_private_call_hash(PrivateKernelInputsInner const& private_inputs) { const auto& start = private_inputs.previous_kernel.public_inputs.end; // TODO: this logic might need to change to accommodate the weird edge 3 initial txs (the 'main' tx, the 'fee' tx, @@ -218,7 +218,7 @@ void validate_this_private_call_hash(PrivateInputs const& private_inputs) * So here we just ensure that the callstack preimages in the kernel's private inputs * matches the function's CallStackItem hashes. */ -void validate_this_private_call_stack(PrivateInputs const& private_inputs) +void validate_this_private_call_stack(PrivateKernelInputsInner const& private_inputs) { const auto& stack = private_inputs.private_call.call_stack_item.public_inputs.private_call_stack; const auto& preimages = private_inputs.private_call.private_call_stack_preimages; @@ -234,7 +234,7 @@ void validate_this_private_call_stack(PrivateInputs const& private_inputs) } }; -void validate_inputs(PrivateInputs const& private_inputs, bool first_iteration) +void validate_inputs(PrivateKernelInputsInner const& private_inputs, bool first_iteration) { // this callstack represents the function currently being processed const auto& this_call_stack_item = private_inputs.private_call.call_stack_item; @@ -318,10 +318,10 @@ void validate_inputs(PrivateInputs const& private_inputs, bool first_iterati // TODO: 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 private_kernel_circuit(Composer& composer, - PrivateInputs const& _private_inputs, + PrivateKernelInputsInner const& _private_inputs, bool first_iteration) { - const PrivateInputs private_inputs = _private_inputs.to_circuit_type(composer); + const PrivateKernelInputsInner private_inputs = _private_inputs.to_circuit_type(composer); // We'll be pushing data to this during execution of this circuit. KernelCircuitPublicInputs public_inputs = KernelCircuitPublicInputs{}.to_circuit_type(composer); diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.hpp b/circuits/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.hpp index 58b6d13b69f..1f006c8ea3f 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.hpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.hpp @@ -2,17 +2,16 @@ #include "init.hpp" -#include -#include +#include "aztec3/circuits/abis/kernel_circuit_public_inputs.hpp" +#include "aztec3/circuits/abis/private_kernel/private_kernel_inputs_inner.hpp" namespace aztec3::circuits::kernel::private_kernel { using aztec3::circuits::abis::KernelCircuitPublicInputs; -using aztec3::circuits::abis::private_kernel::PrivateInputs; +using aztec3::circuits::abis::private_kernel::PrivateKernelInputsInner; KernelCircuitPublicInputs private_kernel_circuit(Composer& composer, - PrivateInputs const& _private_inputs, + PrivateKernelInputsInner const& private_inputs, bool first_iteration); -KernelCircuitPublicInputs private_kernel_native(PrivateInputs const& private_inputs); } // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/utils.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/utils.cpp index ebbf95efec4..852442808f5 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/utils.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/utils.cpp @@ -2,7 +2,7 @@ #include "init.hpp" #include "aztec3/circuits/abis/new_contract_data.hpp" -#include +#include "aztec3/circuits/mock/mock_kernel_circuit.hpp" #include "barretenberg/proof_system/types/composer_type.hpp" diff --git a/circuits/cpp/src/aztec3/circuits/kernel/public/.test.cpp b/circuits/cpp/src/aztec3/circuits/kernel/public/.test.cpp index 2156ca58da5..9786041f606 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/public/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/public/.test.cpp @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/circuits/cpp/src/aztec3/circuits/kernel/public/common.hpp b/circuits/cpp/src/aztec3/circuits/kernel/public/common.hpp index c338911f8ce..bfbf91e6ec2 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/public/common.hpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/public/common.hpp @@ -162,7 +162,6 @@ template void common_validate_kernel_execution(DummyComposer& composer, KernelInput const& public_kernel_inputs) { common_validate_call_context(composer, public_kernel_inputs); - common_validate_call_stack(composer, public_kernel_inputs); }; diff --git a/circuits/cpp/src/aztec3/circuits/kernel/public/native_public_kernel_circuit_no_previous_kernel.cpp b/circuits/cpp/src/aztec3/circuits/kernel/public/native_public_kernel_circuit_no_previous_kernel.cpp index c07c54ee83f..9b7651a22a9 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/public/native_public_kernel_circuit_no_previous_kernel.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/public/native_public_kernel_circuit_no_previous_kernel.cpp @@ -89,6 +89,10 @@ using DummyComposer = aztec3::utils::DummyComposer; KernelCircuitPublicInputs native_public_kernel_circuit_no_previous_kernel( DummyComposer& composer, PublicKernelInputsNoPreviousKernel const& public_kernel_inputs) { + // TODO(dbanks12): consider rename of public_kernel_inputs to just private_inputs? + // or consider other renaming options + // (confusing since they are private inputs to the public kernel) + // There is not circuit state carried over from previous iterations. // We are construcitng fresh state that will be added to during this circuit execution. KernelCircuitPublicInputs public_inputs{}; @@ -102,7 +106,7 @@ KernelCircuitPublicInputs native_public_kernel_circuit_no_previous_kernel( // validate the inputs unique to there being no previous kernel validate_inputs(composer, public_kernel_inputs); - // validate the kernel execution commonn to all invocation circumstances + // validate the kernel execution common to all invocation circumstances common_validate_kernel_execution(composer, public_kernel_inputs); // update the public end state of the circuit diff --git a/circuits/cpp/src/aztec3/circuits/rollup/base/.test.cpp b/circuits/cpp/src/aztec3/circuits/rollup/base/.test.cpp index 0c449eb848c..7a907c01105 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/.test.cpp @@ -7,7 +7,6 @@ #include "aztec3/circuits/abis/new_contract_data.hpp" #include "aztec3/circuits/abis/previous_kernel_data.hpp" #include "aztec3/circuits/abis/public_data_read.hpp" -#include "aztec3/circuits/abis/rollup/nullifier_leaf_preimage.hpp" #include "aztec3/circuits/kernel/private/utils.hpp" #include "aztec3/circuits/rollup/components/components.hpp" #include "aztec3/circuits/rollup/test_utils/utils.hpp" @@ -23,7 +22,6 @@ #include #include #include -#include #include #include #include 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 ee6ec9f5d5e..16012514eab 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/c_bind.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/c_bind.cpp @@ -8,7 +8,6 @@ #include "aztec3/circuits/abis/signed_tx_request.hpp" #include "aztec3/utils/dummy_composer.hpp" #include -#include #include #include #include diff --git a/circuits/cpp/src/aztec3/circuits/rollup/root/.test.cpp b/circuits/cpp/src/aztec3/circuits/rollup/root/.test.cpp index 613d228beed..926cc4dccb8 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/root/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/root/.test.cpp @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include 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 fbe116cc13b..c0e50f2e4e7 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/root/c_bind.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/root/c_bind.cpp @@ -6,7 +6,6 @@ #include "aztec3/circuits/abis/private_kernel/private_call_data.hpp" #include "aztec3/circuits/abis/signed_tx_request.hpp" #include -#include #include #include #include diff --git a/circuits/cpp/src/aztec3/constants.hpp b/circuits/cpp/src/aztec3/constants.hpp index d635b8449e4..e1379d30710 100644 --- a/circuits/cpp/src/aztec3/constants.hpp +++ b/circuits/cpp/src/aztec3/constants.hpp @@ -86,7 +86,8 @@ enum GeneratorIndex { PUBLIC_LEAF_INDEX, PUBLIC_DATA_LEAF, SIGNED_TX_REQUEST, - L1_TO_L2_MESSAGE_SECRET + L1_TO_L2_MESSAGE_SECRET, + FUNCTION_ARGS, }; enum StorageSlotGeneratorIndex { diff --git a/circuits/cpp/src/aztec3/utils/circuit_errors.hpp b/circuits/cpp/src/aztec3/utils/circuit_errors.hpp index e4d97e9769a..739447d002b 100644 --- a/circuits/cpp/src/aztec3/utils/circuit_errors.hpp +++ b/circuits/cpp/src/aztec3/utils/circuit_errors.hpp @@ -28,7 +28,7 @@ enum CircuitErrorCode : uint16_t { PRIVATE_KERNEL__CONSTRUCTOR_EXECUTED_IN_RECURSION = 2014, PRIVATE_KERNEL__PRIVATE_CALL_STACK_EMPTY = 2015, PRIVATE_KERNEL__KERNEL_PROOF_CONTAINS_RECURSIVE_PROOF = 2016, - PRIVATE_KERNEL__NEW_NULLIFIERS_NOT_EMPTY_IN_FIRST_ITERATION = 2017, + PRIVATE_KERNEL__USER_INTENT_MISMATCH_BETWEEN_TX_REQUEST_AND_CALL_STACK_ITEM = 2017, // Public kernel related errors PUBLIC_KERNEL_CIRCUIT_FAILED = 3000, diff --git a/yarn-project/circuits.js/src/structs/generators.ts b/yarn-project/circuits.js/src/structs/generators.ts index b827ee3b734..15da8d99a24 100644 --- a/yarn-project/circuits.js/src/structs/generators.ts +++ b/yarn-project/circuits.js/src/structs/generators.ts @@ -29,4 +29,8 @@ export enum GeneratorIndex { TX_CONTEXT, TX_REQUEST, PUBLIC_LEAF_INDEX, + PUBLIC_DATA_LEAF, + SIGNED_TX_REQUEST, + L1_TO_L2_MESSAGE_SECRET, + FUNCTION_ARGS, } diff --git a/yarn-project/circuits.js/src/structs/kernel/__snapshots__/index.test.ts.snap b/yarn-project/circuits.js/src/structs/kernel/__snapshots__/index.test.ts.snap index 31597a9bfa1..e7ee6e413ad 100644 --- a/yarn-project/circuits.js/src/structs/kernel/__snapshots__/index.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/kernel/__snapshots__/index.test.ts.snap @@ -288,7 +288,7 @@ vk_path: [ 0x1000 0x1001 0x1002 ] " `; -exports[`structs/kernel serializes and prints private_kernel_inputs 1`] = ` +exports[`structs/kernel serializes and prints private_kernel_inputs_init 1`] = ` "signed_tx_request: tx_request: from: 0x1 @@ -312,87 +312,274 @@ chain_id: 0x501 signature: { 0101010101010101010101010101010101010101010101010101010101010101, 0202020202020202020202020202020202020202020202020202020202020202, 3 } -previous_kernel: +private_call: +call_stack_item: +contract_address: 0x1001 +function_data: function_selector: 4098 +is_private: 1 +is_constructor: 1 + +public_inputs: call_context: msg_sender: 0x1012 +storage_contract_address: 0x1013 +portal_contract_address: 0x1014 +is_delegate_call: 1 +is_static_call: 1 +is_contract_deployment: 1 + +args: [ 0x1111 0x1112 0x1113 0x1114 0x1115 0x1116 0x1117 0x1118 ] +return_values: [ 0x1311 0x1312 0x1313 0x1314 ] +emitted_events: [ 0x1211 0x1212 0x1213 0x1214 ] +new_commitments: [ 0x1411 0x1412 0x1413 0x1414 ] +new_nullifiers: [ 0x1511 0x1512 0x1513 0x1514 ] +private_call_stack: [ 0x1611 0x1612 0x1613 0x1614 ] +public_call_stack: [ 0x1711 0x1712 0x1713 0x1714 ] +new_l2_to_l1_msgs: [ 0x1811 0x1812 ] +historic_private_data_tree_root: 0x2011 +historic_nullifier_tree_root: 0x2111 +historic_contract_tree_root: 0x1911 +historic_l1_to_l2_messages_tree_root: 0x2211 +contract_deployment_data: constructor_vk_hash: 0x1 +function_tree_root: 0x2 +contract_address_salt: 0x3 +portal_contract_address: 0x4 + + +is_execution_request: 0 + +private_call_stack_preimages: +[ contract_address: 0x1011 +function_data: function_selector: 1012 +is_private: 1 +is_constructor: 1 + +public_inputs: call_context: msg_sender: 0x1022 +storage_contract_address: 0x1023 +portal_contract_address: 0x1024 +is_delegate_call: 1 +is_static_call: 1 +is_contract_deployment: 1 + +args: [ 0x1121 0x1122 0x1123 0x1124 0x1125 0x1126 0x1127 0x1128 ] +return_values: [ 0x1321 0x1322 0x1323 0x1324 ] +emitted_events: [ 0x1221 0x1222 0x1223 0x1224 ] +new_commitments: [ 0x1421 0x1422 0x1423 0x1424 ] +new_nullifiers: [ 0x1521 0x1522 0x1523 0x1524 ] +private_call_stack: [ 0x1621 0x1622 0x1623 0x1624 ] +public_call_stack: [ 0x1721 0x1722 0x1723 0x1724 ] +new_l2_to_l1_msgs: [ 0x1821 0x1822 ] +historic_private_data_tree_root: 0x2021 +historic_nullifier_tree_root: 0x2121 +historic_contract_tree_root: 0x1921 +historic_l1_to_l2_messages_tree_root: 0x2221 +contract_deployment_data: constructor_vk_hash: 0x1 +function_tree_root: 0x2 +contract_address_salt: 0x3 +portal_contract_address: 0x4 + + +is_execution_request: 0 + contract_address: 0x1012 +function_data: function_selector: 1013 +is_private: 1 +is_constructor: 1 + +public_inputs: call_context: msg_sender: 0x1023 +storage_contract_address: 0x1024 +portal_contract_address: 0x1025 +is_delegate_call: 1 +is_static_call: 1 +is_contract_deployment: 1 + +args: [ 0x1122 0x1123 0x1124 0x1125 0x1126 0x1127 0x1128 0x1129 ] +return_values: [ 0x1322 0x1323 0x1324 0x1325 ] +emitted_events: [ 0x1222 0x1223 0x1224 0x1225 ] +new_commitments: [ 0x1422 0x1423 0x1424 0x1425 ] +new_nullifiers: [ 0x1522 0x1523 0x1524 0x1525 ] +private_call_stack: [ 0x1622 0x1623 0x1624 0x1625 ] +public_call_stack: [ 0x1722 0x1723 0x1724 0x1725 ] +new_l2_to_l1_msgs: [ 0x1822 0x1823 ] +historic_private_data_tree_root: 0x2022 +historic_nullifier_tree_root: 0x2122 +historic_contract_tree_root: 0x1922 +historic_l1_to_l2_messages_tree_root: 0x2222 +contract_deployment_data: constructor_vk_hash: 0x1 +function_tree_root: 0x2 +contract_address_salt: 0x3 +portal_contract_address: 0x4 + + +is_execution_request: 0 + contract_address: 0x1013 +function_data: function_selector: 1014 +is_private: 1 +is_constructor: 1 + +public_inputs: call_context: msg_sender: 0x1024 +storage_contract_address: 0x1025 +portal_contract_address: 0x1026 +is_delegate_call: 1 +is_static_call: 1 +is_contract_deployment: 1 + +args: [ 0x1123 0x1124 0x1125 0x1126 0x1127 0x1128 0x1129 0x112a ] +return_values: [ 0x1323 0x1324 0x1325 0x1326 ] +emitted_events: [ 0x1223 0x1224 0x1225 0x1226 ] +new_commitments: [ 0x1423 0x1424 0x1425 0x1426 ] +new_nullifiers: [ 0x1523 0x1524 0x1525 0x1526 ] +private_call_stack: [ 0x1623 0x1624 0x1625 0x1626 ] +public_call_stack: [ 0x1723 0x1724 0x1725 0x1726 ] +new_l2_to_l1_msgs: [ 0x1823 0x1824 ] +historic_private_data_tree_root: 0x2023 +historic_nullifier_tree_root: 0x2123 +historic_contract_tree_root: 0x1923 +historic_l1_to_l2_messages_tree_root: 0x2223 +contract_deployment_data: constructor_vk_hash: 0x1 +function_tree_root: 0x2 +contract_address_salt: 0x3 +portal_contract_address: 0x4 + + +is_execution_request: 0 + contract_address: 0x1014 +function_data: function_selector: 1015 +is_private: 1 +is_constructor: 1 + +public_inputs: call_context: msg_sender: 0x1025 +storage_contract_address: 0x1026 +portal_contract_address: 0x1027 +is_delegate_call: 1 +is_static_call: 1 +is_contract_deployment: 1 + +args: [ 0x1124 0x1125 0x1126 0x1127 0x1128 0x1129 0x112a 0x112b ] +return_values: [ 0x1324 0x1325 0x1326 0x1327 ] +emitted_events: [ 0x1224 0x1225 0x1226 0x1227 ] +new_commitments: [ 0x1424 0x1425 0x1426 0x1427 ] +new_nullifiers: [ 0x1524 0x1525 0x1526 0x1527 ] +private_call_stack: [ 0x1624 0x1625 0x1626 0x1627 ] +public_call_stack: [ 0x1724 0x1725 0x1726 0x1727 ] +new_l2_to_l1_msgs: [ 0x1824 0x1825 ] +historic_private_data_tree_root: 0x2024 +historic_nullifier_tree_root: 0x2124 +historic_contract_tree_root: 0x1924 +historic_l1_to_l2_messages_tree_root: 0x2224 +contract_deployment_data: constructor_vk_hash: 0x1 +function_tree_root: 0x2 +contract_address_salt: 0x3 +portal_contract_address: 0x4 + + +is_execution_request: 0 + ] +proof: +[ 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 ] +vk: +key.composer_type: 0 +key.circuit_size: 101 +key.num_public_inputs: 102 +key.commitments: [ + A: { 0x200, 0x300 } +] +key.contains_recursive_proof: 1 +key.recursive_proof_public_input_indices: [ 400 401 402 403 404 ] + +function_leaf_membership_witness: +leaf_index: 0x1031 +sibling_path: [ 0x1031 0x1032 0x1033 0x1034 ] + +contract_leaf_membership_witness: +leaf_index: 0x1021 +sibling_path: [ 0x1021 0x1022 0x1023 0x1024 ] + +portal_contract_address: 0x4141414141414141414141414141414141414141 +acir_hash: 0x1061 + +" +`; + +exports[`structs/kernel serializes and prints private_kernel_inputs_inner 1`] = ` +"previous_kernel: public_inputs: end: aggregation_object: -P0: { 0x1001, 0x1002 } -P1: { 0x1101, 0x1102 } +P0: { 0x1, 0x2 } +P1: { 0x101, 0x102 } public_inputs: [ - 0x1003 - 0x1004 - 0x1005 - 0x1006 + 0x3 + 0x4 + 0x5 + 0x6 ] -proof_witness_indices: [ 4103 4104 4105 4106 4107 4108 ] +proof_witness_indices: [ 7 8 9 10 11 12 ] has_data: 0 new_commitments: -[ 0x1101 0x1102 0x1103 0x1104 ] +[ 0x101 0x102 0x103 0x104 ] new_nullifiers: -[ 0x1201 0x1202 0x1203 0x1204 ] +[ 0x201 0x202 0x203 0x204 ] private_call_stack: -[ 0x1301 0x1302 0x1303 0x1304 0x1305 0x1306 0x1307 0x1308 ] +[ 0x301 0x302 0x303 0x304 0x305 0x306 0x307 0x308 ] public_call_stack: -[ 0x1401 0x1402 0x1403 0x1404 0x1405 0x1406 0x1407 0x1408 ] +[ 0x401 0x402 0x403 0x404 0x405 0x406 0x407 0x408 ] new_l2_to_l1_msgs: -[ 0x1501 0x1502 ] +[ 0x501 0x502 ] new_contracts: -[ contract_address: 0x1601 +[ contract_address: 0x601 portal_contract_address: 0x202020202020202020202020202020202020202 -function_tree_root: 0x1603 +function_tree_root: 0x603 ] optionally_revealed_data: -[ call_stack_item_hash: 0x1701 +[ call_stack_item_hash: 0x701 function_data: -function_selector: 1702 +function_selector: 702 is_private: 1 is_constructor: 1 emitted_events: -[ 0x1801 0x1802 0x1803 0x1804 ] -vk_hash: 0x1703 +[ 0x801 0x802 0x803 0x804 ] +vk_hash: 0x703 portal_contract_address: 0x404040404040404040404040404040404040404 pay_fee_from_l1: 1 pay_fee_from_public_l2: 0 called_from_l1: 1 called_from_public_l2: 0 - call_stack_item_hash: 0x1702 + call_stack_item_hash: 0x702 function_data: -function_selector: 1703 +function_selector: 703 is_private: 1 is_constructor: 1 emitted_events: -[ 0x1802 0x1803 0x1804 0x1805 ] -vk_hash: 0x1704 +[ 0x802 0x803 0x804 0x805 ] +vk_hash: 0x704 portal_contract_address: 0x505050505050505050505050505050505050505 pay_fee_from_l1: 1 pay_fee_from_public_l2: 0 called_from_l1: 1 called_from_public_l2: 0 - call_stack_item_hash: 0x1703 + call_stack_item_hash: 0x703 function_data: -function_selector: 1704 +function_selector: 704 is_private: 1 is_constructor: 1 emitted_events: -[ 0x1803 0x1804 0x1805 0x1806 ] -vk_hash: 0x1705 +[ 0x803 0x804 0x805 0x806 ] +vk_hash: 0x705 portal_contract_address: 0x606060606060606060606060606060606060606 pay_fee_from_l1: 1 pay_fee_from_public_l2: 0 called_from_l1: 1 called_from_public_l2: 0 - call_stack_item_hash: 0x1704 + call_stack_item_hash: 0x704 function_data: -function_selector: 1705 +function_selector: 705 is_private: 1 is_constructor: 1 emitted_events: -[ 0x1804 0x1805 0x1806 0x1807 ] -vk_hash: 0x1706 +[ 0x804 0x805 0x806 0x807 ] +vk_hash: 0x706 portal_contract_address: 0x707070707070707070707070707070707070707 pay_fee_from_l1: 1 pay_fee_from_public_l2: 0 @@ -400,45 +587,45 @@ called_from_l1: 1 called_from_public_l2: 0 ] public_data_update_requests: -[ leaf_index: 0x1801 -old_value: 0x1802 -new_value: 0x1803 - leaf_index: 0x1802 -old_value: 0x1803 -new_value: 0x1804 - leaf_index: 0x1803 -old_value: 0x1804 -new_value: 0x1805 - leaf_index: 0x1804 -old_value: 0x1805 -new_value: 0x1806 +[ leaf_index: 0x801 +old_value: 0x802 +new_value: 0x803 + leaf_index: 0x802 +old_value: 0x803 +new_value: 0x804 + leaf_index: 0x803 +old_value: 0x804 +new_value: 0x805 + leaf_index: 0x804 +old_value: 0x805 +new_value: 0x806 ] public_data_reads: -[ leaf_index: 0x1901 -value: 0x1902 - leaf_index: 0x1902 -value: 0x1903 - leaf_index: 0x1903 -value: 0x1904 - leaf_index: 0x1904 -value: 0x1905 +[ leaf_index: 0x901 +value: 0x902 + leaf_index: 0x902 +value: 0x903 + leaf_index: 0x903 +value: 0x904 + leaf_index: 0x904 +value: 0x905 ] constants: -historic_tree_roots: private_historic_tree_roots: private_data_tree_root: 0x1101 -nullifier_tree_root: 0x1102 -contract_tree_root: 0x1103 -l1_to_l2_messages_tree_root: 0x1104 -private_kernel_vk_tree_root: 0x1105 +historic_tree_roots: private_historic_tree_roots: private_data_tree_root: 0x101 +nullifier_tree_root: 0x102 +contract_tree_root: 0x103 +l1_to_l2_messages_tree_root: 0x104 +private_kernel_vk_tree_root: 0x105 tx_context: is_fee_payment_tx: 0 is_rebate_payment_tx: 0 is_contract_deployment_tx: 1 contract_deployment_data: -constructor_vk_hash: 0x1105 -function_tree_root: 0x1106 -contract_address_salt: 0x1107 +constructor_vk_hash: 0x105 +function_tree_root: 0x106 +contract_address_salt: 0x107 portal_contract_address: 0x808080808080808080808080808080808080808 @@ -460,30 +647,30 @@ vk_path: [ 0x1000 0x1001 0x1002 ] private_call: call_stack_item: -contract_address: 0x2001 -function_data: function_selector: 8194 +contract_address: 0x1001 +function_data: function_selector: 4098 is_private: 1 is_constructor: 1 -public_inputs: call_context: msg_sender: 0x2012 -storage_contract_address: 0x2013 -portal_contract_address: 0x2014 +public_inputs: call_context: msg_sender: 0x1012 +storage_contract_address: 0x1013 +portal_contract_address: 0x1014 is_delegate_call: 1 is_static_call: 1 is_contract_deployment: 1 -args: [ 0x2111 0x2112 0x2113 0x2114 0x2115 0x2116 0x2117 0x2118 ] -return_values: [ 0x2311 0x2312 0x2313 0x2314 ] -emitted_events: [ 0x2211 0x2212 0x2213 0x2214 ] -new_commitments: [ 0x2411 0x2412 0x2413 0x2414 ] -new_nullifiers: [ 0x2511 0x2512 0x2513 0x2514 ] -private_call_stack: [ 0x2611 0x2612 0x2613 0x2614 ] -public_call_stack: [ 0x2711 0x2712 0x2713 0x2714 ] -new_l2_to_l1_msgs: [ 0x2811 0x2812 ] -historic_private_data_tree_root: 0x3011 -historic_nullifier_tree_root: 0x3111 -historic_contract_tree_root: 0x2911 -historic_l1_to_l2_messages_tree_root: 0x3211 +args: [ 0x1111 0x1112 0x1113 0x1114 0x1115 0x1116 0x1117 0x1118 ] +return_values: [ 0x1311 0x1312 0x1313 0x1314 ] +emitted_events: [ 0x1211 0x1212 0x1213 0x1214 ] +new_commitments: [ 0x1411 0x1412 0x1413 0x1414 ] +new_nullifiers: [ 0x1511 0x1512 0x1513 0x1514 ] +private_call_stack: [ 0x1611 0x1612 0x1613 0x1614 ] +public_call_stack: [ 0x1711 0x1712 0x1713 0x1714 ] +new_l2_to_l1_msgs: [ 0x1811 0x1812 ] +historic_private_data_tree_root: 0x2011 +historic_nullifier_tree_root: 0x2111 +historic_contract_tree_root: 0x1911 +historic_l1_to_l2_messages_tree_root: 0x2211 contract_deployment_data: constructor_vk_hash: 0x1 function_tree_root: 0x2 contract_address_salt: 0x3 @@ -493,30 +680,30 @@ portal_contract_address: 0x4 is_execution_request: 0 private_call_stack_preimages: -[ contract_address: 0x2011 -function_data: function_selector: 2012 +[ contract_address: 0x1011 +function_data: function_selector: 1012 is_private: 1 is_constructor: 1 -public_inputs: call_context: msg_sender: 0x2022 -storage_contract_address: 0x2023 -portal_contract_address: 0x2024 +public_inputs: call_context: msg_sender: 0x1022 +storage_contract_address: 0x1023 +portal_contract_address: 0x1024 is_delegate_call: 1 is_static_call: 1 is_contract_deployment: 1 -args: [ 0x2121 0x2122 0x2123 0x2124 0x2125 0x2126 0x2127 0x2128 ] -return_values: [ 0x2321 0x2322 0x2323 0x2324 ] -emitted_events: [ 0x2221 0x2222 0x2223 0x2224 ] -new_commitments: [ 0x2421 0x2422 0x2423 0x2424 ] -new_nullifiers: [ 0x2521 0x2522 0x2523 0x2524 ] -private_call_stack: [ 0x2621 0x2622 0x2623 0x2624 ] -public_call_stack: [ 0x2721 0x2722 0x2723 0x2724 ] -new_l2_to_l1_msgs: [ 0x2821 0x2822 ] -historic_private_data_tree_root: 0x3021 -historic_nullifier_tree_root: 0x3121 -historic_contract_tree_root: 0x2921 -historic_l1_to_l2_messages_tree_root: 0x3221 +args: [ 0x1121 0x1122 0x1123 0x1124 0x1125 0x1126 0x1127 0x1128 ] +return_values: [ 0x1321 0x1322 0x1323 0x1324 ] +emitted_events: [ 0x1221 0x1222 0x1223 0x1224 ] +new_commitments: [ 0x1421 0x1422 0x1423 0x1424 ] +new_nullifiers: [ 0x1521 0x1522 0x1523 0x1524 ] +private_call_stack: [ 0x1621 0x1622 0x1623 0x1624 ] +public_call_stack: [ 0x1721 0x1722 0x1723 0x1724 ] +new_l2_to_l1_msgs: [ 0x1821 0x1822 ] +historic_private_data_tree_root: 0x2021 +historic_nullifier_tree_root: 0x2121 +historic_contract_tree_root: 0x1921 +historic_l1_to_l2_messages_tree_root: 0x2221 contract_deployment_data: constructor_vk_hash: 0x1 function_tree_root: 0x2 contract_address_salt: 0x3 @@ -524,30 +711,30 @@ portal_contract_address: 0x4 is_execution_request: 0 - contract_address: 0x2012 -function_data: function_selector: 2013 + contract_address: 0x1012 +function_data: function_selector: 1013 is_private: 1 is_constructor: 1 -public_inputs: call_context: msg_sender: 0x2023 -storage_contract_address: 0x2024 -portal_contract_address: 0x2025 +public_inputs: call_context: msg_sender: 0x1023 +storage_contract_address: 0x1024 +portal_contract_address: 0x1025 is_delegate_call: 1 is_static_call: 1 is_contract_deployment: 1 -args: [ 0x2122 0x2123 0x2124 0x2125 0x2126 0x2127 0x2128 0x2129 ] -return_values: [ 0x2322 0x2323 0x2324 0x2325 ] -emitted_events: [ 0x2222 0x2223 0x2224 0x2225 ] -new_commitments: [ 0x2422 0x2423 0x2424 0x2425 ] -new_nullifiers: [ 0x2522 0x2523 0x2524 0x2525 ] -private_call_stack: [ 0x2622 0x2623 0x2624 0x2625 ] -public_call_stack: [ 0x2722 0x2723 0x2724 0x2725 ] -new_l2_to_l1_msgs: [ 0x2822 0x2823 ] -historic_private_data_tree_root: 0x3022 -historic_nullifier_tree_root: 0x3122 -historic_contract_tree_root: 0x2922 -historic_l1_to_l2_messages_tree_root: 0x3222 +args: [ 0x1122 0x1123 0x1124 0x1125 0x1126 0x1127 0x1128 0x1129 ] +return_values: [ 0x1322 0x1323 0x1324 0x1325 ] +emitted_events: [ 0x1222 0x1223 0x1224 0x1225 ] +new_commitments: [ 0x1422 0x1423 0x1424 0x1425 ] +new_nullifiers: [ 0x1522 0x1523 0x1524 0x1525 ] +private_call_stack: [ 0x1622 0x1623 0x1624 0x1625 ] +public_call_stack: [ 0x1722 0x1723 0x1724 0x1725 ] +new_l2_to_l1_msgs: [ 0x1822 0x1823 ] +historic_private_data_tree_root: 0x2022 +historic_nullifier_tree_root: 0x2122 +historic_contract_tree_root: 0x1922 +historic_l1_to_l2_messages_tree_root: 0x2222 contract_deployment_data: constructor_vk_hash: 0x1 function_tree_root: 0x2 contract_address_salt: 0x3 @@ -555,30 +742,30 @@ portal_contract_address: 0x4 is_execution_request: 0 - contract_address: 0x2013 -function_data: function_selector: 2014 + contract_address: 0x1013 +function_data: function_selector: 1014 is_private: 1 is_constructor: 1 -public_inputs: call_context: msg_sender: 0x2024 -storage_contract_address: 0x2025 -portal_contract_address: 0x2026 +public_inputs: call_context: msg_sender: 0x1024 +storage_contract_address: 0x1025 +portal_contract_address: 0x1026 is_delegate_call: 1 is_static_call: 1 is_contract_deployment: 1 -args: [ 0x2123 0x2124 0x2125 0x2126 0x2127 0x2128 0x2129 0x212a ] -return_values: [ 0x2323 0x2324 0x2325 0x2326 ] -emitted_events: [ 0x2223 0x2224 0x2225 0x2226 ] -new_commitments: [ 0x2423 0x2424 0x2425 0x2426 ] -new_nullifiers: [ 0x2523 0x2524 0x2525 0x2526 ] -private_call_stack: [ 0x2623 0x2624 0x2625 0x2626 ] -public_call_stack: [ 0x2723 0x2724 0x2725 0x2726 ] -new_l2_to_l1_msgs: [ 0x2823 0x2824 ] -historic_private_data_tree_root: 0x3023 -historic_nullifier_tree_root: 0x3123 -historic_contract_tree_root: 0x2923 -historic_l1_to_l2_messages_tree_root: 0x3223 +args: [ 0x1123 0x1124 0x1125 0x1126 0x1127 0x1128 0x1129 0x112a ] +return_values: [ 0x1323 0x1324 0x1325 0x1326 ] +emitted_events: [ 0x1223 0x1224 0x1225 0x1226 ] +new_commitments: [ 0x1423 0x1424 0x1425 0x1426 ] +new_nullifiers: [ 0x1523 0x1524 0x1525 0x1526 ] +private_call_stack: [ 0x1623 0x1624 0x1625 0x1626 ] +public_call_stack: [ 0x1723 0x1724 0x1725 0x1726 ] +new_l2_to_l1_msgs: [ 0x1823 0x1824 ] +historic_private_data_tree_root: 0x2023 +historic_nullifier_tree_root: 0x2123 +historic_contract_tree_root: 0x1923 +historic_l1_to_l2_messages_tree_root: 0x2223 contract_deployment_data: constructor_vk_hash: 0x1 function_tree_root: 0x2 contract_address_salt: 0x3 @@ -586,30 +773,30 @@ portal_contract_address: 0x4 is_execution_request: 0 - contract_address: 0x2014 -function_data: function_selector: 2015 + contract_address: 0x1014 +function_data: function_selector: 1015 is_private: 1 is_constructor: 1 -public_inputs: call_context: msg_sender: 0x2025 -storage_contract_address: 0x2026 -portal_contract_address: 0x2027 +public_inputs: call_context: msg_sender: 0x1025 +storage_contract_address: 0x1026 +portal_contract_address: 0x1027 is_delegate_call: 1 is_static_call: 1 is_contract_deployment: 1 -args: [ 0x2124 0x2125 0x2126 0x2127 0x2128 0x2129 0x212a 0x212b ] -return_values: [ 0x2324 0x2325 0x2326 0x2327 ] -emitted_events: [ 0x2224 0x2225 0x2226 0x2227 ] -new_commitments: [ 0x2424 0x2425 0x2426 0x2427 ] -new_nullifiers: [ 0x2524 0x2525 0x2526 0x2527 ] -private_call_stack: [ 0x2624 0x2625 0x2626 0x2627 ] -public_call_stack: [ 0x2724 0x2725 0x2726 0x2727 ] -new_l2_to_l1_msgs: [ 0x2824 0x2825 ] -historic_private_data_tree_root: 0x3024 -historic_nullifier_tree_root: 0x3124 -historic_contract_tree_root: 0x2924 -historic_l1_to_l2_messages_tree_root: 0x3224 +args: [ 0x1124 0x1125 0x1126 0x1127 0x1128 0x1129 0x112a 0x112b ] +return_values: [ 0x1324 0x1325 0x1326 0x1327 ] +emitted_events: [ 0x1224 0x1225 0x1226 0x1227 ] +new_commitments: [ 0x1424 0x1425 0x1426 0x1427 ] +new_nullifiers: [ 0x1524 0x1525 0x1526 0x1527 ] +private_call_stack: [ 0x1624 0x1625 0x1626 0x1627 ] +public_call_stack: [ 0x1724 0x1725 0x1726 0x1727 ] +new_l2_to_l1_msgs: [ 0x1824 0x1825 ] +historic_private_data_tree_root: 0x2024 +historic_nullifier_tree_root: 0x2124 +historic_contract_tree_root: 0x1924 +historic_l1_to_l2_messages_tree_root: 0x2224 contract_deployment_data: constructor_vk_hash: 0x1 function_tree_root: 0x2 contract_address_salt: 0x3 @@ -631,15 +818,15 @@ key.contains_recursive_proof: 1 key.recursive_proof_public_input_indices: [ 400 401 402 403 404 ] function_leaf_membership_witness: -leaf_index: 0x2031 -sibling_path: [ 0x2031 0x2032 0x2033 0x2034 ] +leaf_index: 0x1031 +sibling_path: [ 0x1031 0x1032 0x1033 0x1034 ] contract_leaf_membership_witness: -leaf_index: 0x2021 -sibling_path: [ 0x2021 0x2022 0x2023 0x2024 ] +leaf_index: 0x1021 +sibling_path: [ 0x1021 0x1022 0x1023 0x1024 ] portal_contract_address: 0x4141414141414141414141414141414141414141 -acir_hash: 0x2061 +acir_hash: 0x1061 " `; diff --git a/yarn-project/circuits.js/src/structs/kernel/index.test.ts b/yarn-project/circuits.js/src/structs/kernel/index.test.ts index 31e65d701b1..ec27d316c3a 100644 --- a/yarn-project/circuits.js/src/structs/kernel/index.test.ts +++ b/yarn-project/circuits.js/src/structs/kernel/index.test.ts @@ -3,7 +3,8 @@ import { makeSignedTxRequest } from '../../tests/factories.js'; import { makeEcdsaSignature } from '../../tests/factories.js'; import { makePreviousKernelData, - makePrivateKernelInputs, + makePrivateKernelInputsInner, + makePrivateKernelInputsInit, makeKernelPublicInputs, makePublicKernelInputsNoKernelInput, makePublicKernelInputs, @@ -19,11 +20,19 @@ describe('structs/kernel', () => { ); }); - it(`serializes and prints private_kernel_inputs`, async () => { - const kernelInputs = makePrivateKernelInputs(); + it(`serializes and prints private_kernel_inputs_init`, async () => { + const kernelInputs = makePrivateKernelInputsInit(); await expectSerializeToMatchSnapshot( kernelInputs.toBuffer(), - 'abis__test_roundtrip_serialize_private_kernel_inputs', + 'abis__test_roundtrip_serialize_private_kernel_inputs_init', + ); + }); + + it(`serializes and prints private_kernel_inputs_inner`, async () => { + const kernelInputs = makePrivateKernelInputsInner(); + await expectSerializeToMatchSnapshot( + kernelInputs.toBuffer(), + 'abis__test_roundtrip_serialize_private_kernel_inputs_inner', ); }); diff --git a/yarn-project/circuits.js/src/structs/kernel/private_kernel.ts b/yarn-project/circuits.js/src/structs/kernel/private_kernel.ts index acf87e6b7b3..d02d2849213 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_kernel.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_kernel.ts @@ -86,14 +86,34 @@ export class PrivateCallData { } /** - * Input to the private kernel circuit. + * Input to the private kernel circuit - initial call. */ -export class PrivateKernelInputs { +export class PrivateKernelInputsInit { constructor( /** * The transaction request which led to the creation of these inputs. */ public signedTxRequest: SignedTxRequest, + /** + * Private calldata corresponding to this iteration of the kernel. + */ + public privateCall: PrivateCallData, + ) {} + + /** + * Serialize this as a buffer. + * @returns The buffer. + */ + toBuffer() { + return serializeToBuffer(this.signedTxRequest, this.privateCall); + } +} + +/** + * Input to the private kernel circuit - Inner call. + */ +export class PrivateKernelInputsInner { + constructor( /** * The previous kernel data (dummy if this is the first kernel). */ @@ -109,6 +129,6 @@ export class PrivateKernelInputs { * @returns The buffer. */ toBuffer() { - return serializeToBuffer(this.signedTxRequest, this.previousKernel, this.privateCall); + return serializeToBuffer(this.previousKernel, this.privateCall); } } diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index dc811052901..ca1a19eb9b1 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -45,7 +45,8 @@ import { PreviousKernelData, Proof, VK_TREE_HEIGHT, - PrivateKernelInputs, + PrivateKernelInputsInit, + PrivateKernelInputsInner, PublicCallStackItem, PublicCallData, CircuitsWasm, @@ -397,16 +398,21 @@ export function makeProof(seed = 1) { } /** - * Makes arbitrary private kernel inputs. + * Makes arbitrary private kernel inputs - initial call. * @param seed - The seed to use for generating the private kernel inputs. * @returns Private kernel inputs. */ -export function makePrivateKernelInputs(seed = 1): PrivateKernelInputs { - return new PrivateKernelInputs( - makeSignedTxRequest(seed), - makePreviousKernelData(seed + 0x1000), - makePrivateCallData(seed + 0x2000), - ); +export function makePrivateKernelInputsInit(seed = 1): PrivateKernelInputsInit { + return new PrivateKernelInputsInit(makeSignedTxRequest(seed), makePrivateCallData(seed + 0x1000)); +} + +/** + * Makes arbitrary private kernel inputs - inner call. + * @param seed - The seed to use for generating the private kernel inputs. + * @returns Private kernel inputs. + */ +export function makePrivateKernelInputsInner(seed = 1): PrivateKernelInputsInner { + return new PrivateKernelInputsInner(makePreviousKernelData(seed), makePrivateCallData(seed + 0x1000)); } /**