From 271edbce0ced0e8a844428f3d6277f33685a64b0 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Wed, 26 Apr 2023 19:06:24 -0300 Subject: [PATCH 1/5] Validate public state reads and writes in native base rollup circuit --- .../src/aztec3/circuits/rollup/base/.test.cpp | 130 ++++++++++++++++++ .../src/aztec3/circuits/rollup/base/init.hpp | 3 + .../base/native_base_rollup_circuit.cpp | 119 ++++++++++++++-- .../circuits/rollup/test_utils/utils.cpp | 85 +++++++++++- .../circuits/rollup/test_utils/utils.hpp | 42 +++++- circuits/cpp/src/aztec3/constants.hpp | 2 +- .../cpp/src/aztec3/utils/circuit_errors.hpp | 1 + 7 files changed, 367 insertions(+), 15 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/rollup/base/.test.cpp b/circuits/cpp/src/aztec3/circuits/rollup/base/.test.cpp index 792557a4fb4..07a20532413 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/.test.cpp @@ -2,11 +2,13 @@ #include "aztec3/circuits/abis/membership_witness.hpp" #include "aztec3/circuits/abis/new_contract_data.hpp" #include "aztec3/circuits/abis/previous_kernel_data.hpp" +#include "aztec3/circuits/abis/public_data_read.hpp" #include "aztec3/circuits/kernel/private/utils.hpp" #include "aztec3/circuits/abis/rollup/nullifier_leaf_preimage.hpp" #include "aztec3/constants.hpp" #include "barretenberg/crypto/sha256/sha256.hpp" #include "barretenberg/ecc/curves/bn254/fr.hpp" +#include "barretenberg/stdlib/merkle_tree/memory_store.hpp" #include "barretenberg/stdlib/merkle_tree/memory_tree.hpp" #include "aztec3/circuits/rollup/test_utils/utils.hpp" @@ -99,6 +101,9 @@ using aztec3::circuits::abis::FunctionData; using aztec3::circuits::abis::NewContractData; using aztec3::circuits::abis::OptionallyRevealedData; +using aztec3::circuits::rollup::test_utils::utils::make_public_read; +using aztec3::circuits::rollup::test_utils::utils::make_public_write; + using DummyComposer = aztec3::utils::DummyComposer; } // namespace @@ -762,4 +767,129 @@ TEST_F(base_rollup_tests, native_cbind_0) run_cbind(inputs, ignored_public_inputs, false); } +TEST_F(base_rollup_tests, native_single_public_state_read) +{ + DummyComposer composer = DummyComposer(); + native_base_rollup::MerkleTree private_data_tree(PRIVATE_DATA_TREE_HEIGHT); + native_base_rollup::MerkleTree contract_tree(CONTRACT_TREE_HEIGHT); + stdlib::merkle_tree::MemoryStore public_data_tree_store; + native_base_rollup::SparseTree public_data_tree(public_data_tree_store, PUBLIC_DATA_TREE_HEIGHT); + + auto data_read = abis::PublicDataRead{ + .leaf_index = fr(1), + .value = fr(42), + }; + + std::array, 2> kernel_data = { get_empty_kernel(), get_empty_kernel() }; + kernel_data[0].public_inputs.end.state_reads[0] = data_read; + auto inputs = test_utils::utils::base_rollup_inputs_from_kernels( + kernel_data, private_data_tree, contract_tree, public_data_tree); + + BaseOrMergeRollupPublicInputs outputs = + aztec3::circuits::rollup::native_base_rollup::base_rollup_circuit(composer, inputs); + + ASSERT_EQ(outputs.start_public_data_tree_snapshot, inputs.start_public_data_tree_snapshot); + ASSERT_EQ(outputs.end_public_data_tree_snapshot.root, public_data_tree.root()); + ASSERT_EQ(outputs.end_public_data_tree_snapshot, outputs.start_public_data_tree_snapshot); + ASSERT_FALSE(composer.failed()); + run_cbind(inputs, outputs); +} + +TEST_F(base_rollup_tests, native_single_public_state_write) +{ + DummyComposer composer = DummyComposer(); + native_base_rollup::MerkleTree private_data_tree(PRIVATE_DATA_TREE_HEIGHT); + native_base_rollup::MerkleTree contract_tree(CONTRACT_TREE_HEIGHT); + stdlib::merkle_tree::MemoryStore public_data_tree_store; + native_base_rollup::SparseTree public_data_tree(public_data_tree_store, PUBLIC_DATA_TREE_HEIGHT); + + auto data_write = abis::PublicDataWrite{ + .leaf_index = fr(1), + .old_value = fr(2), + .new_value = fr(42), + }; + + std::array, 2> kernel_data = { get_empty_kernel(), get_empty_kernel() }; + kernel_data[0].public_inputs.end.state_transitions[0] = data_write; + + auto inputs = test_utils::utils::base_rollup_inputs_from_kernels( + kernel_data, private_data_tree, contract_tree, public_data_tree); + + BaseOrMergeRollupPublicInputs outputs = + aztec3::circuits::rollup::native_base_rollup::base_rollup_circuit(composer, inputs); + + ASSERT_EQ(outputs.start_public_data_tree_snapshot, inputs.start_public_data_tree_snapshot); + ASSERT_EQ(outputs.end_public_data_tree_snapshot.root, public_data_tree.root()); + ASSERT_NE(outputs.end_public_data_tree_snapshot, outputs.start_public_data_tree_snapshot); + ASSERT_FALSE(composer.failed()); + run_cbind(inputs, outputs); +} + +TEST_F(base_rollup_tests, native_multiple_public_state_read_writes) +{ + DummyComposer composer = DummyComposer(); + native_base_rollup::MerkleTree private_data_tree(PRIVATE_DATA_TREE_HEIGHT); + native_base_rollup::MerkleTree contract_tree(CONTRACT_TREE_HEIGHT); + stdlib::merkle_tree::MemoryStore public_data_tree_store; + native_base_rollup::SparseTree public_data_tree(public_data_tree_store, PUBLIC_DATA_TREE_HEIGHT); + + std::array, 2> kernel_data = { get_empty_kernel(), get_empty_kernel() }; + + // We set up reads and writes such that the right tx will read or write to indices already modified by the left tx + kernel_data[0].public_inputs.end.state_reads[0] = make_public_read(fr(1), fr(101)); + kernel_data[0].public_inputs.end.state_reads[1] = make_public_read(fr(2), fr(102)); + kernel_data[0].public_inputs.end.state_transitions[0] = make_public_write(fr(3), fr(103), fr(203)); + kernel_data[0].public_inputs.end.state_transitions[1] = make_public_write(fr(4), fr(104), fr(204)); + kernel_data[0].public_inputs.end.state_transitions[2] = make_public_write(fr(5), fr(105), fr(205)); + + kernel_data[1].public_inputs.end.state_reads[0] = make_public_read(fr(3), fr(203)); + kernel_data[1].public_inputs.end.state_reads[1] = make_public_read(fr(11), fr(211)); + kernel_data[1].public_inputs.end.state_transitions[0] = make_public_write(fr(12), fr(212), fr(312)); + kernel_data[1].public_inputs.end.state_transitions[1] = make_public_write(fr(4), fr(204), fr(304)); + + auto inputs = test_utils::utils::base_rollup_inputs_from_kernels( + kernel_data, private_data_tree, contract_tree, public_data_tree); + + BaseOrMergeRollupPublicInputs outputs = + aztec3::circuits::rollup::native_base_rollup::base_rollup_circuit(composer, inputs); + + ASSERT_EQ(outputs.start_public_data_tree_snapshot, inputs.start_public_data_tree_snapshot); + ASSERT_EQ(outputs.end_public_data_tree_snapshot.root, public_data_tree.root()); + ASSERT_NE(outputs.end_public_data_tree_snapshot, outputs.start_public_data_tree_snapshot); + ASSERT_FALSE(composer.failed()); + run_cbind(inputs, outputs); +} + +TEST_F(base_rollup_tests, native_invalid_public_state_read) +{ + DummyComposer composer = DummyComposer(); + native_base_rollup::MerkleTree private_data_tree(PRIVATE_DATA_TREE_HEIGHT); + native_base_rollup::MerkleTree contract_tree(CONTRACT_TREE_HEIGHT); + stdlib::merkle_tree::MemoryStore public_data_tree_store; + native_base_rollup::SparseTree public_data_tree(public_data_tree_store, PUBLIC_DATA_TREE_HEIGHT); + + auto data_read = abis::PublicDataRead{ + .leaf_index = fr(1), + .value = fr(42), + }; + + std::array, 2> kernel_data = { get_empty_kernel(), get_empty_kernel() }; + kernel_data[0].public_inputs.end.state_reads[0] = data_read; + auto inputs = test_utils::utils::base_rollup_inputs_from_kernels( + kernel_data, private_data_tree, contract_tree, public_data_tree); + + // We change the initial tree root so the read value does not match + public_data_tree.update_element(1, fr(43)); + inputs.start_public_data_tree_snapshot.root = public_data_tree.root(); + + BaseOrMergeRollupPublicInputs outputs = + aztec3::circuits::rollup::native_base_rollup::base_rollup_circuit(composer, inputs); + + ASSERT_EQ(outputs.start_public_data_tree_snapshot, inputs.start_public_data_tree_snapshot); + ASSERT_EQ(outputs.end_public_data_tree_snapshot.root, public_data_tree.root()); + ASSERT_EQ(outputs.end_public_data_tree_snapshot, outputs.start_public_data_tree_snapshot); + ASSERT_TRUE(composer.failed()); + run_cbind(inputs, outputs); +} + } // namespace aztec3::circuits::rollup::base::native_base_rollup_circuit diff --git a/circuits/cpp/src/aztec3/circuits/rollup/base/init.hpp b/circuits/cpp/src/aztec3/circuits/rollup/base/init.hpp index 1447a72f24a..b88681081b0 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/init.hpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/init.hpp @@ -6,7 +6,9 @@ #include "aztec3/circuits/abis/rollup/base/base_rollup_inputs.hpp" #include "aztec3/circuits/abis/rollup/base/base_or_merge_rollup_public_inputs.hpp" #include "aztec3/utils/circuit_errors.hpp" +#include "barretenberg/stdlib/merkle_tree/memory_store.hpp" #include "barretenberg/stdlib/merkle_tree/memory_tree.hpp" +#include "barretenberg/stdlib/merkle_tree/merkle_tree.hpp" #include "barretenberg/stdlib/merkle_tree/nullifier_tree/nullifier_memory_tree.hpp" #include #include @@ -39,5 +41,6 @@ using AppendOnlySnapshot = abis::AppendOnlyTreeSnapshot; using MerkleTree = stdlib::merkle_tree::MemoryTree; using NullifierTree = stdlib::merkle_tree::NullifierMemoryTree; using NullifierLeaf = stdlib::merkle_tree::nullifier_leaf; +using SparseTree = stdlib::merkle_tree::MerkleTree; } // namespace aztec3::circuits::rollup::native_base_rollup \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp b/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp index 21b6db68d71..6f360e3c5b3 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp @@ -1,3 +1,6 @@ +#include "aztec3/circuits/abis/membership_witness.hpp" +#include "aztec3/circuits/abis/public_data_read.hpp" +#include "aztec3/circuits/abis/public_data_write.hpp" #include "aztec3/circuits/hash.hpp" #include "aztec3/constants.hpp" #include "aztec3/utils/circuit_errors.hpp" @@ -428,15 +431,107 @@ AppendOnlySnapshot check_nullifier_tree_non_membership_and_insert_to_tree(DummyC }; } -AppendOnlySnapshot insert_state_transitions(BaseRollupInputs const& baseRollupInputs) +fr insert_state_transitions( + DummyComposer& composer, + fr tree_root, + std::array, STATE_TRANSITIONS_LENGTH> const& state_transitions, + size_t witnesses_offset, + std::array, 2 * STATE_TRANSITIONS_LENGTH> const& witnesses) { - // TODO: Implement me - auto root = baseRollupInputs.start_public_data_tree_snapshot.root; + auto root = tree_root; - return { - .root = root, - .next_available_leaf_index = 0, - }; + for (size_t i = 0; i < STATE_TRANSITIONS_LENGTH; ++i) { + const auto& state_write = state_transitions[i]; + const auto& witness = witnesses[i + witnesses_offset]; + + if (state_write.is_empty()) + continue; + + composer.do_assert( + witness.leaf_index == state_write.leaf_index, + format("mismatch state write ", state_write.leaf_index, " and witness leaf index ", witness.leaf_index), + CircuitErrorCode::BASE__INVALID_PUBLIC_READS); + + check_membership(composer, + state_write.old_value, + state_write.leaf_index, + witness.sibling_path, + root, + format("validate_state_reads index ", i)); + + root = root_from_sibling_path(state_write.new_value, state_write.leaf_index, witness.sibling_path); + } + + return root; +} + +void validate_state_reads( + DummyComposer& composer, + fr tree_root, + std::array, STATE_READS_LENGTH> const& state_reads, + size_t witnesses_offset, + std::array, 2 * STATE_READS_LENGTH> const& witnesses) +{ + for (size_t i = 0; i < STATE_READS_LENGTH; ++i) { + const auto& state_read = state_reads[i]; + const auto& witness = witnesses[i + witnesses_offset]; + + if (state_read.is_empty()) + continue; + + composer.do_assert( + witness.leaf_index == state_read.leaf_index, + format("mismatch state read ", state_read.leaf_index, " and witness leaf index ", witness.leaf_index), + CircuitErrorCode::BASE__INVALID_PUBLIC_READS); + + info(" Checking membership for ", + state_read.value, + " at ", + state_read.leaf_index, + " vs ", + tree_root, + " using ", + witness.sibling_path); + check_membership(composer, + state_read.value, + state_read.leaf_index, + witness.sibling_path, + tree_root, + format("validate_state_reads index ", i + witnesses_offset)); + } +}; + +fr validate_and_process_public_state(DummyComposer& composer, BaseRollupInputs const& baseRollupInputs) +{ + // Process state reads and transitions for left input + validate_state_reads(composer, + baseRollupInputs.start_public_data_tree_snapshot.root, + baseRollupInputs.kernel_data[0].public_inputs.end.state_reads, + 0, + baseRollupInputs.new_state_reads_sibling_paths); + + auto mid_public_data_tree_root = + insert_state_transitions(composer, + baseRollupInputs.start_public_data_tree_snapshot.root, + baseRollupInputs.kernel_data[0].public_inputs.end.state_transitions, + 0, + baseRollupInputs.new_state_transitions_sibling_paths); + + // Process state reads and transitions for right input using the resulting tree root from the left one + validate_state_reads(composer, + mid_public_data_tree_root, + baseRollupInputs.kernel_data[1].public_inputs.end.state_reads, + STATE_READS_LENGTH, + baseRollupInputs.new_state_reads_sibling_paths); + + auto end_public_data_tree_root = + insert_state_transitions(composer, + mid_public_data_tree_root, + baseRollupInputs.kernel_data[1].public_inputs.end.state_transitions, + STATE_TRANSITIONS_LENGTH, + baseRollupInputs.new_state_transitions_sibling_paths); + + return end_public_data_tree_root; } BaseOrMergeRollupPublicInputs base_rollup_circuit(DummyComposer& composer, BaseRollupInputs const& baseRollupInputs) @@ -482,8 +577,14 @@ BaseOrMergeRollupPublicInputs base_rollup_circuit(DummyComposer& composer, BaseR AppendOnlySnapshot end_nullifier_tree_snapshot = check_nullifier_tree_non_membership_and_insert_to_tree(composer, baseRollupInputs); - // Insert state transitions - auto end_public_data_tree_snapshot = insert_state_transitions(baseRollupInputs); + // Validate public state reads and transitions, and update public data tree + fr end_public_data_tree_root = validate_and_process_public_state(composer, baseRollupInputs); + // fr end_public_data_tree_root = baseRollupInputs.start_public_data_tree_snapshot.root; + + AppendOnlySnapshot end_public_data_tree_snapshot = { + .root = end_public_data_tree_root, + .next_available_leaf_index = 0, + }; // Calculate the overall calldata hash std::array calldata_hash = calculate_calldata_hash(baseRollupInputs, contract_leaves); diff --git a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp index 4fc6e7a5ef7..fe1b6b3e726 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp @@ -1,3 +1,8 @@ +#include "aztec3/circuits/abis/membership_witness.hpp" +#include "aztec3/circuits/rollup/base/init.hpp" +#include "barretenberg/numeric/uint256/uint256.hpp" +#include "barretenberg/stdlib/merkle_tree/memory_store.hpp" +#include "barretenberg/stdlib/merkle_tree/merkle_tree.hpp" #include "nullifier_tree_testing_harness.hpp" #include "utils.hpp" #include "aztec3/constants.hpp" @@ -5,6 +10,9 @@ #include #include +#include +#include +#include #include "aztec3/circuits/abis/new_contract_data.hpp" #include "aztec3/circuits/abis/rollup/root/root_rollup_public_inputs.hpp" namespace { @@ -25,6 +33,8 @@ using NullifierLeafPreimage = aztec3::circuits::abis::NullifierLeafPreimage; using MerkleTree = stdlib::merkle_tree::MemoryTree; using NullifierTree = stdlib::merkle_tree::NullifierMemoryTree; using NullifierLeaf = stdlib::merkle_tree::nullifier_leaf; +using MemoryStore = stdlib::merkle_tree::MemoryStore; +using SparseTree = stdlib::merkle_tree::MerkleTree; using aztec3::circuits::abis::BaseOrMergeRollupPublicInputs; using aztec3::circuits::abis::MembershipWitness; @@ -59,7 +69,10 @@ void set_kernel_commitments(KernelData& kernel_data, std::array kernel_data) +BaseRollupInputs base_rollup_inputs_from_kernels(std::array kernel_data, + MerkleTree& private_data_tree, + MerkleTree& contract_tree, + SparseTree& public_data_tree) { // @todo Look at the starting points for all of these. // By supporting as inputs we can make very generic tests, where it is trivial to try new setups. @@ -67,9 +80,6 @@ BaseRollupInputs base_rollup_inputs_from_kernels(std::array kerne MerkleTree historic_contract_tree = MerkleTree(CONTRACT_TREE_ROOTS_TREE_HEIGHT); MerkleTree historic_l1_to_l2_msg_tree = MerkleTree(L1_TO_L2_MSG_TREE_ROOTS_TREE_HEIGHT); - MerkleTree private_data_tree = MerkleTree(PRIVATE_DATA_TREE_HEIGHT); - MerkleTree contract_tree = MerkleTree(CONTRACT_TREE_HEIGHT); - // Historic trees are initialised with an empty root at position 0. historic_private_data_tree.update_element(0, private_data_tree.root()); historic_contract_tree.update_element(0, contract_tree.root()); @@ -130,6 +140,62 @@ BaseRollupInputs base_rollup_inputs_from_kernels(std::array kerne baseRollupInputs.new_commitments_subtree_sibling_path = get_sibling_path(private_data_tree, 0, PRIVATE_DATA_SUBTREE_DEPTH); + // Update public data tree to generate sibling paths: we first set the initial public data tree to the result of all + // state reads and old_values from state transitions. Note that, if the right tx reads or writes an index that was + // already processed by the left one, we don't want to reflect that as part of the initial state, so we skip those. + std::set visited_indices; + for (size_t i = 0; i < 2; i++) { + for (auto state_read : kernel_data[i].public_inputs.end.state_reads) { + auto leaf_index = size_t(uint256_t(state_read.leaf_index)); + if (state_read.is_empty() || visited_indices.contains(leaf_index)) + continue; + visited_indices.insert(leaf_index); + public_data_tree.update_element(leaf_index, state_read.value); + } + + for (auto state_write : kernel_data[i].public_inputs.end.state_transitions) { + auto leaf_index = size_t(uint256_t(state_write.leaf_index)); + if (state_write.is_empty() || visited_indices.contains(leaf_index)) + continue; + visited_indices.insert(leaf_index); + public_data_tree.update_element(leaf_index, state_write.old_value); + } + } + + baseRollupInputs.start_public_data_tree_snapshot = { + .root = public_data_tree.root(), + .next_available_leaf_index = 0, + }; + + // Then we collect all sibling paths for the reads in the left tx, and then apply the state transitions while + // collecting their paths. And then repeat for the right tx. + for (size_t i = 0; i < 2; i++) { + for (size_t j = 0; j < STATE_READS_LENGTH; j++) { + auto state_read = kernel_data[i].public_inputs.end.state_reads[j]; + if (state_read.is_empty()) + continue; + auto leaf_index = size_t(uint256_t(state_read.leaf_index)); + baseRollupInputs.new_state_reads_sibling_paths[i * STATE_READS_LENGTH + j] = + MembershipWitness{ + .leaf_index = state_read.leaf_index, + .sibling_path = get_sibling_path(public_data_tree, leaf_index), + }; + } + + for (size_t j = 0; j < STATE_TRANSITIONS_LENGTH; j++) { + auto state_write = kernel_data[i].public_inputs.end.state_transitions[j]; + if (state_write.is_empty()) + continue; + auto leaf_index = size_t(uint256_t(state_write.leaf_index)); + public_data_tree.update_element(leaf_index, state_write.new_value); + baseRollupInputs.new_state_transitions_sibling_paths[i * STATE_TRANSITIONS_LENGTH + j] = + MembershipWitness{ + .leaf_index = state_write.leaf_index, + .sibling_path = get_sibling_path(public_data_tree, leaf_index), + }; + } + } + baseRollupInputs.historic_private_data_tree_root_membership_witnesses[0] = { .leaf_index = 0, .sibling_path = get_sibling_path(historic_private_data_tree, 0, 0), @@ -147,6 +213,17 @@ BaseRollupInputs base_rollup_inputs_from_kernels(std::array kerne return baseRollupInputs; } +BaseRollupInputs base_rollup_inputs_from_kernels(std::array kernel_data) +{ + MerkleTree private_data_tree = MerkleTree(PRIVATE_DATA_TREE_HEIGHT); + MerkleTree contract_tree = MerkleTree(CONTRACT_TREE_HEIGHT); + + MemoryStore public_data_tree_store; + SparseTree public_data_tree(public_data_tree_store, PUBLIC_DATA_TREE_HEIGHT); + + return base_rollup_inputs_from_kernels(kernel_data, private_data_tree, contract_tree, public_data_tree); +} + std::array, 2> get_previous_rollup_data(DummyComposer& composer, std::array kernel_data) { diff --git a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.hpp b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.hpp index 86c259ccdd7..b1a23748752 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.hpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.hpp @@ -1,4 +1,6 @@ #pragma once +#include "aztec3/circuits/abis/public_data_write.hpp" +#include "barretenberg/numeric/uint256/uint256.hpp" #include "nullifier_tree_testing_harness.hpp" #include "init.hpp" @@ -26,6 +28,8 @@ using MerkleTree = stdlib::merkle_tree::MemoryTree; using NullifierTree = stdlib::merkle_tree::NullifierMemoryTree; using NullifierLeaf = stdlib::merkle_tree::nullifier_leaf; using KernelData = aztec3::circuits::abis::PreviousKernelData; +using MemoryStore = stdlib::merkle_tree::MemoryStore; +using SparseTree = stdlib::merkle_tree::MerkleTree; using aztec3::circuits::abis::MembershipWitness; using aztec3::circuits::abis::PreviousRollupData; @@ -35,8 +39,13 @@ using nullifier_tree_testing_values = std::tuple kernel_data); +BaseRollupInputs base_rollup_inputs_from_kernels(std::array kernel_data, + MerkleTree& private_data_tree, + MerkleTree& contract_tree, + SparseTree& public_data_tree); + template -std::array get_sibling_path(MerkleTree tree, size_t leafIndex, size_t const& subtree_depth_to_skip) +std::array get_sibling_path(MerkleTree& tree, size_t leafIndex, size_t const& subtree_depth_to_skip) { std::array siblingPath; auto path = tree.get_hash_path(leafIndex); @@ -52,6 +61,20 @@ std::array get_sibling_path(MerkleTree tree, size_t leafIndex, size_t con return siblingPath; } +template std::array get_sibling_path(SparseTree& tree, uint256_t leafIndex) +{ + std::array siblingPath; + auto path = tree.get_hash_path(leafIndex); + for (size_t i = 0; i < N; i++) { + if (leafIndex & (uint256_t(1) << i)) { + siblingPath[i] = path[i].first; + } else { + siblingPath[i] = path[i].second; + } + } + return siblingPath; +} + abis::AppendOnlyTreeSnapshot get_snapshot_of_tree_state(NullifierMemoryTreeTestingHarness nullifier_tree); nullifier_tree_testing_values generate_nullifier_tree_testing_values_explicit( @@ -78,4 +101,21 @@ void set_kernel_nullifiers(KernelData& kernel_data, std::array kernel_data); +inline abis::PublicDataWrite make_public_write(fr leaf_index, fr old_value, fr new_value) +{ + return abis::PublicDataWrite{ + .leaf_index = leaf_index, + .old_value = old_value, + .new_value = new_value, + }; +}; + +inline abis::PublicDataRead make_public_read(fr leaf_index, fr value) +{ + return abis::PublicDataRead{ + .leaf_index = leaf_index, + .value = value, + }; +} + } // namespace aztec3::circuits::rollup::test_utils::utils \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/constants.hpp b/circuits/cpp/src/aztec3/constants.hpp index 88941a448b1..b961b50eeab 100644 --- a/circuits/cpp/src/aztec3/constants.hpp +++ b/circuits/cpp/src/aztec3/constants.hpp @@ -38,7 +38,7 @@ constexpr size_t CONTRACT_SUBTREE_DEPTH = 1; constexpr size_t CONTRACT_SUBTREE_INCLUSION_CHECK_DEPTH = CONTRACT_TREE_HEIGHT - CONTRACT_SUBTREE_DEPTH; constexpr size_t PRIVATE_DATA_SUBTREE_DEPTH = 3; -constexpr size_t PRIVATE_DATA_SUBTREE_INCLUSION_CHECK_DEPTH = NULLIFIER_TREE_HEIGHT - PRIVATE_DATA_SUBTREE_DEPTH; +constexpr size_t PRIVATE_DATA_SUBTREE_INCLUSION_CHECK_DEPTH = PRIVATE_DATA_TREE_HEIGHT - PRIVATE_DATA_SUBTREE_DEPTH; constexpr size_t NULLIFIER_SUBTREE_DEPTH = 3; constexpr size_t NULLIFIER_SUBTREE_INCLUSION_CHECK_DEPTH = NULLIFIER_TREE_HEIGHT - NULLIFIER_SUBTREE_DEPTH; diff --git a/circuits/cpp/src/aztec3/utils/circuit_errors.hpp b/circuits/cpp/src/aztec3/utils/circuit_errors.hpp index 1e550619e48..43e8e9b1a25 100644 --- a/circuits/cpp/src/aztec3/utils/circuit_errors.hpp +++ b/circuits/cpp/src/aztec3/utils/circuit_errors.hpp @@ -49,6 +49,7 @@ enum CircuitErrorCode : uint16_t { BASE__INCORRECT_NUM_OF_NEW_COMMITMENTS = 4002, BASE__INVALID_NULLIFIER_SUBTREE = 4003, BASE__INVALID_NULLIFIER_RANGE = 4004, + BASE__INVALID_PUBLIC_READS = 4005, MERGE_CIRCUIT_FAILED = 6000, From 7bb8adbe8aee8dc648eaa17d53777d5e52919c65 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Thu, 27 Apr 2023 09:17:43 -0300 Subject: [PATCH 2/5] Remove debugging statement --- .../circuits/rollup/base/native_base_rollup_circuit.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp b/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp index 6f360e3c5b3..10ba6ad70af 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp @@ -484,14 +484,6 @@ void validate_state_reads( format("mismatch state read ", state_read.leaf_index, " and witness leaf index ", witness.leaf_index), CircuitErrorCode::BASE__INVALID_PUBLIC_READS); - info(" Checking membership for ", - state_read.value, - " at ", - state_read.leaf_index, - " vs ", - tree_root, - " using ", - witness.sibling_path); check_membership(composer, state_read.value, state_read.leaf_index, @@ -579,7 +571,6 @@ BaseOrMergeRollupPublicInputs base_rollup_circuit(DummyComposer& composer, BaseR // Validate public state reads and transitions, and update public data tree fr end_public_data_tree_root = validate_and_process_public_state(composer, baseRollupInputs); - // fr end_public_data_tree_root = baseRollupInputs.start_public_data_tree_snapshot.root; AppendOnlySnapshot end_public_data_tree_snapshot = { .root = end_public_data_tree_root, From 41dc907725f4a61b7887911cf449076db4a57d4d Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Thu, 27 Apr 2023 09:20:14 -0300 Subject: [PATCH 3/5] Remove unused includes --- circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp index fe1b6b3e726..2f24026bb74 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp @@ -10,9 +10,7 @@ #include #include -#include #include -#include #include "aztec3/circuits/abis/new_contract_data.hpp" #include "aztec3/circuits/abis/rollup/root/root_rollup_public_inputs.hpp" namespace { From 4bad0f94a4b7a6c3a1ea1a0202d742776b6bfaa9 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Thu, 27 Apr 2023 10:28:43 -0300 Subject: [PATCH 4/5] Fix tree index type in test util --- .../cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp index 2f24026bb74..b659096d6ef 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp @@ -141,10 +141,10 @@ BaseRollupInputs base_rollup_inputs_from_kernels(std::array kerne // Update public data tree to generate sibling paths: we first set the initial public data tree to the result of all // state reads and old_values from state transitions. Note that, if the right tx reads or writes an index that was // already processed by the left one, we don't want to reflect that as part of the initial state, so we skip those. - std::set visited_indices; + std::set visited_indices; for (size_t i = 0; i < 2; i++) { for (auto state_read : kernel_data[i].public_inputs.end.state_reads) { - auto leaf_index = size_t(uint256_t(state_read.leaf_index)); + auto leaf_index = uint256_t(state_read.leaf_index); if (state_read.is_empty() || visited_indices.contains(leaf_index)) continue; visited_indices.insert(leaf_index); @@ -152,7 +152,7 @@ BaseRollupInputs base_rollup_inputs_from_kernels(std::array kerne } for (auto state_write : kernel_data[i].public_inputs.end.state_transitions) { - auto leaf_index = size_t(uint256_t(state_write.leaf_index)); + auto leaf_index = uint256_t(state_write.leaf_index); if (state_write.is_empty() || visited_indices.contains(leaf_index)) continue; visited_indices.insert(leaf_index); From 3b93091e1746ed9bb8f49752db6751b586de33bd Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Thu, 27 Apr 2023 11:13:55 -0300 Subject: [PATCH 5/5] Fix more tree index type in test util --- circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp index b659096d6ef..693184d7199 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/test_utils/utils.cpp @@ -172,7 +172,7 @@ BaseRollupInputs base_rollup_inputs_from_kernels(std::array kerne auto state_read = kernel_data[i].public_inputs.end.state_reads[j]; if (state_read.is_empty()) continue; - auto leaf_index = size_t(uint256_t(state_read.leaf_index)); + auto leaf_index = uint256_t(state_read.leaf_index); baseRollupInputs.new_state_reads_sibling_paths[i * STATE_READS_LENGTH + j] = MembershipWitness{ .leaf_index = state_read.leaf_index, @@ -184,7 +184,7 @@ BaseRollupInputs base_rollup_inputs_from_kernels(std::array kerne auto state_write = kernel_data[i].public_inputs.end.state_transitions[j]; if (state_write.is_empty()) continue; - auto leaf_index = size_t(uint256_t(state_write.leaf_index)); + auto leaf_index = uint256_t(state_write.leaf_index); public_data_tree.update_element(leaf_index, state_write.new_value); baseRollupInputs.new_state_transitions_sibling_paths[i * STATE_TRANSITIONS_LENGTH + j] = MembershipWitness{