diff --git a/.circleci/config.yml b/.circleci/config.yml index 534fe6bec59..361d11a9a72 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -483,6 +483,9 @@ workflows: # # Used to generate a dynamic 'system' workflow # # This is rewritten to 'system' on the real workflow (otherwise this is ignored by circleci) # equal: [NEVER, << pipeline.parameters.workflow >>] + when: + and: + - equal: [ master, << pipeline.git.branch >> ] jobs: # Noir - noir-x86_64: *defaults diff --git a/.github/workflows/ci-arm.yml b/.github/workflows/ci-arm.yml index 2828c3d3289..6ddc01acf9a 100644 --- a/.github/workflows/ci-arm.yml +++ b/.github/workflows/ci-arm.yml @@ -1,7 +1,9 @@ name: CI (ARM) on: push: - branches: [disabled] + branches: + - master + - '*/*arm-build' workflow_dispatch: inputs: {} concurrency: @@ -12,7 +14,7 @@ env: DOCKERHUB_PASSWORD: "${{ secrets.DOCKERHUB_PASSWORD }}" RUN_ID: ${{ github.run_id }} RUN_ATTEMPT: ${{ github.run_attempt }} - USERNAME: ${{ github.event.pull_request.user.login || github.actor }} + USERNAME: master GITHUB_TOKEN: ${{ github.token }} GH_SELF_HOSTED_RUNNER_TOKEN: ${{ secrets.GH_SELF_HOSTED_RUNNER_TOKEN }} AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} @@ -31,7 +33,7 @@ jobs: timeout-minutes: 40 uses: ./.github/ensure-builder with: - runner_type: builder-x86 + runner_type: builder-arm run: | set -eux git submodule update --init --recursive --recommend-shallow @@ -46,11 +48,12 @@ jobs: - uses: actions/checkout@v4 with: { ref: "${{ github.event.pull_request.head.sha }}" } - name: "Test" - timeout-minutes: 15 + timeout-minutes: 25 uses: ./.github/ensure-builder with: - runner_type: builder-x86 + runner_type: builder-arm run: | + sudo shutdown -P 25 # hack until core part of the scripts set -eux echo ${{ secrets.DOCKERHUB_PASSWORD }} | docker login -u aztecprotocolci --password-stdin scripts/earthly-ci -P --no-output ./yarn-project/end-to-end/+uniswap-trade-on-l1-from-l2 diff --git a/barretenberg/.gitrepo b/barretenberg/.gitrepo index 99d7eb63fb1..19b56482828 100644 --- a/barretenberg/.gitrepo +++ b/barretenberg/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/barretenberg branch = master - commit = af5ae45393b9dba4c77626c5f9591d53897ae6f2 - parent = 1fa59637a0829208d382d1dded36df33f4d61582 + commit = 89a3cfe088ed6be4e6dbe66870000d3ddc369daf + parent = d1095f60bbd05d35748dc9b0188ad0c5f87390f5 method = merge cmdver = 0.4.6 diff --git a/barretenberg/acir_tests/reset_acir_tests.sh b/barretenberg/acir_tests/reset_acir_tests.sh new file mode 100644 index 00000000000..e83bea9189e --- /dev/null +++ b/barretenberg/acir_tests/reset_acir_tests.sh @@ -0,0 +1,7 @@ +cd ~/aztec-packages/noir/noir-repo +cargo clean +noirup -p . +cd test_programs && ./rebuild.sh + +cd ~/aztec-packages/barretenberg/acir_tests +rm -rf acir_tests diff --git a/barretenberg/cpp/src/barretenberg/benchmark/client_ivc_bench/client_ivc.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/client_ivc_bench/client_ivc.bench.cpp index ded7acc08f1..80d3e326144 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/client_ivc_bench/client_ivc.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/client_ivc_bench/client_ivc.bench.cpp @@ -20,7 +20,6 @@ namespace { class ClientIVCBench : public benchmark::Fixture { public: using Builder = GoblinUltraCircuitBuilder; - using VerifierFoldData = GoblinMockCircuits::VerifierFoldData; // Number of function circuits to accumulate(based on Zacs target numbers) static constexpr size_t NUM_ITERATIONS_MEDIUM_COMPLEXITY = 6; @@ -31,6 +30,36 @@ class ClientIVCBench : public benchmark::Fixture { bb::srs::init_grumpkin_crs_factory("../srs_db/grumpkin"); } + /** + * @brief Compute verification key for each circuit in the IVC based on the number of desired function circuits + * @details Assumes the following circuit ordering: one initial function circuit followed by pairs of {function, + * kernel} until the desired number of function circuits has been reached. + * + * @param ivc + * @param num_function_circuits + */ + static auto precompute_verification_keys(ClientIVC& ivc, const size_t num_function_circuits) + { + // Populate the set of mock function and kernel circuits to be accumulated in the IVC + std::vector circuits; + Builder function_circuit{ ivc.goblin.op_queue }; + GoblinMockCircuits::construct_mock_function_circuit(function_circuit); + circuits.emplace_back(function_circuit); + + for (size_t idx = 1; idx < num_function_circuits; ++idx) { + Builder function_circuit{ ivc.goblin.op_queue }; + GoblinMockCircuits::construct_mock_function_circuit(function_circuit); + circuits.emplace_back(function_circuit); + + Builder kernel_circuit{ ivc.goblin.op_queue }; + GoblinMockCircuits::construct_mock_folding_kernel(kernel_circuit); + circuits.emplace_back(kernel_circuit); + } + + // Compute and return the verfication keys corresponding to this set of circuits + return ivc.precompute_folding_verification_keys(circuits); + } + /** * @brief Perform a specified number of function circuit accumulation rounds * @details Each round "accumulates" a mock function circuit and a mock kernel circuit. Each round thus consists of @@ -40,9 +69,13 @@ class ClientIVCBench : public benchmark::Fixture { * we set the size of the function circuit to be 2^17. The first one should be 2^19 but we can't currently support * folding circuits of unequal size. * + * @param NUM_CIRCUITS Number of function circuits to accumulate */ - static void perform_ivc_accumulation_rounds(State& state, ClientIVC& ivc) + static void perform_ivc_accumulation_rounds(size_t NUM_CIRCUITS, ClientIVC& ivc, auto& precomputed_vks) { + size_t TOTAL_NUM_CIRCUITS = NUM_CIRCUITS * 2 - 1; // need one less kernel than number of function circuits + ASSERT(precomputed_vks.size() == TOTAL_NUM_CIRCUITS); // ensure presence of a precomputed VK for each circuit + const size_t size_hint = 1 << 17; // Size hint for reserving wires/selector vector memory in builders std::vector initial_function_circuits(2); @@ -57,31 +90,21 @@ class ClientIVCBench : public benchmark::Fixture { // Prepend queue to the first circuit initial_function_circuits[0].op_queue->prepend_previous_queue(*ivc.goblin.op_queue); // Initialize ivc - ivc.initialize(initial_function_circuits[0]); + ivc.accumulate(initial_function_circuits[0], precomputed_vks[0]); // Retrieve the queue std::swap(*ivc.goblin.op_queue, *initial_function_circuits[0].op_queue); // Prepend queue to the second circuit initial_function_circuits[1].op_queue->prepend_previous_queue(*ivc.goblin.op_queue); // Accumulate another function circuit - auto function_fold_proof = ivc.accumulate(initial_function_circuits[1]); + ivc.accumulate(initial_function_circuits[1], precomputed_vks[1]); // Retrieve the queue std::swap(*ivc.goblin.op_queue, *initial_function_circuits[1].op_queue); - VerifierFoldData function_fold_output = { function_fold_proof, ivc.vks.func_vk }; // Free memory initial_function_circuits.clear(); - auto NUM_CIRCUITS = static_cast(state.range(0)); - // Subtract two to account for the "initialization" round above i.e. we have already folded two function - // circuits - NUM_CIRCUITS -= 2; - - // The accumulator for kernel uses the function accumulation verification key - auto kernel_verifier_accumulator = std::make_shared(ivc.vks.first_func_vk); - - VerifierFoldData kernel_fold_output; - for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { + for (size_t circuit_idx = 2; circuit_idx < TOTAL_NUM_CIRCUITS - 1; circuit_idx += 2) { Builder kernel_circuit{ size_hint, ivc.goblin.op_queue }; Builder function_circuit{ size_hint }; // Construct function and kernel circuits in parallel @@ -90,18 +113,7 @@ class ClientIVCBench : public benchmark::Fixture { parallel_for(2, [&](size_t workload_idx) { // workload index is 0 for kernel and 1 for function if (workload_idx == 0) { - if (circuit_idx == 0) { - - // Create the first folding kernel which only verifies the accumulation of a - // function circuit - kernel_verifier_accumulator = GoblinMockCircuits::construct_mock_folding_kernel( - kernel_circuit, function_fold_output, {}, kernel_verifier_accumulator); - } else { - // Create kernel circuit containing the recursive folding verification of a function circuit - // and a kernel circuit - kernel_verifier_accumulator = GoblinMockCircuits::construct_mock_folding_kernel( - kernel_circuit, function_fold_output, kernel_fold_output, kernel_verifier_accumulator); - } + GoblinMockCircuits::construct_mock_folding_kernel(kernel_circuit); } else { GoblinMockCircuits::construct_mock_function_circuit(function_circuit); } @@ -110,48 +122,25 @@ class ClientIVCBench : public benchmark::Fixture { // No need to prepend queue, it's the same after last swap // Accumulate kernel circuit - auto kernel_fold_proof = ivc.accumulate(kernel_circuit); - - // First iteration and the following ones differ - if (circuit_idx == 0) { - kernel_fold_output = { kernel_fold_proof, ivc.vks.first_kernel_vk }; - } else { - kernel_fold_output = { kernel_fold_proof, ivc.vks.kernel_vk }; - } + ivc.accumulate(kernel_circuit, precomputed_vks[circuit_idx]); // Prepend queue to function circuit function_circuit.op_queue->prepend_previous_queue(*ivc.goblin.op_queue); // Accumulate function circuit - auto function_fold_proof = ivc.accumulate(function_circuit); - function_fold_output = { function_fold_proof, ivc.vks.func_vk }; + ivc.accumulate(function_circuit, precomputed_vks[circuit_idx + 1]); // Retrieve queue std::swap(*ivc.goblin.op_queue, *function_circuit.op_queue); } - // If we haven't entered the cycle, the kernel proof accumulates just function proofs - if (NUM_CIRCUITS == 0) { - // Create and accumulate the first folding kernel which only verifies the accumulation of a function circuit - Builder kernel_circuit{ size_hint, ivc.goblin.op_queue }; - auto kernel_verifier_accumulator = std::make_shared(ivc.vks.first_func_vk); - { - BB_OP_COUNT_TIME_NAME("construct_circuits"); - kernel_verifier_accumulator = GoblinMockCircuits::construct_mock_folding_kernel( - kernel_circuit, function_fold_output, {}, kernel_verifier_accumulator); - } - auto kernel_fold_proof = ivc.accumulate(kernel_circuit); - kernel_fold_output = { kernel_fold_proof, ivc.vks.first_kernel_vk }; - } else { - Builder kernel_circuit{ size_hint, ivc.goblin.op_queue }; - { - BB_OP_COUNT_TIME_NAME("construct_circuits"); - kernel_verifier_accumulator = GoblinMockCircuits::construct_mock_folding_kernel( - kernel_circuit, function_fold_output, kernel_fold_output, kernel_verifier_accumulator); - } - auto kernel_fold_proof = ivc.accumulate(kernel_circuit); - kernel_fold_output = { kernel_fold_proof, ivc.vks.kernel_vk }; + // Final kernel + Builder kernel_circuit{ size_hint, ivc.goblin.op_queue }; + { + BB_OP_COUNT_TIME_NAME("construct_circuits"); + GoblinMockCircuits::construct_mock_folding_kernel(kernel_circuit); } + ivc.accumulate(kernel_circuit, precomputed_vks.back()); } }; @@ -162,11 +151,14 @@ class ClientIVCBench : public benchmark::Fixture { BENCHMARK_DEFINE_F(ClientIVCBench, Full)(benchmark::State& state) { ClientIVC ivc; - ivc.precompute_folding_verification_keys(); + + auto num_circuits = static_cast(state.range(0)); + auto precomputed_vks = precompute_verification_keys(ivc, num_circuits); + for (auto _ : state) { BB_REPORT_OP_COUNT_IN_BENCH(state); // Perform a specified number of iterations of function/kernel accumulation - perform_ivc_accumulation_rounds(state, ivc); + perform_ivc_accumulation_rounds(num_circuits, ivc, precomputed_vks); // Construct IVC scheme proof (fold, decider, merge, eccvm, translator) ivc.prove(); @@ -181,11 +173,14 @@ BENCHMARK_DEFINE_F(ClientIVCBench, FullStructured)(benchmark::State& state) { ClientIVC ivc; ivc.structured_flag = true; - ivc.precompute_folding_verification_keys(); + + auto num_circuits = static_cast(state.range(0)); + auto precomputed_vks = precompute_verification_keys(ivc, num_circuits); + for (auto _ : state) { BB_REPORT_OP_COUNT_IN_BENCH(state); // Perform a specified number of iterations of function/kernel accumulation - perform_ivc_accumulation_rounds(state, ivc); + perform_ivc_accumulation_rounds(num_circuits, ivc, precomputed_vks); // Construct IVC scheme proof (fold, decider, merge, eccvm, translator) ivc.prove(); @@ -199,11 +194,14 @@ BENCHMARK_DEFINE_F(ClientIVCBench, FullStructured)(benchmark::State& state) BENCHMARK_DEFINE_F(ClientIVCBench, Accumulate)(benchmark::State& state) { ClientIVC ivc; - ivc.precompute_folding_verification_keys(); + + auto num_circuits = static_cast(state.range(0)); + auto precomputed_vks = precompute_verification_keys(ivc, num_circuits); + // Perform a specified number of iterations of function/kernel accumulation for (auto _ : state) { BB_REPORT_OP_COUNT_IN_BENCH(state); - perform_ivc_accumulation_rounds(state, ivc); + perform_ivc_accumulation_rounds(num_circuits, ivc, precomputed_vks); } } @@ -214,8 +212,12 @@ BENCHMARK_DEFINE_F(ClientIVCBench, Accumulate)(benchmark::State& state) BENCHMARK_DEFINE_F(ClientIVCBench, Decide)(benchmark::State& state) { ClientIVC ivc; + + auto num_circuits = static_cast(state.range(0)); + auto precomputed_vks = precompute_verification_keys(ivc, num_circuits); + // Perform a specified number of iterations of function/kernel accumulation - perform_ivc_accumulation_rounds(state, ivc); + perform_ivc_accumulation_rounds(num_circuits, ivc, precomputed_vks); // Construct eccvm proof, measure only translator proof construction for (auto _ : state) { @@ -232,8 +234,11 @@ BENCHMARK_DEFINE_F(ClientIVCBench, ECCVM)(benchmark::State& state) { ClientIVC ivc; + auto num_circuits = static_cast(state.range(0)); + auto precomputed_vks = precompute_verification_keys(ivc, num_circuits); + // Perform a specified number of iterations of function/kernel accumulation - perform_ivc_accumulation_rounds(state, ivc); + perform_ivc_accumulation_rounds(num_circuits, ivc, precomputed_vks); // Construct and measure eccvm only for (auto _ : state) { @@ -249,10 +254,15 @@ BENCHMARK_DEFINE_F(ClientIVCBench, ECCVM)(benchmark::State& state) BENCHMARK_DEFINE_F(ClientIVCBench, Translator)(benchmark::State& state) { ClientIVC ivc; - ivc.precompute_folding_verification_keys(); + auto num_circuits = static_cast(state.range(0)); + auto precomputed_vks = precompute_verification_keys(ivc, num_circuits); + + // Perform a specified number of iterations of function/kernel accumulation + perform_ivc_accumulation_rounds(num_circuits, ivc, precomputed_vks); + BB_REPORT_OP_COUNT_IN_BENCH(state); // Perform a specified number of iterations of function/kernel accumulation - perform_ivc_accumulation_rounds(state, ivc); + perform_ivc_accumulation_rounds(num_circuits, ivc, precomputed_vks); // Construct eccvm proof, measure only translator proof construction ivc.goblin.prove_eccvm(); diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp index 758a313658b..71b2ef0f9dd 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp @@ -2,32 +2,48 @@ namespace bb { -/** - * @brief Initialize the IVC with a first circuit - * @details Initializes the accumulator and performs the initial goblin merge - * - * @param circuit - */ -void ClientIVC::initialize(ClientCircuit& circuit) -{ - goblin.merge(circuit); // Construct new merge proof - prover_fold_output.accumulator = std::make_shared(circuit, structured_flag); -} - /** * @brief Accumulate a circuit into the IVC scheme - * @details Performs goblin merge, generates circuit instance, folds into accumulator and constructs a folding proof + * @details If this is the first circuit being accumulated, initialize the prover and verifier accumulators. Otherwise, + * fold the instance for the provided circuit into the accumulator. If a previous fold proof exists, a recursive folding + * verification is appended to the provided circuit prior to its accumulation. Similarly, if a merge proof exists, a + * recursive merge verifier is appended. * * @param circuit Circuit to be accumulated/folded - * @return FoldProof + * @param precomputed_vk Optional precomputed VK (otherwise will be computed herein) */ -ClientIVC::FoldProof ClientIVC::accumulate(ClientCircuit& circuit) +void ClientIVC::accumulate(ClientCircuit& circuit, const std::shared_ptr& precomputed_vk) { - goblin.merge(circuit); // Add recursive merge verifier and construct new merge proof + // If a previous fold proof exists, add a recursive folding verification to the circuit + if (!fold_output.proof.empty()) { + BB_OP_COUNT_TIME_NAME("construct_circuits"); + FoldingRecursiveVerifier verifier{ &circuit, verifier_accumulator, { instance_vk } }; + auto verifier_accum = verifier.verify_folding_proof(fold_output.proof); + verifier_accumulator = std::make_shared(verifier_accum->get_value()); + } + + // Construct a merge proof (and add a recursive merge verifier to the circuit if a previous merge proof exists) + goblin.merge(circuit); + + // Construct the prover instance for circuit prover_instance = std::make_shared(circuit, structured_flag); - FoldingProver folding_prover({ prover_fold_output.accumulator, prover_instance }); - prover_fold_output = folding_prover.fold_instances(); - return prover_fold_output.folding_data; + + // Set the instance verification key from precomputed if available, else compute it + if (precomputed_vk) { + instance_vk = precomputed_vk; + } else { + instance_vk = std::make_shared(prover_instance->proving_key); + } + + // If the IVC is uninitialized, simply initialize the prover and verifier accumulator instances + if (!initialized) { + fold_output.accumulator = prover_instance; + verifier_accumulator = std::make_shared(instance_vk); + initialized = true; + } else { // Otherwise, fold the new instance into the accumulator + FoldingProver folding_prover({ fold_output.accumulator, prover_instance }); + fold_output = folding_prover.fold_instances(); + } } /** @@ -37,7 +53,7 @@ ClientIVC::FoldProof ClientIVC::accumulate(ClientCircuit& circuit) */ ClientIVC::Proof ClientIVC::prove() { - return { prover_fold_output.folding_data, decider_prove(), goblin.prove() }; + return { fold_output.proof, decider_prove(), goblin.prove() }; } /** @@ -46,7 +62,7 @@ ClientIVC::Proof ClientIVC::prove() * @param proof * @return bool */ -bool ClientIVC::verify(Proof& proof, const std::vector& verifier_instances) +bool ClientIVC::verify(Proof& proof, const std::vector>& verifier_instances) { // Goblin verification (merge, eccvm, translator) bool goblin_verified = goblin.verify(proof.goblin_proof); @@ -67,63 +83,38 @@ bool ClientIVC::verify(Proof& proof, const std::vector& ver */ HonkProof ClientIVC::decider_prove() const { - GoblinUltraDeciderProver decider_prover(prover_fold_output.accumulator); + GoblinUltraDeciderProver decider_prover(fold_output.accumulator); return decider_prover.construct_proof(); } /** - * @brief Precompute the array of verification keys by simulating folding. There will be 4 different verification keys: - * initial function verification key (without recursive merge verifier), subsequent function verification key (with - * recursive merge verifier), initial kernel verification key (with recursive merge verifier appended, no previous - * kernel to fold), "full" kernel verification key( two recursive folding verifiers and merge verifier). + * @brief Given a set of circuits, compute the verification keys that will be required by the IVC scheme + * @details The verification keys computed here are in general not the same as the verification keys for the + * raw input circuits because recursive verifier circuits (merge and/or folding) may be appended to the incoming + * circuits as part accumulation. + * @note This method exists for convenience and is not not meant to be used in practice for IVC. Given a set of + * circuits, it could be run once and for all to compute then save the required VKs. It also provides a convenient + * (albeit innefficient) way of separating out the cost of computing VKs from a benchmark. * - * TODO(https://github.com/AztecProtocol/barretenberg/issues/904): This function should ultimately be moved outside of - * this class since it's used only for testing and benchmarking purposes and it requires us to clear state afterwards. - * (e.g. in the Goblin object) + * @param circuits A copy of the circuits to be accumulated (passing by reference would alter the original circuits) + * @return std::vector> */ -void ClientIVC::precompute_folding_verification_keys() +std::vector> ClientIVC::precompute_folding_verification_keys( + std::vector circuits) { - using VerifierInstance = VerifierInstance_; - using VerificationKey = Flavor::VerificationKey; - - ClientCircuit initial_function_circuit{ goblin.op_queue }; - GoblinMockCircuits::construct_mock_function_circuit(initial_function_circuit); - - // Initialise both the first prover and verifier accumulator from the inital function circuit - initialize(initial_function_circuit); - vks.first_func_vk = std::make_shared(prover_fold_output.accumulator->proving_key); - auto initial_verifier_acc = std::make_shared(vks.first_func_vk); - - // Accumulate the next function circuit - ClientCircuit function_circuit{ goblin.op_queue }; - GoblinMockCircuits::construct_mock_function_circuit(function_circuit); - auto function_fold_proof = accumulate(function_circuit); - - // Create its verification key (we have called accumulate so it includes the recursive merge verifier) - vks.func_vk = std::make_shared(prover_instance->proving_key); - - // Create the initial kernel iteration and precompute its verification key - ClientCircuit kernel_circuit{ goblin.op_queue }; - auto kernel_acc = GoblinMockCircuits::construct_mock_folding_kernel( - kernel_circuit, { function_fold_proof, vks.func_vk }, {}, initial_verifier_acc); - auto kernel_fold_proof = accumulate(kernel_circuit); - vks.first_kernel_vk = std::make_shared(prover_instance->proving_key); - - // Create another mock function circuit to run the full kernel - function_circuit = ClientCircuit{ goblin.op_queue }; - GoblinMockCircuits::construct_mock_function_circuit(function_circuit); - function_fold_proof = accumulate(function_circuit); - - // Create the full kernel circuit and compute verification key - kernel_circuit = GoblinUltraCircuitBuilder{ goblin.op_queue }; - kernel_acc = GoblinMockCircuits::construct_mock_folding_kernel( - kernel_circuit, { function_fold_proof, vks.func_vk }, { kernel_fold_proof, vks.first_kernel_vk }, kernel_acc); - kernel_fold_proof = accumulate(kernel_circuit); - - vks.kernel_vk = std::make_shared(prover_instance->proving_key); - - // Clean the Goblin state (reinitialise op_queue with mocking and clear merge proofs) - goblin = Goblin(); + std::vector> vkeys; + + for (auto& circuit : circuits) { + accumulate(circuit); + vkeys.emplace_back(instance_vk); + } + + // Reset the scheme so it can be reused for actual accumulation, maintaining the structured trace flag as is + bool structured = structured_flag; + *this = ClientIVC(); + this->structured_flag = structured; + + return vkeys; } } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp index eafc0f72aef..d44b02f6740 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp @@ -23,8 +23,6 @@ class ClientIVC { using VerificationKey = Flavor::VerificationKey; using FF = Flavor::FF; using FoldProof = std::vector; - using ProverAccumulator = std::shared_ptr>; - using VerifierAccumulator = std::shared_ptr>; using ProverInstance = ProverInstance_; using VerifierInstance = VerifierInstance_; using ClientCircuit = GoblinUltraCircuitBuilder; // can only be GoblinUltra @@ -35,6 +33,11 @@ class ClientIVC { using VerifierInstances = VerifierInstances_; using FoldingVerifier = ProtoGalaxyVerifier_; + using GURecursiveFlavor = GoblinUltraRecursiveFlavor_; + using RecursiveVerifierInstances = bb::stdlib::recursion::honk::RecursiveVerifierInstances_; + using FoldingRecursiveVerifier = + bb::stdlib::recursion::honk::ProtoGalaxyRecursiveVerifier_; + // A full proof for the IVC scheme struct Proof { FoldProof folding_proof; // final fold proof @@ -57,13 +60,6 @@ class ClientIVC { } }; - struct PrecomputedVerificationKeys { - std::shared_ptr first_func_vk; - std::shared_ptr func_vk; - std::shared_ptr first_kernel_vk; - std::shared_ptr kernel_vk; - }; - private: using ProverFoldOutput = FoldingResult; // Note: We need to save the last instance that was folded in order to compute its verification key, this will not @@ -71,28 +67,28 @@ class ClientIVC { public: Goblin goblin; - ProverFoldOutput prover_fold_output; - ProverAccumulator prover_accumulator; - PrecomputedVerificationKeys vks; + ProverFoldOutput fold_output; + std::shared_ptr prover_accumulator; + std::shared_ptr verifier_accumulator; // Note: We need to save the last instance that was folded in order to compute its verification key, this will not // be needed in the real IVC as they are provided as inputs std::shared_ptr prover_instance; + std::shared_ptr instance_vk; // A flag indicating whether or not to construct a structured trace in the ProverInstance bool structured_flag = false; - void initialize(ClientCircuit& circuit); + // A flag indicating whether the IVC has been initialized with an initial instance + bool initialized = false; - FoldProof accumulate(ClientCircuit& circuit); + void accumulate(ClientCircuit& circuit, const std::shared_ptr& precomputed_vk = nullptr); Proof prove(); - bool verify(Proof& proof, const std::vector& verifier_instances); + bool verify(Proof& proof, const std::vector>& verifier_instances); HonkProof decider_prove() const; - void decider_prove_and_verify(const VerifierAccumulator&) const; - - void precompute_folding_verification_keys(); + std::vector> precompute_folding_verification_keys(std::vector); }; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp index 0dd189112b8..6a1676c4883 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp @@ -17,18 +17,11 @@ class ClientIVCTests : public ::testing::Test { using Flavor = ClientIVC::Flavor; using FF = typename Flavor::FF; + using VerificationKey = Flavor::VerificationKey; using Builder = ClientIVC::ClientCircuit; - using ProverAccumulator = ClientIVC::ProverAccumulator; - using VerifierAccumulator = ClientIVC::VerifierAccumulator; + using ProverInstance = ClientIVC::ProverInstance; using VerifierInstance = ClientIVC::VerifierInstance; using FoldProof = ClientIVC::FoldProof; - using VerifierFoldData = GoblinMockCircuits::VerifierFoldData; - using GURecursiveFlavor = GoblinUltraRecursiveFlavor_; - using RecursiveVerifierInstance = ::bb::stdlib::recursion::honk::RecursiveVerifierInstance_; - using RecursiveVerifierAccumulator = std::shared_ptr; - using RecursiveVerifierInstances = ::bb::stdlib::recursion::honk::RecursiveVerifierInstances_; - using FoldingRecursiveVerifier = - bb::stdlib::recursion::honk::ProtoGalaxyRecursiveVerifier_; using DeciderProver = ClientIVC::DeciderProver; using DeciderVerifier = ClientIVC::DeciderVerifier; using ProverInstances = ProverInstances_; @@ -36,6 +29,20 @@ class ClientIVCTests : public ::testing::Test { using VerifierInstances = VerifierInstances_; using FoldingVerifier = ProtoGalaxyVerifier_; + /** + * @brief Prove and verify the IVC scheme + * @details Constructs four proofs: merge, eccvm, translator, decider; Verifies these four plus the final folding + * proof constructed on the last accumulation round + * + */ + static bool prove_and_verify(ClientIVC& ivc) + { + auto proof = ivc.prove(); + + auto verifier_inst = std::make_shared(ivc.instance_vk); + return ivc.verify(proof, { ivc.verifier_accumulator, verifier_inst }); + } + /** * @brief Construct mock circuit with arithmetic gates and goblin ops * @details Currently default sized to 2^16 to match kernel. (Note: dummy op gates added to avoid non-zero @@ -55,111 +62,153 @@ class ClientIVCTests : public ::testing::Test { MockCircuits::construct_goblin_ecc_op_circuit(circuit); return circuit; } +}; - /** - * @brief Construct mock kernel consisting of two recursive folding verifiers to verify the folding of the previous - * function circuit and kernel circuit. - * - * @param builder - * @param func_accum contains the folding proof for the function circuit and the corresponsing function - * verifier instance - * @param kernel_accum contains the folding proof for the kernel circuit and the corresponding kernel verifier - * instance - * @returns the updated verifier accumulator - */ - static VerifierAccumulator construct_mock_folding_kernel(Builder& builder, - VerifierFoldData& func_accum, - VerifierFoldData& kernel_accum, - VerifierAccumulator& prev_kernel_accum) - { +/** + * @brief A simple-as-possible test demonstrating IVC for two mock circuits + * + */ +TEST_F(ClientIVCTests, Basic) +{ + ClientIVC ivc; + + // Initialize the IVC with an arbitrary circuit + Builder circuit_0 = create_mock_circuit(ivc); + ivc.accumulate(circuit_0); - FoldingRecursiveVerifier verifier_1{ &builder, prev_kernel_accum, { func_accum.inst_vk } }; - auto fctn_verifier_accum = verifier_1.verify_folding_proof(func_accum.fold_proof); - auto native_acc = std::make_shared(fctn_verifier_accum->get_value()); - FoldingRecursiveVerifier verifier_2{ &builder, native_acc, { kernel_accum.inst_vk } }; - auto kernel_verifier_accum = verifier_2.verify_folding_proof(kernel_accum.fold_proof); - return std::make_shared(kernel_verifier_accum->get_value()); + // Create another circuit and accumulate + Builder circuit_1 = create_mock_circuit(ivc); + ivc.accumulate(circuit_1); + + EXPECT_TRUE(prove_and_verify(ivc)); +}; + +/** + * @brief Check that the IVC fails to verify if an intermediate fold proof is invalid + * + */ +TEST_F(ClientIVCTests, BasicFailure) +{ + ClientIVC ivc; + + // Initialize the IVC with an arbitrary circuit + Builder circuit_0 = create_mock_circuit(ivc); + ivc.accumulate(circuit_0); + + // Create another circuit and accumulate + Builder circuit_1 = create_mock_circuit(ivc); + ivc.accumulate(circuit_1); + + // Tamper with the fold proof just created in the last accumulation step + for (auto& val : ivc.fold_output.proof) { + if (val > 0) { // tamper by finding the first non-zero value and incrementing it by 1 + val += 1; + break; + } } - /** - * @brief Perform native fold verification and run decider prover/verifier - * - */ - static VerifierAccumulator update_accumulator_and_decide_native( - const ProverAccumulator& prover_accumulator, - const FoldProof& fold_proof, - const VerifierAccumulator& prev_verifier_accumulator, - const std::shared_ptr& verifier_inst_vk) - { - // Verify fold proof - auto new_verifier_inst = std::make_shared(verifier_inst_vk); - FoldingVerifier folding_verifier({ prev_verifier_accumulator, new_verifier_inst }); - auto verifier_accumulator = folding_verifier.verify_folding_proof(fold_proof); - - // Run decider - DeciderProver decider_prover(prover_accumulator); - DeciderVerifier decider_verifier(verifier_accumulator); - auto decider_proof = decider_prover.construct_proof(); - bool decision = decider_verifier.verify_proof(decider_proof); - EXPECT_TRUE(decision); - - return verifier_accumulator; + // Accumulate another circuit; this involves recursive folding verification of the bad proof + Builder circuit_2 = create_mock_circuit(ivc); + ivc.accumulate(circuit_2); + + // The bad fold proof should result in an invalid witness in the final circuit and the IVC should fail to verify + EXPECT_FALSE(prove_and_verify(ivc)); +}; + +/** + * @brief Prove and verify accumulation of an arbitrary set of circuits + * + */ +TEST_F(ClientIVCTests, BasicLarge) +{ + ClientIVC ivc; + + // Construct a set of arbitrary circuits + size_t NUM_CIRCUITS = 5; + std::vector circuits; + for (size_t idx = 0; idx < NUM_CIRCUITS; ++idx) { + circuits.emplace_back(create_mock_circuit(ivc)); + } + + // Accumulate each circuit + for (auto& circuit : circuits) { + ivc.accumulate(circuit); } + + EXPECT_TRUE(prove_and_verify(ivc)); }; /** - * @brief A full Goblin test using PG that mimicks the basic aztec client architecture + * @brief Using a structured trace allows for the accumulation of circuits of varying size * */ -// TODO fix with https://github.com/AztecProtocol/barretenberg/issues/930 -// intermittent failures, presumably due to uninitialized memory -TEST_F(ClientIVCTests, DISABLED_Full) +TEST_F(ClientIVCTests, BasicStructured) { - using VerificationKey = Flavor::VerificationKey; + ClientIVC ivc; + ivc.structured_flag = true; + + // Construct some circuits of varying size + Builder circuit_0 = create_mock_circuit(ivc, /*log2_num_gates=*/5); + Builder circuit_1 = create_mock_circuit(ivc, /*log2_num_gates=*/10); + Builder circuit_2 = create_mock_circuit(ivc, /*log2_num_gates=*/15); + + // The circuits can be accumulated as normal due to the structured trace + ivc.accumulate(circuit_0); + ivc.accumulate(circuit_1); + ivc.accumulate(circuit_2); + + EXPECT_TRUE(prove_and_verify(ivc)); +}; +/** + * @brief Prove and verify accumulation of an arbitrary set of circuits using precomputed verification keys + * + */ +TEST_F(ClientIVCTests, PrecomputedVerificationKeys) +{ ClientIVC ivc; - // Initialize IVC with function circuit - Builder function_circuit = create_mock_circuit(ivc); - ivc.initialize(function_circuit); - - auto function_vk = std::make_shared(ivc.prover_fold_output.accumulator->proving_key); - auto foo_verifier_instance = std::make_shared(function_vk); - // Accumulate kernel circuit (first kernel mocked as simple circuit since no folding proofs yet) - Builder kernel_circuit = create_mock_circuit(ivc); - FoldProof kernel_fold_proof = ivc.accumulate(kernel_circuit); - // This will have a different verification key because we added the recursive merge verification to the circuit - auto function_vk_with_merge = std::make_shared(ivc.prover_instance->proving_key); - auto kernel_vk = function_vk_with_merge; - auto intermediary_acc = update_accumulator_and_decide_native( - ivc.prover_fold_output.accumulator, kernel_fold_proof, foo_verifier_instance, kernel_vk); - - VerifierFoldData kernel_fold_output = { kernel_fold_proof, function_vk_with_merge }; - size_t NUM_CIRCUITS = 1; - for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { - // Accumulate function circuit - Builder function_circuit = create_mock_circuit(ivc); - FoldProof function_fold_proof = ivc.accumulate(function_circuit); - - intermediary_acc = update_accumulator_and_decide_native( - ivc.prover_fold_output.accumulator, function_fold_proof, intermediary_acc, function_vk_with_merge); - - VerifierFoldData function_fold_output = { function_fold_proof, function_vk_with_merge }; - // Accumulate kernel circuit - Builder kernel_circuit{ ivc.goblin.op_queue }; - foo_verifier_instance = construct_mock_folding_kernel( - kernel_circuit, kernel_fold_output, function_fold_output, foo_verifier_instance); - FoldProof kernel_fold_proof = ivc.accumulate(kernel_circuit); - kernel_vk = std::make_shared(ivc.prover_instance->proving_key); - - intermediary_acc = update_accumulator_and_decide_native( - ivc.prover_fold_output.accumulator, kernel_fold_proof, intermediary_acc, kernel_vk); - - VerifierFoldData kernel_fold_output = { kernel_fold_proof, kernel_vk }; + + // Construct a set of arbitrary circuits + size_t NUM_CIRCUITS = 3; + std::vector circuits; + for (size_t idx = 0; idx < NUM_CIRCUITS; ++idx) { + circuits.emplace_back(create_mock_circuit(ivc)); + } + + // Precompute the verification keys that will be needed for the IVC + auto precomputed_vkeys = ivc.precompute_folding_verification_keys(circuits); + + // Accumulate each circuit using the precomputed VKs + for (auto [circuit, precomputed_vk] : zip_view(circuits, precomputed_vkeys)) { + ivc.accumulate(circuit, precomputed_vk); + } + + EXPECT_TRUE(prove_and_verify(ivc)); +}; + +/** + * @brief Perform accumulation with a structured trace and precomputed verification keys + * + */ +TEST_F(ClientIVCTests, StructuredPrecomputedVKs) +{ + ClientIVC ivc; + ivc.structured_flag = true; + + // Construct a set of arbitrary circuits + size_t NUM_CIRCUITS = 3; + std::vector circuits; + for (size_t idx = 0; idx < NUM_CIRCUITS; ++idx) { + circuits.emplace_back(create_mock_circuit(ivc)); } - // Constuct four proofs: merge, eccvm, translator, decider - auto proof = ivc.prove(); - auto inst = std::make_shared(kernel_vk); - // Verify all four proofs - EXPECT_TRUE(ivc.verify(proof, { foo_verifier_instance, inst })); -}; \ No newline at end of file + // Precompute the (structured) verification keys that will be needed for the IVC + auto precomputed_vkeys = ivc.precompute_folding_verification_keys(circuits); + + // Accumulate each circuit + for (auto [circuit, precomputed_vk] : zip_view(circuits, precomputed_vkeys)) { + ivc.accumulate(circuit, precomputed_vk); + } + + EXPECT_TRUE(prove_and_verify(ivc)); +}; diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/mock_kernel_pinning.test.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/mock_kernel_pinning.test.cpp index d4d06758e2f..bb11e2cc670 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/mock_kernel_pinning.test.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/mock_kernel_pinning.test.cpp @@ -12,6 +12,9 @@ using namespace bb; * */ class MockKernelTest : public ::testing::Test { + public: + using Builder = GoblinUltraCircuitBuilder; + protected: static void SetUpTestSuite() { srs::init_crs_factory("../srs_db/ignition"); } }; @@ -19,38 +22,20 @@ class MockKernelTest : public ::testing::Test { TEST_F(MockKernelTest, PinFoldingKernelSizes) { ClientIVC ivc; - ivc.precompute_folding_verification_keys(); - // Accumulate three circuits to generate two folding proofs for input to folding kernel - GoblinUltraCircuitBuilder circuit_1{ ivc.goblin.op_queue }; - GoblinMockCircuits::construct_mock_function_circuit(circuit_1); - ivc.initialize(circuit_1); - auto kernel_acc = std::make_shared(ivc.vks.first_func_vk); - kernel_acc->verification_key = ivc.vks.first_func_vk; - EXPECT_EQ(ivc.prover_instance->proving_key.log_circuit_size, 17); - GoblinUltraCircuitBuilder circuit_2{ ivc.goblin.op_queue }; - GoblinMockCircuits::construct_mock_function_circuit(circuit_2); - auto func_fold_proof = ivc.accumulate(circuit_2); - EXPECT_EQ(ivc.prover_instance->proving_key.log_circuit_size, 17); + // Construct two function circuits and a kernel circuit + Builder circuit_1{ ivc.goblin.op_queue }; + Builder circuit_2{ ivc.goblin.op_queue }; + Builder kernel_circuit{ ivc.goblin.op_queue }; - // Construct kernel circuit - GoblinUltraCircuitBuilder kernel_circuit{ ivc.goblin.op_queue }; - kernel_acc = GoblinMockCircuits::construct_mock_folding_kernel( - kernel_circuit, { func_fold_proof, ivc.vks.func_vk }, {}, kernel_acc); + GoblinMockCircuits::construct_mock_function_circuit(circuit_1); + GoblinMockCircuits::construct_mock_function_circuit(circuit_2); + GoblinMockCircuits::construct_mock_folding_kernel(kernel_circuit); - auto kernel_fold_proof = ivc.accumulate(kernel_circuit); - EXPECT_EQ(ivc.prover_instance->proving_key.log_circuit_size, 17); + // Accumulate all three; The kernel will contain a single recursive folding verifier + ivc.accumulate(circuit_1); + ivc.accumulate(circuit_2); + ivc.accumulate(kernel_circuit); - GoblinUltraCircuitBuilder circuit_3{ ivc.goblin.op_queue }; - GoblinMockCircuits::construct_mock_function_circuit(circuit_3); - func_fold_proof = ivc.accumulate(circuit_3); EXPECT_EQ(ivc.prover_instance->proving_key.log_circuit_size, 17); - - kernel_circuit = GoblinUltraCircuitBuilder{ ivc.goblin.op_queue }; - kernel_acc = GoblinMockCircuits::construct_mock_folding_kernel(kernel_circuit, - { kernel_fold_proof, ivc.vks.first_kernel_vk }, - { func_fold_proof, ivc.vks.func_vk }, - kernel_acc); - auto instance = std::make_shared(kernel_circuit); - EXPECT_EQ(instance->proving_key.log_circuit_size, 17); } \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp index f74228a115f..3dc7fc15e6c 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp @@ -10,7 +10,10 @@ template class DSLBigInts; template class DSLBigInts; template -void build_constraints(Builder& builder, AcirFormat const& constraint_system, bool has_valid_witness_assignments) +void build_constraints(Builder& builder, + AcirFormat const& constraint_system, + bool has_valid_witness_assignments, + bool honk_recursion) { // Add arithmetic gates for (const auto& constraint : constraint_system.poly_triple_constraints) { @@ -118,6 +121,7 @@ void build_constraints(Builder& builder, AcirFormat const& constraint_system, bo create_bigint_to_le_bytes_constraint(builder, constraint, dsl_bigints); } + // RecursionConstraint // TODO(https://github.com/AztecProtocol/barretenberg/issues/817): disable these for UGH for now since we're not yet // dealing with proper recursion if constexpr (IsGoblinUltraBuilder) { @@ -161,7 +165,7 @@ void build_constraints(Builder& builder, AcirFormat const& constraint_system, bo auto error_string = format( "Public inputs are always stripped from proofs unless we have a recursive proof.\n" "Thus, public inputs attached to a proof must match the recursive aggregation object in size " - "which is {}\n", + "which is ", RecursionConstraint::AGGREGATION_OBJECT_SIZE); throw_or_abort(error_string); } @@ -206,6 +210,121 @@ void build_constraints(Builder& builder, AcirFormat const& constraint_system, bo builder.set_recursive_proof(proof_output_witness_indices); } } + + // HonkRecursionConstraint + // TODO(https://github.com/AztecProtocol/barretenberg/issues/817): disable these for UGH for now since we're not yet + // dealing with proper recursion + if constexpr (IsGoblinUltraBuilder) { + if (!constraint_system.honk_recursion_constraints.empty()) { + info("WARNING: this circuit contains honk_recursion_constraints!"); + } + } else { + // These are set and modified whenever we encounter a recursion opcode + // + // These should not be set by the caller + // TODO(maxim): Check if this is always the case. ie I won't receive a proof that will set the first + // TODO(maxim): input_aggregation_object to be non-zero. + // TODO(maxim): if not, we can add input_aggregation_object to the proof too for all recursive proofs + // TODO(maxim): This might be the case for proof trees where the proofs are created on different machines + std::array current_aggregation_object = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + // Get the size of proof with no public inputs prepended to it + // This is used while processing recursion constraints to determine whether + // the proof we are verifying contains a recursive proof itself + auto proof_size_no_pub_inputs = recursion_honk_proof_size_without_public_inputs(); + + // Add recursion constraints + for (auto constraint : constraint_system.honk_recursion_constraints) { + // A proof passed into the constraint should be stripped of its public inputs, except in the case where a + // proof contains an aggregation object itself. We refer to this as the `nested_aggregation_object`. The + // verifier circuit requires that the indices to a nested proof aggregation state are a circuit constant. + // The user tells us they how they want these constants set by keeping the nested aggregation object + // attached to the proof as public inputs. As this is the only object that can prepended to the proof if the + // proof is above the expected size (with public inputs stripped) + std::array nested_aggregation_object = {}; + // If the proof has public inputs attached to it, we should handle setting the nested aggregation object + // The public inputs attached to a proof should match the aggregation object in size + if (constraint.proof.size() - proof_size_no_pub_inputs != + HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE) { + auto error_string = format( + "Public inputs are always stripped from proofs unless we have a recursive proof.\n" + "Thus, public inputs attached to a proof must match the recursive aggregation object in size " + "which is ", + HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE); + throw_or_abort(error_string); + } + for (size_t i = 0; i < HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE; ++i) { + // Set the nested aggregation object indices to the current size of the public inputs + // This way we know that the nested aggregation object indices will always be the last + // indices of the public inputs + nested_aggregation_object[i] = static_cast(constraint.public_inputs.size()); + // Attach the nested aggregation object to the end of the public inputs to fill in + // the slot where the nested aggregation object index will point into + constraint.public_inputs.emplace_back(constraint.proof[i]); + } + // Remove the aggregation object so that they can be handled as normal public inputs + // in they way taht the recursion constraint expects + constraint.proof.erase(constraint.proof.begin(), + constraint.proof.begin() + + static_cast(HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE)); + current_aggregation_object = create_honk_recursion_constraints(builder, + constraint, + current_aggregation_object, + nested_aggregation_object, + has_valid_witness_assignments); + } + + // Now that the circuit has been completely built, we add the output aggregation as public + // inputs. + if (!constraint_system.honk_recursion_constraints.empty()) { + + // First add the output aggregation object as public inputs + // Set the indices as public inputs because they are no longer being + // created in ACIR + for (const auto& idx : current_aggregation_object) { + builder.set_public_input(idx); + } + + // Make sure the verification key records the public input indices of the + // final recursion output. + std::vector proof_output_witness_indices(current_aggregation_object.begin(), + current_aggregation_object.end()); + builder.set_recursive_proof(proof_output_witness_indices); + } else if (honk_recursion && + builder.is_recursive_circuit) { // Set a default aggregation object if we don't have one. + // TODO(https://github.com/AztecProtocol/barretenberg/issues/911): These are pairing points extracted from + // a valid proof. This is a workaround because we can't represent the point at infinity in biggroup yet. + fq x0("0x031e97a575e9d05a107acb64952ecab75c020998797da7842ab5d6d1986846cf"); + fq y0("0x178cbf4206471d722669117f9758a4c410db10a01750aebb5666547acf8bd5a4"); + + fq x1("0x0f94656a2ca489889939f81e9c74027fd51009034b3357f0e91b8a11e7842c38"); + fq y1("0x1b52c2020d7464a0c80c0da527a08193fe27776f50224bd6fb128b46c1ddb67f"); + std::vector aggregation_object_fq_values = { x0, y0, x1, y1 }; + size_t agg_obj_indices_idx = 0; + for (fq val : aggregation_object_fq_values) { + const uint256_t x = val; + std::array val_limbs = { + x.slice(0, fq_ct::NUM_LIMB_BITS), + x.slice(fq_ct::NUM_LIMB_BITS, fq_ct::NUM_LIMB_BITS * 2), + x.slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 3), + x.slice(fq_ct::NUM_LIMB_BITS * 3, bb::stdlib::field_conversion::TOTAL_BITS) + }; + for (size_t i = 0; i < fq_ct::NUM_LIMBS; ++i) { + uint32_t idx = builder.add_variable(val_limbs[i]); + builder.set_public_input(idx); + current_aggregation_object[agg_obj_indices_idx] = idx; + agg_obj_indices_idx++; + } + } + // Make sure the verification key records the public input indices of the + // final recursion output. + std::vector proof_output_witness_indices(current_aggregation_object.begin(), + current_aggregation_object.end()); + builder.set_recursive_proof(proof_output_witness_indices); + } + } } /** @@ -218,14 +337,17 @@ void build_constraints(Builder& builder, AcirFormat const& constraint_system, bo * @return Builder */ template <> -UltraCircuitBuilder create_circuit(const AcirFormat& constraint_system, size_t size_hint, WitnessVector const& witness) +UltraCircuitBuilder create_circuit(const AcirFormat& constraint_system, + size_t size_hint, + WitnessVector const& witness, + bool honk_recursion) { Builder builder{ size_hint, witness, constraint_system.public_inputs, constraint_system.varnum, constraint_system.recursive }; bool has_valid_witness_assignments = !witness.empty(); - build_constraints(builder, constraint_system, has_valid_witness_assignments); + build_constraints(builder, constraint_system, has_valid_witness_assignments, honk_recursion); builder.finalize_circuit(); @@ -244,7 +366,8 @@ UltraCircuitBuilder create_circuit(const AcirFormat& constraint_system, size_t s template <> GoblinUltraCircuitBuilder create_circuit(const AcirFormat& constraint_system, [[maybe_unused]] size_t size_hint, - WitnessVector const& witness) + WitnessVector const& witness, + bool honk_recursion) { // Construct a builder using the witness and public input data from acir and with the goblin-owned op_queue auto op_queue = std::make_shared(); // instantiate empty op_queue @@ -253,13 +376,13 @@ GoblinUltraCircuitBuilder create_circuit(const AcirFormat& constraint_system, // Populate constraints in the builder via the data in constraint_system bool has_valid_witness_assignments = !witness.empty(); - acir_format::build_constraints(builder, constraint_system, has_valid_witness_assignments); + acir_format::build_constraints(builder, constraint_system, has_valid_witness_assignments, honk_recursion); builder.finalize_circuit(); return builder; }; -template void build_constraints(GoblinUltraCircuitBuilder&, AcirFormat const&, bool); +template void build_constraints(GoblinUltraCircuitBuilder&, AcirFormat const&, bool, bool); } // namespace acir_format diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp index 9add17a1451..35d4d1fe6c1 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp @@ -9,6 +9,7 @@ #include "ec_operations.hpp" #include "ecdsa_secp256k1.hpp" #include "ecdsa_secp256r1.hpp" +#include "honk_recursion_constraint.hpp" #include "keccak_constraint.hpp" #include "logic_constraint.hpp" #include "multi_scalar_mul.hpp" @@ -54,6 +55,7 @@ struct AcirFormat { std::vector multi_scalar_mul_constraints; std::vector ec_add_constraints; std::vector recursion_constraints; + std::vector honk_recursion_constraints; std::vector bigint_from_le_bytes_constraints; std::vector bigint_to_le_bytes_constraints; std::vector bigint_operations; @@ -89,6 +91,7 @@ struct AcirFormat { multi_scalar_mul_constraints, ec_add_constraints, recursion_constraints, + honk_recursion_constraints, poly_triple_constraints, block_constraints, bigint_from_le_bytes_constraints, @@ -102,9 +105,17 @@ using WitnessVector = std::vector>; using WitnessVectorStack = std::vector>; template -Builder create_circuit(const AcirFormat& constraint_system, size_t size_hint = 0, WitnessVector const& witness = {}); +Builder create_circuit(const AcirFormat& constraint_system, + size_t size_hint = 0, + WitnessVector const& witness = {}, + bool honk_recursion = false); template -void build_constraints(Builder& builder, AcirFormat const& constraint_system, bool has_valid_witness_assignments); +void build_constraints(Builder& builder, + AcirFormat const& constraint_system, + bool has_valid_witness_assignments, + bool honk_recursion = false); // honk_recursion means we will honk to recursively verify this + // circuit. This distinction is needed to not add the default + // aggregation object when we're not using the honk RV. } // namespace acir_format diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp index 038db2a28f9..cf6df51ea90 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp @@ -52,6 +52,7 @@ TEST_F(AcirFormatTests, TestASingleConstraintNoPubInputs) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, @@ -170,6 +171,7 @@ TEST_F(AcirFormatTests, TestLogicGateFromNoirCircuit) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, @@ -240,6 +242,7 @@ TEST_F(AcirFormatTests, TestSchnorrVerifyPass) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, @@ -337,6 +340,7 @@ TEST_F(AcirFormatTests, TestSchnorrVerifySmallRange) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, @@ -453,6 +457,7 @@ TEST_F(AcirFormatTests, TestVarKeccak) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, @@ -502,6 +507,7 @@ TEST_F(AcirFormatTests, TestKeccakPermutation) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp index 1cc86262bd1..923d496fd8d 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp @@ -189,6 +189,7 @@ TEST_F(BigIntTests, TestBigIntConstraintMultiple) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, @@ -259,6 +260,7 @@ TEST_F(BigIntTests, TestBigIntConstraintSimple) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = { from_le_bytes_constraint_bigint1 }, .bigint_to_le_bytes_constraints = { result2_to_le_bytes }, .bigint_operations = { add_constraint }, @@ -314,6 +316,7 @@ TEST_F(BigIntTests, TestBigIntConstraintReuse) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, @@ -373,6 +376,7 @@ TEST_F(BigIntTests, TestBigIntConstraintReuse2) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, @@ -453,6 +457,7 @@ TEST_F(BigIntTests, TestBigIntDIV) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = { from_le_bytes_constraint_bigint1, from_le_bytes_constraint_bigint2 }, .bigint_to_le_bytes_constraints = { result3_to_le_bytes }, .bigint_operations = { div_constraint }, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp index 5d649d8feb3..eb377b5b532 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp @@ -131,6 +131,7 @@ TEST_F(UltraPlonkRAM, TestBlockConstraint) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp index 59333ddc0d4..1cd34c076f8 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp @@ -76,6 +76,7 @@ TEST_F(EcOperations, TestECOperations) .multi_scalar_mul_constraints = {}, .ec_add_constraints = { ec_add_constraint }, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, @@ -161,6 +162,7 @@ TEST_F(EcOperations, TestECMultiScalarMul) .multi_scalar_mul_constraints = { msm_constrain }, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp index 61782002c85..90a5546068d 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp @@ -111,6 +111,7 @@ TEST_F(ECDSASecp256k1, TestECDSAConstraintSucceed) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, @@ -162,6 +163,7 @@ TEST_F(ECDSASecp256k1, TestECDSACompilesForVerifier) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, @@ -208,6 +210,7 @@ TEST_F(ECDSASecp256k1, TestECDSAConstraintFail) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp index de1d0931d8c..257bcf4a2e2 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp @@ -145,6 +145,7 @@ TEST(ECDSASecp256r1, test_hardcoded) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, @@ -198,6 +199,7 @@ TEST(ECDSASecp256r1, TestECDSAConstraintSucceed) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, @@ -249,6 +251,7 @@ TEST(ECDSASecp256r1, TestECDSACompilesForVerifier) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, @@ -295,6 +298,7 @@ TEST(ECDSASecp256r1, TestECDSAConstraintFail) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.cpp new file mode 100644 index 00000000000..fb46384ce01 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.cpp @@ -0,0 +1,370 @@ +#include "honk_recursion_constraint.hpp" +#include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp" +#include "barretenberg/plonk/transcript/transcript_wrappers.hpp" +#include "barretenberg/stdlib/plonk_recursion/aggregation_state/aggregation_state.hpp" +#include "barretenberg/stdlib/plonk_recursion/verifier/verifier.hpp" +#include "barretenberg/stdlib/primitives/bigfield/constants.hpp" +#include "recursion_constraint.hpp" + +namespace acir_format { + +using namespace bb::plonk; + +/** + * @brief Add constraints required to recursively verify an UltraPlonk proof + * + * @param builder + * @param input + * @tparam has_valid_witness_assignment. Do we have witnesses or are we just generating keys? + * @tparam inner_proof_contains_recursive_proof. Do we expect the inner proof to also have performed recursive + * verification? We need to know this at circuit-compile time. + * + * @note We currently only support HonkRecursionConstraint where inner_proof_contains_recursive_proof = false. + * We would either need a separate ACIR opcode where inner_proof_contains_recursive_proof = true, + * or we need non-witness data to be provided as metadata in the ACIR opcode + */ +std::array create_honk_recursion_constraints( + Builder& builder, + const HonkRecursionConstraint& input, + std::array input_aggregation_object, + std::array nested_aggregation_object, + bool has_valid_witness_assignments) +{ + const auto& nested_aggregation_indices = nested_aggregation_object; + const bool inner_proof_contains_recursive_proof = true; + + // If we do not have a witness, we must ensure that our dummy witness will not trigger + // on-curve errors and inverting-zero errors + { + // get a fake key/proof that satisfies on-curve + inversion-zero checks + const std::vector dummy_key = export_dummy_honk_key_in_recursion_format( + PolynomialManifest(Builder::CIRCUIT_TYPE), inner_proof_contains_recursive_proof); + const auto manifest = Composer::create_manifest(input.public_inputs.size()); + std::vector dummy_proof = + export_dummy_honk_transcript_in_recursion_format(manifest, inner_proof_contains_recursive_proof); + + for (size_t i = 0; i < input.public_inputs.size(); ++i) { + const auto public_input_idx = input.public_inputs[i]; + // if we do NOT have a witness assignment (i.e. are just building the proving/verification keys), + // we add our dummy public input values as Builder variables. + // if we DO have a valid witness assignment, we use the real witness assignment + bb::fr dummy_field = + has_valid_witness_assignments ? builder.get_variable(public_input_idx) : dummy_proof[i]; + // Create a copy constraint between our dummy field and the witness index provided by + // HonkRecursionConstraint. This will make the HonkRecursionConstraint idx equal to `dummy_field`. In the + // case of a valid witness assignment, this does nothing (as dummy_field = real value) In the case of no + // valid witness assignment, this makes sure that the HonkRecursionConstraint witness indices will not + // trigger basic errors (check inputs are on-curve, check we are not inverting 0) + // + // Failing to do these copy constraints on public inputs will trigger these basic errors + // in the case of a nested proof, as an aggregation object is expected to be two G1 points even + // in the case of no valid witness assignments. + builder.assert_equal(builder.add_variable(dummy_field), public_input_idx); + } + // Remove the public inputs from the dummy proof + // The proof supplied to the recursion constraint will already be stripped of public inputs + // while the barretenberg API works with public inputs prepended to the proof. + dummy_proof.erase(dummy_proof.begin(), + dummy_proof.begin() + static_cast(input.public_inputs.size())); + for (size_t i = 0; i < input.proof.size(); ++i) { + const auto proof_field_idx = input.proof[i]; + bb::fr dummy_field = has_valid_witness_assignments ? builder.get_variable(proof_field_idx) : dummy_proof[i]; + builder.assert_equal(builder.add_variable(dummy_field), proof_field_idx); + } + for (size_t i = 0; i < input.key.size(); ++i) { + const auto key_field_idx = input.key[i]; + bb::fr dummy_field = has_valid_witness_assignments ? builder.get_variable(key_field_idx) : dummy_key[i]; + builder.assert_equal(builder.add_variable(dummy_field), key_field_idx); + } + } + + // Construct an in-circuit representation of the verification key. + // For now, the v-key is a circuit constant and is fixed for the circuit. + // (We may need a separate recursion opcode for this to vary, or add more config witnesses to this opcode) + const auto& aggregation_input = input_aggregation_object; + aggregation_state_ct previous_aggregation; + + // If we have previously recursively verified proofs, `inner_aggregation_object_nonzero = true` + // For now this is a complile-time constant i.e. whether this is true/false is fixed for the circuit! + bool inner_aggregation_indices_all_zero = true; + for (const auto& idx : aggregation_input) { + inner_aggregation_indices_all_zero &= (idx == 0); + } + + if (!inner_aggregation_indices_all_zero) { + std::array aggregation_elements; + for (size_t i = 0; i < 4; ++i) { + aggregation_elements[i] = + bn254::BaseField(field_ct::from_witness_index(&builder, aggregation_input[4 * i]), + field_ct::from_witness_index(&builder, aggregation_input[4 * i + 1]), + field_ct::from_witness_index(&builder, aggregation_input[4 * i + 2]), + field_ct::from_witness_index(&builder, aggregation_input[4 * i + 3])); + aggregation_elements[i].assert_is_in_field(); + } + // If we have a previous aggregation object, assign it to `previous_aggregation` so that it is included + // in stdlib::recursion::verify_proof + previous_aggregation.P0 = bn254::Group(aggregation_elements[0], aggregation_elements[1]); + previous_aggregation.P1 = bn254::Group(aggregation_elements[2], aggregation_elements[3]); + previous_aggregation.has_data = true; + } else { + previous_aggregation.has_data = false; + } + + transcript::Manifest manifest = Composer::create_manifest(input.public_inputs.size()); + + std::vector key_fields; + key_fields.reserve(input.key.size()); + for (const auto& idx : input.key) { + auto field = field_ct::from_witness_index(&builder, idx); + key_fields.emplace_back(field); + } + + std::vector proof_fields; + // Prepend the public inputs to the proof fields because this is how the + // core barretenberg library processes proofs (with the public inputs first and not separated) + proof_fields.reserve(input.proof.size() + input.public_inputs.size()); + for (const auto& idx : input.public_inputs) { + auto field = field_ct::from_witness_index(&builder, idx); + proof_fields.emplace_back(field); + } + for (const auto& idx : input.proof) { + auto field = field_ct::from_witness_index(&builder, idx); + proof_fields.emplace_back(field); + } + + // recursively verify the proof + std::shared_ptr vkey = verification_key_ct::from_field_elements( + &builder, key_fields, inner_proof_contains_recursive_proof, nested_aggregation_indices); + vkey->program_width = noir_recursive_settings::program_width; + + Transcript_ct transcript(&builder, manifest, proof_fields, input.public_inputs.size()); + aggregation_state_ct result = bb::stdlib::recursion::verify_proof_( + &builder, vkey, transcript, previous_aggregation); + + // Assign correct witness value to the verification key hash + vkey->hash().assert_equal(field_ct::from_witness_index(&builder, input.key_hash)); + + ASSERT(result.public_inputs.size() == input.public_inputs.size()); + + // Assign the `public_input` field to the public input of the inner proof + for (size_t i = 0; i < input.public_inputs.size(); ++i) { + result.public_inputs[i].assert_equal(field_ct::from_witness_index(&builder, input.public_inputs[i])); + } + + // We want to return an array, so just copy the vector into the array + ASSERT(result.proof_witness_indices.size() == HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE); + std::array resulting_output_aggregation_object; + std::copy(result.proof_witness_indices.begin(), + result.proof_witness_indices.begin() + HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE, + resulting_output_aggregation_object.begin()); + + return resulting_output_aggregation_object; +} + +/** + * @brief When recursively verifying proofs, we represent the verification key using field elements. + * This method exports the key formatted in the manner our recursive verifier expects. + * NOTE: only used by the dsl at the moment. Might be cleaner to make this a dsl function? + * + * @return std::vector + */ +std::vector export_honk_key_in_recursion_format(std::shared_ptr const& vkey) +{ + std::vector output; + output.emplace_back(vkey->domain.root); + output.emplace_back(vkey->domain.domain); + output.emplace_back(vkey->domain.generator); + output.emplace_back(vkey->circuit_size); + output.emplace_back(vkey->num_public_inputs); + output.emplace_back(vkey->contains_recursive_proof); + for (size_t i = 0; i < HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE; ++i) { + if (vkey->recursive_proof_public_input_indices.size() > i) { + output.emplace_back(vkey->recursive_proof_public_input_indices[i]); + } else { + output.emplace_back(0); + ASSERT(vkey->contains_recursive_proof == false); + } + } + for (const auto& descriptor : vkey->polynomial_manifest.get()) { + if (descriptor.source == PolynomialSource::SELECTOR || descriptor.source == PolynomialSource::PERMUTATION) { + const auto element = vkey->commitments.at(std::string(descriptor.commitment_label)); + auto g1_as_fields = export_g1_affine_element_as_fields(element); + output.emplace_back(g1_as_fields.x_lo); + output.emplace_back(g1_as_fields.x_hi); + output.emplace_back(g1_as_fields.y_lo); + output.emplace_back(g1_as_fields.y_hi); + } + } + + verification_key_data vkey_data{ + .circuit_type = static_cast(vkey->circuit_type), + .circuit_size = static_cast(vkey->circuit_size), + .num_public_inputs = static_cast(vkey->num_public_inputs), + .commitments = vkey->commitments, + .contains_recursive_proof = vkey->contains_recursive_proof, + .recursive_proof_public_input_indices = vkey->recursive_proof_public_input_indices, + }; + output.emplace_back(vkey_data.hash_native(0)); // key_hash + return output; +} + +/** + * @brief When recursively verifying proofs, we represent the verification key using field elements. + * This method exports the key formatted in the manner our recursive verifier expects. + * A dummy key is used when building a circuit without a valid witness assignment. + * We want the transcript to contain valid G1 points to prevent on-curve errors being thrown. + * We want a non-zero circuit size as this element will be inverted by the circuit + * and we do not want an "inverting 0" error thrown + * + * @return std::vector + */ +std::vector export_dummy_honk_key_in_recursion_format(const PolynomialManifest& polynomial_manifest, + const bool contains_recursive_proof) +{ + std::vector output; + output.emplace_back(1); // domain.domain (will be inverted) + output.emplace_back(1); // domain.root (will be inverted) + output.emplace_back(1); // domain.generator (will be inverted) + + output.emplace_back(1); // circuit size + output.emplace_back(1); // num public inputs + + output.emplace_back(contains_recursive_proof); // contains_recursive_proof + for (size_t i = 0; i < HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE; ++i) { + output.emplace_back(0); // recursive_proof_public_input_indices + } + + for (const auto& descriptor : polynomial_manifest.get()) { + if (descriptor.source == PolynomialSource::SELECTOR || descriptor.source == PolynomialSource::PERMUTATION) { + // the std::biggroup class creates unsatisfiable constraints when identical points are added/subtracted. + // (when verifying zk proofs this is acceptable as we make sure verification key points are not identical. + // And prover points should contain randomness for an honest Prover). + // This check can also trigger a runtime error due to causing 0 to be inverted. + // When creating dummy verification key points we must be mindful of the above and make sure that each + // transcript point is unique. + auto scalar = bb::fr::random_element(); + const auto element = bb::g1::affine_element(bb::g1::one * scalar); + auto g1_as_fields = export_g1_affine_element_as_fields(element); + output.emplace_back(g1_as_fields.x_lo); + output.emplace_back(g1_as_fields.x_hi); + output.emplace_back(g1_as_fields.y_lo); + output.emplace_back(g1_as_fields.y_hi); + } + } + + output.emplace_back(0); // key_hash + + return output; +} + +/** + * @brief Returns transcript represented as a vector of bb::fr. + * Used to represent recursive proofs (i.e. proof represented as circuit-native field elements) + * + * @return std::vector + */ +std::vector export_honk_transcript_in_recursion_format(const transcript::StandardTranscript& transcript) +{ + std::vector fields; + const auto num_rounds = transcript.get_manifest().get_num_rounds(); + for (size_t i = 0; i < num_rounds; ++i) { + for (const auto& manifest_element : transcript.get_manifest().get_round_manifest(i).elements) { + if (!manifest_element.derived_by_verifier) { + if (manifest_element.num_bytes == 32 && manifest_element.name != "public_inputs") { + fields.emplace_back(transcript.get_field_element(manifest_element.name)); + } else if (manifest_element.num_bytes == 64 && manifest_element.name != "public_inputs") { + const auto group_element = transcript.get_group_element(manifest_element.name); + auto g1_as_fields = export_g1_affine_element_as_fields(group_element); + fields.emplace_back(g1_as_fields.x_lo); + fields.emplace_back(g1_as_fields.x_hi); + fields.emplace_back(g1_as_fields.y_lo); + fields.emplace_back(g1_as_fields.y_hi); + } else { + ASSERT(manifest_element.name == "public_inputs"); + const auto public_inputs_vector = transcript.get_field_element_vector(manifest_element.name); + for (const auto& ele : public_inputs_vector) { + fields.emplace_back(ele); + } + } + } + } + } + return fields; +} + +/** + * @brief Get a dummy fake proof for recursion. All elliptic curve group elements are still valid points to prevent + * errors being thrown. + * + * @param manifest + * @return std::vector + */ +std::vector export_dummy_honk_transcript_in_recursion_format(const transcript::Manifest& manifest, + const bool contains_recursive_proof) +{ + std::vector fields; + const auto num_rounds = manifest.get_num_rounds(); + for (size_t i = 0; i < num_rounds; ++i) { + for (const auto& manifest_element : manifest.get_round_manifest(i).elements) { + if (!manifest_element.derived_by_verifier) { + if (manifest_element.num_bytes == 32 && manifest_element.name != "public_inputs") { + // auto scalar = bb::fr::random_element(); + fields.emplace_back(0); + } else if (manifest_element.num_bytes == 64 && manifest_element.name != "public_inputs") { + // the std::biggroup class creates unsatisfiable constraints when identical points are + // added/subtracted. + // (when verifying zk proofs this is acceptable as we make sure verification key points are not + // identical. And prover points should contain randomness for an honest Prover). This check can + // also trigger a runtime error due to causing 0 to be inverted. When creating dummy proof + // points we must be mindful of the above and make sure that each point is unique. + auto scalar = bb::fr::random_element(); + const auto group_element = bb::g1::affine_element(bb::g1::one * scalar); + auto g1_as_fields = export_g1_affine_element_as_fields(group_element); + fields.emplace_back(g1_as_fields.x_lo); + fields.emplace_back(g1_as_fields.x_hi); + fields.emplace_back(g1_as_fields.y_lo); + fields.emplace_back(g1_as_fields.y_hi); + } else { + ASSERT(manifest_element.name == "public_inputs"); + const size_t num_public_inputs = manifest_element.num_bytes / 32; + // If we have a recursive proofs the public inputs must describe an aggregation object that + // is composed of two valid G1 points on the curve. Without this conditional we will get a + // runtime error that we are attempting to invert 0. + if (contains_recursive_proof) { + // When setting up the ACIR we emplace back the nested aggregation object + // fetched from the proof onto the public inputs. Thus, we can expect the + // nested aggregation object to always be at the end of the public inputs. + for (size_t k = 0; k < num_public_inputs - HonkRecursionConstraint::AGGREGATION_OBJECT_SIZE; + ++k) { + fields.emplace_back(0); + } + for (size_t k = 0; k < HonkRecursionConstraint::NUM_AGGREGATION_ELEMENTS; ++k) { + auto scalar = bb::fr::random_element(); + const auto group_element = bb::g1::affine_element(bb::g1::one * scalar); + auto g1_as_fields = export_g1_affine_element_as_fields(group_element); + fields.emplace_back(g1_as_fields.x_lo); + fields.emplace_back(g1_as_fields.x_hi); + fields.emplace_back(g1_as_fields.y_lo); + fields.emplace_back(g1_as_fields.y_hi); + } + } else { + for (size_t j = 0; j < num_public_inputs; ++j) { + // auto scalar = bb::fr::random_element(); + fields.emplace_back(0); + } + } + } + } + } + } + return fields; +} + +size_t recursion_honk_proof_size_without_public_inputs() +{ + const auto manifest = Composer::create_manifest(0); + auto dummy_transcript = export_dummy_honk_transcript_in_recursion_format(manifest, false); + return dummy_transcript.size(); +} + +} // namespace acir_format diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.hpp new file mode 100644 index 00000000000..8696e9ef073 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.hpp @@ -0,0 +1,76 @@ +#pragma once +#include "barretenberg/dsl/types.hpp" +#include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp" +#include + +namespace acir_format { + +using namespace bb::plonk; + +/** + * @brief HonkRecursionConstraint struct contains information required to recursively verify a proof! + * + * @details The recursive verifier algorithm produces an 'aggregation object' representing 2 G1 points, expressed as 16 + * witness values. The smart contract Verifier must be aware of this aggregation object in order to complete the full + * recursive verification. If the circuit verifies more than 1 proof, the recursion algorithm will update a pre-existing + * aggregation object (`input_aggregation_object`). + * + * @details We currently require that the inner circuit being verified only has a single public input. If more are + * required, the outer circuit can hash them down to 1 input. + * + * @param verification_key_data The inner circuit vkey. Is converted into circuit witness values (internal to the + * backend) + * @param proof The plonk proof. Is converted into circuit witness values (internal to the backend) + * @param is_aggregation_object_nonzero A flag to tell us whether the circuit has already recursively verified proofs + * (and therefore an aggregation object is present) + * @param public_input The index of the single public input + * @param input_aggregation_object Witness indices of pre-existing aggregation object (if it exists) + * @param output_aggregation_object Witness indices of the aggregation object produced by recursive verification + * @param nested_aggregation_object Public input indices of an aggregation object inside the proof. + * + * @note If input_aggregation_object witness indices are all zero, we interpret this to mean that the inner proof does + * NOT contain a previously recursively verified proof + * @note nested_aggregation_object is used for cases where the proof being verified contains an aggregation object in + * its public inputs! If this is the case, we record the public input locations in `nested_aggregation_object`. If the + * inner proof is of a circuit that does not have a nested aggregation object, these values are all zero. + * + * To outline the interaction between the input_aggergation_object and the nested_aggregation_object take the following + * example: If we have a circuit that verifies 2 proofs A and B, the recursion constraint for B will have an + * input_aggregation_object that points to the aggregation output produced by verifying A. If circuit B also verifies a + * proof, in the above example the recursion constraint for verifying B will have a nested object that describes the + * aggregation object in B’s public inputs as well as an input aggregation object that points to the object produced by + * the previous recursion constraint in the circuit (the one that verifies A) + * + */ +struct HonkRecursionConstraint { + // An aggregation state is represented by two G1 affine elements. Each G1 point has + // two field element coordinates (x, y). Thus, four field elements + static constexpr size_t NUM_AGGREGATION_ELEMENTS = 4; + // Four limbs are used when simulating a non-native field using the bigfield class + static constexpr size_t AGGREGATION_OBJECT_SIZE = + NUM_AGGREGATION_ELEMENTS * NUM_QUOTIENT_PARTS; // 16 field elements + std::vector key; + std::vector proof; + std::vector public_inputs; + uint32_t key_hash; + + friend bool operator==(HonkRecursionConstraint const& lhs, HonkRecursionConstraint const& rhs) = default; +}; + +std::array create_honk_recursion_constraints( + Builder& builder, + const HonkRecursionConstraint& input, + std::array input_aggregation_object, + std::array nested_aggregation_object, + bool has_valid_witness_assignments = false); + +std::vector export_honk_key_in_recursion_format(std::shared_ptr const& vkey); +std::vector export_dummy_honk_key_in_recursion_format(const PolynomialManifest& polynomial_manifest, + bool contains_recursive_proof = 0); + +std::vector export_honk_transcript_in_recursion_format(const transcript::StandardTranscript& transcript); +std::vector export_dummy_honk_transcript_in_recursion_format(const transcript::Manifest& manifest, + const bool contains_recursive_proof); +size_t recursion_honk_proof_size_without_public_inputs(); + +} // namespace acir_format diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.test.cpp new file mode 100644 index 00000000000..7ac1fc58eb0 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/honk_recursion_constraint.test.cpp @@ -0,0 +1,365 @@ +#include "honk_recursion_constraint.hpp" +#include "acir_format.hpp" +#include "barretenberg/plonk/proof_system/types/proof.hpp" +#include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp" + +#include +#include + +using namespace acir_format; +using namespace bb::plonk; + +class AcirHonkRecursionConstraint : public ::testing::Test { + public: + Builder create_inner_circuit() + { + /** + * constraints produced by Noir program: + * fn main(x : u32, y : pub u32) { + * let z = x ^ y; + * + * constrain z != 10; + * } + **/ + RangeConstraint range_a{ + .witness = 0, + .num_bits = 32, + }; + RangeConstraint range_b{ + .witness = 1, + .num_bits = 32, + }; + + LogicConstraint logic_constraint{ + .a = 0, + .b = 1, + .result = 2, + .num_bits = 32, + .is_xor_gate = 1, + }; + poly_triple expr_a{ + .a = 2, + .b = 3, + .c = 0, + .q_m = 0, + .q_l = 1, + .q_r = -1, + .q_o = 0, + .q_c = -10, + }; + poly_triple expr_b{ + .a = 3, + .b = 4, + .c = 5, + .q_m = 1, + .q_l = 0, + .q_r = 0, + .q_o = -1, + .q_c = 0, + }; + poly_triple expr_c{ + .a = 3, + .b = 5, + .c = 3, + .q_m = 1, + .q_l = 0, + .q_r = 0, + .q_o = -1, + .q_c = 0, + + }; + poly_triple expr_d{ + .a = 5, + .b = 0, + .c = 0, + .q_m = 0, + .q_l = -1, + .q_r = 0, + .q_o = 0, + .q_c = 1, + }; + + AcirFormat constraint_system{ .varnum = 6, + .recursive = true, + .num_acir_opcodes = 7, + .public_inputs = { 1, 2 }, + .logic_constraints = { logic_constraint }, + .range_constraints = { range_a, range_b }, + .aes128_constraints = {}, + .sha256_constraints = {}, + .sha256_compression = {}, + .schnorr_constraints = {}, + .ecdsa_k1_constraints = {}, + .ecdsa_r1_constraints = {}, + .blake2s_constraints = {}, + .blake3_constraints = {}, + .keccak_constraints = {}, + .keccak_permutations = {}, + .pedersen_constraints = {}, + .pedersen_hash_constraints = {}, + .poseidon2_constraints = {}, + .multi_scalar_mul_constraints = {}, + .ec_add_constraints = {}, + .recursion_constraints = {}, + .honk_recursion_constraints = {}, + .bigint_from_le_bytes_constraints = {}, + .bigint_to_le_bytes_constraints = {}, + .bigint_operations = {}, + .poly_triple_constraints = { expr_a, expr_b, expr_c, expr_d }, + .quad_constraints = {}, + .block_constraints = {} }; + + uint256_t inverse_of_five = fr(5).invert(); + WitnessVector witness{ + 5, 10, 15, 5, inverse_of_five, 1, + }; + auto builder = create_circuit(constraint_system, /*size_hint*/ 0, witness, /*honk recursion*/ true); + + return builder; + } + + /** + * @brief Create a circuit that recursively verifies one or more inner circuits + * + * @param inner_circuits + * @return Composer + */ + Builder create_outer_circuit(std::vector& inner_circuits) + { + std::vector honk_recursion_constraints; + + size_t witness_offset = 0; + std::vector> witness; + + for (auto& inner_circuit : inner_circuits) { + + auto inner_composer = Composer(); + auto inner_prover = inner_composer.create_prover(inner_circuit); + auto inner_proof = inner_prover.construct_proof(); + auto inner_verifier = inner_composer.create_verifier(inner_circuit); + + const size_t num_inner_public_inputs = inner_circuit.get_public_inputs().size(); + transcript::StandardTranscript transcript(inner_proof.proof_data, + Composer::create_manifest(num_inner_public_inputs), + transcript::HashType::PedersenBlake3s, + 16); + + std::vector proof_witnesses = export_honk_transcript_in_recursion_format(transcript); + // - Save the public inputs so that we can set their values. + // - Then truncate them from the proof because the ACIR API expects proofs without public inputs + std::vector inner_public_input_values( + proof_witnesses.begin(), + proof_witnesses.begin() + static_cast(num_inner_public_inputs - + RecursionConstraint::AGGREGATION_OBJECT_SIZE)); + + // We want to make sure that we do not remove the nested aggregation object. + proof_witnesses.erase(proof_witnesses.begin(), + proof_witnesses.begin() + + static_cast(num_inner_public_inputs - + RecursionConstraint::AGGREGATION_OBJECT_SIZE)); + + std::vector key_witnesses = export_honk_key_in_recursion_format(inner_verifier.key); + bb::fr key_hash = key_witnesses.back(); + key_witnesses.pop_back(); + + const uint32_t key_hash_start_idx = static_cast(witness_offset); + const uint32_t public_input_start_idx = key_hash_start_idx + 1; + const uint32_t proof_indices_start_idx = static_cast( + public_input_start_idx + num_inner_public_inputs - RecursionConstraint::AGGREGATION_OBJECT_SIZE); + const uint32_t key_indices_start_idx = + static_cast(proof_indices_start_idx + proof_witnesses.size()); + + std::vector proof_indices; + std::vector key_indices; + std::vector inner_public_inputs; + for (size_t i = 0; i < proof_witnesses.size(); ++i) { + proof_indices.emplace_back(static_cast(i + proof_indices_start_idx)); + } + const size_t key_size = key_witnesses.size(); + for (size_t i = 0; i < key_size; ++i) { + key_indices.emplace_back(static_cast(i + key_indices_start_idx)); + } + // We keep the nested aggregation object attached to the proof, + // thus we do not explicitly have to keep the public inputs while setting up the initial recursion + // constraint. They will later be attached as public inputs when creating the circuit. + for (size_t i = 0; i < num_inner_public_inputs - RecursionConstraint::AGGREGATION_OBJECT_SIZE; ++i) { + inner_public_inputs.push_back(static_cast(i + public_input_start_idx)); + } + + HonkRecursionConstraint honk_recursion_constraint{ + .key = key_indices, + .proof = proof_indices, + .public_inputs = inner_public_inputs, + .key_hash = key_hash_start_idx, + }; + honk_recursion_constraints.push_back(honk_recursion_constraint); + + witness.emplace_back(key_hash); + for (size_t i = 0; i < proof_indices_start_idx - public_input_start_idx; ++i) { + witness.emplace_back(0); + } + for (const auto& wit : proof_witnesses) { + witness.emplace_back(wit); + } + + for (const auto& wit : key_witnesses) { + witness.emplace_back(wit); + } + + // Set the values for the inner public inputs + // TODO(maxim): check this is wrong I think + // Note: this is confusing, but we minus one here due to the fact that the + // witness values have not taken into account that zero is taken up by the zero_idx + // + // We once again have to check whether we have a nested proof, because if we do have one + // then we could get a segmentation fault as `inner_public_inputs` was never filled with values. + for (size_t i = 0; i < num_inner_public_inputs - RecursionConstraint::AGGREGATION_OBJECT_SIZE; ++i) { + witness[inner_public_inputs[i]] = inner_public_input_values[i]; + } + + witness_offset = key_indices_start_idx + key_witnesses.size(); + } + + AcirFormat constraint_system{ .varnum = static_cast(witness.size()), + .recursive = false, + .num_acir_opcodes = static_cast(honk_recursion_constraints.size()), + .public_inputs = {}, + .logic_constraints = {}, + .range_constraints = {}, + .aes128_constraints = {}, + .sha256_constraints = {}, + .sha256_compression = {}, + .schnorr_constraints = {}, + .ecdsa_k1_constraints = {}, + .ecdsa_r1_constraints = {}, + .blake2s_constraints = {}, + .blake3_constraints = {}, + .keccak_constraints = {}, + .keccak_permutations = {}, + .pedersen_constraints = {}, + .pedersen_hash_constraints = {}, + .poseidon2_constraints = {}, + .multi_scalar_mul_constraints = {}, + .ec_add_constraints = {}, + .recursion_constraints = {}, + .honk_recursion_constraints = honk_recursion_constraints, + .bigint_from_le_bytes_constraints = {}, + .bigint_to_le_bytes_constraints = {}, + .bigint_operations = {}, + .poly_triple_constraints = {}, + .quad_constraints = {}, + .block_constraints = {} }; + + auto outer_circuit = create_circuit(constraint_system, /*size_hint*/ 0, witness, /*honk recursion*/ true); + + return outer_circuit; + } + + protected: + static void SetUpTestSuite() { bb::srs::init_crs_factory("../srs_db/ignition"); } +}; + +TEST_F(AcirHonkRecursionConstraint, TestBasicDoubleHonkRecursionConstraints) +{ + std::vector layer_1_circuits; + layer_1_circuits.push_back(create_inner_circuit()); + + layer_1_circuits.push_back(create_inner_circuit()); + + auto layer_2_circuit = create_outer_circuit(layer_1_circuits); + + info("circuit gates = ", layer_2_circuit.get_num_gates()); + + auto layer_2_composer = Composer(); + auto prover = layer_2_composer.create_ultra_with_keccak_prover(layer_2_circuit); + info("prover gates = ", prover.circuit_size); + auto proof = prover.construct_proof(); + auto verifier = layer_2_composer.create_ultra_with_keccak_verifier(layer_2_circuit); + EXPECT_EQ(verifier.verify_proof(proof), true); +} + +TEST_F(AcirHonkRecursionConstraint, TestOneOuterRecursiveCircuit) +{ + /** + * We want to test the following: + * 1. circuit that verifies a proof of another circuit + * 2. the above, but the inner circuit contains a recursive proof output that we have to aggregate + * 3. the above, but the outer circuit verifies 2 proofs, the aggregation outputs from the 2 proofs (+ the recursive + * proof output from 2) are aggregated together + * + * A = basic circuit + * B = circuit that verifies proof of A + * C = circuit that verifies proof of B and a proof of A + * + * Layer 1 = proof of A + * Layer 2 = verifies proof of A and proof of B + * Layer 3 = verifies proof of C + * + * Attempt at a visual graphic + * =========================== + * + * C + * ^ + * | + * | - B + * ^ ^ + * | | + * | -A + * | + * - A + * + * =========================== + * + * Final aggregation object contains aggregated proofs for 2 instances of A and 1 instance of B + */ + std::vector layer_1_circuits; + layer_1_circuits.push_back(create_inner_circuit()); + info("created first inner circuit"); + + std::vector layer_2_circuits; + layer_2_circuits.push_back(create_inner_circuit()); + info("created second inner circuit"); + + layer_2_circuits.push_back(create_outer_circuit(layer_1_circuits)); + info("created first outer circuit"); + + auto layer_3_circuit = create_outer_circuit(layer_2_circuits); + info("created second outer circuit"); + info("number of gates in layer 3 = ", layer_3_circuit.get_num_gates()); + + auto layer_3_composer = Composer(); + auto prover = layer_3_composer.create_ultra_with_keccak_prover(layer_3_circuit); + info("prover gates = ", prover.circuit_size); + auto proof = prover.construct_proof(); + auto verifier = layer_3_composer.create_ultra_with_keccak_verifier(layer_3_circuit); + EXPECT_EQ(verifier.verify_proof(proof), true); +} + +TEST_F(AcirHonkRecursionConstraint, TestFullRecursiveComposition) +{ + std::vector layer_b_1_circuits; + layer_b_1_circuits.push_back(create_inner_circuit()); + info("created first inner circuit"); + + std::vector layer_b_2_circuits; + layer_b_2_circuits.push_back(create_inner_circuit()); + info("created second inner circuit"); + + std::vector layer_2_circuits; + layer_2_circuits.push_back(create_outer_circuit(layer_b_1_circuits)); + info("created first outer circuit"); + + layer_2_circuits.push_back(create_outer_circuit(layer_b_2_circuits)); + info("created second outer circuit"); + + auto layer_3_circuit = create_outer_circuit(layer_2_circuits); + info("created third outer circuit"); + info("number of gates in layer 3 circuit = ", layer_3_circuit.get_num_gates()); + + auto layer_3_composer = Composer(); + auto prover = layer_3_composer.create_ultra_with_keccak_prover(layer_3_circuit); + info("prover gates = ", prover.circuit_size); + auto proof = prover.construct_proof(); + auto verifier = layer_3_composer.create_ultra_with_keccak_verifier(layer_3_circuit); + EXPECT_EQ(verifier.verify_proof(proof), true); +} diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/poseidon2_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/poseidon2_constraint.test.cpp index 4922c63cd69..71e2cc2160f 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/poseidon2_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/poseidon2_constraint.test.cpp @@ -51,6 +51,7 @@ TEST_F(Poseidon2Tests, TestPoseidon2Permutation) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp index b837f94ba2a..65e049fe0ca 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp @@ -103,6 +103,7 @@ Builder create_inner_circuit() .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, @@ -130,13 +131,9 @@ Builder create_outer_circuit(std::vector& inner_circuits) std::vector recursion_constraints; size_t witness_offset = 0; - std::array output_aggregation_object; std::vector> witness; - size_t circuit_idx = 0; for (auto& inner_circuit : inner_circuits) { - const bool has_input_aggregation_object = circuit_idx > 0; - auto inner_composer = Composer(); auto inner_prover = inner_composer.create_prover(inner_circuit); auto inner_proof = inner_prover.construct_proof(); @@ -162,33 +159,25 @@ Builder create_outer_circuit(std::vector& inner_circuits) if (!has_nested_proof) { proof_witnesses.erase(proof_witnesses.begin(), proof_witnesses.begin() + static_cast(num_inner_public_inputs)); + } else { + proof_witnesses.erase(proof_witnesses.begin(), + proof_witnesses.begin() + + static_cast(num_inner_public_inputs - + RecursionConstraint::AGGREGATION_OBJECT_SIZE)); } const std::vector key_witnesses = export_key_in_recursion_format(inner_verifier.key); const uint32_t key_hash_start_idx = static_cast(witness_offset); const uint32_t public_input_start_idx = key_hash_start_idx + 1; - const uint32_t output_aggregation_object_start_idx = - static_cast(public_input_start_idx + num_inner_public_inputs + (has_nested_proof ? 16 : 0)); - const uint32_t proof_indices_start_idx = output_aggregation_object_start_idx + 16; + const uint32_t proof_indices_start_idx = + static_cast(public_input_start_idx + num_inner_public_inputs - + (has_nested_proof ? RecursionConstraint::AGGREGATION_OBJECT_SIZE : 0)); const uint32_t key_indices_start_idx = static_cast(proof_indices_start_idx + proof_witnesses.size()); std::vector proof_indices; std::vector key_indices; std::vector inner_public_inputs; - std::array input_aggregation_object = {}; - std::array nested_aggregation_object = {}; - if (has_input_aggregation_object) { - input_aggregation_object = output_aggregation_object; - } - for (size_t i = 0; i < 16; ++i) { - output_aggregation_object[i] = (static_cast(i + output_aggregation_object_start_idx)); - } - if (has_nested_proof) { - for (size_t i = 0; i < 16; ++i) { - nested_aggregation_object[i] = inner_circuit.recursive_proof_public_input_indices[i]; - } - } for (size_t i = 0; i < proof_witnesses.size(); ++i) { proof_indices.emplace_back(static_cast(i + proof_indices_start_idx)); } @@ -203,6 +192,10 @@ Builder create_outer_circuit(std::vector& inner_circuits) for (size_t i = 0; i < num_inner_public_inputs; ++i) { inner_public_inputs.push_back(static_cast(i + public_input_start_idx)); } + } else { + for (size_t i = 0; i < num_inner_public_inputs - RecursionConstraint::AGGREGATION_OBJECT_SIZE; ++i) { + inner_public_inputs.push_back(static_cast(i + public_input_start_idx)); + } } RecursionConstraint recursion_constraint{ @@ -234,10 +227,13 @@ Builder create_outer_circuit(std::vector& inner_circuits) for (size_t i = 0; i < num_inner_public_inputs; ++i) { witness[inner_public_inputs[i]] = inner_public_input_values[i]; } + } else { + for (size_t i = 0; i < num_inner_public_inputs - RecursionConstraint::AGGREGATION_OBJECT_SIZE; ++i) { + witness[inner_public_inputs[i]] = inner_public_input_values[i]; + } } witness_offset = key_indices_start_idx + key_witnesses.size(); - circuit_idx++; } AcirFormat constraint_system{ .varnum = static_cast(witness.size()), @@ -262,6 +258,7 @@ Builder create_outer_circuit(std::vector& inner_circuits) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = recursion_constraints, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/sha256_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/sha256_constraint.test.cpp index 5af032bedd1..82fda6f8d81 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/sha256_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/sha256_constraint.test.cpp @@ -53,6 +53,7 @@ TEST_F(Sha256Tests, TestSha256Compression) .multi_scalar_mul_constraints = {}, .ec_add_constraints = {}, .recursion_constraints = {}, + .honk_recursion_constraints = {}, .bigint_from_le_bytes_constraints = {}, .bigint_to_le_bytes_constraints = {}, .bigint_operations = {}, diff --git a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp index 46586ff58da..a3234dbc984 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp @@ -41,15 +41,6 @@ class GoblinMockCircuits { std::shared_ptr verification_key; }; - /** - * @brief Information required by the verifier to verify a folding round besides the previous accumulator. - */ - struct VerifierFoldData { - std::vector fold_proof; // folding proof - std::shared_ptr - inst_vk; // Verification key of the instance to be folded (note: this would be a vector if k > 1 ) - }; - /** * @brief Populate a builder with some arbitrary but nontrivial constraints * @details Although the details of the circuit constructed here are arbitrary, the intent is to mock something a @@ -64,12 +55,16 @@ class GoblinMockCircuits { // Determine number of times to execute the below operations that constitute the mock circuit logic. Note that // the circuit size does not scale linearly with number of iterations due to e.g. amortization of lookup costs const size_t NUM_ITERATIONS_LARGE = 12; // results in circuit size 2^19 (502238 gates) - const size_t NUM_ITERATIONS_MEDIUM = 3; // results in circuit size 2^17 (124843 gates) - const size_t NUM_ITERATIONS = large ? NUM_ITERATIONS_LARGE : NUM_ITERATIONS_MEDIUM; - stdlib::generate_sha256_test_circuit(builder, NUM_ITERATIONS); // min gates: ~39k - stdlib::generate_ecdsa_verification_test_circuit(builder, NUM_ITERATIONS); // min gates: ~41k - stdlib::generate_merkle_membership_test_circuit(builder, NUM_ITERATIONS); // min gates: ~29k + if (large) { + stdlib::generate_sha256_test_circuit(builder, NUM_ITERATIONS_LARGE); + stdlib::generate_ecdsa_verification_test_circuit(builder, NUM_ITERATIONS_LARGE); + stdlib::generate_merkle_membership_test_circuit(builder, NUM_ITERATIONS_LARGE); + } else { // Results in circuit size 2^17 when accumulated via ClientIvc + stdlib::generate_sha256_test_circuit(builder, 5); + stdlib::generate_ecdsa_verification_test_circuit(builder, 2); + stdlib::generate_merkle_membership_test_circuit(builder, 10); + } // TODO(https://github.com/AztecProtocol/barretenberg/issues/911): We require goblin ops to be added to the // function circuit because we cannot support zero commtiments. While the builder handles this at @@ -177,50 +172,24 @@ class GoblinMockCircuits { } /** - * @brief Construct a mock kernel circuit based on folding - * @details This circuit contains (1) some arbitrary operations representing general kernel logic, (2) recursive - * folding verification of a function circuit folding proof, and (3) recursive folding verification of a previous - * kernel circuit folding proof. The arbitrary kernel logic is structured to bring the final dyadic circuit size of - * the kernel to 2^17. + * @brief Construct a mock kernel circuit + * @details Construct an arbitrary circuit meant to represent the aztec private function execution kernel. Recursive + * folding verification is handled internally by ClientIvc, not in the kernel. * * @param builder * @param function_fold_proof * @param kernel_fold_proof */ - static std::shared_ptr construct_mock_folding_kernel( - GoblinUltraBuilder& builder, - const VerifierFoldData& func, - const VerifierFoldData& kernel, - std::shared_ptr& prev_kernel_accum) + static void construct_mock_folding_kernel(GoblinUltraBuilder& builder) { - using GURecursiveFlavor = GoblinUltraRecursiveFlavor_; - using RecursiveVerifierInstances = - bb::stdlib::recursion::honk::RecursiveVerifierInstances_; - using FoldingRecursiveVerifier = - bb::stdlib::recursion::honk::ProtoGalaxyRecursiveVerifier_; - // Add operations representing general kernel logic e.g. state updates. Note: these are structured to make - // the kernel "full" within the dyadic size 2^17 (130914 gates) - const size_t NUM_MERKLE_CHECKS = 25; - const size_t NUM_ECDSA_VERIFICATIONS = 1; + // the kernel "full" within the dyadic size 2^17 + const size_t NUM_MERKLE_CHECKS = 20; + const size_t NUM_ECDSA_VERIFICATIONS = 2; const size_t NUM_SHA_HASHES = 1; stdlib::generate_merkle_membership_test_circuit(builder, NUM_MERKLE_CHECKS); stdlib::generate_ecdsa_verification_test_circuit(builder, NUM_ECDSA_VERIFICATIONS); stdlib::generate_sha256_test_circuit(builder, NUM_SHA_HASHES); - - // Initial kernel iteration does not have a previous kernel to fold - if (kernel.fold_proof.empty()) { - FoldingRecursiveVerifier verifier_1{ &builder, prev_kernel_accum, { func.inst_vk } }; - auto fctn_verifier_accum = verifier_1.verify_folding_proof(func.fold_proof); - return std::make_shared(fctn_verifier_accum->get_value()); - } - - FoldingRecursiveVerifier verifier_2{ &builder, prev_kernel_accum, { kernel.inst_vk } }; - auto kernel_verifier_accum = verifier_2.verify_folding_proof(kernel.fold_proof); - auto native_acc = std::make_shared(kernel_verifier_accum->get_value()); - FoldingRecursiveVerifier verifier_1{ &builder, native_acc, { func.inst_vk } }; - auto fctn_verifier_accum = verifier_1.verify_folding_proof(func.fold_proof); - return std::make_shared(fctn_verifier_accum->get_value()); } /** diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/folding_result.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/folding_result.hpp index 4bf3eb88fff..61d6fdf3dd3 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/folding_result.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/folding_result.hpp @@ -13,6 +13,6 @@ template struct FoldingResult { public: std::shared_ptr> accumulator; // TODO(https://github.com/AztecProtocol/barretenberg/issues/656): turn folding data into a struct - std::vector folding_data; + std::vector proof; }; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp index 6d67ab10576..e003418a524 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp @@ -192,7 +192,7 @@ template void ProtoGalaxyProver_::accum FF combiner_challenge = transcript->template get_challenge("combiner_quotient_challenge"); std::shared_ptr next_accumulator = compute_next_accumulator(instances, state.combiner_quotient, combiner_challenge, state.compressed_perturbator); - state.result.folding_data = transcript->proof_data; + state.result.proof = transcript->proof_data; state.result.accumulator = next_accumulator; }; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.test.cpp index 673d7234df9..786d75545fc 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.test.cpp @@ -195,14 +195,14 @@ template class ProtoGalaxyRecursiveTests : public tes OuterBuilder folding_circuit; auto verifier = FoldingRecursiveVerifier(&folding_circuit, verifier_instance_1, { verifier_instance_2->verification_key }); - verifier.verify_folding_proof(folding_proof.folding_data); + verifier.verify_folding_proof(folding_proof.proof); info("Folding Recursive Verifier: num gates = ", folding_circuit.num_gates); EXPECT_EQ(folding_circuit.failed(), false) << folding_circuit.err(); // Perform native folding verification and ensure it returns the same result (either true or false) as // calling check_circuit on the recursive folding verifier InnerFoldingVerifier native_folding_verifier({ verifier_instance_1, verifier_instance_2 }); - native_folding_verifier.verify_folding_proof(folding_proof.folding_data); + native_folding_verifier.verify_folding_proof(folding_proof.proof); // Ensure that the underlying native and recursive folding verification algorithms agree by ensuring the // manifestsproduced by each agree. @@ -259,7 +259,7 @@ template class ProtoGalaxyRecursiveTests : public tes OuterBuilder folding_circuit; auto verifier = FoldingRecursiveVerifier(&folding_circuit, verifier_instance_1, { verifier_instance_2->verification_key }); - auto recursive_verifier_accumulator = verifier.verify_folding_proof(folding_proof.folding_data); + auto recursive_verifier_accumulator = verifier.verify_folding_proof(folding_proof.proof); auto native_verifier_acc = std::make_shared(recursive_verifier_accumulator->get_value()); info("Folding Recursive Verifier: num gates = ", folding_circuit.num_gates); @@ -269,7 +269,7 @@ template class ProtoGalaxyRecursiveTests : public tes // Perform native folding verification and ensure it returns the same result (either true or false) as // calling check_circuit on the recursive folding verifier InnerFoldingVerifier native_folding_verifier({ verifier_instance_1, verifier_instance_2 }); - auto verifier_accumulator = native_folding_verifier.verify_folding_proof(folding_proof.folding_data); + auto verifier_accumulator = native_folding_verifier.verify_folding_proof(folding_proof.proof); // Ensure that the underlying native and recursive folding verification algorithms agree by ensuring the // manifestsproduced by each agree. @@ -359,7 +359,7 @@ template class ProtoGalaxyRecursiveTests : public tes FoldingRecursiveVerifier verifier{ &folding_circuit, verifier_accumulator, { verifier_inst->verification_key } }; - auto recursive_verifier_acc = verifier.verify_folding_proof(folding_proof.folding_data); + auto recursive_verifier_acc = verifier.verify_folding_proof(folding_proof.proof); // Validate that the target sum between prover and verifier is now different EXPECT_FALSE(folding_proof.accumulator->target_sum == recursive_verifier_acc->target_sum.get_value()); }; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield.hpp index 2fc3572cec3..e015988c5c3 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield.hpp @@ -48,6 +48,11 @@ template class bigfield { field_t element; uint256_t maximum_value; }; + static constexpr size_t NUM_LIMBS = 4; + + Builder* context; + mutable Limb binary_basis_limbs[NUM_LIMBS]; + mutable field_t prime_basis_limb; bigfield(const field_t& low_bits, const field_t& high_bits, @@ -121,11 +126,11 @@ template class bigfield { static constexpr uint256_t DEFAULT_MAXIMUM_LIMB = (uint256_t(1) << NUM_LIMB_BITS) - uint256_t(1); static constexpr uint256_t DEFAULT_MAXIMUM_MOST_SIGNIFICANT_LIMB = (uint256_t(1) << NUM_LAST_LIMB_BITS) - uint256_t(1); - static constexpr uint64_t LOG2_BINARY_MODULUS = NUM_LIMB_BITS * 4; + static constexpr uint64_t LOG2_BINARY_MODULUS = NUM_LIMB_BITS * NUM_LIMBS; static constexpr bool is_composite = true; // false only when fr is native static constexpr uint256_t prime_basis_maximum_limb = - uint256_t(modulus_u512.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4)); + uint256_t(modulus_u512.slice(NUM_LIMB_BITS * (NUM_LIMBS - 1), NUM_LIMB_BITS* NUM_LIMBS)); static constexpr Basis prime_basis{ uint512_t(bb::fr::modulus), bb::fr::modulus.get_msb() + 1 }; static constexpr Basis binary_basis{ uint512_t(1) << LOG2_BINARY_MODULUS, LOG2_BINARY_MODULUS }; static constexpr Basis target_basis{ modulus_u512, modulus_u512.get_msb() + 1 }; @@ -136,13 +141,13 @@ template class bigfield { static constexpr bb::fr shift_right_2 = bb::fr(1) / shift_2; static constexpr bb::fr negative_prime_modulus_mod_binary_basis = -bb::fr(uint256_t(modulus_u512)); static constexpr uint512_t negative_prime_modulus = binary_basis.modulus - target_basis.modulus; - static constexpr uint256_t neg_modulus_limbs_u256[4]{ + static constexpr uint256_t neg_modulus_limbs_u256[NUM_LIMBS]{ uint256_t(negative_prime_modulus.slice(0, NUM_LIMB_BITS).lo), uint256_t(negative_prime_modulus.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo), uint256_t(negative_prime_modulus.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo), uint256_t(negative_prime_modulus.slice(NUM_LIMB_BITS * 3, NUM_LIMB_BITS * 4).lo), }; - static constexpr bb::fr neg_modulus_limbs[4]{ + static constexpr bb::fr neg_modulus_limbs[NUM_LIMBS]{ bb::fr(negative_prime_modulus.slice(0, NUM_LIMB_BITS).lo), bb::fr(negative_prime_modulus.slice(NUM_LIMB_BITS, NUM_LIMB_BITS * 2).lo), bb::fr(negative_prime_modulus.slice(NUM_LIMB_BITS * 2, NUM_LIMB_BITS * 3).lo), @@ -428,9 +433,6 @@ template class bigfield { static constexpr uint256_t get_maximum_unreduced_limb_value() { return uint256_t(1) << MAX_UNREDUCED_LIMB_SIZE; } static_assert(MAX_UNREDUCED_LIMB_SIZE < (NUM_LIMB_BITS * 2)); - Builder* context; - mutable Limb binary_basis_limbs[4]; - mutable field_t prime_basis_limb; private: static std::pair compute_quotient_remainder_values(const bigfield& a, diff --git a/l1-contracts/test/fixtures/empty_block_0.json b/l1-contracts/test/fixtures/empty_block_0.json index 6fed6b71ba1..91216c12952 100644 --- a/l1-contracts/test/fixtures/empty_block_0.json +++ b/l1-contracts/test/fixtures/empty_block_0.json @@ -8,7 +8,7 @@ "l2ToL1Messages": [] }, "block": { - "archive": "0x2ef0cbb8a2651d0ddd89c84019bcbfa6f992adcf28831c4767a2c592f35d41ba", + "archive": "0x0ed815d35918f1aabf391fa174a1d95476da157e40b7fc581b2c8f4cfd23e6b3", "body": "0x00000000", "txsEffectsHash": "0x002676dbd818b1ba16e11597cb5c07b06aa7771127b02a77d0c3a6039bb9fef1", "decodedHeader": { @@ -23,8 +23,8 @@ "chainId": 31337, "timestamp": 0, "version": 1, - "coinbase": "0xe8bf4f268ec70317922965dcc848cab31883f841", - "feeRecipient": "0x2d2fc61c2ed4df01168b2e4bff9e801fa0feb1bb2b874944e60402e21f611e9a", + "coinbase": "0xbe70f89d75a00bd140342ebc63beb517cf9735bc", + "feeRecipient": "0x08eb6120958820f4b4fd61a9bcaa32c33349663034e1db315ba57c67d155b172", "gasFees": { "feePerDaGas": 0, "feePerL2Gas": 0 @@ -55,8 +55,8 @@ } } }, - "header": "0x067a48e3140b6f15d71751ededfa0cccde3d436bb71aa7fec226b0bfe51dc5cf000000010000000000000000000000000000000000000000000000000000000000000001002676dbd818b1ba16e11597cb5c07b06aa7771127b02a77d0c3a6039bb9fef100089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c31864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000800bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000800000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000e8bf4f268ec70317922965dcc848cab31883f8412d2fc61c2ed4df01168b2e4bff9e801fa0feb1bb2b874944e60402e21f611e9a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "publicInputsHash": "0x002afd32d173b032a180992cb05bba5f791137d345d59e8a84b0c4fb511fab69", + "header": "0x067a48e3140b6f15d71751ededfa0cccde3d436bb71aa7fec226b0bfe51dc5cf000000010000000000000000000000000000000000000000000000000000000000000001002676dbd818b1ba16e11597cb5c07b06aa7771127b02a77d0c3a6039bb9fef100089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c31864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000800bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000800000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000be70f89d75a00bd140342ebc63beb517cf9735bc08eb6120958820f4b4fd61a9bcaa32c33349663034e1db315ba57c67d155b17200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x00e9c95b88dbc49351e6a0a9b660918147d3c69410df4fba105c047a4f253a47", "numTxs": 0 } } \ No newline at end of file diff --git a/l1-contracts/test/fixtures/empty_block_1.json b/l1-contracts/test/fixtures/empty_block_1.json index 494959bcf7b..0596ade5a0a 100644 --- a/l1-contracts/test/fixtures/empty_block_1.json +++ b/l1-contracts/test/fixtures/empty_block_1.json @@ -8,7 +8,7 @@ "l2ToL1Messages": [] }, "block": { - "archive": "0x2d89a13b4dacdf6ce914ba3266a7ff4db3c2685ad1c8cbb15e2c51567c9f3732", + "archive": "0x18c171439670152671eb523cdf11eb61a45c27b7685ad86a7229fbe635e9ea18", "body": "0x00000000", "txsEffectsHash": "0x002676dbd818b1ba16e11597cb5c07b06aa7771127b02a77d0c3a6039bb9fef1", "decodedHeader": { @@ -21,10 +21,10 @@ "globalVariables": { "blockNumber": 2, "chainId": 31337, - "timestamp": 1715959589, + "timestamp": 1716042415, "version": 1, - "coinbase": "0xe8bf4f268ec70317922965dcc848cab31883f841", - "feeRecipient": "0x2d2fc61c2ed4df01168b2e4bff9e801fa0feb1bb2b874944e60402e21f611e9a", + "coinbase": "0xbe70f89d75a00bd140342ebc63beb517cf9735bc", + "feeRecipient": "0x08eb6120958820f4b4fd61a9bcaa32c33349663034e1db315ba57c67d155b172", "gasFees": { "feePerDaGas": 0, "feePerL2Gas": 0 @@ -32,7 +32,7 @@ }, "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x2ef0cbb8a2651d0ddd89c84019bcbfa6f992adcf28831c4767a2c592f35d41ba" + "root": "0x0ed815d35918f1aabf391fa174a1d95476da157e40b7fc581b2c8f4cfd23e6b3" }, "stateReference": { "l1ToL2MessageTree": { @@ -55,8 +55,8 @@ } } }, - "header": "0x2ef0cbb8a2651d0ddd89c84019bcbfa6f992adcf28831c4767a2c592f35d41ba000000020000000000000000000000000000000000000000000000000000000000000001002676dbd818b1ba16e11597cb5c07b06aa7771127b02a77d0c3a6039bb9fef100089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c31864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000002016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000001000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000c00000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000066477725e8bf4f268ec70317922965dcc848cab31883f8412d2fc61c2ed4df01168b2e4bff9e801fa0feb1bb2b874944e60402e21f611e9a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "publicInputsHash": "0x00d89e3c39acef7f079096f4efbef7d34addd5e3524d5d0a8849ff6aae4fd55d", + "header": "0x0ed815d35918f1aabf391fa174a1d95476da157e40b7fc581b2c8f4cfd23e6b3000000020000000000000000000000000000000000000000000000000000000000000001002676dbd818b1ba16e11597cb5c07b06aa7771127b02a77d0c3a6039bb9fef100089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c31864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000002016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000001000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000c00000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000006648baafbe70f89d75a00bd140342ebc63beb517cf9735bc08eb6120958820f4b4fd61a9bcaa32c33349663034e1db315ba57c67d155b17200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x0033d4785f37dafeeb7e50eeef42002f0af7d1d62913119754b81cfe7ebc5217", "numTxs": 0 } } \ No newline at end of file diff --git a/l1-contracts/test/fixtures/mixed_block_0.json b/l1-contracts/test/fixtures/mixed_block_0.json index 4ac9dde40b0..48f9c97bf8f 100644 --- a/l1-contracts/test/fixtures/mixed_block_0.json +++ b/l1-contracts/test/fixtures/mixed_block_0.json @@ -34,7 +34,7 @@ ] }, "block": { - "archive": "0x11a629e4167f118118a0389eddd379b5a7338added581a7e3b3474d4693d76c1", + "archive": "0x21a504c1644ee56efe1d5c7690d6edc47b21a389e718f2202bcdc6ea4f879b0e", "body": "0x00000004000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000015100000000000000000000000000000000000000000000000000000000000001520000000000000000000000000000000000000000000000000000000000000153000000000000000000000000000000000000000000000000000000000000015400000000000000000000000000000000000000000000000000000000000001550000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000015700000000000000000000000000000000000000000000000000000000000001580000000000000000000000000000000000000000000000000000000000000159000000000000000000000000000000000000000000000000000000000000015a000000000000000000000000000000000000000000000000000000000000015b000000000000000000000000000000000000000000000000000000000000015c000000000000000000000000000000000000000000000000000000000000015d000000000000000000000000000000000000000000000000000000000000015e000000000000000000000000000000000000000000000000000000000000015f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f0000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000017100000000000000000000000000000000000000000000000000000000000001720000000000000000000000000000000000000000000000000000000000000173000000000000000000000000000000000000000000000000000000000000017400000000000000000000000000000000000000000000000000000000000001750000000000000000000000000000000000000000000000000000000000000176000000000000000000000000000000000000000000000000000000000000017700000000000000000000000000000000000000000000000000000000000001780000000000000000000000000000000000000000000000000000000000000179000000000000000000000000000000000000000000000000000000000000017a000000000000000000000000000000000000000000000000000000000000017b000000000000000000000000000000000000000000000000000000000000017c000000000000000000000000000000000000000000000000000000000000017d000000000000000000000000000000000000000000000000000000000000017e000000000000000000000000000000000000000000000000000000000000017f3f0000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f0000000000000000000000000000000000000000000000000000000000000270000000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000002720000000000000000000000000000000000000000000000000000000000000273000000000000000000000000000000000000000000000000000000000000027400000000000000000000000000000000000000000000000000000000000002750000000000000000000000000000000000000000000000000000000000000276000000000000000000000000000000000000000000000000000000000000027700000000000000000000000000000000000000000000000000000000000002780000000000000000000000000000000000000000000000000000000000000279000000000000000000000000000000000000000000000000000000000000027a000000000000000000000000000000000000000000000000000000000000027b000000000000000000000000000000000000000000000000000000000000027c000000000000000000000000000000000000000000000000000000000000027d000000000000000000000000000000000000000000000000000000000000027e0200000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000341200000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000544000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000545000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000054700000000000000000000000000000000000000000000000000000000000005510000000000000000000000000000000000000000000000000000000000000548000000000000000000000000000000000000000000000000000000000000055200000000000000000000000000000000000000000000000000000000000005490000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000556000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000557000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005590000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000055a0000000000000000000000000000000000000000000000000000000000000551000000000000000000000000000000000000000000000000000000000000055b0000000000000000000000000000000000000000000000000000000000000552000000000000000000000000000000000000000000000000000000000000055c0000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000055d0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000055e0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000055f00000000000000000000000000000000000000000000000000000000000005560000000000000000000000000000000000000000000000000000000000000560000000000000000000000000000000000000000000000000000000000000055700000000000000000000000000000000000000000000000000000000000005610000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000056200000000000000000000000000000000000000000000000000000000000005590000000000000000000000000000000000000000000000000000000000000563000000000000000000000000000000000000000000000000000000000000055a0000000000000000000000000000000000000000000000000000000000000564000000000000000000000000000000000000000000000000000000000000055b0000000000000000000000000000000000000000000000000000000000000565000000000000000000000000000000000000000000000000000000000000055c0000000000000000000000000000000000000000000000000000000000000566000000000000000000000000000000000000000000000000000000000000055d0000000000000000000000000000000000000000000000000000000000000567000000000000000000000000000000000000000000000000000000000000055e0000000000000000000000000000000000000000000000000000000000000568000000000000000000000000000000000000000000000000000000000000055f000000000000000000000000000000000000000000000000000000000000056900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f0000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019100000000000000000000000000000000000000000000000000000000000001920000000000000000000000000000000000000000000000000000000000000193000000000000000000000000000000000000000000000000000000000000019400000000000000000000000000000000000000000000000000000000000001950000000000000000000000000000000000000000000000000000000000000196000000000000000000000000000000000000000000000000000000000000019700000000000000000000000000000000000000000000000000000000000001980000000000000000000000000000000000000000000000000000000000000199000000000000000000000000000000000000000000000000000000000000019a000000000000000000000000000000000000000000000000000000000000019b000000000000000000000000000000000000000000000000000000000000019c000000000000000000000000000000000000000000000000000000000000019d000000000000000000000000000000000000000000000000000000000000019e000000000000000000000000000000000000000000000000000000000000019f00000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001a100000000000000000000000000000000000000000000000000000000000001a200000000000000000000000000000000000000000000000000000000000001a300000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000001a500000000000000000000000000000000000000000000000000000000000001a600000000000000000000000000000000000000000000000000000000000001a700000000000000000000000000000000000000000000000000000000000001a800000000000000000000000000000000000000000000000000000000000001a900000000000000000000000000000000000000000000000000000000000001aa00000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000001ac00000000000000000000000000000000000000000000000000000000000001ad00000000000000000000000000000000000000000000000000000000000001ae00000000000000000000000000000000000000000000000000000000000001af00000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b100000000000000000000000000000000000000000000000000000000000001b200000000000000000000000000000000000000000000000000000000000001b300000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001b500000000000000000000000000000000000000000000000000000000000001b600000000000000000000000000000000000000000000000000000000000001b700000000000000000000000000000000000000000000000000000000000001b800000000000000000000000000000000000000000000000000000000000001b900000000000000000000000000000000000000000000000000000000000001ba00000000000000000000000000000000000000000000000000000000000001bb00000000000000000000000000000000000000000000000000000000000001bc00000000000000000000000000000000000000000000000000000000000001bd00000000000000000000000000000000000000000000000000000000000001be00000000000000000000000000000000000000000000000000000000000001bf3f0000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b700000000000000000000000000000000000000000000000000000000000002b800000000000000000000000000000000000000000000000000000000000002b900000000000000000000000000000000000000000000000000000000000002ba00000000000000000000000000000000000000000000000000000000000002bb00000000000000000000000000000000000000000000000000000000000002bc00000000000000000000000000000000000000000000000000000000000002bd00000000000000000000000000000000000000000000000000000000000002be0200000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000381200000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005860000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000058700000000000000000000000000000000000000000000000000000000000005910000000000000000000000000000000000000000000000000000000000000588000000000000000000000000000000000000000000000000000000000000059200000000000000000000000000000000000000000000000000000000000005890000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000596000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000597000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000598000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005990000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000059a0000000000000000000000000000000000000000000000000000000000000591000000000000000000000000000000000000000000000000000000000000059b0000000000000000000000000000000000000000000000000000000000000592000000000000000000000000000000000000000000000000000000000000059c0000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000059d0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000059e0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000059f000000000000000000000000000000000000000000000000000000000000059600000000000000000000000000000000000000000000000000000000000005a0000000000000000000000000000000000000000000000000000000000000059700000000000000000000000000000000000000000000000000000000000005a1000000000000000000000000000000000000000000000000000000000000059800000000000000000000000000000000000000000000000000000000000005a2000000000000000000000000000000000000000000000000000000000000059900000000000000000000000000000000000000000000000000000000000005a3000000000000000000000000000000000000000000000000000000000000059a00000000000000000000000000000000000000000000000000000000000005a4000000000000000000000000000000000000000000000000000000000000059b00000000000000000000000000000000000000000000000000000000000005a5000000000000000000000000000000000000000000000000000000000000059c00000000000000000000000000000000000000000000000000000000000005a6000000000000000000000000000000000000000000000000000000000000059d00000000000000000000000000000000000000000000000000000000000005a7000000000000000000000000000000000000000000000000000000000000059e00000000000000000000000000000000000000000000000000000000000005a8000000000000000000000000000000000000000000000000000000000000059f00000000000000000000000000000000000000000000000000000000000005a9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001c100000000000000000000000000000000000000000000000000000000000001c200000000000000000000000000000000000000000000000000000000000001c300000000000000000000000000000000000000000000000000000000000001c400000000000000000000000000000000000000000000000000000000000001c500000000000000000000000000000000000000000000000000000000000001c600000000000000000000000000000000000000000000000000000000000001c700000000000000000000000000000000000000000000000000000000000001c800000000000000000000000000000000000000000000000000000000000001c900000000000000000000000000000000000000000000000000000000000001ca00000000000000000000000000000000000000000000000000000000000001cb00000000000000000000000000000000000000000000000000000000000001cc00000000000000000000000000000000000000000000000000000000000001cd00000000000000000000000000000000000000000000000000000000000001ce00000000000000000000000000000000000000000000000000000000000001cf00000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001d100000000000000000000000000000000000000000000000000000000000001d200000000000000000000000000000000000000000000000000000000000001d300000000000000000000000000000000000000000000000000000000000001d400000000000000000000000000000000000000000000000000000000000001d500000000000000000000000000000000000000000000000000000000000001d600000000000000000000000000000000000000000000000000000000000001d700000000000000000000000000000000000000000000000000000000000001d800000000000000000000000000000000000000000000000000000000000001d900000000000000000000000000000000000000000000000000000000000001da00000000000000000000000000000000000000000000000000000000000001db00000000000000000000000000000000000000000000000000000000000001dc00000000000000000000000000000000000000000000000000000000000001dd00000000000000000000000000000000000000000000000000000000000001de00000000000000000000000000000000000000000000000000000000000001df00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001e100000000000000000000000000000000000000000000000000000000000001e200000000000000000000000000000000000000000000000000000000000001e300000000000000000000000000000000000000000000000000000000000001e400000000000000000000000000000000000000000000000000000000000001e500000000000000000000000000000000000000000000000000000000000001e600000000000000000000000000000000000000000000000000000000000001e700000000000000000000000000000000000000000000000000000000000001e800000000000000000000000000000000000000000000000000000000000001e900000000000000000000000000000000000000000000000000000000000001ea00000000000000000000000000000000000000000000000000000000000001eb00000000000000000000000000000000000000000000000000000000000001ec00000000000000000000000000000000000000000000000000000000000001ed00000000000000000000000000000000000000000000000000000000000001ee00000000000000000000000000000000000000000000000000000000000001ef00000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000001f100000000000000000000000000000000000000000000000000000000000001f200000000000000000000000000000000000000000000000000000000000001f300000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000001f500000000000000000000000000000000000000000000000000000000000001f600000000000000000000000000000000000000000000000000000000000001f700000000000000000000000000000000000000000000000000000000000001f800000000000000000000000000000000000000000000000000000000000001f900000000000000000000000000000000000000000000000000000000000001fa00000000000000000000000000000000000000000000000000000000000001fb00000000000000000000000000000000000000000000000000000000000001fc00000000000000000000000000000000000000000000000000000000000001fd00000000000000000000000000000000000000000000000000000000000001fe00000000000000000000000000000000000000000000000000000000000001ff3f00000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f700000000000000000000000000000000000000000000000000000000000002f800000000000000000000000000000000000000000000000000000000000002f900000000000000000000000000000000000000000000000000000000000002fa00000000000000000000000000000000000000000000000000000000000002fb00000000000000000000000000000000000000000000000000000000000002fc00000000000000000000000000000000000000000000000000000000000002fd00000000000000000000000000000000000000000000000000000000000002fe0200000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c12000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005c100000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005c200000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005c300000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005c400000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005c500000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005c600000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005c700000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005c800000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005c900000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005d900000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005da00000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005db00000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005dc00000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005dd00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005de00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005df00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005e000000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005e100000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005e200000000000000000000000000000000000000000000000000000000000005d900000000000000000000000000000000000000000000000000000000000005e300000000000000000000000000000000000000000000000000000000000005da00000000000000000000000000000000000000000000000000000000000005e400000000000000000000000000000000000000000000000000000000000005db00000000000000000000000000000000000000000000000000000000000005e500000000000000000000000000000000000000000000000000000000000005dc00000000000000000000000000000000000000000000000000000000000005e600000000000000000000000000000000000000000000000000000000000005dd00000000000000000000000000000000000000000000000000000000000005e700000000000000000000000000000000000000000000000000000000000005de00000000000000000000000000000000000000000000000000000000000005e800000000000000000000000000000000000000000000000000000000000005df00000000000000000000000000000000000000000000000000000000000005e900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020100000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000000000000000000000000000000000020400000000000000000000000000000000000000000000000000000000000002050000000000000000000000000000000000000000000000000000000000000206000000000000000000000000000000000000000000000000000000000000020700000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000209000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020d000000000000000000000000000000000000000000000000000000000000020e000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000021100000000000000000000000000000000000000000000000000000000000002120000000000000000000000000000000000000000000000000000000000000213000000000000000000000000000000000000000000000000000000000000021400000000000000000000000000000000000000000000000000000000000002150000000000000000000000000000000000000000000000000000000000000216000000000000000000000000000000000000000000000000000000000000021700000000000000000000000000000000000000000000000000000000000002180000000000000000000000000000000000000000000000000000000000000219000000000000000000000000000000000000000000000000000000000000021a000000000000000000000000000000000000000000000000000000000000021b000000000000000000000000000000000000000000000000000000000000021c000000000000000000000000000000000000000000000000000000000000021d000000000000000000000000000000000000000000000000000000000000021e000000000000000000000000000000000000000000000000000000000000021f0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e000000000000000000000000000000000000000000000000000000000000022f0000000000000000000000000000000000000000000000000000000000000230000000000000000000000000000000000000000000000000000000000000023100000000000000000000000000000000000000000000000000000000000002320000000000000000000000000000000000000000000000000000000000000233000000000000000000000000000000000000000000000000000000000000023400000000000000000000000000000000000000000000000000000000000002350000000000000000000000000000000000000000000000000000000000000236000000000000000000000000000000000000000000000000000000000000023700000000000000000000000000000000000000000000000000000000000002380000000000000000000000000000000000000000000000000000000000000239000000000000000000000000000000000000000000000000000000000000023a000000000000000000000000000000000000000000000000000000000000023b000000000000000000000000000000000000000000000000000000000000023c000000000000000000000000000000000000000000000000000000000000023d000000000000000000000000000000000000000000000000000000000000023e000000000000000000000000000000000000000000000000000000000000023f3f0000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f0000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000033100000000000000000000000000000000000000000000000000000000000003320000000000000000000000000000000000000000000000000000000000000333000000000000000000000000000000000000000000000000000000000000033400000000000000000000000000000000000000000000000000000000000003350000000000000000000000000000000000000000000000000000000000000336000000000000000000000000000000000000000000000000000000000000033700000000000000000000000000000000000000000000000000000000000003380000000000000000000000000000000000000000000000000000000000000339000000000000000000000000000000000000000000000000000000000000033a000000000000000000000000000000000000000000000000000000000000033b000000000000000000000000000000000000000000000000000000000000033c000000000000000000000000000000000000000000000000000000000000033d000000000000000000000000000000000000000000000000000000000000033e0200000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000401200000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000601000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000602000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000603000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000604000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000605000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006060000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000060700000000000000000000000000000000000000000000000000000000000006110000000000000000000000000000000000000000000000000000000000000608000000000000000000000000000000000000000000000000000000000000061200000000000000000000000000000000000000000000000000000000000006090000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000616000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000617000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006190000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000061a0000000000000000000000000000000000000000000000000000000000000611000000000000000000000000000000000000000000000000000000000000061b0000000000000000000000000000000000000000000000000000000000000612000000000000000000000000000000000000000000000000000000000000061c0000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000061d0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000061e0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000061f00000000000000000000000000000000000000000000000000000000000006160000000000000000000000000000000000000000000000000000000000000620000000000000000000000000000000000000000000000000000000000000061700000000000000000000000000000000000000000000000000000000000006210000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000062200000000000000000000000000000000000000000000000000000000000006190000000000000000000000000000000000000000000000000000000000000623000000000000000000000000000000000000000000000000000000000000061a0000000000000000000000000000000000000000000000000000000000000624000000000000000000000000000000000000000000000000000000000000061b0000000000000000000000000000000000000000000000000000000000000625000000000000000000000000000000000000000000000000000000000000061c0000000000000000000000000000000000000000000000000000000000000626000000000000000000000000000000000000000000000000000000000000061d0000000000000000000000000000000000000000000000000000000000000627000000000000000000000000000000000000000000000000000000000000061e0000000000000000000000000000000000000000000000000000000000000628000000000000000000000000000000000000000000000000000000000000061f000000000000000000000000000000000000000000000000000000000000062900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "txsEffectsHash": "0x0048ce729bd26a2be2b87719b8682891daaf022265be6cb3460d1f654f325dab", "decodedHeader": { @@ -49,8 +49,8 @@ "chainId": 31337, "timestamp": 0, "version": 1, - "coinbase": "0x43c5c3afd0f9b6c7cee8242ff8af10404a1ba21c", - "feeRecipient": "0x0e1c708110a8c246a71094fa18ac188fe2df70ea87235a2fcb86e80c9534c33c", + "coinbase": "0xe19d288dac593449f143689ea3563e9d960e0ae6", + "feeRecipient": "0x20f9afacaabdb5bca38f3586fad6ab2e72f75560e1504f8c3de2061b2283b25a", "gasFees": { "feePerDaGas": 0, "feePerL2Gas": 0 @@ -81,8 +81,8 @@ } } }, - "header": "0x067a48e3140b6f15d71751ededfa0cccde3d436bb71aa7fec226b0bfe51dc5cf0000000100000000000000000000000000000000000000000000000000000000000000020048ce729bd26a2be2b87719b8682891daaf022265be6cb3460d1f654f325dab00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c00198704eb051da0e43ff1a9b3285f168389ba3dd93f8ec1f75f6cafcadbaeb61864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000100d944282e11bdcfa5e8f2b55fe80db4c586087bfc10e0bbba5724d30b8c15e2e0000010001c16141039343d4d403501e66deecff1b024bd76794820a43dc3424087813a20000018028d06967b6a4a1cc3c799fb6f008b63a2ffecd5034b81aa10792a6659f8aca22000000c00000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000043c5c3afd0f9b6c7cee8242ff8af10404a1ba21c0e1c708110a8c246a71094fa18ac188fe2df70ea87235a2fcb86e80c9534c33c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "publicInputsHash": "0x00fd059737300f8388174cd8c94763f185b83bd2f3be6c219a4c7b7fd895e0eb", + "header": "0x067a48e3140b6f15d71751ededfa0cccde3d436bb71aa7fec226b0bfe51dc5cf0000000100000000000000000000000000000000000000000000000000000000000000020048ce729bd26a2be2b87719b8682891daaf022265be6cb3460d1f654f325dab00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c00198704eb051da0e43ff1a9b3285f168389ba3dd93f8ec1f75f6cafcadbaeb61864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000100d944282e11bdcfa5e8f2b55fe80db4c586087bfc10e0bbba5724d30b8c15e2e0000010001c16141039343d4d403501e66deecff1b024bd76794820a43dc3424087813a20000018028d06967b6a4a1cc3c799fb6f008b63a2ffecd5034b81aa10792a6659f8aca22000000c00000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000e19d288dac593449f143689ea3563e9d960e0ae620f9afacaabdb5bca38f3586fad6ab2e72f75560e1504f8c3de2061b2283b25a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x004af29de40359d7c79637dce0ef57c561cb5ff283602607c6f644cb019fa526", "numTxs": 4 } } \ No newline at end of file diff --git a/l1-contracts/test/fixtures/mixed_block_1.json b/l1-contracts/test/fixtures/mixed_block_1.json index 193f0b0395a..2fe88df3c70 100644 --- a/l1-contracts/test/fixtures/mixed_block_1.json +++ b/l1-contracts/test/fixtures/mixed_block_1.json @@ -34,7 +34,7 @@ ] }, "block": { - "archive": "0x0af5731229853077b73680999f50f0a61a30191a16b5b03fb2a78008a444893d", + "archive": "0x1d882133187105c8d7ed6177b59d8c5462ce1a562537ccec510d9879caf10c7c", "body": "0x00000004000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f0000000000000000000000000000000000000000000000000000000000000270000000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000002720000000000000000000000000000000000000000000000000000000000000273000000000000000000000000000000000000000000000000000000000000027400000000000000000000000000000000000000000000000000000000000002750000000000000000000000000000000000000000000000000000000000000276000000000000000000000000000000000000000000000000000000000000027700000000000000000000000000000000000000000000000000000000000002780000000000000000000000000000000000000000000000000000000000000279000000000000000000000000000000000000000000000000000000000000027a000000000000000000000000000000000000000000000000000000000000027b000000000000000000000000000000000000000000000000000000000000027c000000000000000000000000000000000000000000000000000000000000027d000000000000000000000000000000000000000000000000000000000000027e000000000000000000000000000000000000000000000000000000000000027f3f0000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003420000000000000000000000000000000000000000000000000000000000000343000000000000000000000000000000000000000000000000000000000000034400000000000000000000000000000000000000000000000000000000000003450000000000000000000000000000000000000000000000000000000000000346000000000000000000000000000000000000000000000000000000000000034700000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000349000000000000000000000000000000000000000000000000000000000000034a000000000000000000000000000000000000000000000000000000000000034b000000000000000000000000000000000000000000000000000000000000034c000000000000000000000000000000000000000000000000000000000000034d000000000000000000000000000000000000000000000000000000000000034e000000000000000000000000000000000000000000000000000000000000034f0000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035100000000000000000000000000000000000000000000000000000000000003520000000000000000000000000000000000000000000000000000000000000353000000000000000000000000000000000000000000000000000000000000035400000000000000000000000000000000000000000000000000000000000003550000000000000000000000000000000000000000000000000000000000000356000000000000000000000000000000000000000000000000000000000000035700000000000000000000000000000000000000000000000000000000000003580000000000000000000000000000000000000000000000000000000000000359000000000000000000000000000000000000000000000000000000000000035a000000000000000000000000000000000000000000000000000000000000035b000000000000000000000000000000000000000000000000000000000000035c000000000000000000000000000000000000000000000000000000000000035d000000000000000000000000000000000000000000000000000000000000035e000000000000000000000000000000000000000000000000000000000000035f0000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036100000000000000000000000000000000000000000000000000000000000003620000000000000000000000000000000000000000000000000000000000000363000000000000000000000000000000000000000000000000000000000000036400000000000000000000000000000000000000000000000000000000000003650000000000000000000000000000000000000000000000000000000000000366000000000000000000000000000000000000000000000000000000000000036700000000000000000000000000000000000000000000000000000000000003680000000000000000000000000000000000000000000000000000000000000369000000000000000000000000000000000000000000000000000000000000036a000000000000000000000000000000000000000000000000000000000000036b000000000000000000000000000000000000000000000000000000000000036c000000000000000000000000000000000000000000000000000000000000036d000000000000000000000000000000000000000000000000000000000000036e000000000000000000000000000000000000000000000000000000000000036f0000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000037100000000000000000000000000000000000000000000000000000000000003720000000000000000000000000000000000000000000000000000000000000373000000000000000000000000000000000000000000000000000000000000037400000000000000000000000000000000000000000000000000000000000003750000000000000000000000000000000000000000000000000000000000000376000000000000000000000000000000000000000000000000000000000000037700000000000000000000000000000000000000000000000000000000000003780000000000000000000000000000000000000000000000000000000000000379000000000000000000000000000000000000000000000000000000000000037a000000000000000000000000000000000000000000000000000000000000037b000000000000000000000000000000000000000000000000000000000000037c000000000000000000000000000000000000000000000000000000000000037d000000000000000000000000000000000000000000000000000000000000037e0200000000000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000441200000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000641000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000642000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000643000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000644000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000645000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006460000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000064700000000000000000000000000000000000000000000000000000000000006510000000000000000000000000000000000000000000000000000000000000648000000000000000000000000000000000000000000000000000000000000065200000000000000000000000000000000000000000000000000000000000006490000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000656000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000657000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006590000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000065a0000000000000000000000000000000000000000000000000000000000000651000000000000000000000000000000000000000000000000000000000000065b0000000000000000000000000000000000000000000000000000000000000652000000000000000000000000000000000000000000000000000000000000065c0000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000065d0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000065e0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000065f00000000000000000000000000000000000000000000000000000000000006560000000000000000000000000000000000000000000000000000000000000660000000000000000000000000000000000000000000000000000000000000065700000000000000000000000000000000000000000000000000000000000006610000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000066200000000000000000000000000000000000000000000000000000000000006590000000000000000000000000000000000000000000000000000000000000663000000000000000000000000000000000000000000000000000000000000065a0000000000000000000000000000000000000000000000000000000000000664000000000000000000000000000000000000000000000000000000000000065b0000000000000000000000000000000000000000000000000000000000000665000000000000000000000000000000000000000000000000000000000000065c0000000000000000000000000000000000000000000000000000000000000666000000000000000000000000000000000000000000000000000000000000065d0000000000000000000000000000000000000000000000000000000000000667000000000000000000000000000000000000000000000000000000000000065e0000000000000000000000000000000000000000000000000000000000000668000000000000000000000000000000000000000000000000000000000000065f000000000000000000000000000000000000000000000000000000000000066900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b700000000000000000000000000000000000000000000000000000000000002b800000000000000000000000000000000000000000000000000000000000002b900000000000000000000000000000000000000000000000000000000000002ba00000000000000000000000000000000000000000000000000000000000002bb00000000000000000000000000000000000000000000000000000000000002bc00000000000000000000000000000000000000000000000000000000000002bd00000000000000000000000000000000000000000000000000000000000002be00000000000000000000000000000000000000000000000000000000000002bf3f0000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003820000000000000000000000000000000000000000000000000000000000000383000000000000000000000000000000000000000000000000000000000000038400000000000000000000000000000000000000000000000000000000000003850000000000000000000000000000000000000000000000000000000000000386000000000000000000000000000000000000000000000000000000000000038700000000000000000000000000000000000000000000000000000000000003880000000000000000000000000000000000000000000000000000000000000389000000000000000000000000000000000000000000000000000000000000038a000000000000000000000000000000000000000000000000000000000000038b000000000000000000000000000000000000000000000000000000000000038c000000000000000000000000000000000000000000000000000000000000038d000000000000000000000000000000000000000000000000000000000000038e000000000000000000000000000000000000000000000000000000000000038f0000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000039100000000000000000000000000000000000000000000000000000000000003920000000000000000000000000000000000000000000000000000000000000393000000000000000000000000000000000000000000000000000000000000039400000000000000000000000000000000000000000000000000000000000003950000000000000000000000000000000000000000000000000000000000000396000000000000000000000000000000000000000000000000000000000000039700000000000000000000000000000000000000000000000000000000000003980000000000000000000000000000000000000000000000000000000000000399000000000000000000000000000000000000000000000000000000000000039a000000000000000000000000000000000000000000000000000000000000039b000000000000000000000000000000000000000000000000000000000000039c000000000000000000000000000000000000000000000000000000000000039d000000000000000000000000000000000000000000000000000000000000039e000000000000000000000000000000000000000000000000000000000000039f00000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a100000000000000000000000000000000000000000000000000000000000003a200000000000000000000000000000000000000000000000000000000000003a300000000000000000000000000000000000000000000000000000000000003a400000000000000000000000000000000000000000000000000000000000003a500000000000000000000000000000000000000000000000000000000000003a600000000000000000000000000000000000000000000000000000000000003a700000000000000000000000000000000000000000000000000000000000003a800000000000000000000000000000000000000000000000000000000000003a900000000000000000000000000000000000000000000000000000000000003aa00000000000000000000000000000000000000000000000000000000000003ab00000000000000000000000000000000000000000000000000000000000003ac00000000000000000000000000000000000000000000000000000000000003ad00000000000000000000000000000000000000000000000000000000000003ae00000000000000000000000000000000000000000000000000000000000003af00000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b100000000000000000000000000000000000000000000000000000000000003b200000000000000000000000000000000000000000000000000000000000003b300000000000000000000000000000000000000000000000000000000000003b400000000000000000000000000000000000000000000000000000000000003b500000000000000000000000000000000000000000000000000000000000003b600000000000000000000000000000000000000000000000000000000000003b700000000000000000000000000000000000000000000000000000000000003b800000000000000000000000000000000000000000000000000000000000003b900000000000000000000000000000000000000000000000000000000000003ba00000000000000000000000000000000000000000000000000000000000003bb00000000000000000000000000000000000000000000000000000000000003bc00000000000000000000000000000000000000000000000000000000000003bd00000000000000000000000000000000000000000000000000000000000003be0200000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000481200000000000000000000000000000000000000000000000000000000000000680000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000681000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000682000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000683000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000684000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000685000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006860000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000068700000000000000000000000000000000000000000000000000000000000006910000000000000000000000000000000000000000000000000000000000000688000000000000000000000000000000000000000000000000000000000000069200000000000000000000000000000000000000000000000000000000000006890000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000696000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000697000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000698000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006990000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000069a0000000000000000000000000000000000000000000000000000000000000691000000000000000000000000000000000000000000000000000000000000069b0000000000000000000000000000000000000000000000000000000000000692000000000000000000000000000000000000000000000000000000000000069c0000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000069d0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000069e0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000069f000000000000000000000000000000000000000000000000000000000000069600000000000000000000000000000000000000000000000000000000000006a0000000000000000000000000000000000000000000000000000000000000069700000000000000000000000000000000000000000000000000000000000006a1000000000000000000000000000000000000000000000000000000000000069800000000000000000000000000000000000000000000000000000000000006a2000000000000000000000000000000000000000000000000000000000000069900000000000000000000000000000000000000000000000000000000000006a3000000000000000000000000000000000000000000000000000000000000069a00000000000000000000000000000000000000000000000000000000000006a4000000000000000000000000000000000000000000000000000000000000069b00000000000000000000000000000000000000000000000000000000000006a5000000000000000000000000000000000000000000000000000000000000069c00000000000000000000000000000000000000000000000000000000000006a6000000000000000000000000000000000000000000000000000000000000069d00000000000000000000000000000000000000000000000000000000000006a7000000000000000000000000000000000000000000000000000000000000069e00000000000000000000000000000000000000000000000000000000000006a8000000000000000000000000000000000000000000000000000000000000069f00000000000000000000000000000000000000000000000000000000000006a9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f700000000000000000000000000000000000000000000000000000000000002f800000000000000000000000000000000000000000000000000000000000002f900000000000000000000000000000000000000000000000000000000000002fa00000000000000000000000000000000000000000000000000000000000002fb00000000000000000000000000000000000000000000000000000000000002fc00000000000000000000000000000000000000000000000000000000000002fd00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000002ff3f00000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000003c200000000000000000000000000000000000000000000000000000000000003c300000000000000000000000000000000000000000000000000000000000003c400000000000000000000000000000000000000000000000000000000000003c500000000000000000000000000000000000000000000000000000000000003c600000000000000000000000000000000000000000000000000000000000003c700000000000000000000000000000000000000000000000000000000000003c800000000000000000000000000000000000000000000000000000000000003c900000000000000000000000000000000000000000000000000000000000003ca00000000000000000000000000000000000000000000000000000000000003cb00000000000000000000000000000000000000000000000000000000000003cc00000000000000000000000000000000000000000000000000000000000003cd00000000000000000000000000000000000000000000000000000000000003ce00000000000000000000000000000000000000000000000000000000000003cf00000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d100000000000000000000000000000000000000000000000000000000000003d200000000000000000000000000000000000000000000000000000000000003d300000000000000000000000000000000000000000000000000000000000003d400000000000000000000000000000000000000000000000000000000000003d500000000000000000000000000000000000000000000000000000000000003d600000000000000000000000000000000000000000000000000000000000003d700000000000000000000000000000000000000000000000000000000000003d800000000000000000000000000000000000000000000000000000000000003d900000000000000000000000000000000000000000000000000000000000003da00000000000000000000000000000000000000000000000000000000000003db00000000000000000000000000000000000000000000000000000000000003dc00000000000000000000000000000000000000000000000000000000000003dd00000000000000000000000000000000000000000000000000000000000003de00000000000000000000000000000000000000000000000000000000000003df00000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e100000000000000000000000000000000000000000000000000000000000003e200000000000000000000000000000000000000000000000000000000000003e300000000000000000000000000000000000000000000000000000000000003e400000000000000000000000000000000000000000000000000000000000003e500000000000000000000000000000000000000000000000000000000000003e600000000000000000000000000000000000000000000000000000000000003e700000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000003ea00000000000000000000000000000000000000000000000000000000000003eb00000000000000000000000000000000000000000000000000000000000003ec00000000000000000000000000000000000000000000000000000000000003ed00000000000000000000000000000000000000000000000000000000000003ee00000000000000000000000000000000000000000000000000000000000003ef00000000000000000000000000000000000000000000000000000000000003f000000000000000000000000000000000000000000000000000000000000003f100000000000000000000000000000000000000000000000000000000000003f200000000000000000000000000000000000000000000000000000000000003f300000000000000000000000000000000000000000000000000000000000003f400000000000000000000000000000000000000000000000000000000000003f500000000000000000000000000000000000000000000000000000000000003f600000000000000000000000000000000000000000000000000000000000003f700000000000000000000000000000000000000000000000000000000000003f800000000000000000000000000000000000000000000000000000000000003f900000000000000000000000000000000000000000000000000000000000003fa00000000000000000000000000000000000000000000000000000000000003fb00000000000000000000000000000000000000000000000000000000000003fc00000000000000000000000000000000000000000000000000000000000003fd00000000000000000000000000000000000000000000000000000000000003fe0200000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004c12000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006c100000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006c200000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006c300000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006c400000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006c500000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006c600000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006c700000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006c800000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006c900000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006d900000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006da00000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006db00000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006dc00000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006dd00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006de00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006df00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006e000000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006e100000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006e200000000000000000000000000000000000000000000000000000000000006d900000000000000000000000000000000000000000000000000000000000006e300000000000000000000000000000000000000000000000000000000000006da00000000000000000000000000000000000000000000000000000000000006e400000000000000000000000000000000000000000000000000000000000006db00000000000000000000000000000000000000000000000000000000000006e500000000000000000000000000000000000000000000000000000000000006dc00000000000000000000000000000000000000000000000000000000000006e600000000000000000000000000000000000000000000000000000000000006dd00000000000000000000000000000000000000000000000000000000000006e700000000000000000000000000000000000000000000000000000000000006de00000000000000000000000000000000000000000000000000000000000006e800000000000000000000000000000000000000000000000000000000000006df00000000000000000000000000000000000000000000000000000000000006e900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f0000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000033100000000000000000000000000000000000000000000000000000000000003320000000000000000000000000000000000000000000000000000000000000333000000000000000000000000000000000000000000000000000000000000033400000000000000000000000000000000000000000000000000000000000003350000000000000000000000000000000000000000000000000000000000000336000000000000000000000000000000000000000000000000000000000000033700000000000000000000000000000000000000000000000000000000000003380000000000000000000000000000000000000000000000000000000000000339000000000000000000000000000000000000000000000000000000000000033a000000000000000000000000000000000000000000000000000000000000033b000000000000000000000000000000000000000000000000000000000000033c000000000000000000000000000000000000000000000000000000000000033d000000000000000000000000000000000000000000000000000000000000033e000000000000000000000000000000000000000000000000000000000000033f3f0000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040100000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000403000000000000000000000000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000004050000000000000000000000000000000000000000000000000000000000000406000000000000000000000000000000000000000000000000000000000000040700000000000000000000000000000000000000000000000000000000000004080000000000000000000000000000000000000000000000000000000000000409000000000000000000000000000000000000000000000000000000000000040a000000000000000000000000000000000000000000000000000000000000040b000000000000000000000000000000000000000000000000000000000000040c000000000000000000000000000000000000000000000000000000000000040d000000000000000000000000000000000000000000000000000000000000040e000000000000000000000000000000000000000000000000000000000000040f0000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000041100000000000000000000000000000000000000000000000000000000000004120000000000000000000000000000000000000000000000000000000000000413000000000000000000000000000000000000000000000000000000000000041400000000000000000000000000000000000000000000000000000000000004150000000000000000000000000000000000000000000000000000000000000416000000000000000000000000000000000000000000000000000000000000041700000000000000000000000000000000000000000000000000000000000004180000000000000000000000000000000000000000000000000000000000000419000000000000000000000000000000000000000000000000000000000000041a000000000000000000000000000000000000000000000000000000000000041b000000000000000000000000000000000000000000000000000000000000041c000000000000000000000000000000000000000000000000000000000000041d000000000000000000000000000000000000000000000000000000000000041e000000000000000000000000000000000000000000000000000000000000041f0000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000042100000000000000000000000000000000000000000000000000000000000004220000000000000000000000000000000000000000000000000000000000000423000000000000000000000000000000000000000000000000000000000000042400000000000000000000000000000000000000000000000000000000000004250000000000000000000000000000000000000000000000000000000000000426000000000000000000000000000000000000000000000000000000000000042700000000000000000000000000000000000000000000000000000000000004280000000000000000000000000000000000000000000000000000000000000429000000000000000000000000000000000000000000000000000000000000042a000000000000000000000000000000000000000000000000000000000000042b000000000000000000000000000000000000000000000000000000000000042c000000000000000000000000000000000000000000000000000000000000042d000000000000000000000000000000000000000000000000000000000000042e000000000000000000000000000000000000000000000000000000000000042f0000000000000000000000000000000000000000000000000000000000000430000000000000000000000000000000000000000000000000000000000000043100000000000000000000000000000000000000000000000000000000000004320000000000000000000000000000000000000000000000000000000000000433000000000000000000000000000000000000000000000000000000000000043400000000000000000000000000000000000000000000000000000000000004350000000000000000000000000000000000000000000000000000000000000436000000000000000000000000000000000000000000000000000000000000043700000000000000000000000000000000000000000000000000000000000004380000000000000000000000000000000000000000000000000000000000000439000000000000000000000000000000000000000000000000000000000000043a000000000000000000000000000000000000000000000000000000000000043b000000000000000000000000000000000000000000000000000000000000043c000000000000000000000000000000000000000000000000000000000000043d000000000000000000000000000000000000000000000000000000000000043e0200000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000501200000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000701000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000702000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000704000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000705000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007060000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000070700000000000000000000000000000000000000000000000000000000000007110000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000000071200000000000000000000000000000000000000000000000000000000000007090000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000716000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000717000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007190000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000071a0000000000000000000000000000000000000000000000000000000000000711000000000000000000000000000000000000000000000000000000000000071b0000000000000000000000000000000000000000000000000000000000000712000000000000000000000000000000000000000000000000000000000000071c0000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000071d0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000071e0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000071f00000000000000000000000000000000000000000000000000000000000007160000000000000000000000000000000000000000000000000000000000000720000000000000000000000000000000000000000000000000000000000000071700000000000000000000000000000000000000000000000000000000000007210000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000072200000000000000000000000000000000000000000000000000000000000007190000000000000000000000000000000000000000000000000000000000000723000000000000000000000000000000000000000000000000000000000000071a0000000000000000000000000000000000000000000000000000000000000724000000000000000000000000000000000000000000000000000000000000071b0000000000000000000000000000000000000000000000000000000000000725000000000000000000000000000000000000000000000000000000000000071c0000000000000000000000000000000000000000000000000000000000000726000000000000000000000000000000000000000000000000000000000000071d0000000000000000000000000000000000000000000000000000000000000727000000000000000000000000000000000000000000000000000000000000071e0000000000000000000000000000000000000000000000000000000000000728000000000000000000000000000000000000000000000000000000000000071f000000000000000000000000000000000000000000000000000000000000072900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "txsEffectsHash": "0x00f8afbbf042432cf18d704499f6533cc95ea378b5b2ef1dc75f2438873a62b1", "decodedHeader": { @@ -47,10 +47,10 @@ "globalVariables": { "blockNumber": 2, "chainId": 31337, - "timestamp": 1715959547, + "timestamp": 1716042373, "version": 1, - "coinbase": "0x43c5c3afd0f9b6c7cee8242ff8af10404a1ba21c", - "feeRecipient": "0x0e1c708110a8c246a71094fa18ac188fe2df70ea87235a2fcb86e80c9534c33c", + "coinbase": "0xe19d288dac593449f143689ea3563e9d960e0ae6", + "feeRecipient": "0x20f9afacaabdb5bca38f3586fad6ab2e72f75560e1504f8c3de2061b2283b25a", "gasFees": { "feePerDaGas": 0, "feePerL2Gas": 0 @@ -58,7 +58,7 @@ }, "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x11a629e4167f118118a0389eddd379b5a7338added581a7e3b3474d4693d76c1" + "root": "0x21a504c1644ee56efe1d5c7690d6edc47b21a389e718f2202bcdc6ea4f879b0e" }, "stateReference": { "l1ToL2MessageTree": { @@ -81,8 +81,8 @@ } } }, - "header": "0x11a629e4167f118118a0389eddd379b5a7338added581a7e3b3474d4693d76c100000002000000000000000000000000000000000000000000000000000000000000000200f8afbbf042432cf18d704499f6533cc95ea378b5b2ef1dc75f2438873a62b100212ff46db74e06c26240f9a92fb6fea84709380935d657361bbd5bcb89193700a5a7c9f331ce6832a69dc81873ed87de7ceeaaed2af1d595cb14ca9616eddd2e0232573b292e99cb24c082c3ef340d619341ab76aa1e9dff1ab1914963452d0000002024c6dc6d357aad01e10fe1adb877bb28b1df97375b874116e488086ca76e5f9600000200268020a622156e2beac47431b0cd70e1c81fef9a6aa3c365bfcbed9aa7301c5e000002802ecba8caa69552bb0d9bdf0d13eb328aeb6f166a1509678d9bfa9970971d69ab000001400000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000664776fb43c5c3afd0f9b6c7cee8242ff8af10404a1ba21c0e1c708110a8c246a71094fa18ac188fe2df70ea87235a2fcb86e80c9534c33c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "publicInputsHash": "0x00f84128e2b3d2ac7edce11ee5e5c2d6faf6a04742df34162e246aea4533f0d4", + "header": "0x21a504c1644ee56efe1d5c7690d6edc47b21a389e718f2202bcdc6ea4f879b0e00000002000000000000000000000000000000000000000000000000000000000000000200f8afbbf042432cf18d704499f6533cc95ea378b5b2ef1dc75f2438873a62b100212ff46db74e06c26240f9a92fb6fea84709380935d657361bbd5bcb89193700a5a7c9f331ce6832a69dc81873ed87de7ceeaaed2af1d595cb14ca9616eddd2e0232573b292e99cb24c082c3ef340d619341ab76aa1e9dff1ab1914963452d0000002024c6dc6d357aad01e10fe1adb877bb28b1df97375b874116e488086ca76e5f9600000200268020a622156e2beac47431b0cd70e1c81fef9a6aa3c365bfcbed9aa7301c5e000002802ecba8caa69552bb0d9bdf0d13eb328aeb6f166a1509678d9bfa9970971d69ab000001400000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000006648ba85e19d288dac593449f143689ea3563e9d960e0ae620f9afacaabdb5bca38f3586fad6ab2e72f75560e1504f8c3de2061b2283b25a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "publicInputsHash": "0x007402eac386598833154a72f24a89eb5152eec68dfd43c12dd847da5a99289b", "numTxs": 4 } } \ No newline at end of file diff --git a/noir-projects/aztec-nr/.gitrepo b/noir-projects/aztec-nr/.gitrepo index 543deac1913..7ab6c0eb1c9 100644 --- a/noir-projects/aztec-nr/.gitrepo +++ b/noir-projects/aztec-nr/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/aztec-nr branch = master - commit = 5a57900bc92e9fa056db8a689d5622e86a15211b + commit = 440a187b5bb985f3da4ff563d6c4943c88556fa7 method = merge cmdver = 0.4.6 - parent = 3809e3d58a55d189de14f2c002bb1e0c985cb111 + parent = 18bb55229dd973f6a93a4314f7519d45d3b21b1b diff --git a/noir-projects/aztec-nr/address-note/src/address_note.nr b/noir-projects/aztec-nr/address-note/src/address_note.nr index 3d33ecb4a52..df33796ed35 100644 --- a/noir-projects/aztec-nr/address-note/src/address_note.nr +++ b/noir-projects/aztec-nr/address-note/src/address_note.nr @@ -44,7 +44,7 @@ impl NoteInterface for AddressNote { // Broadcasts the note as an encrypted log on L1. fn broadcast(self, context: &mut PrivateContext, slot: Field, ivpk_m: GrumpkinPoint) { // docs:start:encrypted - context.emit_note_encrypted_log( + context.encrypt_and_emit_note( (*context).this_address(), slot, Self::get_note_type_id(), diff --git a/noir-projects/aztec-nr/aztec/src/context/private_context.nr b/noir-projects/aztec-nr/aztec/src/context/private_context.nr index 1986c667f1b..645ea474ad2 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -1,12 +1,13 @@ use crate::{ context::{inputs::PrivateContextInputs, interface::ContextInterface}, messaging::process_l1_to_l2_message, - hash::{hash_args_array, ArgsHasher, compute_encrypted_log_hash, compute_unencrypted_log_hash}, + hash::{hash_args_array, ArgsHasher, compute_unencrypted_log_hash}, note::{note_interface::NoteInterface, utils::compute_note_hash_for_insertion}, oracle::{ nullifier_keys::get_nullifier_key_validation_request, arguments, returns, call_private_function::call_private_function_internal, header::get_header_at, - logs::emit_encrypted_log, logs_traits::{LensForEncryptedLog, ToBytesForUnencryptedLog}, + logs::{emit_encrypted_log, emit_encrypted_note_log, compute_encrypted_log}, + logs_traits::{LensForEncryptedLog, ToBytesForUnencryptedLog}, enqueue_public_function_call::{ enqueue_public_function_call_internal, set_public_teardown_function_call_internal, parse_public_call_stack_item_from_oracle @@ -14,6 +15,7 @@ use crate::{ } }; use dep::protocol_types::{ + hash::sha256_to_field, abis::{ function_selector::FunctionSelector, max_block_number::MaxBlockNumber, nullifier_key_validation_request::NullifierKeyValidationRequest, @@ -281,42 +283,34 @@ impl PrivateContext { let side_effect = LogHash { value: log_hash, counter, length: len }; self.unencrypted_logs_hashes.push(side_effect); } - // TODO(1139): Convert to generic input once we encrypt inside the circuit - pub fn emit_encrypted_log( + + pub fn encrypt_and_emit_log( &mut self, contract_address: AztecAddress, storage_slot: Field, note_type_id: Field, ivpk_m: GrumpkinPoint, preimage: [Field; N] - ) where [Field; N]: LensForEncryptedLog { - // TODO(1139): perform encryption in the circuit - // The oracle call should come last, but we require the encrypted value for now + ) where [Field; N]: LensForEncryptedLog { + // We are currently just encrypting it EXACTLY the same way as if it was a note. let counter = self.next_counter(); - let encrypted_log: [Field; M] = emit_encrypted_log( - contract_address, - storage_slot, - note_type_id, - ivpk_m, - preimage, - counter - ); - // = 32*all fields + bytes for encryption (112) + processed log len (4) - let len = 112 + 32 * (N + 3) + 4; - let log_hash = compute_encrypted_log_hash(encrypted_log); + let encrypted_log: [u8; M] = compute_encrypted_log(contract_address, storage_slot, note_type_id, ivpk_m, preimage); + emit_encrypted_log(encrypted_log, counter); + let len = 32 + 32 + 64 + 48 + 48 + 176 + 64 + (preimage.len() as Field * 32) + 16 + 4; + let log_hash = sha256_to_field(encrypted_log); let side_effect = LogHash { value: log_hash, counter, length: len }; self.encrypted_logs_hashes.push(side_effect); } - pub fn emit_note_encrypted_log( + pub fn encrypt_and_emit_note( &mut self, contract_address: AztecAddress, storage_slot: Field, note_type_id: Field, - encryption_pub_key: GrumpkinPoint, + ivpk_m: GrumpkinPoint, note: Note - ) where Note: NoteInterface, [Field; N]: LensForEncryptedLog { - let note_hash = compute_note_hash_for_insertion(note); + ) where Note: NoteInterface, [Field; N]: LensForEncryptedLog { + let note_hash: Field = compute_note_hash_for_insertion(note); let note_exists_index = find_index( self.new_note_hashes.storage, |n: NoteHash| n.value == note_hash @@ -327,19 +321,24 @@ impl PrivateContext { let note_hash_counter = self.new_note_hashes.storage[note_exists_index].counter; let preimage = note.serialize_content(); let counter = self.next_counter(); - // TODO(1139): perform encryption in the circuit - // The oracle call should come last, but we require the encrypted value for now - let encrypted_log: [Field; M] = emit_encrypted_log( - contract_address, - storage_slot, - note_type_id, - encryption_pub_key, - preimage, - counter - ); - // = 32*all fields + bytes for encryption (112) + processed log len (4) - let len = 112 + 32 * (preimage.len() as Field + 3) + 4; - let log_hash = compute_encrypted_log_hash(encrypted_log); + + // TODO(#1139 | #6408): perform encryption in the circuit + let encrypted_log: [u8; M] = compute_encrypted_log(contract_address, storage_slot, note_type_id, ivpk_m, preimage); + emit_encrypted_note_log(note_hash, encrypted_log, counter); + + // Current unoptimized size of the encrypted log + // incoming_tag (32 bytes) + // outgoing_tag (32 bytes) + // eph_pk (64 bytes) + // incoming_header (48 bytes) + // outgoing_header (48 bytes) + // outgoing_body (176 bytes) + // incoming_body_fixed (64 bytes) + // incoming_body_variable (N * 32 bytes + 16 bytes padding) + // len of processed log (4 bytes) + let len = 32 + 32 + 64 + 48 + 48 + 176 + 64 + (preimage.len() as Field * 32) + 16 + 4; + + let log_hash = sha256_to_field(encrypted_log); let side_effect = NoteLogHash { value: log_hash, counter, length: len, note_hash_counter }; self.note_encrypted_logs_hashes.push(side_effect); } diff --git a/noir-projects/aztec-nr/aztec/src/hash.nr b/noir-projects/aztec-nr/aztec/src/hash.nr index f0abd4912e1..322db82b966 100644 --- a/noir-projects/aztec-nr/aztec/src/hash.nr +++ b/noir-projects/aztec-nr/aztec/src/hash.nr @@ -12,24 +12,6 @@ pub fn compute_secret_hash(secret: Field) -> Field { pedersen_hash([secret], GENERATOR_INDEX__SECRET_HASH) } -pub fn compute_encrypted_log_hash(encrypted_log: [Field; M]) -> Field where [Field; N]: LensForEncryptedLog { - let mut bytes = [0; L]; - // Note that bytes.append(encrypted_log[i].to_be_bytes(31)) results in bound error - for i in 0..M - 1 { - let to_add = encrypted_log[i].to_be_bytes(31); - for j in 0..31 { - bytes[i*31 + j] = to_add[j]; - } - } - // can't assign as L - not in scope error for: L-31*(M-1) - let num_bytes = bytes.len() as u32 - 31 * (M - 1); - let to_add_final = encrypted_log[M - 1].to_be_bytes(num_bytes); - for j in 0..num_bytes { - bytes[(M-1)*31 + j] = to_add_final[j]; - } - sha256_to_field(bytes) -} - pub fn compute_unencrypted_log_hash( contract_address: AztecAddress, event_selector: Field, @@ -167,44 +149,6 @@ fn compute_var_args_hash() { assert(hash == 0x05a1023fef839ac88731f49ae983e172c1b600a3c8f3393ad0ac25d819ac0f0f); } -#[test] -fn compute_enc_log_hash_304() { - let input = [ - 0x0000000000000000000000000000000000000000000000000000000000000000, - 0x0021a0d4aa9989656b592187cf6da1965df53ab2ff2277421e663465cf20d3e9, - 0x00c3969cc350f3474f8187a33ac1317181961f5f94043b07ce888d85a5d20cb5, - 0x0058198041ed1547b056955b5141a5a8a1551b0c8d094255ec9daaf3604d9348, - 0x00247ad96df2e4d984cf795ed7316234743a681f824a45c46253de8bfde48850, - 0x007fc251f4ce44f4e9aba3dbf6567228be28fac85660156f2825ddb0b0577457, - 0x009315851323c6bc2aaa42e23fe5f3be97208f2d8167eafdfc5742d94f2f4dd4, - 0x00b938289e563b0fe01982cd9b8d9e33e3069046768ad01c0fb05e429e7b7909, - 0x00fbcc257a3211f705b471eee763b0f43876a2b2178fab6d2b09bd2b7e086584, - 0x000000000000008c3289b5793b7448f4d45ecde039d004b6f037cad10b5c2336 - ]; - let hash = compute_encrypted_log_hash(input); - assert(hash == 0x001e3c013994947fe28957a876bf1b2c3a69ac69cc92909efd4f2ae9b972f893); -} - -#[test] -fn compute_enc_log_hash_368() { - let input = [ - 0x0000000000000000000000000000000000000000000000000000000000000000, - 0x002190697d2a50e229a7a077e0951073f7d51e46679f10466153c308b63b1ea9, - 0x00543e346facc6799b94514c9d461bcc836c04b083b13c2e4544a39130473c1e, - 0x000df76d59526f8f953bcc7d9f77cdaefd36435931f0d7348f794bc275b42ded, - 0x00a6d390ee1723af7f7ac1ae4fc81a266b2370fe07040a36d06dbe242e02413e, - 0x00acbce15b6af1fbe94bd0f7b70f11768265dff77bfe63398f2a053efdfdf26d, - 0x00b8b131b9f42c689beb095ba4f4a836d4d15c9068d0422e9add6ca82b786329, - 0x00661a6a654b38f0f97d404ef5553e0efea9ed670561ae86685b31bbb2824fac, - 0x00113a6b58edfaec0065b365f66ba8d8aa68254b8690035e8d671a17a843f0a1, - 0x0023f2d2eae8c4449bac8f268a3e62a3faace1fe1401f0efdc8b0ccfbc8fb271, - 0x00cf6603f8c61993dd2f662c719671c61727a2f4e925fb988b23d31feccd77d9, - 0x0000000000a402a84b7294671799c38dd805f6a827a3a12633fdf91a57debe1f - ]; - let hash = compute_encrypted_log_hash(input); - assert(hash == 0x00a0d651ac0cbc01b72430fa6a05d91738595af6e0229347b4c9968223387aeb); -} - #[test] fn compute_unenc_log_hash_array() { let contract_address = AztecAddress::from_field(0x233a3e0df23b2b15b324194cb4a151f26c0b7333250781d34cc269d85dc334c6); diff --git a/noir-projects/aztec-nr/aztec/src/oracle/logs.nr b/noir-projects/aztec-nr/aztec/src/oracle/logs.nr index a1d933915ee..148b12a79b5 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/logs.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/logs.nr @@ -1,32 +1,40 @@ use dep::protocol_types::{address::AztecAddress, grumpkin_point::GrumpkinPoint}; -// TODO(1139): Should take encrypted data. -// Currently returns encrypted data to be hashed -// = 112 + 32 * (N + 3) bytes = N + 7 fields +// = 480 + 32 * N bytes +#[oracle(emitEncryptedNoteLog)] +fn emit_encrypted_note_log_oracle(_note_hash: Field, _encrypted_note: [u8; M], _counter: u32) {} + +unconstrained pub fn emit_encrypted_note_log( + note_hash: Field, + encrypted_note: [u8; M], + counter: u32 +) { + emit_encrypted_note_log_oracle(note_hash, encrypted_note, counter) +} + #[oracle(emitEncryptedLog)] -fn emit_encrypted_log_oracle( +fn emit_encrypted_log_oracle(_encrypted_note: [u8; M], _counter: u32) {} + +unconstrained pub fn emit_encrypted_log(encrypted_note: [u8; M], counter: u32) { + emit_encrypted_log_oracle(encrypted_note, counter) +} + +// = 480 + 32 * N bytes +#[oracle(computeEncryptedLog)] +fn compute_encrypted_log_oracle( _contract_address: AztecAddress, _storage_slot: Field, _note_type_id: Field, _encryption_pub_key: GrumpkinPoint, - _preimage: [Field; N], - _counter: u32 -) -> [Field; M] {} + _preimage: [Field; N] +) -> [u8; M] {} -unconstrained pub fn emit_encrypted_log( +unconstrained pub fn compute_encrypted_log( contract_address: AztecAddress, storage_slot: Field, note_type_id: Field, ivpk_m: GrumpkinPoint, - preimage: [Field; N], - counter: u32 -) -> [Field; M] { - emit_encrypted_log_oracle( - contract_address, - storage_slot, - note_type_id, - ivpk_m, - preimage, - counter - ) + preimage: [Field; N] +) -> [u8; M] { + compute_encrypted_log_oracle(contract_address, storage_slot, note_type_id, ivpk_m, preimage) } diff --git a/noir-projects/aztec-nr/aztec/src/oracle/logs_traits.nr b/noir-projects/aztec-nr/aztec/src/oracle/logs_traits.nr index 267979da364..c6632f5a4d3 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/logs_traits.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/logs_traits.nr @@ -1,8 +1,7 @@ use dep::protocol_types::address::AztecAddress; -// TODO: this is awful but since we can't have a fn that maps [Field; N] -> [Field; N+7] -// (where N is encrypted log preimage size and N+7 is encryption output size) -// and can't return slices from oracles, this at least compiles and runs +// TODO: this is awful but since we can't have a fn that maps [Field; N] -> [u8; 480 + N * 32] +// (where N is the note pre-image size and 480 + N * 32 is the encryption output size) // The fns for LensForEncryptedLog are never used, it's just to tell the compiler what the lens are // The to_bytes fn for ToBytesForUnencryptedLog is used to allow us to hash some generic T @@ -10,37 +9,38 @@ use dep::protocol_types::address::AztecAddress; // I could have omitted N from the trait, but wanted to keep it strictly for field arrs // TODO(1139): Once we enc inside the circuit, we will no longer need the oracle to return // anything, so we can remove this trait -trait LensForEncryptedLog { +trait LensForEncryptedLog { // N = note preimage input in fields - // M = encryption output len in fields (= N + 7 = N + 3 fields for addr, slot, type + 3.5 fields for AES data) - // L = encryption output len in bytes (= 32*M - 16) - fn output_fields(self: [Field; N]) -> [Field; M]; - fn output_bytes(self: [Field; N]) -> [u8; L]; + // M = encryption output len in bytes (= 480 + N * 32) + fn output_fields(self: [Field; N]) -> [Field; N]; + fn output_bytes(self: [Field; N]) -> [u8; M]; } -impl LensForEncryptedLog<1, 8, 240> for [Field; 1] { - fn output_fields(self) -> [Field; 8] {[self[0]; 8]} - fn output_bytes(self) -> [u8; 240] {[self[0] as u8; 240]} +impl LensForEncryptedLog<1, 512> for [Field; 1] { + fn output_fields(self) -> [Field; 1] {[self[0]; 1]} + fn output_bytes(self) -> [u8; 512] {[self[0] as u8; 512]} } -impl LensForEncryptedLog<2, 9, 272> for [Field; 2] { - fn output_fields(self) -> [Field; 9] {[self[0]; 9]} - fn output_bytes(self) -> [u8; 272] {[self[0] as u8; 272]} +impl LensForEncryptedLog<2, 544> for [Field; 2] { + fn output_fields(self) -> [Field; 2] {[self[0]; 2]} + fn output_bytes(self) -> [u8; 544] {[self[0] as u8; 544]} } -impl LensForEncryptedLog<3, 10, 304> for [Field; 3] { - fn output_fields(self) -> [Field; 10] {[self[0]; 10]} - fn output_bytes(self) -> [u8; 304] {[self[0] as u8; 304]} +impl LensForEncryptedLog<3, 576> for [Field; 3] { + fn output_fields(self) -> [Field; 3] {[self[0]; 3]} + fn output_bytes(self) -> [u8; 576] {[self[0] as u8; 576]} } -impl LensForEncryptedLog<4, 11, 336> for [Field; 4] { - fn output_fields(self) -> [Field; 11] {[self[0]; 11]} - fn output_bytes(self) -> [u8; 336] {[self[0] as u8; 336]} +impl LensForEncryptedLog<4, 608> for [Field; 4] { + fn output_fields(self) -> [Field; 4] {[self[0]; 4]} + fn output_bytes(self) -> [u8; 608] {[self[0] as u8; 608]} + } -impl LensForEncryptedLog<5, 12, 368> for [Field; 5] { - fn output_fields(self) -> [Field; 12] {[self[0]; 12]} - fn output_bytes(self) -> [u8; 368] {[self[0] as u8; 368]} +impl LensForEncryptedLog<5, 640> for [Field; 5] { + fn output_fields(self) -> [Field; 5] {[self[0]; 5]} + fn output_bytes(self) -> [u8; 640] {[self[0] as u8; 640]} } -impl LensForEncryptedLog<6, 13, 400> for [Field; 6] { - fn output_fields(self) -> [Field; 13] {[self[0]; 13]} - fn output_bytes(self) -> [u8; 400] {[self[0] as u8; 400]} +impl LensForEncryptedLog<6, 672> for [Field; 6] { + fn output_fields(self) -> [Field; 6] {[self[0]; 6]} + fn output_bytes(self) -> [u8; 672] {[self[0] as u8; 672]} + } // This trait defines the length of the inputs in bytes to diff --git a/noir-projects/aztec-nr/value-note/src/value_note.nr b/noir-projects/aztec-nr/value-note/src/value_note.nr index 06c01fcbaa4..7e057b8912e 100644 --- a/noir-projects/aztec-nr/value-note/src/value_note.nr +++ b/noir-projects/aztec-nr/value-note/src/value_note.nr @@ -47,7 +47,7 @@ impl NoteInterface for ValueNote { // Broadcasts the note as an encrypted log on L1. fn broadcast(self, context: &mut PrivateContext, slot: Field, ivpk_m: GrumpkinPoint) { - context.emit_note_encrypted_log( + context.encrypt_and_emit_note( (*context).this_address(), slot, Self::get_note_type_id(), diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr index e8e2dd2f2e5..7de5917b11d 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr @@ -40,7 +40,7 @@ impl NoteInterface for SubscriptionNote { // Broadcasts the note as an encrypted log on L1. fn broadcast(self, context: &mut PrivateContext, slot: Field, ivpk_m: GrumpkinPoint) { - context.emit_note_encrypted_log( + context.encrypt_and_emit_note( (*context).this_address(), slot, Self::get_note_type_id(), diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr index 2c3100cbc60..5efd1e93879 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr @@ -51,7 +51,7 @@ impl NoteInterface for CardNote { // Broadcasts the note as an encrypted log on L1. fn broadcast(self, context: &mut PrivateContext, slot: Field, ivpk_m: GrumpkinPoint) { - context.emit_note_encrypted_log( + context.encrypt_and_emit_note( (*context).this_address(), slot, Self::get_note_type_id(), diff --git a/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr b/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr index fa1b79f879d..f716dc5a5f8 100644 --- a/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr +++ b/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr @@ -24,7 +24,7 @@ impl NoteInterface for EcdsaPublicKeyNote { // [1] = x[31] // [2] = y[0..31] // [3] = y[31] - // [4] = owner + // [4] = npk_m_hash fn serialize_content(self) -> [Field; ECDSA_PUBLIC_KEY_NOTE_LEN] { let mut x: Field = 0; let mut y: Field = 0; @@ -86,7 +86,7 @@ impl NoteInterface for EcdsaPublicKeyNote { // Broadcasts the note as an encrypted log on L1. fn broadcast(self, context: &mut PrivateContext, slot: Field, ivpk_m: GrumpkinPoint) { - context.emit_note_encrypted_log( + context.encrypt_and_emit_note( (*context).this_address(), slot, Self::get_note_type_id(), diff --git a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr index 3b675374f11..df6e72b61b3 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr @@ -39,7 +39,7 @@ impl NoteInterface for PublicKeyNote { // Broadcasts the note as an encrypted log on L1. fn broadcast(self, context: &mut PrivateContext, slot: Field, ivpk_m: GrumpkinPoint) { - context.emit_note_encrypted_log( + context.encrypt_and_emit_note( (*context).this_address(), slot, Self::get_note_type_id(), diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr index 721dc23ad24..204023a21ab 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr @@ -51,7 +51,7 @@ impl NoteInterface for TokenNote { // We only bother inserting the note if non-empty to save funds on gas. // TODO: (#5901) This will be changed a lot, as it should use the updated encrypted log format if !(self.amount == U128::from_integer(0)) { - context.emit_note_encrypted_log( + context.encrypt_and_emit_note( (*context).this_address(), slot, Self::get_note_type_id(), diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr index 721dc23ad24..204023a21ab 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr @@ -51,7 +51,7 @@ impl NoteInterface for TokenNote { // We only bother inserting the note if non-empty to save funds on gas. // TODO: (#5901) This will be changed a lot, as it should use the updated encrypted log format if !(self.amount == U128::from_integer(0)) { - context.emit_note_encrypted_log( + context.encrypt_and_emit_note( (*context).this_address(), slot, Self::get_note_type_id(), diff --git a/yarn-project/circuit-types/src/logs/encrypted_log_payload.test.ts b/yarn-project/circuit-types/src/logs/encrypted_log_payload.test.ts deleted file mode 100644 index bb62424faf0..00000000000 --- a/yarn-project/circuit-types/src/logs/encrypted_log_payload.test.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { AztecAddress, GrumpkinScalar } from '@aztec/circuits.js'; -import { Grumpkin } from '@aztec/circuits.js/barretenberg'; - -import { EncryptedLogPayload } from './encrypted_log_payload.js'; -import { L1NotePayload } from './l1_note_payload/l1_note_payload.js'; - -describe('encrypt and decrypt a full log', () => { - let grumpkin: Grumpkin; - - let ovsk: GrumpkinScalar; - let ivsk: GrumpkinScalar; - - let payload: EncryptedLogPayload; - let encrypted: Buffer; - - beforeAll(() => { - grumpkin = new Grumpkin(); - - ovsk = GrumpkinScalar.random(); - ivsk = GrumpkinScalar.random(); - - const ephSk = GrumpkinScalar.random(); - - const recipientAddress = AztecAddress.random(); - const ivpk = grumpkin.mul(Grumpkin.generator, ivsk); - - payload = EncryptedLogPayload.fromL1NotePayload(L1NotePayload.random()); - encrypted = payload.encrypt(ephSk, recipientAddress, ivpk, ovsk); - }); - - it('decrypt a log as incoming', () => { - const recreated = EncryptedLogPayload.decryptAsIncoming(encrypted, ivsk); - - expect(recreated.toBuffer()).toEqual(payload.toBuffer()); - }); - - it('decrypt a log as outgoing', () => { - const recreated = EncryptedLogPayload.decryptAsOutgoing(encrypted, ovsk); - - expect(recreated.toBuffer()).toEqual(payload.toBuffer()); - }); -}); diff --git a/yarn-project/circuit-types/src/logs/encrypted_log_payload.ts b/yarn-project/circuit-types/src/logs/encrypted_log_payload.ts deleted file mode 100644 index 6ef1cc82add..00000000000 --- a/yarn-project/circuit-types/src/logs/encrypted_log_payload.ts +++ /dev/null @@ -1,209 +0,0 @@ -import { - AztecAddress, - Fr, - type GrumpkinPrivateKey, - Point, - type PublicKey, - computeIvpkApp, - computeIvskApp, - computeOvskApp, - derivePublicKeyFromSecretKey, -} from '@aztec/circuits.js'; -import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; - -import { EncryptedLogHeader } from './encrypted_log_header.js'; -import { EncryptedLogIncomingBody } from './encrypted_log_incoming_body.js'; -import { EncryptedLogOutgoingBody } from './encrypted_log_outgoing_body.js'; -import { type L1NotePayload } from './l1_note_payload/l1_note_payload.js'; -import { Note } from './l1_note_payload/note.js'; - -// A placeholder tag until we have a proper tag system in place. -const PLACEHOLDER_TAG = new Fr(33); - -// Both the incoming and the outgoing header are 48 bytes. -// 32 bytes for the address, and 16 bytes padding to follow PKCS#7 -const HEADER_SIZE = 48; - -// The outgoing body is constant size of 176 bytes. -// 160 bytes for the secret key, address, and public key, and 16 bytes padding to follow PKCS#7 -const OUTGOING_BODY_SIZE = 176; - -export class EncryptedLogPayload { - constructor( - /** - * A note as emitted from Noir contract. Can be used along with private key to compute nullifier. - */ - public note: Note, - /** - * Address of the contract this tx is interacting with. - */ - public contractAddress: AztecAddress, - /** - * Storage slot of the underlying note. - */ - public storageSlot: Fr, - /** - * Type identifier for the underlying note, required to determine how to compute its hash and nullifier. - */ - public noteTypeId: Fr, - ) {} - - toBuffer() { - return serializeToBuffer([this.note, this.contractAddress, this.storageSlot, this.noteTypeId]); - } - - static fromBuffer(buffer: Buffer | BufferReader): EncryptedLogPayload { - const reader = BufferReader.asReader(buffer); - return new EncryptedLogPayload( - reader.readObject(Note), - reader.readObject(AztecAddress), - Fr.fromBuffer(reader), - Fr.fromBuffer(reader), - ); - } - - static fromL1NotePayload(l1NotePayload: L1NotePayload) { - return new EncryptedLogPayload( - l1NotePayload.note, - l1NotePayload.contractAddress, - l1NotePayload.storageSlot, - l1NotePayload.noteTypeId, - ); - } - - /** - * Encrypts a note payload for a given recipient and sender. - * Creates an incoming log the the recipient using the recipient's ivsk, and - * an outgoing log for the sender using the sender's ovsk. - * - * @param ephSk - An ephemeral secret key used for the encryption - * @param recipient - The recipient address, retrievable by the sender for his logs - * @param ivpk - The incoming viewing public key of the recipient - * @param ovsk - The outgoing viewing secret key of the sender - * @returns A buffer containing the encrypted log payload - */ - public encrypt(ephSk: GrumpkinPrivateKey, recipient: AztecAddress, ivpk: PublicKey, ovsk: GrumpkinPrivateKey) { - const ephPk = derivePublicKeyFromSecretKey(ephSk); - const ovpk = derivePublicKeyFromSecretKey(ovsk); - - const header = new EncryptedLogHeader(this.contractAddress); - - const incomingHeaderCiphertext = header.computeCiphertext(ephSk, ivpk); - const outgoingHeaderCiphertext = header.computeCiphertext(ephSk, ovpk); - - const ivpkApp = computeIvpkApp(ivpk, this.contractAddress); - - const incomingBodyCiphertext = new EncryptedLogIncomingBody( - this.storageSlot, - this.noteTypeId, - this.note, - ).computeCiphertext(ephSk, ivpkApp); - - const ovskApp = computeOvskApp(ovsk, this.contractAddress); - - const outgoingBodyCiphertext = new EncryptedLogOutgoingBody(ephSk, recipient, ivpkApp).computeCiphertext( - ovskApp, - ephPk, - ); - - return Buffer.concat([ - PLACEHOLDER_TAG.toBuffer(), - PLACEHOLDER_TAG.toBuffer(), - ephPk.toBuffer(), - incomingHeaderCiphertext, - outgoingHeaderCiphertext, - outgoingBodyCiphertext, - incomingBodyCiphertext, - ]); - } - - /** - * Decrypts a ciphertext as an incoming log. - * - * This is executable by the recipient of the note, and uses the ivsk to decrypt the payload. - * The outgoing parts of the log are ignored entirely. - * - * Produces the same output as `decryptAsOutgoing`. - * - * @param ciphertext - The ciphertext for the log - * @param ivsk - The incoming viewing secret key, used to decrypt the logs - * @returns The decrypted log payload - */ - public static decryptAsIncoming(ciphertext: Buffer | bigint[], ivsk: GrumpkinPrivateKey) { - const input = Buffer.isBuffer(ciphertext) ? ciphertext : Buffer.from(ciphertext.map((x: bigint) => Number(x))); - const reader = BufferReader.asReader(input); - - // We don't use the tags as part of the decryption here, we just gotta read to skip them. - reader.readObject(Fr); // incoming tag - reader.readObject(Fr); // outgoing tag - - const ephPk = reader.readObject(Point); - - const incomingHeader = EncryptedLogHeader.fromCiphertext(reader.readBytes(HEADER_SIZE), ivsk, ephPk); - - // Skipping the outgoing header and body - reader.readBytes(HEADER_SIZE); - reader.readBytes(OUTGOING_BODY_SIZE); - - // The incoming can be of variable size, so we read until the end - const incomingBodySlice = reader.readToEnd(); - - const ivskApp = computeIvskApp(ivsk, incomingHeader.address); - const incomingBody = EncryptedLogIncomingBody.fromCiphertext(incomingBodySlice, ivskApp, ephPk); - - return new EncryptedLogPayload( - incomingBody.note, - incomingHeader.address, - incomingBody.storageSlot, - incomingBody.noteTypeId, - ); - } - - /** - * Decrypts a ciphertext as an outgoing log. - * - * This is executable by the sender of the note, and uses the ovsk to decrypt the payload. - * The outgoing parts are decrypted to retrieve information that allows the sender to - * decrypt the incoming log, and learn about the note contents. - * - * Produces the same output as `decryptAsIncoming`. - * - * @param ciphertext - The ciphertext for the log - * @param ovsk - The outgoing viewing secret key, used to decrypt the logs - * @returns The decrypted log payload - */ - public static decryptAsOutgoing(ciphertext: Buffer | bigint[], ovsk: GrumpkinPrivateKey) { - const input = Buffer.isBuffer(ciphertext) ? ciphertext : Buffer.from(ciphertext.map((x: bigint) => Number(x))); - const reader = BufferReader.asReader(input); - - // We don't use the tags as part of the decryption here, we just gotta read to skip them. - reader.readObject(Fr); // incoming tag - reader.readObject(Fr); // outgoing tag - - const ephPk = reader.readObject(Point); - - // Skip the incoming header - reader.readBytes(HEADER_SIZE); - - const outgoingHeader = EncryptedLogHeader.fromCiphertext(reader.readBytes(HEADER_SIZE), ovsk, ephPk); - - const ovskApp = computeOvskApp(ovsk, outgoingHeader.address); - const outgoingBody = EncryptedLogOutgoingBody.fromCiphertext(reader.readBytes(OUTGOING_BODY_SIZE), ovskApp, ephPk); - - // The incoming can be of variable size, so we read until the end - const incomingBodySlice = reader.readToEnd(); - - const incomingBody = EncryptedLogIncomingBody.fromCiphertext( - incomingBodySlice, - outgoingBody.ephSk, - outgoingBody.recipientIvpkApp, - ); - - return new EncryptedLogPayload( - incomingBody.note, - outgoingHeader.address, - incomingBody.storageSlot, - incomingBody.noteTypeId, - ); - } -} diff --git a/yarn-project/circuit-types/src/logs/index.ts b/yarn-project/circuit-types/src/logs/index.ts index 0e4b8200391..6b4a4199c28 100644 --- a/yarn-project/circuit-types/src/logs/index.ts +++ b/yarn-project/circuit-types/src/logs/index.ts @@ -10,6 +10,6 @@ export * from './l1_note_payload/index.js'; export * from './tx_l2_logs.js'; export * from './unencrypted_l2_log.js'; export * from './extended_unencrypted_l2_log.js'; -export * from './encrypted_log_header.js'; -export * from './encrypted_log_incoming_body.js'; -export * from './encrypted_log_outgoing_body.js'; +export * from './l1_note_payload/encrypted_log_header.js'; +export * from './l1_note_payload/encrypted_log_incoming_body.js'; +export * from './l1_note_payload/encrypted_log_outgoing_body.js'; diff --git a/yarn-project/circuit-types/src/logs/l1_note_payload/encrypt_buffer.test.ts b/yarn-project/circuit-types/src/logs/l1_note_payload/encrypt_buffer.test.ts index d8a0c4b9998..3db91fe87a0 100644 --- a/yarn-project/circuit-types/src/logs/l1_note_payload/encrypt_buffer.test.ts +++ b/yarn-project/circuit-types/src/logs/l1_note_payload/encrypt_buffer.test.ts @@ -3,7 +3,8 @@ import { Grumpkin } from '@aztec/circuits.js/barretenberg'; import { randomBytes } from '@aztec/foundation/crypto'; import { updateInlineTestData } from '@aztec/foundation/testing'; -import { decryptBuffer, deriveAESSecret, encryptBuffer } from './encrypt_buffer.js'; +import { decryptBuffer, encryptBuffer } from './encrypt_buffer.js'; +import { deriveAESSecret } from './encryption_utils.js'; describe('encrypt buffer', () => { let grumpkin: Grumpkin; diff --git a/yarn-project/circuit-types/src/logs/l1_note_payload/encrypt_buffer.ts b/yarn-project/circuit-types/src/logs/l1_note_payload/encrypt_buffer.ts index 28262ff3ba6..dd8e954a7af 100644 --- a/yarn-project/circuit-types/src/logs/l1_note_payload/encrypt_buffer.ts +++ b/yarn-project/circuit-types/src/logs/l1_note_payload/encrypt_buffer.ts @@ -1,30 +1,10 @@ -import { GeneratorIndex, type GrumpkinPrivateKey, type PublicKey } from '@aztec/circuits.js'; +import { type GrumpkinPrivateKey, type PublicKey } from '@aztec/circuits.js'; import { Grumpkin } from '@aztec/circuits.js/barretenberg'; -import { sha256 } from '@aztec/foundation/crypto'; import { Point } from '@aztec/foundation/fields'; -import { numToUInt8 } from '@aztec/foundation/serialize'; import { createCipheriv, createDecipheriv } from 'browserify-cipher'; -/** - * Derive an AES secret key using Elliptic Curve Diffie-Hellman (ECDH) and SHA-256. - * The function takes in an ECDH public key, a private key, and a Grumpkin instance to compute - * the shared secret. The shared secret is then hashed using SHA-256 to produce the final - * AES secret key. - * - * @param secretKey - The secret key used to derive shared secret. - * @param publicKey - The public key used to derive shared secret. - * @returns A derived AES secret key. - * TODO(#5726): This function is called point_to_symmetric_key in Noir. I don't like that name much since point is not - * the only input of the function. Unify naming once we have a better name. - */ -export function deriveAESSecret(secretKey: GrumpkinPrivateKey, publicKey: PublicKey): Buffer { - const curve = new Grumpkin(); - const sharedSecret = curve.mul(publicKey, secretKey); - const secretBuffer = Buffer.concat([sharedSecret.toBuffer(), numToUInt8(GeneratorIndex.SYMMETRIC_KEY)]); - const hash = sha256(secretBuffer); - return hash; -} +import { deriveAESSecret } from './encryption_utils.js'; /** * Encrypt a given data buffer using the owner's public key and an ephemeral private key. diff --git a/yarn-project/circuit-types/src/logs/encrypted_log_header.test.ts b/yarn-project/circuit-types/src/logs/l1_note_payload/encrypted_log_header.test.ts similarity index 100% rename from yarn-project/circuit-types/src/logs/encrypted_log_header.test.ts rename to yarn-project/circuit-types/src/logs/l1_note_payload/encrypted_log_header.test.ts diff --git a/yarn-project/circuit-types/src/logs/encrypted_log_header.ts b/yarn-project/circuit-types/src/logs/l1_note_payload/encrypted_log_header.ts similarity index 96% rename from yarn-project/circuit-types/src/logs/encrypted_log_header.ts rename to yarn-project/circuit-types/src/logs/l1_note_payload/encrypted_log_header.ts index baef6cc264b..ac19b40cc3c 100644 --- a/yarn-project/circuit-types/src/logs/encrypted_log_header.ts +++ b/yarn-project/circuit-types/src/logs/l1_note_payload/encrypted_log_header.ts @@ -1,7 +1,7 @@ import { AztecAddress, type GrumpkinPrivateKey, type PublicKey } from '@aztec/circuits.js'; import { Aes128 } from '@aztec/circuits.js/barretenberg'; -import { deriveAESSecret } from './l1_note_payload/encrypt_buffer.js'; +import { deriveAESSecret } from './encryption_utils.js'; /** * An encrypted log header, containing the address of the log along with utility diff --git a/yarn-project/circuit-types/src/logs/encrypted_log_incoming_body.test.ts b/yarn-project/circuit-types/src/logs/l1_note_payload/encrypted_log_incoming_body.test.ts similarity index 97% rename from yarn-project/circuit-types/src/logs/encrypted_log_incoming_body.test.ts rename to yarn-project/circuit-types/src/logs/l1_note_payload/encrypted_log_incoming_body.test.ts index bb1ab2c2588..934621b508e 100644 --- a/yarn-project/circuit-types/src/logs/encrypted_log_incoming_body.test.ts +++ b/yarn-project/circuit-types/src/logs/l1_note_payload/encrypted_log_incoming_body.test.ts @@ -3,7 +3,7 @@ import { Grumpkin } from '@aztec/circuits.js/barretenberg'; import { updateInlineTestData } from '@aztec/foundation/testing'; import { EncryptedLogIncomingBody } from './encrypted_log_incoming_body.js'; -import { Note } from './l1_note_payload/note.js'; +import { Note } from './note.js'; describe('encrypt log incoming body', () => { let grumpkin: Grumpkin; diff --git a/yarn-project/circuit-types/src/logs/encrypted_log_incoming_body.ts b/yarn-project/circuit-types/src/logs/l1_note_payload/encrypted_log_incoming_body.ts similarity index 97% rename from yarn-project/circuit-types/src/logs/encrypted_log_incoming_body.ts rename to yarn-project/circuit-types/src/logs/l1_note_payload/encrypted_log_incoming_body.ts index 45e1f5382bf..3001d6963de 100644 --- a/yarn-project/circuit-types/src/logs/encrypted_log_incoming_body.ts +++ b/yarn-project/circuit-types/src/logs/l1_note_payload/encrypted_log_incoming_body.ts @@ -2,7 +2,8 @@ import { Fr, type GrumpkinPrivateKey, type PublicKey } from '@aztec/circuits.js' import { Aes128 } from '@aztec/circuits.js/barretenberg'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; -import { Note, deriveAESSecret } from './l1_note_payload/index.js'; +import { deriveAESSecret } from './encryption_utils.js'; +import { Note } from './note.js'; export class EncryptedLogIncomingBody { constructor(public storageSlot: Fr, public noteTypeId: Fr, public note: Note) {} diff --git a/yarn-project/circuit-types/src/logs/encrypted_log_outgoing_body.test.ts b/yarn-project/circuit-types/src/logs/l1_note_payload/encrypted_log_outgoing_body.test.ts similarity index 100% rename from yarn-project/circuit-types/src/logs/encrypted_log_outgoing_body.test.ts rename to yarn-project/circuit-types/src/logs/l1_note_payload/encrypted_log_outgoing_body.test.ts diff --git a/yarn-project/circuit-types/src/logs/encrypted_log_outgoing_body.ts b/yarn-project/circuit-types/src/logs/l1_note_payload/encrypted_log_outgoing_body.ts similarity index 100% rename from yarn-project/circuit-types/src/logs/encrypted_log_outgoing_body.ts rename to yarn-project/circuit-types/src/logs/l1_note_payload/encrypted_log_outgoing_body.ts diff --git a/yarn-project/circuit-types/src/logs/l1_note_payload/encryption_utils.ts b/yarn-project/circuit-types/src/logs/l1_note_payload/encryption_utils.ts new file mode 100644 index 00000000000..2673af92c61 --- /dev/null +++ b/yarn-project/circuit-types/src/logs/l1_note_payload/encryption_utils.ts @@ -0,0 +1,24 @@ +import { GeneratorIndex, type GrumpkinPrivateKey, type PublicKey } from '@aztec/circuits.js'; +import { Grumpkin } from '@aztec/circuits.js/barretenberg'; +import { sha256 } from '@aztec/foundation/crypto'; +import { numToUInt8 } from '@aztec/foundation/serialize'; + +/** + * Derive an AES secret key using Elliptic Curve Diffie-Hellman (ECDH) and SHA-256. + * The function takes in an ECDH public key, a private key, and a Grumpkin instance to compute + * the shared secret. The shared secret is then hashed using SHA-256 to produce the final + * AES secret key. + * + * @param secretKey - The secret key used to derive shared secret. + * @param publicKey - The public key used to derive shared secret. + * @returns A derived AES secret key. + * TODO(#5726): This function is called point_to_symmetric_key in Noir. I don't like that name much since point is not + * the only input of the function. Unify naming once we have a better name. + */ +export function deriveAESSecret(secretKey: GrumpkinPrivateKey, publicKey: PublicKey): Buffer { + const curve = new Grumpkin(); + const sharedSecret = curve.mul(publicKey, secretKey); + const secretBuffer = Buffer.concat([sharedSecret.toBuffer(), numToUInt8(GeneratorIndex.SYMMETRIC_KEY)]); + const hash = sha256(secretBuffer); + return hash; +} diff --git a/yarn-project/circuit-types/src/logs/l1_note_payload/l1_note_payload.test.ts b/yarn-project/circuit-types/src/logs/l1_note_payload/l1_note_payload.test.ts index 288e46db36d..321a8e82985 100644 --- a/yarn-project/circuit-types/src/logs/l1_note_payload/l1_note_payload.test.ts +++ b/yarn-project/circuit-types/src/logs/l1_note_payload/l1_note_payload.test.ts @@ -1,5 +1,6 @@ +import { AztecAddress } from '@aztec/circuits.js'; import { Grumpkin } from '@aztec/circuits.js/barretenberg'; -import { GrumpkinScalar, Point } from '@aztec/foundation/fields'; +import { GrumpkinScalar } from '@aztec/foundation/fields'; import { L1NotePayload } from './l1_note_payload.js'; @@ -16,22 +17,36 @@ describe('L1 Note Payload', () => { expect(L1NotePayload.fromBuffer(buf)).toEqual(payload); }); - it('convert to and from encrypted buffer', () => { - const payload = L1NotePayload.random(); - const ownerPrivKey = GrumpkinScalar.random(); - const ownerPubKey = grumpkin.mul(Grumpkin.generator, ownerPrivKey); - const encrypted = payload.toEncryptedBuffer(ownerPubKey); - const decrypted = L1NotePayload.fromEncryptedBuffer(encrypted, ownerPrivKey); - expect(decrypted).not.toBeUndefined(); - expect(decrypted).toEqual(payload); - }); + describe('encrypt and decrypt a full log', () => { + let ovsk: GrumpkinScalar; + let ivsk: GrumpkinScalar; - it('return undefined if unable to decrypt the encrypted buffer', () => { - const payload = L1NotePayload.random(); - const ownerPubKey = Point.random(); - const encrypted = payload.toEncryptedBuffer(ownerPubKey); - const randomPrivKey = GrumpkinScalar.random(); - const decrypted = L1NotePayload.fromEncryptedBuffer(encrypted, randomPrivKey); - expect(decrypted).toBeUndefined(); + let payload: L1NotePayload; + let encrypted: Buffer; + + beforeAll(() => { + ovsk = GrumpkinScalar.random(); + ivsk = GrumpkinScalar.random(); + + const ephSk = GrumpkinScalar.random(); + + const recipientAddress = AztecAddress.random(); + const ivpk = grumpkin.mul(Grumpkin.generator, ivsk); + + payload = L1NotePayload.random(); + encrypted = payload.encrypt(ephSk, recipientAddress, ivpk, ovsk); + }); + + it('decrypt a log as incoming', () => { + const recreated = L1NotePayload.decryptAsIncoming(encrypted, ivsk); + + expect(recreated.toBuffer()).toEqual(payload.toBuffer()); + }); + + it('decrypt a log as outgoing', () => { + const recreated = L1NotePayload.decryptAsOutgoing(encrypted, ovsk); + + expect(recreated.toBuffer()).toEqual(payload.toBuffer()); + }); }); }); diff --git a/yarn-project/circuit-types/src/logs/l1_note_payload/l1_note_payload.ts b/yarn-project/circuit-types/src/logs/l1_note_payload/l1_note_payload.ts index 463512782a7..285befd192d 100644 --- a/yarn-project/circuit-types/src/logs/l1_note_payload/l1_note_payload.ts +++ b/yarn-project/circuit-types/src/logs/l1_note_payload/l1_note_payload.ts @@ -1,10 +1,27 @@ -import { AztecAddress, type GrumpkinPrivateKey, type PublicKey } from '@aztec/circuits.js'; -import { Fr, GrumpkinScalar } from '@aztec/foundation/fields'; +import { + AztecAddress, + type GrumpkinPrivateKey, + type PublicKey, + computeIvpkApp, + computeIvskApp, + computeOvskApp, + derivePublicKeyFromSecretKey, +} from '@aztec/circuits.js'; +import { Fr, Point } from '@aztec/foundation/fields'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; -import { decryptBuffer, encryptBuffer } from './encrypt_buffer.js'; +import { EncryptedLogHeader } from './encrypted_log_header.js'; +import { EncryptedLogIncomingBody } from './encrypted_log_incoming_body.js'; +import { EncryptedLogOutgoingBody } from './encrypted_log_outgoing_body.js'; import { Note } from './note.js'; +// Both the incoming and the outgoing header are 48 bytes. +// 32 bytes for the address, and 16 bytes padding to follow PKCS#7 +const HEADER_SIZE = 48; + +// The outgoing body is constant size of 176 bytes. +// 160 bytes for the secret key, address, and public key, and 16 bytes padding to follow PKCS#7 +const OUTGOING_BODY_SIZE = 176; /** * A class which wraps note data which is pushed on L1. * @remarks This data is required to compute a nullifier/to spend a note. Along with that this class contains @@ -21,7 +38,7 @@ export class L1NotePayload { */ public contractAddress: AztecAddress, /** - * Storage slot of the contract this tx is interacting with. + * Storage slot of the underlying note. */ public storageSlot: Fr, /** @@ -54,34 +71,136 @@ export class L1NotePayload { } /** - * Encrypt the L1NotePayload object using the owner's public key and the ephemeral private key. - * @param incomingViewingPubKey - Public key of the owner of the L1NotePayload object. - * @returns The encrypted L1NotePayload object. + * Create a random L1NotePayload object (useful for testing purposes). + * @returns A random L1NotePayload object. */ - public toEncryptedBuffer(incomingViewingPubKey: PublicKey): Buffer { - const ephSecretKey: GrumpkinPrivateKey = GrumpkinScalar.random(); - return encryptBuffer(this.toBuffer(), ephSecretKey, incomingViewingPubKey); + static random() { + return new L1NotePayload(Note.random(), AztecAddress.random(), Fr.random(), Fr.random()); } /** - * Decrypts the L1NotePayload object using the owner's incoming viewing secret key. - * @param data - Encrypted L1NotePayload object. - * @param incomingViewingSecretKey - Incoming viewing secret key of the owner of the L1NotePayload object. - * @returns Instance of L1NotePayload if the decryption was successful, undefined otherwise. + * Encrypts a note payload for a given recipient and sender. + * Creates an incoming log the the recipient using the recipient's ivsk, and + * an outgoing log for the sender using the sender's ovsk. + * + * @param ephSk - An ephemeral secret key used for the encryption + * @param recipient - The recipient address, retrievable by the sender for his logs + * @param ivpk - The incoming viewing public key of the recipient + * @param ovsk - The outgoing viewing secret key of the sender + * @returns A buffer containing the encrypted log payload */ - static fromEncryptedBuffer(data: Buffer, incomingViewingSecretKey: GrumpkinPrivateKey): L1NotePayload | undefined { - const buf = decryptBuffer(data, incomingViewingSecretKey); - if (!buf) { - return; - } - return L1NotePayload.fromBuffer(buf); + public encrypt(ephSk: GrumpkinPrivateKey, recipient: AztecAddress, ivpk: PublicKey, ovsk: GrumpkinPrivateKey) { + const ephPk = derivePublicKeyFromSecretKey(ephSk); + const ovpk = derivePublicKeyFromSecretKey(ovsk); + + const header = new EncryptedLogHeader(this.contractAddress); + + const incomingHeaderCiphertext = header.computeCiphertext(ephSk, ivpk); + const outgoingHeaderCiphertext = header.computeCiphertext(ephSk, ovpk); + + const ivpkApp = computeIvpkApp(ivpk, this.contractAddress); + + const incomingBodyCiphertext = new EncryptedLogIncomingBody( + this.storageSlot, + this.noteTypeId, + this.note, + ).computeCiphertext(ephSk, ivpkApp); + + const ovskApp = computeOvskApp(ovsk, this.contractAddress); + + const outgoingBodyCiphertext = new EncryptedLogOutgoingBody(ephSk, recipient, ivpkApp).computeCiphertext( + ovskApp, + ephPk, + ); + + return Buffer.concat([ + ephPk.toBuffer(), + incomingHeaderCiphertext, + outgoingHeaderCiphertext, + outgoingBodyCiphertext, + incomingBodyCiphertext, + ]); } /** - * Create a random L1NotePayload object (useful for testing purposes). - * @returns A random L1NotePayload object. + * Decrypts a ciphertext as an incoming log. + * + * This is executable by the recipient of the note, and uses the ivsk to decrypt the payload. + * The outgoing parts of the log are ignored entirely. + * + * Produces the same output as `decryptAsOutgoing`. + * + * @param ciphertext - The ciphertext for the log + * @param ivsk - The incoming viewing secret key, used to decrypt the logs + * @returns The decrypted log payload */ - static random() { - return new L1NotePayload(Note.random(), AztecAddress.random(), Fr.random(), Fr.random()); + public static decryptAsIncoming(ciphertext: Buffer | bigint[], ivsk: GrumpkinPrivateKey) { + const input = Buffer.isBuffer(ciphertext) ? ciphertext : Buffer.from(ciphertext.map((x: bigint) => Number(x))); + const reader = BufferReader.asReader(input); + + const ephPk = reader.readObject(Point); + + const incomingHeader = EncryptedLogHeader.fromCiphertext(reader.readBytes(HEADER_SIZE), ivsk, ephPk); + + // Skipping the outgoing header and body + reader.readBytes(HEADER_SIZE); + reader.readBytes(OUTGOING_BODY_SIZE); + + // The incoming can be of variable size, so we read until the end + const incomingBodySlice = reader.readToEnd(); + + const ivskApp = computeIvskApp(ivsk, incomingHeader.address); + const incomingBody = EncryptedLogIncomingBody.fromCiphertext(incomingBodySlice, ivskApp, ephPk); + + return new L1NotePayload( + incomingBody.note, + incomingHeader.address, + incomingBody.storageSlot, + incomingBody.noteTypeId, + ); + } + + /** + * Decrypts a ciphertext as an outgoing log. + * + * This is executable by the sender of the note, and uses the ovsk to decrypt the payload. + * The outgoing parts are decrypted to retrieve information that allows the sender to + * decrypt the incoming log, and learn about the note contents. + * + * Produces the same output as `decryptAsIncoming`. + * + * @param ciphertext - The ciphertext for the log + * @param ovsk - The outgoing viewing secret key, used to decrypt the logs + * @returns The decrypted log payload + */ + public static decryptAsOutgoing(ciphertext: Buffer | bigint[], ovsk: GrumpkinPrivateKey) { + const input = Buffer.isBuffer(ciphertext) ? ciphertext : Buffer.from(ciphertext.map((x: bigint) => Number(x))); + const reader = BufferReader.asReader(input); + + const ephPk = reader.readObject(Point); + + // Skip the incoming header + reader.readBytes(HEADER_SIZE); + + const outgoingHeader = EncryptedLogHeader.fromCiphertext(reader.readBytes(HEADER_SIZE), ovsk, ephPk); + + const ovskApp = computeOvskApp(ovsk, outgoingHeader.address); + const outgoingBody = EncryptedLogOutgoingBody.fromCiphertext(reader.readBytes(OUTGOING_BODY_SIZE), ovskApp, ephPk); + + // The incoming can be of variable size, so we read until the end + const incomingBodySlice = reader.readToEnd(); + + const incomingBody = EncryptedLogIncomingBody.fromCiphertext( + incomingBodySlice, + outgoingBody.ephSk, + outgoingBody.recipientIvpkApp, + ); + + return new L1NotePayload( + incomingBody.note, + outgoingHeader.address, + incomingBody.storageSlot, + incomingBody.noteTypeId, + ); } } diff --git a/yarn-project/circuit-types/src/logs/l1_note_payload/tagged_note.test.ts b/yarn-project/circuit-types/src/logs/l1_note_payload/tagged_note.test.ts index bbd171f3702..392291c794b 100644 --- a/yarn-project/circuit-types/src/logs/l1_note_payload/tagged_note.test.ts +++ b/yarn-project/circuit-types/src/logs/l1_note_payload/tagged_note.test.ts @@ -1,5 +1,6 @@ +import { AztecAddress } from '@aztec/circuits.js'; import { Grumpkin } from '@aztec/circuits.js/barretenberg'; -import { GrumpkinScalar, Point } from '@aztec/foundation/fields'; +import { GrumpkinScalar } from '@aztec/foundation/fields'; import { L1NotePayload } from './l1_note_payload.js'; import { TaggedNote } from './tagged_note.js'; @@ -18,24 +19,39 @@ describe('L1 Note Payload', () => { expect(TaggedNote.fromBuffer(buf).notePayload).toEqual(taggedNote.notePayload); }); - it('convert to and from encrypted buffer', () => { - const payload = L1NotePayload.random(); - const taggedNote = new TaggedNote(payload); - const ownerPrivKey = GrumpkinScalar.random(); - const ownerPubKey = grumpkin.mul(Grumpkin.generator, ownerPrivKey); - const encrypted = taggedNote.toEncryptedBuffer(ownerPubKey); - const decrypted = TaggedNote.fromEncryptedBuffer(encrypted, ownerPrivKey); - expect(decrypted).not.toBeUndefined(); - expect(decrypted?.notePayload).toEqual(payload); - }); + describe('encrypt and decrypt a full log', () => { + let ovsk: GrumpkinScalar; + let ivsk: GrumpkinScalar; - it('return undefined if unable to decrypt the encrypted buffer', () => { - const payload = L1NotePayload.random(); - const taggedNote = new TaggedNote(payload); - const ownerPubKey = Point.random(); - const encrypted = taggedNote.toEncryptedBuffer(ownerPubKey); - const randomPrivKey = GrumpkinScalar.random(); - const decrypted = TaggedNote.fromEncryptedBuffer(encrypted, randomPrivKey); - expect(decrypted).toBeUndefined(); + let taggedNote: TaggedNote; + let encrypted: Buffer; + + beforeAll(() => { + ovsk = GrumpkinScalar.random(); + ivsk = GrumpkinScalar.random(); + + const ephSk = GrumpkinScalar.random(); + + const recipientAddress = AztecAddress.random(); + const ivpk = grumpkin.mul(Grumpkin.generator, ivsk); + + const payload = L1NotePayload.random(); + + taggedNote = new TaggedNote(payload); + + encrypted = taggedNote.encrypt(ephSk, recipientAddress, ivpk, ovsk); + }); + + it('decrypt a log as incoming', () => { + const recreated = TaggedNote.decryptAsIncoming(encrypted, ivsk); + + expect(recreated?.toBuffer()).toEqual(taggedNote.toBuffer()); + }); + + it('decrypt a log as outgoing', () => { + const recreated = TaggedNote.decryptAsOutgoing(encrypted, ovsk); + + expect(recreated?.toBuffer()).toEqual(taggedNote.toBuffer()); + }); }); }); diff --git a/yarn-project/circuit-types/src/logs/l1_note_payload/tagged_note.ts b/yarn-project/circuit-types/src/logs/l1_note_payload/tagged_note.ts index 4e698e382eb..aa1e45a1aa1 100644 --- a/yarn-project/circuit-types/src/logs/l1_note_payload/tagged_note.ts +++ b/yarn-project/circuit-types/src/logs/l1_note_payload/tagged_note.ts @@ -1,4 +1,4 @@ -import { type GrumpkinPrivateKey, type PublicKey } from '@aztec/circuits.js'; +import { type AztecAddress, type GrumpkinPrivateKey, type PublicKey } from '@aztec/circuits.js'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; @@ -11,7 +11,11 @@ const PLACEHOLDER_TAG = new Fr(33); * Encrypted note payload with a tag used for retrieval by clients. */ export class TaggedNote { - constructor(public notePayload: L1NotePayload, public tag = PLACEHOLDER_TAG) {} + constructor( + public notePayload: L1NotePayload, + public incomingTag = PLACEHOLDER_TAG, + public outgoingTag = PLACEHOLDER_TAG, + ) {} /** * Deserializes the TaggedNote object from a Buffer. @@ -20,9 +24,10 @@ export class TaggedNote { */ static fromBuffer(buffer: Buffer | BufferReader): TaggedNote { const reader = BufferReader.asReader(buffer); - const tag = Fr.fromBuffer(reader); + const incomingTag = Fr.fromBuffer(reader); + const outgoingTag = Fr.fromBuffer(reader); const payload = L1NotePayload.fromBuffer(reader); - return new TaggedNote(payload, tag); + return new TaggedNote(payload, incomingTag, outgoingTag); } /** @@ -30,39 +35,53 @@ export class TaggedNote { * @returns Buffer representation of the TaggedNote object (unencrypted). */ public toBuffer(): Buffer { - return serializeToBuffer(this.tag, this.notePayload); + return serializeToBuffer(this.incomingTag, this.outgoingTag, this.notePayload); } - /** - * Encrypt the L1NotePayload object using the owner's public key and the ephemeral private key, then attach the tag. - * @param ownerPubKey - Public key of the owner of the TaggedNote object. - * @returns The encrypted TaggedNote object. - */ - public toEncryptedBuffer(ownerPubKey: PublicKey): Buffer { - const encryptedL1NotePayload = this.notePayload.toEncryptedBuffer(ownerPubKey); - return serializeToBuffer(this.tag, encryptedL1NotePayload); + static random(): TaggedNote { + return new TaggedNote(L1NotePayload.random()); } - /** - * Decrypts the L1NotePayload object using the owner's private key. - * @param data - Encrypted TaggedNote object. - * @param ownerPrivKey - Private key of the owner of the TaggedNote object. - * @returns Instance of TaggedNote if the decryption was successful, undefined otherwise. - */ - static fromEncryptedBuffer(data: Buffer, ownerPrivKey: GrumpkinPrivateKey): TaggedNote | undefined { - const reader = BufferReader.asReader(data); - const tag = Fr.fromBuffer(reader); - - const encryptedL1NotePayload = reader.readToEnd(); + public encrypt( + ephSk: GrumpkinPrivateKey, + recipient: AztecAddress, + ivpk: PublicKey, + ovsk: GrumpkinPrivateKey, + ): Buffer { + return serializeToBuffer( + this.incomingTag, + this.outgoingTag, + this.notePayload.encrypt(ephSk, recipient, ivpk, ovsk), + ); + } - const payload = L1NotePayload.fromEncryptedBuffer(encryptedL1NotePayload, ownerPrivKey); - if (!payload) { + static decryptAsIncoming(data: Buffer | bigint[], ivsk: GrumpkinPrivateKey) { + // Right now heavily abusing that we will likely fail if bad decryption + // as some field will likely end up not being in the field etc. + try { + const input = Buffer.isBuffer(data) ? data : Buffer.from(data.map((x: bigint) => Number(x))); + const reader = BufferReader.asReader(input); + const incomingTag = Fr.fromBuffer(reader); + const outgoingTag = Fr.fromBuffer(reader); + const payload = L1NotePayload.decryptAsIncoming(reader.readToEnd(), ivsk); + return new TaggedNote(payload, incomingTag, outgoingTag); + } catch (e) { return; } - return new TaggedNote(payload, tag); } - static random(): TaggedNote { - return new TaggedNote(L1NotePayload.random()); + static decryptAsOutgoing(data: Buffer | bigint[], ovsk: GrumpkinPrivateKey) { + // Right now heavily abusing that we will likely fail if bad decryption + // as some field will likely end up not being in the field etc. + try { + const input = Buffer.isBuffer(data) ? data : Buffer.from(data.map((x: bigint) => Number(x))); + const reader = BufferReader.asReader(input); + const incomingTag = Fr.fromBuffer(reader); + const outgoingTag = Fr.fromBuffer(reader); + const payload = L1NotePayload.decryptAsOutgoing(reader.readToEnd(), ovsk); + return new TaggedNote(payload, incomingTag, outgoingTag); + } catch (e) { + return; + } } } diff --git a/yarn-project/end-to-end/src/benchmarks/bench_tx_size_fees.test.ts b/yarn-project/end-to-end/src/benchmarks/bench_tx_size_fees.test.ts index a73f08a32d2..a55331b5f3b 100644 --- a/yarn-project/end-to-end/src/benchmarks/bench_tx_size_fees.test.ts +++ b/yarn-project/end-to-end/src/benchmarks/bench_tx_size_fees.test.ts @@ -67,28 +67,28 @@ describe('benchmarks/tx_size_fees', () => { 'native fee', () => NativeFeePaymentMethod.create(aliceWallet), // DA: - // non-rev: 1 nullifiers, overhead; rev: 2 note hashes, 1 nullifier, 616 B enc logs, 0 B unenc logs, teardown + // non-rev: 1 nullifiers, overhead; rev: 2 note hashes, 1 nullifier, 1168 B enc note logs, 0 B enc logs, 0 B unenc logs, teardown // L2: // non-rev: 0; rev: 0 - 200012416n, + 200021120n, ], [ 'public fee', () => Promise.resolve(new PublicFeePaymentMethod(token.address, fpc.address, aliceWallet)), // DA: - // non-rev: 1 nullifiers, overhead; rev: 2 note hashes, 1 nullifier, 616 B enc logs, 0 B unenc logs, teardown + // non-rev: 1 nullifiers, overhead; rev: 2 note hashes, 1 nullifier, 1168 B enc note logs, 0 B enc logs,0 B unenc logs, teardown // L2: // non-rev: 0; rev: 0 - 200012416n, + 200021120n, ], [ 'private fee', () => Promise.resolve(new PrivateFeePaymentMethod(token.address, fpc.address, aliceWallet)), // DA: - // non-rev: 3 nullifiers, overhead; rev: 2 note hashes, 616 B enc logs, 0 B unenc logs, teardown + // non-rev: 3 nullifiers, overhead; rev: 2 note hashes, 1168 B enc note logs, 0 B enc logs, 0 B unenc logs, teardown // L2: // non-rev: 0; rev: 0 - 200012928n, + 200021632n, ], ] as const)( 'sends a tx with a fee with %s payment method', diff --git a/yarn-project/end-to-end/src/e2e_block_building.test.ts b/yarn-project/end-to-end/src/e2e_block_building.test.ts index cbafb01600a..e923674e705 100644 --- a/yarn-project/end-to-end/src/e2e_block_building.test.ts +++ b/yarn-project/end-to-end/src/e2e_block_building.test.ts @@ -273,7 +273,7 @@ describe('e2e_block_building', () => { expect(rct.status).toEqual('mined'); const decryptedLogs = tx.noteEncryptedLogs .unrollLogs() - .map(l => TaggedNote.fromEncryptedBuffer(l.data, keys.masterIncomingViewingSecretKey)); + .map(l => TaggedNote.decryptAsIncoming(l.data, keys.masterIncomingViewingSecretKey)); const notevalues = decryptedLogs.map(l => l?.notePayload.note.items[0]); expect(notevalues[0]).toEqual(new Fr(10)); expect(notevalues[1]).toEqual(new Fr(11)); diff --git a/yarn-project/prover-client/src/orchestrator/orchestrator.ts b/yarn-project/prover-client/src/orchestrator/orchestrator.ts index 48d144b05fd..eb7198b7607 100644 --- a/yarn-project/prover-client/src/orchestrator/orchestrator.ts +++ b/yarn-project/prover-client/src/orchestrator/orchestrator.ts @@ -425,6 +425,7 @@ export class ProvingOrchestrator { .toBuffer() .equals(tx.processedTx.encryptedLogs.hash()) ) { + // @todo This rejection messages is never seen. Never making it out to the logs provingState.reject( `Encrypted logs hash mismatch: ${ tx.baseRollupInputs.kernelData.publicInputs.end.encryptedLogsHash diff --git a/yarn-project/pxe/src/note_processor/note_processor.test.ts b/yarn-project/pxe/src/note_processor/note_processor.test.ts index 8c2ba5d8b01..e9c656c09d3 100644 --- a/yarn-project/pxe/src/note_processor/note_processor.test.ts +++ b/yarn-project/pxe/src/note_processor/note_processor.test.ts @@ -10,6 +10,7 @@ import { TaggedNote, } from '@aztec/circuit-types'; import { + AztecAddress, Fr, type GrumpkinPrivateKey, INITIAL_L2_BLOCK_NUM, @@ -18,7 +19,7 @@ import { deriveKeys, } from '@aztec/circuits.js'; import { pedersenHash } from '@aztec/foundation/crypto'; -import { Point } from '@aztec/foundation/fields'; +import { GrumpkinScalar, Point } from '@aztec/foundation/fields'; import { openTmpStore } from '@aztec/kv-store/utils'; import { type AcirSimulator } from '@aztec/simulator'; @@ -62,7 +63,7 @@ describe('Note Processor', () => { const logs: EncryptedFunctionL2Logs[] = []; for (let noteIndex = 0; noteIndex < MAX_NEW_NOTE_HASHES_PER_TX; ++noteIndex) { const isOwner = ownedDataIndices.includes(noteIndex); - const publicKey = isOwner ? ownerMasterIncomingViewingPublicKey : Point.random(); + const ivsk = isOwner ? ownerMasterIncomingViewingPublicKey : Point.random(); const note = (isOwner && ownedNotes[usedOwnedNote]) || TaggedNote.random(); usedOwnedNote += note === ownedNotes[usedOwnedNote] ? 1 : 0; newNotes.push(note); @@ -70,7 +71,12 @@ describe('Note Processor', () => { ownedL1NotePayloads.push(note.notePayload); } // const encryptedNote = - const log = note.toEncryptedBuffer(publicKey); + //const log = note.toEncryptedBuffer(publicKey); + + const ephSk = GrumpkinScalar.random(); + const ovsk = GrumpkinScalar.random(); + const recipient = AztecAddress.random(); + const log = note.encrypt(ephSk, recipient, ivsk, ovsk); // 1 tx containing 1 function invocation containing 1 log logs.push(new EncryptedFunctionL2Logs([new EncryptedL2Log(log)])); } diff --git a/yarn-project/pxe/src/note_processor/note_processor.ts b/yarn-project/pxe/src/note_processor/note_processor.ts index 3eaa6b3006d..f8b4c13b571 100644 --- a/yarn-project/pxe/src/note_processor/note_processor.ts +++ b/yarn-project/pxe/src/note_processor/note_processor.ts @@ -130,7 +130,8 @@ export class NoteProcessor { for (const functionLogs of txFunctionLogs) { for (const log of functionLogs.logs) { this.stats.seen++; - const taggedNote = TaggedNote.fromEncryptedBuffer(log.data, secretKey); + // @todo Issue(#6410) We should also try decrypting as outgoing if this fails. + const taggedNote = TaggedNote.decryptAsIncoming(log.data, secretKey); if (taggedNote?.notePayload) { const { notePayload: payload } = taggedNote; // We have successfully decrypted the data. diff --git a/yarn-project/simulator/src/acvm/oracle/oracle.ts b/yarn-project/simulator/src/acvm/oracle/oracle.ts index 9def84c9f12..26d8de73567 100644 --- a/yarn-project/simulator/src/acvm/oracle/oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/oracle.ts @@ -286,33 +286,39 @@ export class Oracle { return newValues.map(toACVMField); } - emitEncryptedLog( + emitEncryptedLog(encryptedLog: ACVMField[], [counter]: ACVMField[]): void { + // Convert each field to a number and then to a buffer (1 byte is stored in 1 field) + const processedInput = Buffer.from(encryptedLog.map(fromACVMField).map(f => f.toNumber())); + this.typedOracle.emitEncryptedLog(processedInput, +counter); + } + + emitEncryptedNoteLog([noteHash]: ACVMField[], encryptedNote: ACVMField[], [counter]: ACVMField[]): void { + // Convert each field to a number and then to a buffer (1 byte is stored in 1 field) + const processedInput = Buffer.from(encryptedNote.map(fromACVMField).map(f => f.toNumber())); + this.typedOracle.emitEncryptedNoteLog(fromACVMField(noteHash), processedInput, +counter); + } + + computeEncryptedLog( [contractAddress]: ACVMField[], [storageSlot]: ACVMField[], [noteTypeId]: ACVMField[], [publicKeyX]: ACVMField[], [publicKeyY]: ACVMField[], - log: ACVMField[], - [counter]: ACVMField[], + preimage: ACVMField[], ): ACVMField[] { const publicKey = new Point(fromACVMField(publicKeyX), fromACVMField(publicKeyY)); - const encLog = this.typedOracle.emitEncryptedLog( + const encLog = this.typedOracle.computeEncryptedLog( AztecAddress.fromString(contractAddress), Fr.fromString(storageSlot), Fr.fromString(noteTypeId), publicKey, - log.map(fromACVMField), - +counter, + preimage.map(fromACVMField), ); - // TODO(1139): We should encrypt in the circuit, but instead we inject here - // encryption output is 112 + 32 * (N + 3) bytes, for log len N - // so split into N + 7 fields (gross but avoids 300+ ACVMFields) - const encLogFields = []; - for (let i = 0; i < Math.ceil(encLog.length / 31); i++) { - encLogFields.push(toACVMField(encLog.subarray(31 * i, Math.min(31 * (i + 1), encLog.length)))); - } - - return encLogFields; + const bytes: ACVMField[] = []; + encLog.forEach(v => { + bytes.push(toACVMField(v)); + }); + return bytes; } emitUnencryptedLog( diff --git a/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts b/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts index 4a910040384..9c39638adea 100644 --- a/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts @@ -183,15 +183,22 @@ export abstract class TypedOracle { throw new OracleMethodNotAvailableError('storageWrite'); } - emitEncryptedLog( + emitEncryptedLog(_encryptedNote: Buffer, _counter: number): void { + throw new OracleMethodNotAvailableError('emitEncryptedLog'); + } + + emitEncryptedNoteLog(_noteHash: Fr, _encryptedNote: Buffer, _counter: number): void { + throw new OracleMethodNotAvailableError('emitEncryptedNoteLog'); + } + + computeEncryptedLog( _contractAddress: AztecAddress, _storageSlot: Fr, _noteTypeId: Fr, _publicKey: PublicKey, - _log: Fr[], - _counter: number, + _preimage: Fr[], ): Buffer { - throw new OracleMethodNotAvailableError('emitEncryptedLog'); + throw new OracleMethodNotAvailableError('computeEncryptedLog'); } emitUnencryptedLog(_log: UnencryptedL2Log, _counter: number): void { diff --git a/yarn-project/simulator/src/client/client_execution_context.ts b/yarn-project/simulator/src/client/client_execution_context.ts index 10ba67b01ad..148cddf078e 100644 --- a/yarn-project/simulator/src/client/client_execution_context.ts +++ b/yarn-project/simulator/src/client/client_execution_context.ts @@ -7,7 +7,6 @@ import { type NoteStatus, TaggedNote, type UnencryptedL2Log, - encryptBuffer, } from '@aztec/circuit-types'; import { CallContext, @@ -19,18 +18,11 @@ import { type TxContext, } from '@aztec/circuits.js'; import { Aes128 } from '@aztec/circuits.js/barretenberg'; -import { - computeInnerNoteHash, - computeNoteContentHash, - computePublicDataTreeLeafSlot, - computeUniqueNoteHash, - siloNoteHash, -} from '@aztec/circuits.js/hash'; +import { computePublicDataTreeLeafSlot, computeUniqueNoteHash, siloNoteHash } from '@aztec/circuits.js/hash'; import { type FunctionAbi, type FunctionArtifact, countArgumentsSize } from '@aztec/foundation/abi'; -import { type AztecAddress } from '@aztec/foundation/aztec-address'; +import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr, GrumpkinScalar, type Point } from '@aztec/foundation/fields'; import { applyStringFormatting, createDebugLogger } from '@aztec/foundation/log'; -import { serializeToBuffer } from '@aztec/foundation/serialize'; import { type NoteData, toACVMWitness } from '../acvm/index.js'; import { type PackedValuesCache } from '../common/packed_values_cache.js'; @@ -362,44 +354,53 @@ export class ClientExecutionContext extends ViewDataOracle { } /** - * Encrypt a note and emit it as a log. + * Emit encrypted data + * @param encryptedNote - The encrypted data. + * @param counter - The effects counter. + */ + public override emitEncryptedLog(encryptedData: Buffer, counter: number) { + const encryptedLog = new CountedLog(new EncryptedL2Log(encryptedData), counter); + this.encryptedLogs.push(encryptedLog); + } + + /** + * Emit encrypted note data + * @param noteHash - The note hash. + * @param encryptedNote - The encrypted note data. + * @param counter - The effects counter. + */ + public override emitEncryptedNoteLog(noteHash: Fr, encryptedNote: Buffer, counter: number) { + const encryptedLog = new CountedLog(new EncryptedL2Log(encryptedNote), counter); + this.noteEncryptedLogs.push(encryptedLog); + this.noteCache.addNewLog(encryptedLog, noteHash); + } + + /** + * Encrypt a note * @param contractAddress - The contract address of the note. * @param storageSlot - The storage slot the note is at. * @param noteTypeId - The type ID of the note. - * @param publicKey - The public key of the account that can decrypt the log. - * @param log - The log contents. + * @param ivpk - The master incoming viewing public key. + * @param preimage - The note preimage. */ - public override emitEncryptedLog( + public override computeEncryptedLog( contractAddress: AztecAddress, storageSlot: Fr, noteTypeId: Fr, - publicKey: Point, - log: Fr[], - counter: number, + ivpk: Point, + preimage: Fr[], ) { - // TODO(Miranda): This is a temporary solution until we encrypt logs in the circuit - // Then we require a new oracle that deals only with notes - const note = new Note(log); - const innerNoteHash = computeInnerNoteHash(storageSlot, computeNoteContentHash(log)); - const noteExists = this.noteCache.checkNoteExists(contractAddress, innerNoteHash); - if (noteExists) { - // Log linked to note - const l1NotePayload = new L1NotePayload(note, contractAddress, storageSlot, noteTypeId); - const taggedNote = new TaggedNote(l1NotePayload); - const encryptedNote = taggedNote.toEncryptedBuffer(publicKey); - const encryptedLog = new CountedLog(new EncryptedL2Log(encryptedNote), counter); - this.noteEncryptedLogs.push(encryptedLog); - this.noteCache.addNewLog(encryptedLog, innerNoteHash); - return encryptedNote; - } else { - // Generic non-note log - // We assume only the log and address are required - const preimage = Buffer.concat([contractAddress.toBuffer(), serializeToBuffer(log)]); - const encryptedMsg = encryptBuffer(preimage, GrumpkinScalar.random(), publicKey); - const encryptedLog = new EncryptedL2Log(encryptedMsg); - this.encryptedLogs.push(new CountedLog(encryptedLog, counter)); - return encryptedMsg; - } + const note = new Note(preimage); + const l1NotePayload = new L1NotePayload(note, contractAddress, storageSlot, noteTypeId); + const taggedNote = new TaggedNote(l1NotePayload); + + const ephSk = GrumpkinScalar.random(); + + // @todo Issue(#6410) Right now we are completely ignoring the outgoing log. Just drawing random data. + const ovsk = GrumpkinScalar.random(); + const recipient = AztecAddress.random(); + + return taggedNote.encrypt(ephSk, recipient, ivpk, ovsk); } /**