From c61557ae926f89cead7306368197fdbe8f23dd6d Mon Sep 17 00:00:00 2001 From: Jean M <132435771+jeanmon@users.noreply.github.com> Date: Wed, 30 Aug 2023 16:10:10 +0200 Subject: [PATCH] chore(1074): remove read request data from final private kernel circuit public inputs (#1840) Resolves #1074 Refactor task consisting in defining a specific struct for the public inputs of final ordering private kernel circuit. This new struct is named: KernelCircuitPublicInputsFinal This struct is identical to KernelCircuitPublicInputs except that we trimmed the 4 following members from CombinedAccumulatedData (a struct named FinalAccumulatedData was introduced for this purpose): - read_requests - read_request_membership_witnesses - public_data_update_requests - public_data_reads In addition, one commit which resolves #1865 was added. # Checklist: Remove the checklist to signal you've completed it. Enable auto-merge if the PR is ready to merge. - [x] If the pull request requires a cryptography review (e.g. cryptographic algorithm implementations) I have added the 'crypto' tag. - [x] I have reviewed my diff in github, line by line and removed unexpected formatting changes, testing logs, or commented-out code. - [x] Every change is related to the PR description. - [x] I have [linked](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) this pull request to relevant issues (if any exist). --- .../cpp/src/aztec3/circuits/abis/c_bind.cpp | 13 ++ .../circuits/abis/combined_constant_data.hpp | 3 +- .../circuits/abis/final_accumulated_data.hpp | 194 +++++++++++++++++ .../abis/kernel_circuit_public_inputs.hpp | 2 +- .../kernel_circuit_public_inputs_final.hpp | 79 +++++++ .../src/aztec3/circuits/abis/tx_request.hpp | 1 - .../aztec3/circuits/kernel/private/common.cpp | 29 --- .../aztec3/circuits/kernel/private/common.hpp | 28 ++- .../native_private_kernel_circuit.test.cpp | 22 +- ...native_private_kernel_circuit_ordering.cpp | 15 +- ...native_private_kernel_circuit_ordering.hpp | 11 +- ...e_private_kernel_circuit_ordering.test.cpp | 8 - .../src/aztec_rpc_server/aztec_rpc_server.ts | 4 +- .../src/kernel_prover/kernel_prover.ts | 10 +- .../src/kernel_prover/proof_creator.ts | 26 ++- .../circuits.js/src/cbind/circuits.gen.ts | 184 +++++++++++++++- yarn-project/circuits.js/src/cbind/types.ts | 3 +- .../src/kernel/public_kernel.test.ts | 11 +- yarn-project/circuits.js/src/structs/index.ts | 1 + .../kernel/__snapshots__/index.test.ts.snap | 205 ++++++++++++++++++ .../kernel/combined_accumulated_data.test.ts | 12 +- .../kernel/combined_accumulated_data.ts | 171 +++++++++++++++ .../src/structs/kernel/index.test.ts | 18 ++ .../src/structs/kernel/public_inputs_final.ts | 57 +++++ .../circuits.js/src/tests/factories.ts | 67 +++--- yarn-project/p2p/src/service/tx_messages.ts | 4 +- .../block_builder/solo_block_builder.test.ts | 4 +- .../src/sequencer/processed_tx.ts | 23 +- .../src/sequencer/public_processor.test.ts | 22 +- .../src/sequencer/public_processor.ts | 7 +- yarn-project/types/src/mocks.ts | 4 +- yarn-project/types/src/tx/tx.ts | 10 +- 32 files changed, 1105 insertions(+), 143 deletions(-) create mode 100644 circuits/cpp/src/aztec3/circuits/abis/final_accumulated_data.hpp create mode 100644 circuits/cpp/src/aztec3/circuits/abis/kernel_circuit_public_inputs_final.hpp create mode 100644 yarn-project/circuits.js/src/structs/kernel/public_inputs_final.ts diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp index 81f84e0407c..0b371c3acbd 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp @@ -4,6 +4,7 @@ #include "function_data.hpp" #include "function_leaf_preimage.hpp" #include "kernel_circuit_public_inputs.hpp" +#include "kernel_circuit_public_inputs_final.hpp" #include "previous_kernel_data.hpp" #include "private_circuit_public_inputs.hpp" #include "tx_context.hpp" @@ -16,6 +17,7 @@ #include "rollup/root/root_rollup_public_inputs.hpp" #include "aztec3/circuits/abis/combined_accumulated_data.hpp" +#include "aztec3/circuits/abis/final_accumulated_data.hpp" #include "aztec3/circuits/abis/new_contract_data.hpp" #include "aztec3/circuits/abis/packers.hpp" #include "aztec3/circuits/abis/point.hpp" @@ -593,6 +595,11 @@ WASM_EXPORT const char* abis__test_roundtrip_serialize_combined_accumulated_data return as_string_output>(input, size); } +WASM_EXPORT const char* abis__test_roundtrip_serialize_final_accumulated_data(uint8_t const* input, uint32_t* size) +{ + return as_string_output>(input, size); +} + WASM_EXPORT const char* abis__test_roundtrip_serialize_signature(uint8_t const* input, uint32_t* size) { return as_string_output(input, size); @@ -614,6 +621,12 @@ WASM_EXPORT const char* abis__test_roundtrip_serialize_kernel_circuit_public_inp return as_string_output>(input, size); } +WASM_EXPORT const char* abis__test_roundtrip_serialize_kernel_circuit_public_inputs_final(uint8_t const* input, + uint32_t* size) +{ + return as_string_output>(input, size); +} + WASM_EXPORT const char* abis__test_roundtrip_serialize_public_kernel_inputs(uint8_t const* input, uint32_t* size) { return as_string_output>(input, size); diff --git a/circuits/cpp/src/aztec3/circuits/abis/combined_constant_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/combined_constant_data.hpp index 29078da22c7..21beafda197 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/combined_constant_data.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/combined_constant_data.hpp @@ -4,7 +4,6 @@ #include "aztec3/circuits/abis/historic_block_data.hpp" #include "aztec3/utils/types/circuit_types.hpp" -#include "aztec3/utils/types/convert.hpp" #include "aztec3/utils/types/native_types.hpp" #include @@ -27,7 +26,7 @@ template struct CombinedConstantData { MSGPACK_FIELDS(block_data, tx_context); boolean operator==(CombinedConstantData const& other) const { - return block_data == other.block_data && tx_context == other.tx_context; + return msgpack_derived_equals(*this, other); } template CombinedConstantData> to_circuit_type(Builder& builder) const diff --git a/circuits/cpp/src/aztec3/circuits/abis/final_accumulated_data.hpp b/circuits/cpp/src/aztec3/circuits/abis/final_accumulated_data.hpp new file mode 100644 index 00000000000..9aba003e806 --- /dev/null +++ b/circuits/cpp/src/aztec3/circuits/abis/final_accumulated_data.hpp @@ -0,0 +1,194 @@ +#pragma once +#include "new_contract_data.hpp" +#include "optionally_revealed_data.hpp" +#include "public_data_read.hpp" +#include "public_data_update_request.hpp" + +#include "aztec3/circuits/abis/membership_witness.hpp" +#include "aztec3/circuits/abis/read_request_membership_witness.hpp" +#include "aztec3/constants.hpp" +#include "aztec3/utils/types/circuit_types.hpp" +#include "aztec3/utils/types/convert.hpp" +#include "aztec3/utils/types/native_types.hpp" + +#include + +#include +#include + +namespace aztec3::circuits::abis { + +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; +using std::is_same; + +template struct FinalAccumulatedData { + using fr = typename NCT::fr; + using uint32 = typename NCT::uint32; + using boolean = typename NCT::boolean; + using AggregationObject = typename NCT::AggregationObject; + + AggregationObject aggregation_object{}; + + std::array new_commitments{}; + std::array new_nullifiers{}; + std::array nullified_commitments{}; + // For pending nullifiers, we have: + // nullifiedCommitments[j] != 0 <==> newNullifiers[j] nullifies nullifiedCommitments[j] + + std::array private_call_stack{}; + std::array public_call_stack{}; + std::array new_l2_to_l1_msgs{}; + + std::array encrypted_logs_hash{}; + std::array unencrypted_logs_hash{}; + + // Here so that the gas cost of this request can be measured by circuits, without actually needing to feed in the + // variable-length data. + fr encrypted_log_preimages_length = 0; + fr unencrypted_log_preimages_length = 0; + + std::array, MAX_NEW_CONTRACTS_PER_TX> new_contracts{}; + + std::array, MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX> optionally_revealed_data{}; + + // for serialization, update with new fields + MSGPACK_FIELDS(aggregation_object, + new_commitments, + new_nullifiers, + nullified_commitments, + private_call_stack, + public_call_stack, + new_l2_to_l1_msgs, + encrypted_logs_hash, + unencrypted_logs_hash, + encrypted_log_preimages_length, + unencrypted_log_preimages_length, + new_contracts, + optionally_revealed_data); + boolean operator==(FinalAccumulatedData const& other) const + { + return msgpack_derived_equals(*this, other); + }; + + template FinalAccumulatedData> to_circuit_type(Builder& builder) const + { + typedef CircuitTypes CT; + static_assert((std::is_same::value)); + + // Capture the circuit builder: + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(builder, e); }; + auto to_circuit_type = [&](auto& e) { return e.to_circuit_type(builder); }; + + FinalAccumulatedData acc_data = { + typename CT::AggregationObject{ + to_ct(aggregation_object.P0), + to_ct(aggregation_object.P1), + to_ct(aggregation_object.public_inputs), + aggregation_object.proof_witness_indices, + aggregation_object.has_data, + }, + + to_ct(new_commitments), + to_ct(new_nullifiers), + to_ct(nullified_commitments), + + to_ct(private_call_stack), + to_ct(public_call_stack), + to_ct(new_l2_to_l1_msgs), + + to_ct(encrypted_logs_hash), + to_ct(unencrypted_logs_hash), + + to_ct(encrypted_log_preimages_length), + to_ct(unencrypted_log_preimages_length), + + map(new_contracts, to_circuit_type), + map(optionally_revealed_data, to_circuit_type), + }; + + return acc_data; + }; + + template FinalAccumulatedData to_native_type() const + { + static_assert(std::is_same, NCT>::value); + auto to_nt = [&](auto& e) { return aztec3::utils::types::to_nt(e); }; + auto to_native_type = [](T& e) { return e.template to_native_type(); }; + + FinalAccumulatedData acc_data = { + typename NativeTypes::AggregationObject{ + to_nt(aggregation_object.P0), + to_nt(aggregation_object.P1), + to_nt(aggregation_object.public_inputs), + aggregation_object.proof_witness_indices, + aggregation_object.has_data, + }, + + to_nt(new_commitments), + to_nt(new_nullifiers), + to_nt(nullified_commitments), + + to_nt(private_call_stack), + to_nt(public_call_stack), + to_nt(new_l2_to_l1_msgs), + + to_nt(encrypted_logs_hash), + to_nt(unencrypted_logs_hash), + + to_nt(encrypted_log_preimages_length), + to_nt(unencrypted_log_preimages_length), + + map(new_contracts, to_native_type), + map(optionally_revealed_data, to_native_type), + }; + return acc_data; + } + + void set_public() + { + static_assert(!(std::is_same::value)); + + aggregation_object.add_proof_outputs_as_public_inputs(); + + set_array_public(new_commitments); + set_array_public(new_nullifiers); + set_array_public(nullified_commitments); + + set_array_public(private_call_stack); + set_array_public(public_call_stack); + set_array_public(new_l2_to_l1_msgs); + + set_array_public(encrypted_logs_hash); + set_array_public(unencrypted_logs_hash); + + set_array_public(new_contracts); + set_array_public(optionally_revealed_data); + } + + template void set_array_public(std::array& arr) + { + static_assert(!(std::is_same::value)); + for (T& e : arr) { + fr(e).set_public(); + } + } + + template void set_array_public(std::array, SIZE>& arr) + { + static_assert(!(std::is_same::value)); + for (auto& e : arr) { + e.set_public(); + } + } + + template void set_array_public(std::array, SIZE>& arr) + { + static_assert(!(std::is_same::value)); + for (auto& e : arr) { + e.set_public(); + } + } +}; + +} // namespace aztec3::circuits::abis diff --git a/circuits/cpp/src/aztec3/circuits/abis/kernel_circuit_public_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/kernel_circuit_public_inputs.hpp index b9be2fd0854..d14a11eb796 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/kernel_circuit_public_inputs.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/kernel_circuit_public_inputs.hpp @@ -28,7 +28,7 @@ template struct KernelCircuitPublicInputs { boolean operator==(KernelCircuitPublicInputs const& other) const { - return end == other.end && constants == other.constants && is_private == other.is_private; + return msgpack_derived_equals(*this, other); }; template KernelCircuitPublicInputs> to_circuit_type(Builder& builder) const diff --git a/circuits/cpp/src/aztec3/circuits/abis/kernel_circuit_public_inputs_final.hpp b/circuits/cpp/src/aztec3/circuits/abis/kernel_circuit_public_inputs_final.hpp new file mode 100644 index 00000000000..90ce25eedd2 --- /dev/null +++ b/circuits/cpp/src/aztec3/circuits/abis/kernel_circuit_public_inputs_final.hpp @@ -0,0 +1,79 @@ +#pragma once +#include "combined_constant_data.hpp" +#include "final_accumulated_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 { + +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; +using std::is_same; + +template struct KernelCircuitPublicInputsFinal { + using fr = typename NCT::fr; + using boolean = typename NCT::boolean; + + FinalAccumulatedData end{}; + CombinedConstantData constants{}; + + boolean is_private = true; // TODO: might need to instantiate from witness! + + // for serialization, update with new fields + MSGPACK_FIELDS(end, constants, is_private); + + boolean operator==(KernelCircuitPublicInputsFinal const& other) const + { + return msgpack_derived_equals(*this, other); + } + + template + KernelCircuitPublicInputsFinal> to_circuit_type(Builder& builder) const + { + static_assert((std::is_same::value)); + + // Capture the circuit builder: + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(builder, e); }; + + KernelCircuitPublicInputsFinal> private_inputs = { + end.to_circuit_type(builder), + constants.to_circuit_type(builder), + + to_ct(is_private), + }; + + return private_inputs; + }; + + template KernelCircuitPublicInputsFinal to_native_type() const + { + static_assert(std::is_same, NCT>::value); + auto to_nt = [&](auto& e) { return aztec3::utils::types::to_nt(e); }; + auto to_native_type = [](T& e) { return e.template to_native_type(); }; + + KernelCircuitPublicInputsFinal pis = { + to_native_type(end), + to_native_type(constants), + + to_nt(is_private), + }; + + return pis; + }; + + void set_public() + { + static_assert(!(std::is_same::value)); + + end.set_public(); + constants.set_public(); + + fr(is_private).set_public(); + } +}; + +} // namespace aztec3::circuits::abis diff --git a/circuits/cpp/src/aztec3/circuits/abis/tx_request.hpp b/circuits/cpp/src/aztec3/circuits/abis/tx_request.hpp index 9b525d2e6aa..de01c08e279 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/tx_request.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/tx_request.hpp @@ -2,7 +2,6 @@ #include "function_data.hpp" #include "tx_context.hpp" -#include "aztec3/utils/array.hpp" #include "aztec3/utils/types/circuit_types.hpp" #include "aztec3/utils/types/convert.hpp" #include "aztec3/utils/types/native_types.hpp" diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/common.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/common.cpp index a1b028a0409..61c45e5c70c 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/common.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/common.cpp @@ -6,7 +6,6 @@ #include "aztec3/circuits/abis/function_data.hpp" #include "aztec3/circuits/abis/kernel_circuit_public_inputs.hpp" #include "aztec3/circuits/abis/new_contract_data.hpp" -#include "aztec3/circuits/abis/previous_kernel_data.hpp" #include "aztec3/circuits/abis/private_kernel/private_call_data.hpp" #include "aztec3/circuits/abis/read_request_membership_witness.hpp" #include "aztec3/circuits/hash.hpp" @@ -21,7 +20,6 @@ using aztec3::circuits::abis::ContractLeafPreimage; using aztec3::circuits::abis::FunctionData; using aztec3::circuits::abis::KernelCircuitPublicInputs; using aztec3::circuits::abis::NewContractData; -using aztec3::circuits::abis::PreviousKernelData; using aztec3::circuits::abis::ReadRequestMembershipWitness; using aztec3::utils::array_length; @@ -423,31 +421,4 @@ void common_contract_logic(DummyBuilder& builder, } } -void common_initialise_end_values(PreviousKernelData const& previous_kernel, - KernelCircuitPublicInputs& public_inputs) -{ - public_inputs.constants = previous_kernel.public_inputs.constants; - - // Ensure the arrays are the same as previously, before we start pushing more data onto them in other - // functions within this circuit: - auto& end = public_inputs.end; - const auto& start = previous_kernel.public_inputs.end; - - end.new_commitments = start.new_commitments; - end.new_nullifiers = start.new_nullifiers; - end.nullified_commitments = start.nullified_commitments; - - end.private_call_stack = start.private_call_stack; - end.public_call_stack = start.public_call_stack; - end.new_l2_to_l1_msgs = start.new_l2_to_l1_msgs; - - end.encrypted_logs_hash = start.encrypted_logs_hash; - end.unencrypted_logs_hash = start.unencrypted_logs_hash; - - end.encrypted_log_preimages_length = start.encrypted_log_preimages_length; - end.unencrypted_log_preimages_length = start.unencrypted_log_preimages_length; - - end.optionally_revealed_data = start.optionally_revealed_data; -} - } // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/common.hpp b/circuits/cpp/src/aztec3/circuits/kernel/private/common.hpp index 23ffc938588..fd125983aa4 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/common.hpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/common.hpp @@ -48,7 +48,31 @@ void common_contract_logic(DummyBuilder& builder, ContractDeploymentData const& contract_dep_data, FunctionData const& function_data); -void common_initialise_end_values(PreviousKernelData const& previous_kernel, - KernelCircuitPublicInputs& public_inputs); +template +void common_initialise_end_values(PreviousKernelData const& previous_kernel, KernelPublicInputs& public_inputs) +{ + public_inputs.constants = previous_kernel.public_inputs.constants; + + // Ensure the arrays are the same as previously, before we start pushing more data onto them in other + // functions within this circuit: + auto& end = public_inputs.end; + const auto& start = previous_kernel.public_inputs.end; + + end.new_commitments = start.new_commitments; + end.new_nullifiers = start.new_nullifiers; + end.nullified_commitments = start.nullified_commitments; + + end.private_call_stack = start.private_call_stack; + end.public_call_stack = start.public_call_stack; + end.new_l2_to_l1_msgs = start.new_l2_to_l1_msgs; + + end.encrypted_logs_hash = start.encrypted_logs_hash; + end.unencrypted_logs_hash = start.unencrypted_logs_hash; + + end.encrypted_log_preimages_length = start.encrypted_log_preimages_length; + end.unencrypted_log_preimages_length = start.unencrypted_log_preimages_length; + + end.optionally_revealed_data = start.optionally_revealed_data; +} } // namespace aztec3::circuits::kernel::private_kernel \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit.test.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit.test.cpp index 5f762180166..0ac6741cbad 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit.test.cpp @@ -89,15 +89,11 @@ TEST_F(native_private_kernel_tests, native_accumulate_transient_read_requests) auto& previous_kernel = private_inputs_inner.previous_kernel; previous_kernel.public_inputs = public_inputs; - public_inputs = native_private_kernel_circuit_ordering(builder, previous_kernel); + auto final_public_inputs = native_private_kernel_circuit_ordering(builder, previous_kernel); ASSERT_FALSE(builder.failed()) << "failure: " << builder.get_first_failure() << " with code: " << builder.get_first_failure().code; - ASSERT_TRUE(array_length(public_inputs.end.new_commitments) == 2); // no commitments squashed - // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1074): read_request*s - // can be removed from final public inputs - ASSERT_TRUE(array_length(public_inputs.end.read_requests) == 0); - ASSERT_TRUE(array_length(public_inputs.end.read_request_membership_witnesses) == 0); + ASSERT_TRUE(array_length(final_public_inputs.end.new_commitments) == 2); // no commitments squashed } // 1. We send transient read request on value 23 and pending commitment 10 @@ -146,16 +142,12 @@ TEST_F(native_private_kernel_tests, native_transient_read_requests_no_match) auto& previous_kernel = private_inputs_inner.previous_kernel; previous_kernel.public_inputs = public_inputs; - public_inputs = native_private_kernel_circuit_ordering(builder, previous_kernel); + auto final_public_inputs = native_private_kernel_circuit_ordering(builder, previous_kernel); ASSERT_TRUE(builder.failed()); ASSERT_TRUE(builder.get_first_failure().code == CircuitErrorCode::PRIVATE_KERNEL__TRANSIENT_READ_REQUEST_NO_MATCH); - ASSERT_TRUE(array_length(public_inputs.end.new_commitments) == 2); // no commitments squashed - // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1074): read_request*s - // can be removed from final public inputs - ASSERT_TRUE(array_length(public_inputs.end.read_requests) == 0); - ASSERT_TRUE(array_length(public_inputs.end.read_request_membership_witnesses) == 0); + ASSERT_TRUE(array_length(final_public_inputs.end.new_commitments) == 2); // no commitments squashed } // Testing that the special value EMPTY_NULLIFIED_COMMITMENT keeps new_nullifiers aligned with nullified_commitments. @@ -198,13 +190,13 @@ TEST_F(native_private_kernel_tests, native_empty_nullified_commitment_respected) auto& previous_kernel = private_inputs_inner.previous_kernel; previous_kernel.public_inputs = public_inputs; - public_inputs = native_private_kernel_circuit_ordering(builder, previous_kernel); + auto final_public_inputs = native_private_kernel_circuit_ordering(builder, previous_kernel); ASSERT_FALSE(builder.failed()) << "failure: " << builder.get_first_failure() << " with code: " << builder.get_first_failure().code; - ASSERT_TRUE(array_length(public_inputs.end.new_commitments) == 1); // 1/2 commitment squashed - ASSERT_TRUE(array_length(public_inputs.end.new_nullifiers) == 1); // 1/2 nullifier squashed + ASSERT_TRUE(array_length(final_public_inputs.end.new_commitments) == 1); // 1/2 commitment squashed + ASSERT_TRUE(array_length(final_public_inputs.end.new_nullifiers) == 1); // 1/2 nullifier squashed } } // namespace aztec3::circuits::kernel::private_kernel diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_ordering.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_ordering.cpp index 842c5ce9725..53ed6899866 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_ordering.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_ordering.cpp @@ -1,7 +1,7 @@ #include "common.hpp" #include "init.hpp" -#include "aztec3/circuits/abis/kernel_circuit_public_inputs.hpp" +#include "aztec3/circuits/abis/kernel_circuit_public_inputs_final.hpp" #include "aztec3/circuits/abis/previous_kernel_data.hpp" #include "aztec3/circuits/hash.hpp" #include "aztec3/constants.hpp" @@ -14,7 +14,7 @@ namespace { using NT = aztec3::utils::types::NativeTypes; -using aztec3::circuits::abis::KernelCircuitPublicInputs; +using aztec3::circuits::abis::KernelCircuitPublicInputsFinal; using aztec3::circuits::abis::PreviousKernelData; using aztec3::circuits::kernel::private_kernel::common_initialise_end_values; using aztec3::utils::array_length; @@ -22,7 +22,8 @@ using aztec3::utils::array_rearrange; using aztec3::utils::CircuitErrorCode; using aztec3::utils::DummyCircuitBuilder; -void initialise_end_values(PreviousKernelData const& previous_kernel, KernelCircuitPublicInputs& public_inputs) +void initialise_end_values(PreviousKernelData const& previous_kernel, + KernelCircuitPublicInputsFinal& public_inputs) { common_initialise_end_values(previous_kernel, public_inputs); public_inputs.end.new_contracts = previous_kernel.public_inputs.end.new_contracts; @@ -192,11 +193,11 @@ void apply_commitment_nonces(NT::fr const& first_nullifier, } } -KernelCircuitPublicInputs native_private_kernel_circuit_ordering(DummyCircuitBuilder& builder, - PreviousKernelData const& previous_kernel) +KernelCircuitPublicInputsFinal native_private_kernel_circuit_ordering(DummyCircuitBuilder& builder, + PreviousKernelData const& previous_kernel) { // We'll be pushing data to this during execution of this circuit. - KernelCircuitPublicInputs public_inputs{}; + KernelCircuitPublicInputsFinal public_inputs{}; // Do this before any functions can modify the inputs. initialise_end_values(previous_kernel, public_inputs); @@ -217,8 +218,6 @@ KernelCircuitPublicInputs native_private_kernel_circuit_ordering(DummyCircui previous_kernel.public_inputs.end.read_requests, previous_kernel.public_inputs.end.read_request_membership_witnesses, previous_kernel.public_inputs.end.new_commitments); - // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1074): ideally final public_inputs - // shouldn't even include read_requests and read_request_membership_witnesses as they should be empty. // Matching nullifiers to pending commitments requires the full list of new commitments accumulated over // all iterations of the private kernel. Therefore, we match nullifiers (their nullified_commitments) diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_ordering.hpp b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_ordering.hpp index 5f04d941b24..9122d9a04b3 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_ordering.hpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_ordering.hpp @@ -2,22 +2,19 @@ #include "init.hpp" -#include "aztec3/circuits/abis/kernel_circuit_public_inputs.hpp" +#include "aztec3/circuits/abis/kernel_circuit_public_inputs_final.hpp" #include "aztec3/circuits/abis/previous_kernel_data.hpp" -#include "aztec3/circuits/abis/read_request_membership_witness.hpp" #include "aztec3/utils/dummy_circuit_builder.hpp" #include namespace aztec3::circuits::kernel::private_kernel { -using aztec3::circuits::abis::KernelCircuitPublicInputs; +using aztec3::circuits::abis::KernelCircuitPublicInputsFinal; using aztec3::circuits::abis::PreviousKernelData; using DummyBuilder = aztec3::utils::DummyCircuitBuilder; -using aztec3::circuits::abis::ReadRequestMembershipWitness; -using aztec3::utils::CircuitResult; -KernelCircuitPublicInputs native_private_kernel_circuit_ordering(DummyBuilder& builder, - PreviousKernelData const& previous_kernel); +KernelCircuitPublicInputsFinal native_private_kernel_circuit_ordering( + DummyBuilder& builder, PreviousKernelData const& previous_kernel); } // 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_ordering.test.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_ordering.test.cpp index 1e123ce8100..e19e3273899 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_ordering.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/native_private_kernel_circuit_ordering.test.cpp @@ -65,10 +65,6 @@ TEST_F(native_private_kernel_ordering_tests, native_matching_one_read_request_to ASSERT_FALSE(builder.failed()) << "failure: " << builder.get_first_failure(); ASSERT_TRUE(array_length(public_inputs.end.new_commitments) == 1); ASSERT_TRUE(public_inputs.end.new_commitments[0] == unique_siloed_commitments[0]); - // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1074): read_request*s - // can be removed from final public inputs - ASSERT_TRUE(array_length(public_inputs.end.read_requests) == 0); - ASSERT_TRUE(array_length(public_inputs.end.read_request_membership_witnesses) == 0); } TEST_F(native_private_kernel_ordering_tests, native_matching_some_read_requests_to_commitments_works) @@ -115,10 +111,6 @@ TEST_F(native_private_kernel_ordering_tests, native_matching_some_read_requests_ for (size_t c_idx = 0; c_idx < MAX_NEW_COMMITMENTS_PER_TX; c_idx++) { ASSERT_TRUE(public_inputs.end.new_commitments[c_idx] == unique_siloed_commitments[c_idx]); } - // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1074): read_request*s - // can be removed from final public inputs - ASSERT_TRUE(array_length(public_inputs.end.read_requests) == 0); - ASSERT_TRUE(array_length(public_inputs.end.read_request_membership_witnesses) == 0); } TEST_F(native_private_kernel_ordering_tests, native_read_request_unknown_fails) diff --git a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts index 6cdeba9a74b..ec51c50d1a1 100644 --- a/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts +++ b/yarn-project/aztec-rpc/src/aztec_rpc_server/aztec_rpc_server.ts @@ -10,7 +10,7 @@ import { CompleteAddress, EthAddress, FunctionData, - KernelCircuitPublicInputs, + KernelCircuitPublicInputsFinal, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, PartialAddress, PrivateKey, @@ -509,7 +509,7 @@ export class AztecRPCServer implements AztecRPC { // See https://github.com/AztecProtocol/aztec-packages/issues/1615 // TODO(#757): Enforce proper ordering of enqueued public calls private async patchPublicCallStackOrdering( - publicInputs: KernelCircuitPublicInputs, + publicInputs: KernelCircuitPublicInputsFinal, enqueuedPublicCalls: PublicCallRequest[], ) { const callToHash = (call: PublicCallRequest) => call.toPublicCallStackItem().then(item => item.hash()); diff --git a/yarn-project/aztec-rpc/src/kernel_prover/kernel_prover.ts b/yarn-project/aztec-rpc/src/kernel_prover/kernel_prover.ts index 94afeca021d..8791f403328 100644 --- a/yarn-project/aztec-rpc/src/kernel_prover/kernel_prover.ts +++ b/yarn-project/aztec-rpc/src/kernel_prover/kernel_prover.ts @@ -18,7 +18,7 @@ import { } from '@aztec/circuits.js'; import { assertLength } from '@aztec/foundation/serialize'; -import { KernelProofCreator, ProofCreator, ProofOutput } from './proof_creator.js'; +import { KernelProofCreator, ProofCreator, ProofOutput, ProofOutputFinal } from './proof_creator.js'; import { ProvingDataOracle } from './proving_data_oracle.js'; /** @@ -45,7 +45,7 @@ export interface OutputNoteData { * Represents the output data of the Kernel Prover. * Provides information about the newly created notes, along with the public inputs and proof. */ -export interface KernelProverOutput extends ProofOutput { +export interface KernelProverOutput extends ProofOutputFinal { /** * An array of output notes containing the contract address, note data, and commitment for each new note. */ @@ -163,13 +163,13 @@ export class KernelProver { assertLength(previousVkMembershipWitness.siblingPath, VK_TREE_HEIGHT), ); - output = await this.proofCreator.createProofOrdering(previousKernelData); + const outputFinal = await this.proofCreator.createProofOrdering(previousKernelData); // Only return the notes whose commitment is in the commitments of the final proof. - const finalNewCommitments = output.publicInputs.end.newCommitments; + const finalNewCommitments = outputFinal.publicInputs.end.newCommitments; const outputNotes = finalNewCommitments.map(c => newNotes[c.toString()]).filter(c => !!c); - return { ...output, outputNotes }; + return { ...outputFinal, outputNotes }; } private async createPrivateCallData( diff --git a/yarn-project/aztec-rpc/src/kernel_prover/proof_creator.ts b/yarn-project/aztec-rpc/src/kernel_prover/proof_creator.ts index fe6ce191bd8..1fc7712f33d 100644 --- a/yarn-project/aztec-rpc/src/kernel_prover/proof_creator.ts +++ b/yarn-project/aztec-rpc/src/kernel_prover/proof_creator.ts @@ -2,6 +2,7 @@ import { CircuitError, CircuitsWasm, KernelCircuitPublicInputs, + KernelCircuitPublicInputsFinal, PreviousKernelData, PrivateCallData, PrivateCircuitPublicInputs, @@ -17,8 +18,8 @@ import { Fr } from '@aztec/foundation/fields'; import { createDebugLogger } from '@aztec/foundation/log'; /** - * Represents the output of the proof creation process. - * Contains the public inputs required for the kernel circuit and the generated proof. + * Represents the output of the proof creation process for init and inner private kernel circuit. + * Contains the public inputs required for the init and inner private kernel circuit and the generated proof. */ export interface ProofOutput { /** @@ -31,6 +32,21 @@ export interface ProofOutput { proof: Proof; } +/** + * Represents the output of the proof creation process for final ordering private kernel circuit. + * Contains the public inputs required for the final ordering private kernel circuit and the generated proof. + */ +export interface ProofOutputFinal { + /** + * The public inputs required for the proof generation process. + */ + publicInputs: KernelCircuitPublicInputsFinal; + /** + * The zk-SNARK proof for the kernel execution. + */ + proof: Proof; +} + /** * ProofCreator provides functionality to create and validate proofs, and retrieve * siloed commitments necessary for maintaining transaction privacy and security on the network. @@ -68,7 +84,7 @@ export interface ProofCreator { * @param previousKernelData - The previous kernel data object. * @returns A Promise resolving to a ProofOutput object containing public inputs and the kernel proof. */ - createProofOrdering(previousKernelData: PreviousKernelData): Promise; + createProofOrdering(previousKernelData: PreviousKernelData): Promise; } /** @@ -121,7 +137,7 @@ export class KernelProofCreator implements ProofCreator { }; } - public async createProofOrdering(previousKernelData: PreviousKernelData): Promise { + public async createProofOrdering(previousKernelData: PreviousKernelData): Promise { const wasm = await CircuitsWasm.get(); this.log('Executing private kernel simulation ordering...'); const result = privateKernelSimOrdering(wasm, previousKernelData); @@ -133,7 +149,7 @@ export class KernelProofCreator implements ProofCreator { const proof = makeEmptyProof(); this.log('Ordering Kernel Prover Ordering Completed!'); - const publicInputs = result as KernelCircuitPublicInputs; + const publicInputs = result as KernelCircuitPublicInputsFinal; return { publicInputs, diff --git a/yarn-project/circuits.js/src/cbind/circuits.gen.ts b/yarn-project/circuits.js/src/cbind/circuits.gen.ts index a847c8864f1..25b21e0df04 100644 --- a/yarn-project/circuits.js/src/cbind/circuits.gen.ts +++ b/yarn-project/circuits.js/src/cbind/circuits.gen.ts @@ -16,6 +16,7 @@ import { ContractDeploymentData, ContractStorageRead, ContractStorageUpdateRequest, + FinalAccumulatedData, Fq, Fr, FunctionData, @@ -24,6 +25,7 @@ import { GlobalVariables, HistoricBlockData, KernelCircuitPublicInputs, + KernelCircuitPublicInputsFinal, NativeAggregationState, NewContractData, OptionallyRevealedData, @@ -1117,6 +1119,182 @@ export function fromCircuitError(o: CircuitError): MsgpackCircuitError { }; } +interface MsgpackFinalAccumulatedData { + aggregation_object: MsgpackNativeAggregationState; + new_commitments: Tuple; + new_nullifiers: Tuple; + nullified_commitments: Tuple; + private_call_stack: Tuple; + public_call_stack: Tuple; + new_l2_to_l1_msgs: Tuple; + encrypted_logs_hash: Tuple; + unencrypted_logs_hash: Tuple; + encrypted_log_preimages_length: Buffer; + unencrypted_log_preimages_length: Buffer; + new_contracts: Tuple; + optionally_revealed_data: Tuple; +} + +export function toFinalAccumulatedData(o: MsgpackFinalAccumulatedData): FinalAccumulatedData { + if (o.aggregation_object === undefined) { + throw new Error('Expected aggregation_object in FinalAccumulatedData deserialization'); + } + if (o.new_commitments === undefined) { + throw new Error('Expected new_commitments in FinalAccumulatedData deserialization'); + } + if (o.new_nullifiers === undefined) { + throw new Error('Expected new_nullifiers in FinalAccumulatedData deserialization'); + } + if (o.nullified_commitments === undefined) { + throw new Error('Expected nullified_commitments in FinalAccumulatedData deserialization'); + } + if (o.private_call_stack === undefined) { + throw new Error('Expected private_call_stack in FinalAccumulatedData deserialization'); + } + if (o.public_call_stack === undefined) { + throw new Error('Expected public_call_stack in FinalAccumulatedData deserialization'); + } + if (o.new_l2_to_l1_msgs === undefined) { + throw new Error('Expected new_l2_to_l1_msgs in FinalAccumulatedData deserialization'); + } + if (o.encrypted_logs_hash === undefined) { + throw new Error('Expected encrypted_logs_hash in FinalAccumulatedData deserialization'); + } + if (o.unencrypted_logs_hash === undefined) { + throw new Error('Expected unencrypted_logs_hash in FinalAccumulatedData deserialization'); + } + if (o.encrypted_log_preimages_length === undefined) { + throw new Error('Expected encrypted_log_preimages_length in FinalAccumulatedData deserialization'); + } + if (o.unencrypted_log_preimages_length === undefined) { + throw new Error('Expected unencrypted_log_preimages_length in FinalAccumulatedData deserialization'); + } + if (o.new_contracts === undefined) { + throw new Error('Expected new_contracts in FinalAccumulatedData deserialization'); + } + if (o.optionally_revealed_data === undefined) { + throw new Error('Expected optionally_revealed_data in FinalAccumulatedData deserialization'); + } + return new FinalAccumulatedData( + toNativeAggregationState(o.aggregation_object), + mapTuple(o.new_commitments, (v: Buffer) => Fr.fromBuffer(v)), + mapTuple(o.new_nullifiers, (v: Buffer) => Fr.fromBuffer(v)), + mapTuple(o.nullified_commitments, (v: Buffer) => Fr.fromBuffer(v)), + mapTuple(o.private_call_stack, (v: Buffer) => Fr.fromBuffer(v)), + mapTuple(o.public_call_stack, (v: Buffer) => Fr.fromBuffer(v)), + mapTuple(o.new_l2_to_l1_msgs, (v: Buffer) => Fr.fromBuffer(v)), + mapTuple(o.encrypted_logs_hash, (v: Buffer) => Fr.fromBuffer(v)), + mapTuple(o.unencrypted_logs_hash, (v: Buffer) => Fr.fromBuffer(v)), + Fr.fromBuffer(o.encrypted_log_preimages_length), + Fr.fromBuffer(o.unencrypted_log_preimages_length), + mapTuple(o.new_contracts, (v: MsgpackNewContractData) => toNewContractData(v)), + mapTuple(o.optionally_revealed_data, (v: MsgpackOptionallyRevealedData) => toOptionallyRevealedData(v)), + ); +} + +export function fromFinalAccumulatedData(o: FinalAccumulatedData): MsgpackFinalAccumulatedData { + if (o.aggregationObject === undefined) { + throw new Error('Expected aggregationObject in FinalAccumulatedData serialization'); + } + if (o.newCommitments === undefined) { + throw new Error('Expected newCommitments in FinalAccumulatedData serialization'); + } + if (o.newNullifiers === undefined) { + throw new Error('Expected newNullifiers in FinalAccumulatedData serialization'); + } + if (o.nullifiedCommitments === undefined) { + throw new Error('Expected nullifiedCommitments in FinalAccumulatedData serialization'); + } + if (o.privateCallStack === undefined) { + throw new Error('Expected privateCallStack in FinalAccumulatedData serialization'); + } + if (o.publicCallStack === undefined) { + throw new Error('Expected publicCallStack in FinalAccumulatedData serialization'); + } + if (o.newL2ToL1Msgs === undefined) { + throw new Error('Expected newL2ToL1Msgs in FinalAccumulatedData serialization'); + } + if (o.encryptedLogsHash === undefined) { + throw new Error('Expected encryptedLogsHash in FinalAccumulatedData serialization'); + } + if (o.unencryptedLogsHash === undefined) { + throw new Error('Expected unencryptedLogsHash in FinalAccumulatedData serialization'); + } + if (o.encryptedLogPreimagesLength === undefined) { + throw new Error('Expected encryptedLogPreimagesLength in FinalAccumulatedData serialization'); + } + if (o.unencryptedLogPreimagesLength === undefined) { + throw new Error('Expected unencryptedLogPreimagesLength in FinalAccumulatedData serialization'); + } + if (o.newContracts === undefined) { + throw new Error('Expected newContracts in FinalAccumulatedData serialization'); + } + if (o.optionallyRevealedData === undefined) { + throw new Error('Expected optionallyRevealedData in FinalAccumulatedData serialization'); + } + return { + aggregation_object: fromNativeAggregationState(o.aggregationObject), + new_commitments: mapTuple(o.newCommitments, (v: Fr) => toBuffer(v)), + new_nullifiers: mapTuple(o.newNullifiers, (v: Fr) => toBuffer(v)), + nullified_commitments: mapTuple(o.nullifiedCommitments, (v: Fr) => toBuffer(v)), + private_call_stack: mapTuple(o.privateCallStack, (v: Fr) => toBuffer(v)), + public_call_stack: mapTuple(o.publicCallStack, (v: Fr) => toBuffer(v)), + new_l2_to_l1_msgs: mapTuple(o.newL2ToL1Msgs, (v: Fr) => toBuffer(v)), + encrypted_logs_hash: mapTuple(o.encryptedLogsHash, (v: Fr) => toBuffer(v)), + unencrypted_logs_hash: mapTuple(o.unencryptedLogsHash, (v: Fr) => toBuffer(v)), + encrypted_log_preimages_length: toBuffer(o.encryptedLogPreimagesLength), + unencrypted_log_preimages_length: toBuffer(o.unencryptedLogPreimagesLength), + new_contracts: mapTuple(o.newContracts, (v: NewContractData) => fromNewContractData(v)), + optionally_revealed_data: mapTuple(o.optionallyRevealedData, (v: OptionallyRevealedData) => + fromOptionallyRevealedData(v), + ), + }; +} + +interface MsgpackKernelCircuitPublicInputsFinal { + end: MsgpackFinalAccumulatedData; + constants: MsgpackCombinedConstantData; + is_private: boolean; +} + +export function toKernelCircuitPublicInputsFinal( + o: MsgpackKernelCircuitPublicInputsFinal, +): KernelCircuitPublicInputsFinal { + if (o.end === undefined) { + throw new Error('Expected end in KernelCircuitPublicInputsFinal deserialization'); + } + if (o.constants === undefined) { + throw new Error('Expected constants in KernelCircuitPublicInputsFinal deserialization'); + } + if (o.is_private === undefined) { + throw new Error('Expected is_private in KernelCircuitPublicInputsFinal deserialization'); + } + return new KernelCircuitPublicInputsFinal( + toFinalAccumulatedData(o.end), + toCombinedConstantData(o.constants), + o.is_private, + ); +} + +export function fromKernelCircuitPublicInputsFinal( + o: KernelCircuitPublicInputsFinal, +): MsgpackKernelCircuitPublicInputsFinal { + if (o.end === undefined) { + throw new Error('Expected end in KernelCircuitPublicInputsFinal serialization'); + } + if (o.constants === undefined) { + throw new Error('Expected constants in KernelCircuitPublicInputsFinal serialization'); + } + if (o.isPrivate === undefined) { + throw new Error('Expected isPrivate in KernelCircuitPublicInputsFinal serialization'); + } + return { + end: fromFinalAccumulatedData(o.end), + constants: fromCombinedConstantData(o.constants), + is_private: o.isPrivate, + }; +} + interface MsgpackCallContext { msg_sender: Buffer; storage_contract_address: Buffer; @@ -1590,9 +1768,9 @@ export function privateKernelDummyPreviousKernel(wasm: IWasmModule): PreviousKer export function privateKernelSimOrdering( wasm: IWasmModule, arg0: PreviousKernelData, -): CircuitError | KernelCircuitPublicInputs { - return ((v: MsgpackCircuitError | MsgpackKernelCircuitPublicInputs) => - isCircuitError(v) ? toCircuitError(v) : toKernelCircuitPublicInputs(v))( +): CircuitError | KernelCircuitPublicInputsFinal { + return ((v: MsgpackCircuitError | MsgpackKernelCircuitPublicInputsFinal) => + isCircuitError(v) ? toCircuitError(v) : toKernelCircuitPublicInputsFinal(v))( callCbind(wasm, 'private_kernel__sim_ordering', [fromPreviousKernelData(arg0)]), ); } diff --git a/yarn-project/circuits.js/src/cbind/types.ts b/yarn-project/circuits.js/src/cbind/types.ts index 527c6c9b244..a20febec714 100644 --- a/yarn-project/circuits.js/src/cbind/types.ts +++ b/yarn-project/circuits.js/src/cbind/types.ts @@ -22,7 +22,6 @@ export { AggregationObject as NativeAggregationState, AztecAddress as Address, VerificationKey as VerificationKeyData, - PrivateKernelPublicInputs as PublicInputs, Fr, Fq, G1AffineElement, @@ -33,11 +32,13 @@ export { PublicDataUpdateRequest, ReadRequestMembershipWitness, CombinedAccumulatedData, + FinalAccumulatedData, HistoricBlockData, ContractDeploymentData, TxContext, CombinedConstantData, KernelCircuitPublicInputs, + KernelCircuitPublicInputsFinal, Proof, PreviousKernelData, CallContext, diff --git a/yarn-project/circuits.js/src/kernel/public_kernel.test.ts b/yarn-project/circuits.js/src/kernel/public_kernel.test.ts index 7bf12b12942..c8b28c2daa7 100644 --- a/yarn-project/circuits.js/src/kernel/public_kernel.test.ts +++ b/yarn-project/circuits.js/src/kernel/public_kernel.test.ts @@ -1,15 +1,17 @@ import { CircuitError, + Fr, + MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_DATA_READS_PER_CALL, MAX_PUBLIC_DATA_READS_PER_TX, makeTuple, simulatePublicKernelCircuit, } from '../index.js'; -import { makePublicDataRead, makePublicKernelInputsWithEmptyOutput } from '../tests/factories.js'; +import { makePublicDataRead, makePublicKernelInputsWithTweak } from '../tests/factories.js'; describe('kernel/public_kernel', () => { it('simulates public kernel circuit with previous public kernel', async function () { - const input = await makePublicKernelInputsWithEmptyOutput(1, input => { + const input = await makePublicKernelInputsWithTweak(1, input => { input.publicCall.callStackItem.functionData.isConstructor = false; input.publicCall.callStackItem.functionData.isPrivate = false; input.previousKernel.publicInputs.isPrivate = false; @@ -19,15 +21,16 @@ describe('kernel/public_kernel', () => { }); it('simulates public kernel circuit with previous private kernel', async function () { - const input = await makePublicKernelInputsWithEmptyOutput(1, input => { + const input = await makePublicKernelInputsWithTweak(1, input => { input.previousKernel.publicInputs.isPrivate = true; + input.previousKernel.publicInputs.end.privateCallStack = makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, Fr.zero); }); const result = await simulatePublicKernelCircuit(input); expect(result).toBeDefined(); }); it('simulating public kernel circuit fails when aggregating proofs will overflow', async function () { - const input = await makePublicKernelInputsWithEmptyOutput(1, input => { + const input = await makePublicKernelInputsWithTweak(1, input => { input.publicCall.callStackItem.functionData.isConstructor = false; input.publicCall.callStackItem.functionData.isPrivate = false; input.previousKernel.publicInputs.isPrivate = false; diff --git a/yarn-project/circuits.js/src/structs/index.ts b/yarn-project/circuits.js/src/structs/index.ts index 12307c66e25..7e31d2957b4 100644 --- a/yarn-project/circuits.js/src/structs/index.ts +++ b/yarn-project/circuits.js/src/structs/index.ts @@ -14,6 +14,7 @@ export * from './kernel/combined_constant_data.js'; export * from './kernel/historic_block_data.js'; export * from './kernel/previous_kernel_data.js'; export * from './kernel/public_inputs.js'; +export * from './kernel/public_inputs_final.js'; export * from './private_circuit_public_inputs.js'; export * from './public_circuit_public_inputs.js'; export * from './circuit_error.js'; 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 e59f9774e75..6791a7073b4 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 @@ -237,6 +237,93 @@ value: 0xe11 exports[`structs/kernel serializes and prints EcdsaSignature 1`] = `"{ 0101010101010101010101010101010101010101010101010101010101010101, 0101010101010101010101010101010101010101010101010101010101010101 }"`; +exports[`structs/kernel serializes and prints FinalAccumulatedData 1`] = ` +"aggregation_object: +P0: { 0x1, 0x2 } +P1: { 0x101, 0x102 } +public_inputs: [ + 0x3 + 0x4 + 0x5 + 0x6 +] +proof_witness_indices: [ 7 8 9 10 11 12 ] +has_data: 0 + +new_commitments: [ 0x101 0x102 0x103 0x104 0x105 0x106 0x107 0x108 0x109 0x10a 0x10b 0x10c 0x10d 0x10e 0x10f 0x110 ] +new_nullifiers: [ 0x201 0x202 0x203 0x204 0x205 0x206 0x207 0x208 0x209 0x20a 0x20b 0x20c 0x20d 0x20e 0x20f 0x210 ] +nullified_commitments: [ 0x301 0x302 0x303 0x304 0x305 0x306 0x307 0x308 0x309 0x30a 0x30b 0x30c 0x30d 0x30e 0x30f 0x310 ] +private_call_stack: [ 0x401 0x402 0x403 0x404 0x405 0x406 0x407 0x408 ] +public_call_stack: [ 0x501 0x502 0x503 0x504 0x505 0x506 0x507 0x508 ] +new_l2_to_l1_msgs: [ 0x601 0x602 ] +encrypted_logs_hash: [ 0x701 0x702 ] +unencrypted_logs_hash: [ 0x801 0x802 ] +encrypted_log_preimages_length: 0x901 +unencrypted_log_preimages_length: 0xa01 +new_contracts: [ contract_address: 0xb01 +portal_contract_address: 0x202020202020202020202020202020202020202 +function_tree_root: 0xb03 + ] +optionally_revealed_data: [ call_stack_item_hash: 0xc01 +function_data: selector: +value: c02 + +is_internal: 0 +is_private: 1 +is_constructor: 1 + +vk_hash: 0xc03 +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: 0xc02 +function_data: selector: +value: c03 + +is_internal: 0 +is_private: 1 +is_constructor: 1 + +vk_hash: 0xc04 +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: 0xc03 +function_data: selector: +value: c04 + +is_internal: 0 +is_private: 1 +is_constructor: 1 + +vk_hash: 0xc05 +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: 0xc04 +function_data: selector: +value: c05 + +is_internal: 0 +is_private: 1 +is_constructor: 1 + +vk_hash: 0xc06 +portal_contract_address: 0x707070707070707070707070707070707070707 +pay_fee_from_l1: 1 +pay_fee_from_public_l2: 0 +called_from_l1: 1 +called_from_public_l2: 0 + ] +" +`; + exports[`structs/kernel serializes and prints previous_kernel_data 1`] = ` "public_inputs: end: @@ -1682,6 +1769,124 @@ chain_id: 0x0 version: 0x0 +is_private: 1 +" +`; + +exports[`structs/kernel serializes and prints private_kernel_public_inputs for ordering circuit 1`] = ` +"end: +aggregation_object: +P0: { 0x1, 0x2 } +P1: { 0x101, 0x102 } +public_inputs: [ + 0x3 + 0x4 + 0x5 + 0x6 +] +proof_witness_indices: [ 7 8 9 10 11 12 ] +has_data: 0 + +new_commitments: [ 0x101 0x102 0x103 0x104 0x105 0x106 0x107 0x108 0x109 0x10a 0x10b 0x10c 0x10d 0x10e 0x10f 0x110 ] +new_nullifiers: [ 0x201 0x202 0x203 0x204 0x205 0x206 0x207 0x208 0x209 0x20a 0x20b 0x20c 0x20d 0x20e 0x20f 0x210 ] +nullified_commitments: [ 0x301 0x302 0x303 0x304 0x305 0x306 0x307 0x308 0x309 0x30a 0x30b 0x30c 0x30d 0x30e 0x30f 0x310 ] +private_call_stack: [ 0x401 0x402 0x403 0x404 0x405 0x406 0x407 0x408 ] +public_call_stack: [ 0x501 0x502 0x503 0x504 0x505 0x506 0x507 0x508 ] +new_l2_to_l1_msgs: [ 0x601 0x602 ] +encrypted_logs_hash: [ 0x701 0x702 ] +unencrypted_logs_hash: [ 0x801 0x802 ] +encrypted_log_preimages_length: 0x901 +unencrypted_log_preimages_length: 0xa01 +new_contracts: [ contract_address: 0xb01 +portal_contract_address: 0x202020202020202020202020202020202020202 +function_tree_root: 0xb03 + ] +optionally_revealed_data: [ call_stack_item_hash: 0xc01 +function_data: selector: +value: c02 + +is_internal: 0 +is_private: 1 +is_constructor: 1 + +vk_hash: 0xc03 +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: 0xc02 +function_data: selector: +value: c03 + +is_internal: 0 +is_private: 1 +is_constructor: 1 + +vk_hash: 0xc04 +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: 0xc03 +function_data: selector: +value: c04 + +is_internal: 0 +is_private: 1 +is_constructor: 1 + +vk_hash: 0xc05 +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: 0xc04 +function_data: selector: +value: c05 + +is_internal: 0 +is_private: 1 +is_constructor: 1 + +vk_hash: 0xc06 +portal_contract_address: 0x707070707070707070707070707070707070707 +pay_fee_from_l1: 1 +pay_fee_from_public_l2: 0 +called_from_l1: 1 +called_from_public_l2: 0 + ] + +constants: +block_data: +private_data_tree_root: 0x101 +nullifier_tree_root: 0x102 +contract_tree_root: 0x103 +l1_to_l2_messages_tree_root: 0x104 +blocks_tree_root: 0x105 +private_kernel_vk_tree_root: 0x106 +public_data_tree_root: 0x107 +global_variables_hash: 0x108 + +tx_context: +is_fee_payment_tx: 0 +is_rebate_payment_tx: 0 +is_contract_deployment_tx: 1 +contract_deployment_data: deployer_public_key: +x: 0x105 +y: 0x106 + +constructor_vk_hash: 0x106 +function_tree_root: 0x107 +contract_address_salt: 0x108 +portal_contract_address: 0x909090909090909090909090909090909090909 + +chain_id: 0x0 +version: 0x0 + + is_private: 1 " `; diff --git a/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.test.ts b/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.test.ts index 55b0fbf406f..ed756135156 100644 --- a/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.test.ts +++ b/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.test.ts @@ -1,5 +1,5 @@ -import { makeAccumulatedData } from '../../tests/factories.js'; -import { CombinedAccumulatedData } from './combined_accumulated_data.js'; +import { makeAccumulatedData, makeFinalAccumulatedData } from '../../tests/factories.js'; +import { CombinedAccumulatedData, FinalAccumulatedData } from './combined_accumulated_data.js'; describe('CombinedAccumulatedData', () => { it('Data after serialization and deserialization is equal to the original', () => { @@ -8,3 +8,11 @@ describe('CombinedAccumulatedData', () => { expect(original).toEqual(afterSerialization); }); }); + +describe('FinalAccumulatedData', () => { + it('Data after serialization and deserialization is equal to the original', () => { + const original = makeFinalAccumulatedData(); + const afterSerialization = FinalAccumulatedData.fromBuffer(original.toBuffer()); + expect(original).toEqual(afterSerialization); + }); +}); diff --git a/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts b/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts index 8b5ef26a4ba..43f4134ab41 100644 --- a/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts @@ -15,6 +15,7 @@ import { NUM_FIELDS_PER_SHA256, } from '../../cbind/constants.gen.js'; import { assertMemberLength, makeTuple } from '../../index.js'; +import { makeEmptyReadRequestMembershipWitness } from '../../tests/factories.js'; import { serializeToBuffer } from '../../utils/serialize.js'; import { AggregationObject, @@ -428,6 +429,28 @@ export class CombinedAccumulatedData { ); } + static fromFinalAccumulatedData(finalData: FinalAccumulatedData): CombinedAccumulatedData { + return new CombinedAccumulatedData( + finalData.aggregationObject, + makeTuple(MAX_READ_REQUESTS_PER_TX, Fr.zero), + makeTuple(MAX_READ_REQUESTS_PER_TX, makeEmptyReadRequestMembershipWitness), + finalData.newCommitments, + finalData.newNullifiers, + finalData.nullifiedCommitments, + finalData.privateCallStack, + finalData.publicCallStack, + finalData.newL2ToL1Msgs, + finalData.encryptedLogsHash, + finalData.unencryptedLogsHash, + finalData.encryptedLogPreimagesLength, + finalData.unencryptedLogPreimagesLength, + finalData.newContracts, + finalData.optionallyRevealedData, + makeTuple(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataUpdateRequest.empty), + makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, PublicDataRead.empty), + ); + } + /** * Deserializes from a string, corresponding to a write in cpp. * @param str - String to read from. @@ -459,3 +482,151 @@ export class CombinedAccumulatedData { ); } } + +/** + * Specific accumululated data structure for the final ordering private kernel circuit. It is included + * in the final public inputs of private kernel circuit. + */ +export class FinalAccumulatedData { + constructor( + /** + * Aggregated proof of all the previous kernel iterations. + */ + public aggregationObject: AggregationObject, // Contains the aggregated proof of all previous kernel iterations + /** + * The new commitments made in this transaction. + */ + public newCommitments: Tuple, + /** + * The new nullifiers made in this transaction. + */ + public newNullifiers: Tuple, + /** + * The commitments which are nullified by a nullifier in the above list. For pending nullifiers, we have: + * nullifiedCommitments[j] != 0 if and only if newNullifiers[j] nullifies nullifiedCommitments[j] + */ + public nullifiedCommitments: Tuple, + /** + * Current private call stack. + */ + public privateCallStack: Tuple, + /** + * Current public call stack. + */ + public publicCallStack: Tuple, + /** + * All the new L2 to L1 messages created in this transaction. + */ + public newL2ToL1Msgs: Tuple, + /** + * Accumulated encrypted logs hash from all the previous kernel iterations. + * Note: Represented as a tuple of 2 fields in order to fit in all of the 256 bits of sha256 hash. + */ + public encryptedLogsHash: Tuple, + /** + * Accumulated unencrypted logs hash from all the previous kernel iterations. + * Note: Represented as a tuple of 2 fields in order to fit in all of the 256 bits of sha256 hash. + */ + public unencryptedLogsHash: Tuple, + /** + * Total accumulated length of the encrypted log preimages emitted in all the previous kernel iterations + */ + public encryptedLogPreimagesLength: Fr, + /** + * Total accumulated length of the unencrypted log preimages emitted in all the previous kernel iterations + */ + public unencryptedLogPreimagesLength: Fr, + /** + * All the new contracts deployed in this transaction. + */ + public newContracts: Tuple, + /** + * All the optionally revealed data in this transaction. + */ + public optionallyRevealedData: Tuple, + ) { + assertMemberLength(this, 'newCommitments', MAX_NEW_COMMITMENTS_PER_TX); + assertMemberLength(this, 'newNullifiers', MAX_NEW_NULLIFIERS_PER_TX); + assertMemberLength(this, 'nullifiedCommitments', MAX_NEW_NULLIFIERS_PER_TX); + assertMemberLength(this, 'privateCallStack', MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX); + assertMemberLength(this, 'publicCallStack', MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX); + assertMemberLength(this, 'newL2ToL1Msgs', MAX_NEW_L2_TO_L1_MSGS_PER_TX); + assertMemberLength(this, 'encryptedLogsHash', NUM_FIELDS_PER_SHA256); + assertMemberLength(this, 'unencryptedLogsHash', NUM_FIELDS_PER_SHA256); + assertMemberLength(this, 'newContracts', MAX_NEW_CONTRACTS_PER_TX); + assertMemberLength(this, 'optionallyRevealedData', MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX); + } + + toBuffer() { + return serializeToBuffer( + this.aggregationObject, + this.newCommitments, + this.newNullifiers, + this.nullifiedCommitments, + this.privateCallStack, + this.publicCallStack, + this.newL2ToL1Msgs, + this.encryptedLogsHash, + this.unencryptedLogsHash, + this.encryptedLogPreimagesLength, + this.unencryptedLogPreimagesLength, + this.newContracts, + this.optionallyRevealedData, + ); + } + + toString() { + return this.toBuffer().toString(); + } + + /** + * Deserializes from a buffer or reader, corresponding to a write in cpp. + * @param buffer - Buffer or reader to read from. + * @returns Deserialized object. + */ + static fromBuffer(buffer: Buffer | BufferReader): FinalAccumulatedData { + const reader = BufferReader.asReader(buffer); + return new FinalAccumulatedData( + reader.readObject(AggregationObject), + reader.readArray(MAX_NEW_COMMITMENTS_PER_TX, Fr), + reader.readArray(MAX_NEW_NULLIFIERS_PER_TX, Fr), + reader.readArray(MAX_NEW_NULLIFIERS_PER_TX, Fr), + reader.readArray(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, Fr), + reader.readArray(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, Fr), + reader.readArray(MAX_NEW_L2_TO_L1_MSGS_PER_TX, Fr), + reader.readArray(2, Fr), + reader.readArray(2, Fr), + reader.readFr(), + reader.readFr(), + reader.readArray(MAX_NEW_CONTRACTS_PER_TX, NewContractData), + reader.readArray(MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX, OptionallyRevealedData), + ); + } + + /** + * Deserializes from a string, corresponding to a write in cpp. + * @param str - String to read from. + * @returns Deserialized object. + */ + static fromString(str: string) { + return FinalAccumulatedData.fromBuffer(Buffer.from(str, 'hex')); + } + + static empty() { + return new FinalAccumulatedData( + AggregationObject.makeFake(), + makeTuple(MAX_NEW_COMMITMENTS_PER_TX, Fr.zero), + makeTuple(MAX_NEW_NULLIFIERS_PER_TX, Fr.zero), + makeTuple(MAX_NEW_NULLIFIERS_PER_TX, Fr.zero), + makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, Fr.zero), + makeTuple(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, Fr.zero), + makeTuple(MAX_NEW_L2_TO_L1_MSGS_PER_TX, Fr.zero), + makeTuple(2, Fr.zero), + makeTuple(2, Fr.zero), + Fr.zero(), + Fr.zero(), + makeTuple(MAX_NEW_CONTRACTS_PER_TX, NewContractData.empty), + makeTuple(MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX, OptionallyRevealedData.empty), + ); + } +} 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 7c13b7347b7..23d14a579b9 100644 --- a/yarn-project/circuits.js/src/structs/kernel/index.test.ts +++ b/yarn-project/circuits.js/src/structs/kernel/index.test.ts @@ -1,7 +1,9 @@ import { expectSerializeToMatchSnapshot } from '../../tests/expectSerialize.js'; import { makeAccumulatedData, + makeFinalAccumulatedData, makeKernelPublicInputs, + makeKernelPublicInputsFinal, makePreviousKernelData, makePrivateKernelInputsInit, makePrivateKernelInputsInner, @@ -44,6 +46,14 @@ describe('structs/kernel', () => { 'abis__test_roundtrip_serialize_combined_accumulated_data', ); }); + + it(`serializes and prints FinalAccumulatedData`, async (seed = 1) => { + await expectSerializeToMatchSnapshot( + makeFinalAccumulatedData(seed, true).toBuffer(), + 'abis__test_roundtrip_serialize_final_accumulated_data', + ); + }); + it(`serializes and prints private_kernel_public_inputs`, async () => { const kernelInputs = makeKernelPublicInputs(); await expectSerializeToMatchSnapshot( @@ -52,6 +62,14 @@ describe('structs/kernel', () => { ); }); + it(`serializes and prints private_kernel_public_inputs for ordering circuit`, async () => { + const kernelInputs = makeKernelPublicInputsFinal(); + await expectSerializeToMatchSnapshot( + kernelInputs.toBuffer(), + 'abis__test_roundtrip_serialize_kernel_circuit_public_inputs_final', + ); + }); + it(`serializes and prints public_kernel_inputs`, async () => { const kernelInputs = await makePublicKernelInputs(); await expectSerializeToMatchSnapshot( diff --git a/yarn-project/circuits.js/src/structs/kernel/public_inputs_final.ts b/yarn-project/circuits.js/src/structs/kernel/public_inputs_final.ts new file mode 100644 index 00000000000..6962edb9bbd --- /dev/null +++ b/yarn-project/circuits.js/src/structs/kernel/public_inputs_final.ts @@ -0,0 +1,57 @@ +import { BufferReader } from '@aztec/foundation/serialize'; + +import { serializeToBuffer } from '../../utils/serialize.js'; +import { FinalAccumulatedData } from './combined_accumulated_data.js'; +import { CombinedConstantData } from './combined_constant_data.js'; + +/** + * Public inputs of the final ordering private kernel circuit. + * @see circuits/cpp/src/aztec3/circuits/abis/kernel_circuit_public_inputs_final.hpp + */ +export class KernelCircuitPublicInputsFinal { + constructor( + /** + * Final data accumulated for ordering privated kernel circuit. + */ + public end: FinalAccumulatedData, + /** + * Data which is not modified by the circuits. + */ + public constants: CombinedConstantData, + /** + * Indicates whether the input is for a private or public kernel. + */ + public isPrivate: boolean, + ) {} + + toBuffer() { + return serializeToBuffer(this.end, this.constants, this.isPrivate); + } + + /** + * Deserializes from a buffer or reader, corresponding to a write in cpp. + * @param buffer - Buffer or reader to read from. + * @returns A new instance of KernelCircuitPublicInputsFinal. + */ + static fromBuffer(buffer: Buffer | BufferReader): KernelCircuitPublicInputsFinal { + const reader = BufferReader.asReader(buffer); + return new KernelCircuitPublicInputsFinal( + reader.readObject(FinalAccumulatedData), + reader.readObject(CombinedConstantData), + reader.readBoolean(), + ); + } + + static empty() { + return new KernelCircuitPublicInputsFinal(FinalAccumulatedData.empty(), CombinedConstantData.empty(), true); + } +} + +/** + * Public inputs of the final private kernel circuit. + */ +export class PrivateKernelPublicInputsFinal extends KernelCircuitPublicInputsFinal { + constructor(end: FinalAccumulatedData, constants: CombinedConstantData) { + super(end, constants, true); + } +} diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index c0601731407..e21871d2d8a 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -21,6 +21,7 @@ import { ContractStorageRead, ContractStorageUpdateRequest, FUNCTION_TREE_HEIGHT, + FinalAccumulatedData, Fq, Fr, FunctionData, @@ -29,6 +30,7 @@ import { HISTORIC_BLOCKS_TREE_HEIGHT, HistoricBlockData, KernelCircuitPublicInputs, + KernelCircuitPublicInputsFinal, L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH, MAX_NEW_COMMITMENTS_PER_CALL, MAX_NEW_COMMITMENTS_PER_TX, @@ -192,11 +194,11 @@ export function makeContractStorageRead(seed = 1): ContractStorageRead { } /** - * Creates empty accumulated data. + * Creates arbitrary accumulated data. * @param seed - The seed to use for generating the accumulated data. - * @returns An empty accumulated data. + * @returns An accumulated data. */ -export function makeEmptyAccumulatedData(seed = 1, full = false): CombinedAccumulatedData { +export function makeAccumulatedData(seed = 1, full = false): CombinedAccumulatedData { const tupleGenerator = full ? makeTuple : makeHalfFullTuple; return new CombinedAccumulatedData( @@ -206,7 +208,7 @@ export function makeEmptyAccumulatedData(seed = 1, full = false): CombinedAccumu tupleGenerator(MAX_NEW_COMMITMENTS_PER_TX, fr, seed + 0x100), tupleGenerator(MAX_NEW_NULLIFIERS_PER_TX, fr, seed + 0x200), tupleGenerator(MAX_NEW_NULLIFIERS_PER_TX, fr, seed + 0x300), - tupleGenerator(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, Fr.zero), // private call stack must be empty + tupleGenerator(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, fr, seed + 0x400), tupleGenerator(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, fr, seed + 0x500), tupleGenerator(MAX_NEW_L2_TO_L1_MSGS_PER_TX, fr, seed + 0x600), tupleGenerator(2, fr, seed + 0x700), // encrypted logs hash @@ -215,23 +217,21 @@ export function makeEmptyAccumulatedData(seed = 1, full = false): CombinedAccumu fr(seed + 0xa00), // unencrypted_log_preimages_length tupleGenerator(MAX_NEW_CONTRACTS_PER_TX, makeNewContractData, seed + 0xb00), tupleGenerator(MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX, makeOptionallyRevealedData, seed + 0xc00), - tupleGenerator(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, makeEmptyPublicDataUpdateRequest, seed + 0xd00), - tupleGenerator(MAX_PUBLIC_DATA_READS_PER_TX, makeEmptyPublicDataRead, seed + 0xe00), + tupleGenerator(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, makePublicDataUpdateRequest, seed + 0xd00), + tupleGenerator(MAX_PUBLIC_DATA_READS_PER_TX, makePublicDataRead, seed + 0xe00), ); } /** - * Creates arbitrary accumulated data. - * @param seed - The seed to use for generating the accumulated data. - * @returns An accumulated data. + * Creates arbitrary final accumulated data. + * @param seed - The seed to use for generating the final accumulated data. + * @returns A final accumulated data. */ -export function makeAccumulatedData(seed = 1, full = false): CombinedAccumulatedData { +export function makeFinalAccumulatedData(seed = 1, full = false): FinalAccumulatedData { const tupleGenerator = full ? makeTuple : makeHalfFullTuple; - return new CombinedAccumulatedData( + return new FinalAccumulatedData( makeAggregationObject(seed), - tupleGenerator(MAX_READ_REQUESTS_PER_TX, fr, seed + 0x80), - tupleGenerator(MAX_READ_REQUESTS_PER_TX, i => makeReadRequestMembershipWitness(i * 123), seed + 0x90), tupleGenerator(MAX_NEW_COMMITMENTS_PER_TX, fr, seed + 0x100), tupleGenerator(MAX_NEW_NULLIFIERS_PER_TX, fr, seed + 0x200), tupleGenerator(MAX_NEW_NULLIFIERS_PER_TX, fr, seed + 0x300), @@ -244,8 +244,6 @@ export function makeAccumulatedData(seed = 1, full = false): CombinedAccumulated fr(seed + 0xa00), // unencrypted_log_preimages_length tupleGenerator(MAX_NEW_CONTRACTS_PER_TX, makeNewContractData, seed + 0xb00), tupleGenerator(MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX, makeOptionallyRevealedData, seed + 0xc00), - tupleGenerator(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, makePublicDataUpdateRequest, seed + 0xd00), - tupleGenerator(MAX_PUBLIC_DATA_READS_PER_TX, makePublicDataRead, seed + 0xe00), ); } @@ -331,21 +329,25 @@ export function makePublicCircuitPublicInputs( } /** - * Creates empty kernel circuit public inputs. + * Creates arbitrary kernel circuit public inputs. * @param seed - The seed to use for generating the kernel circuit public inputs. - * @returns Empty kernel circuit public inputs. + * @returns Kernel circuit public inputs. */ -export function makeEmptyKernelPublicInputs(seed = 1): KernelCircuitPublicInputs { - return new KernelCircuitPublicInputs(makeEmptyAccumulatedData(seed), makeConstantData(seed + 0x100), true); +export function makeKernelPublicInputs(seed = 1, fullAccumulatedData = true): KernelCircuitPublicInputs { + return new KernelCircuitPublicInputs( + makeAccumulatedData(seed, fullAccumulatedData), + makeConstantData(seed + 0x100), + true, + ); } /** - * Creates arbitrary kernel circuit public inputs. - * @param seed - The seed to use for generating the kernel circuit public inputs. - * @returns Kernel circuit public inputs. + * Creates arbitrary final ordering kernel circuit public inputs. + * @param seed - The seed to use for generating the final ordering kernel circuit public inputs. + * @returns Final ordering kernel circuit public inputs. */ -export function makeKernelPublicInputs(seed = 1): KernelCircuitPublicInputs { - return new KernelCircuitPublicInputs(makeAccumulatedData(seed, true), makeConstantData(seed + 0x100), true); +export function makeKernelPublicInputsFinal(seed = 1): KernelCircuitPublicInputsFinal { + return new KernelCircuitPublicInputsFinal(makeFinalAccumulatedData(seed, true), makeConstantData(seed + 0x100), true); } /** @@ -396,6 +398,15 @@ export function makeReadRequestMembershipWitness(start: number): ReadRequestMemb ); } +/** + * Creates empty membership witness where the sibling paths is an array of fields filled with zeros. + * @param start - The start of the membership witness. + * @returns Non-transient empty read request membership witness. + */ +export function makeEmptyReadRequestMembershipWitness(): ReadRequestMembershipWitness { + return new ReadRequestMembershipWitness(new Fr(0), makeTuple(PRIVATE_DATA_TREE_HEIGHT, Fr.zero), false, new Fr(0)); +} + /** * Creates arbitrary/mocked verification key. * @returns A verification key. @@ -430,7 +441,7 @@ export function makePoint(seed = 1): Point { */ export function makePreviousKernelData(seed = 1, kernelPublicInputs?: KernelCircuitPublicInputs): PreviousKernelData { return new PreviousKernelData( - kernelPublicInputs ?? makeKernelPublicInputs(seed), + kernelPublicInputs ?? makeKernelPublicInputs(seed, true), new Proof(Buffer.alloc(16, seed + 0x80)), makeVerificationKey(), 0x42, @@ -548,16 +559,16 @@ export async function makePublicKernelInputs(seed = 1): Promise void, ): Promise { - const kernelCircuitPublicInputs = makeEmptyKernelPublicInputs(seed); + const kernelCircuitPublicInputs = makeKernelPublicInputs(seed, false); const publicKernelInputs = new PublicKernelInputs( makePreviousKernelData(seed, kernelCircuitPublicInputs), await makePublicCallData(seed + 0x1000), diff --git a/yarn-project/p2p/src/service/tx_messages.ts b/yarn-project/p2p/src/service/tx_messages.ts index 33eea14ceaf..f0070f58191 100644 --- a/yarn-project/p2p/src/service/tx_messages.ts +++ b/yarn-project/p2p/src/service/tx_messages.ts @@ -1,4 +1,4 @@ -import { KernelCircuitPublicInputs, MAX_NEW_CONTRACTS_PER_TX, Proof, PublicCallRequest } from '@aztec/circuits.js'; +import { KernelCircuitPublicInputsFinal, MAX_NEW_CONTRACTS_PER_TX, Proof, PublicCallRequest } from '@aztec/circuits.js'; import { Tuple, numToUInt32BE } from '@aztec/foundation/serialize'; import { ExtendedContractData, Tx, TxHash, TxL2Logs } from '@aztec/types'; @@ -186,7 +186,7 @@ export function fromTxMessage(buffer: Buffer): Tx { }; // this is the opposite of the 'toMessage' function // so the first 4 bytes is the complete length, skip it - const publicInputs = toObject(buffer.subarray(4), KernelCircuitPublicInputs); + const publicInputs = toObject(buffer.subarray(4), KernelCircuitPublicInputsFinal); const proof = toObject(publicInputs.remainingData, Proof); const encryptedLogs = toObject(proof.remainingData, TxL2Logs); diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts index fcc9a06e607..27d3653512c 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts @@ -22,7 +22,7 @@ import { computeBlockHashWithGlobals, computeContractLeaf } from '@aztec/circuit import { fr, makeBaseOrMergeRollupPublicInputs, - makeKernelPublicInputs, + makeKernelPublicInputsFinal, makeNewContractData, makeProof, makePublicCallRequest, @@ -169,7 +169,7 @@ describe('sequencer/solo_block_builder', () => { }; const buildMockSimulatorInputs = async () => { - const kernelOutput = makeKernelPublicInputs(); + const kernelOutput = makeKernelPublicInputsFinal(); kernelOutput.constants.blockData = await getHistoricBlockData(expectsDb); const tx = await makeProcessedTx( diff --git a/yarn-project/sequencer-client/src/sequencer/processed_tx.ts b/yarn-project/sequencer-client/src/sequencer/processed_tx.ts index 7c4ce3e64da..c4b4a93ed8d 100644 --- a/yarn-project/sequencer-client/src/sequencer/processed_tx.ts +++ b/yarn-project/sequencer-client/src/sequencer/processed_tx.ts @@ -1,11 +1,22 @@ -import { Fr, HistoricBlockData, KernelCircuitPublicInputs, Proof, makeEmptyProof } from '@aztec/circuits.js'; +import { + CombinedAccumulatedData, + Fr, + HistoricBlockData, + KernelCircuitPublicInputs, + Proof, + makeEmptyProof, +} from '@aztec/circuits.js'; import { Tx, TxHash, TxL2Logs } from '@aztec/types'; /** * Represents a tx that has been processed by the sequencer public processor, * so its kernel circuit public inputs are filled in. */ -export type ProcessedTx = Pick & { +export type ProcessedTx = Pick & { + /** + * Output of the public kernel circuit for this tx. + */ + data: KernelCircuitPublicInputs; /** * Hash of the transaction. */ @@ -61,7 +72,13 @@ export async function makeProcessedTx( ): Promise { return { hash: await tx.getTxHash(), - data: kernelOutput ?? tx.data, + data: + kernelOutput ?? + new KernelCircuitPublicInputs( + CombinedAccumulatedData.fromFinalAccumulatedData(tx.data.end), + tx.data.constants, + tx.data.isPrivate, + ), proof: proof ?? tx.proof, encryptedLogs: tx.encryptedLogs, unencryptedLogs: tx.unencryptedLogs, diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts index 385b926f3e6..efd21627ab2 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts @@ -4,11 +4,13 @@ import { AztecAddress, CallContext, CircuitsWasm, + CombinedAccumulatedData, EthAddress, Fr, FunctionData, GlobalVariables, HistoricBlockData, + KernelCircuitPublicInputs, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, PUBLIC_DATA_TREE_HEIGHT, @@ -20,7 +22,7 @@ import { import { computeCallStackItemHash } from '@aztec/circuits.js/abis'; import { makeAztecAddress, - makeKernelPublicInputs, + makeKernelPublicInputsFinal, makePublicCallRequest, makeSelector, } from '@aztec/circuits.js/factories'; @@ -39,7 +41,6 @@ import { import { MerkleTreeOperations, TreeInfo } from '@aztec/world-state'; import { MockProxy, mock } from 'jest-mock-extended'; -import pick from 'lodash.pick'; import times from 'lodash.times'; import { PublicProver } from '../prover/index.js'; @@ -101,7 +102,18 @@ describe('public_processor', () => { const [processed, failed] = await processor.process([tx]); expect(processed).toEqual([ - { isEmpty: false, hash, ...pick(tx, 'data', 'proof', 'encryptedLogs', 'unencryptedLogs') }, + { + isEmpty: false, + hash, + data: new KernelCircuitPublicInputs( + CombinedAccumulatedData.fromFinalAccumulatedData(tx.data.end), + tx.data.constants, + tx.data.isPrivate, + ), + proof: tx.proof, + encryptedLogs: tx.encryptedLogs, + unencryptedLogs: tx.unencryptedLogs, + }, ]); expect(failed).toEqual([]); }); @@ -151,7 +163,7 @@ describe('public_processor', () => { const callStackItems = await Promise.all(callRequests.map(call => call.toPublicCallStackItem())); const callStackHashes = callStackItems.map(call => computeCallStackItemHash(wasm, call)); - const kernelOutput = makeKernelPublicInputs(0x10); + const kernelOutput = makeKernelPublicInputsFinal(0x10); kernelOutput.end.publicCallStack = padArrayEnd(callStackHashes, Fr.ZERO, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX); kernelOutput.end.privateCallStack = padArrayEnd([], Fr.ZERO, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX); @@ -181,7 +193,7 @@ describe('public_processor', () => { const callStackItem = await callRequest.toPublicCallStackItem(); const callStackHash = computeCallStackItemHash(wasm, callStackItem); - const kernelOutput = makeKernelPublicInputs(0x10); + const kernelOutput = makeKernelPublicInputsFinal(0x10); kernelOutput.end.publicCallStack = padArrayEnd([callStackHash], Fr.ZERO, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX); kernelOutput.end.privateCallStack = padArrayEnd([], Fr.ZERO, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX); diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.ts b/yarn-project/sequencer-client/src/sequencer/public_processor.ts index 8b00cfa592c..ee1b3ea397c 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.ts @@ -9,6 +9,7 @@ import { import { AztecAddress, CircuitsWasm, + CombinedAccumulatedData, ContractStorageRead, ContractStorageUpdateRequest, Fr, @@ -153,7 +154,11 @@ export class PublicProcessor { this.log(`Executing enqueued public calls for tx ${await tx.getTxHash()}`); if (!tx.enqueuedPublicFunctionCalls) throw new Error(`Missing preimages for enqueued public calls`); - let kernelOutput = tx.data; + let kernelOutput = new KernelCircuitPublicInputs( + CombinedAccumulatedData.fromFinalAccumulatedData(tx.data.end), + tx.data.constants, + tx.data.isPrivate, + ); let kernelProof = tx.proof; const newUnencryptedFunctionLogs: FunctionL2Logs[] = []; diff --git a/yarn-project/types/src/mocks.ts b/yarn-project/types/src/mocks.ts index 91065c6a6fe..a3b52f5ad77 100644 --- a/yarn-project/types/src/mocks.ts +++ b/yarn-project/types/src/mocks.ts @@ -5,7 +5,7 @@ import { MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, Proof, } from '@aztec/circuits.js'; -import { makeKernelPublicInputs, makePublicCallRequest } from '@aztec/circuits.js/factories'; +import { makeKernelPublicInputsFinal, makePublicCallRequest } from '@aztec/circuits.js/factories'; import { ContractAbi } from '@aztec/foundation/abi'; import { randomBytes } from '@aztec/foundation/crypto'; import { Tuple } from '@aztec/foundation/serialize'; @@ -25,7 +25,7 @@ export function makeEmptyLogs(): TxL2Logs { export const mockTx = (seed = 1) => { return new Tx( - makeKernelPublicInputs(seed), + makeKernelPublicInputsFinal(seed), new Proof(Buffer.alloc(0)), TxL2Logs.random(8, 3), // 8 priv function invocations creating 3 encrypted logs each TxL2Logs.random(11, 2), // 8 priv + 3 pub function invocations creating 2 unencrypted logs each diff --git a/yarn-project/types/src/tx/tx.ts b/yarn-project/types/src/tx/tx.ts index 8160f76eb02..0a47fbe56f7 100644 --- a/yarn-project/types/src/tx/tx.ts +++ b/yarn-project/types/src/tx/tx.ts @@ -1,5 +1,5 @@ import { - KernelCircuitPublicInputs, + KernelCircuitPublicInputsFinal, MAX_NEW_CONTRACTS_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, Proof, @@ -21,7 +21,7 @@ export class Tx { /** * Output of the private kernel circuit for this tx. */ - public readonly data: KernelCircuitPublicInputs, + public readonly data: KernelCircuitPublicInputsFinal, /** * Proof from the private kernel circuit. */ @@ -73,7 +73,7 @@ export class Tx { static fromBuffer(buffer: Buffer | BufferReader): Tx { const reader = BufferReader.asReader(buffer); return new Tx( - reader.readObject(KernelCircuitPublicInputs), + reader.readObject(KernelCircuitPublicInputsFinal), reader.readObject(Proof), reader.readObject(TxL2Logs), reader.readObject(TxL2Logs), @@ -118,7 +118,7 @@ export class Tx { * @returns A Tx class object. */ public static fromJSON(obj: any) { - const publicInputs = KernelCircuitPublicInputs.fromBuffer(Buffer.from(obj.data, 'hex')); + const publicInputs = KernelCircuitPublicInputsFinal.fromBuffer(Buffer.from(obj.data, 'hex')); const encryptedLogs = TxL2Logs.fromBuffer(Buffer.from(obj.encryptedLogs, 'hex')); const unencryptedLogs = TxL2Logs.fromBuffer(Buffer.from(obj.unencryptedLogs, 'hex')); const proof = Buffer.from(obj.proof, 'hex'); @@ -162,7 +162,7 @@ export class Tx { * @returns The cloned transaction. */ static clone(tx: Tx): Tx { - const publicInputs = KernelCircuitPublicInputs.fromBuffer(tx.data.toBuffer()); + const publicInputs = KernelCircuitPublicInputsFinal.fromBuffer(tx.data.toBuffer()); const proof = Proof.fromBuffer(tx.proof.toBuffer()); const encryptedLogs = TxL2Logs.fromBuffer(tx.encryptedLogs.toBuffer()); const unencryptedLogs = TxL2Logs.fromBuffer(tx.unencryptedLogs.toBuffer());