diff --git a/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp b/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp index 30d64d37..5d464545 100644 --- a/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp +++ b/cpp/src/aztec3/circuits/rollup/base/native_base_rollup_circuit.cpp @@ -20,6 +20,11 @@ namespace aztec3::circuits::rollup::native_base_rollup { +const uint8_t COMMITMENTS_SUBTREE_DEPTH = 3; +const uint8_t CONTRACTS_SUBTREE_DEPTH = 1; +const NT::fr EMPTY_COMMITMENTS_SUBTREE_ROOT = stdlib::merkle_tree::MemoryTree(COMMITMENTS_SUBTREE_DEPTH).root(); +const NT::fr EMPTY_CONTRACTS_SUBTREE_ROOT = stdlib::merkle_tree::MemoryTree(CONTRACTS_SUBTREE_DEPTH).root(); + // TODO: can we aggregate proofs if we do not have a working circuit impl // TODO: change the public inputs array - we wont be using this? @@ -89,6 +94,46 @@ std::vector calculate_contract_leaves(BaseRollupInputs baseRollupInputs) return contract_leaves; } +template +NT::fr iterate_through_tree_via_sibling_path(NT::fr leaf, NT::uint32 leafIndex, std::array siblingPath) +{ + for (size_t i = 0; i < siblingPath.size(); i++) { + if (leafIndex & (1 << i)) { + leaf = crypto::pedersen_hash::hash_multiple({ leaf, siblingPath[i] }); + } else { + leaf = crypto::pedersen_hash::hash_multiple({ siblingPath[i], leaf }); + } + } + return leaf; +} + +template +void check_membership(NT::fr leaf, NT::uint32 leafIndex, std::array siblingPath, NT::fr root) +{ + auto calculatedRoot = iterate_through_tree_via_sibling_path(leaf, leafIndex, siblingPath); + if (calculatedRoot != root) { + // throw std::runtime_error("Merkle membership check failed"); + } +} + +template +AppendOnlySnapshot insert_subtree_to_snapshot_tree(std::array siblingPath, + NT::uint32 nextAvailableLeafIndex, + NT::fr subtreeRootToInsert, + uint8_t subtreeDepth) +{ + // TODO: Sanity check len of siblingPath > height of subtree + // TODO: Ensure height of subtree is correct (eg 3 for commitments, 1 for contracts) + auto leafIndexAtDepth = nextAvailableLeafIndex >> subtreeDepth; + auto new_root = iterate_through_tree_via_sibling_path(subtreeRootToInsert, leafIndexAtDepth, siblingPath); + // 2^subtreeDepth is the number of leaves added. 2^x = 1 << x + auto new_next_available_leaf_index = nextAvailableLeafIndex + (uint8_t(1) << subtreeDepth); + + AppendOnlySnapshot newTreeSnapshot = { .root = new_root, + .next_available_leaf_index = new_next_available_leaf_index }; + return newTreeSnapshot; +} + std::array calculate_new_subtrees(BaseRollupInputs baseRollupInputs, std::vector contract_leaves) { // Leaves that will be added to the new trees @@ -97,8 +142,8 @@ std::array calculate_new_subtrees(BaseRollupInputs baseRollupInputs, // TODO: we have at size two for now, but we will need - stdlib::merkle_tree::MemoryTree contracts_tree = stdlib::merkle_tree::MemoryTree(2); - stdlib::merkle_tree::MemoryTree commitments_tree = stdlib::merkle_tree::MemoryTree(3); + stdlib::merkle_tree::MemoryTree contracts_tree = stdlib::merkle_tree::MemoryTree(CONTRACTS_SUBTREE_DEPTH); + stdlib::merkle_tree::MemoryTree commitments_tree = stdlib::merkle_tree::MemoryTree(COMMITMENTS_SUBTREE_DEPTH); // TODO: nullifier tree will be a different tree impl - indexed merkle tree // stdlib::merkle_tree::MemoryTree nullifier_tree = stdlib::merkle_tree::MemoryTree(2); @@ -186,26 +231,6 @@ NT::fr calculate_calldata_hash(BaseRollupInputs baseRollupInputs, std::vector witness) -{ - // Extract values - NT::uint32 leaf_index = witness.leaf_index; - auto sibling_path = witness.sibling_path; - - // Perform merkle membership check with the provided sibling path up to the root - for (size_t i = 0; i < PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT; i++) { - if (leaf_index & (1 << i)) { - leaf = crypto::pedersen_hash::hash_multiple({ leaf, sibling_path[i] }); - } else { - leaf = crypto::pedersen_hash::hash_multiple({ sibling_path[i], leaf }); - } - } - if (leaf != root) { - // throw std::runtime_error("Merkle membership check failed"); - } -} /** * @brief Check all of the provided commitments against the historical tree roots * @@ -223,7 +248,7 @@ void perform_historical_private_data_tree_membership_checks(BaseRollupInputs bas abis::MembershipWitness historic_root_witness = baseRollupInputs.historic_private_data_tree_root_membership_witnesses[i]; - check_membership(historic_root, leaf, historic_root_witness); + check_membership(leaf, historic_root_witness.leaf_index, historic_root_witness.sibling_path, historic_root); } } @@ -236,7 +261,7 @@ void perform_historical_contract_data_tree_membership_checks(BaseRollupInputs ba abis::MembershipWitness historic_root_witness = baseRollupInputs.historic_contract_tree_root_membership_witnesses[i]; - check_membership(historic_root, leaf, historic_root_witness); + check_membership(leaf, historic_root_witness.leaf_index, historic_root_witness.sibling_path, historic_root); } } // Important types: @@ -256,11 +281,48 @@ BaseRollupPublicInputs base_rollup_circuit(BaseRollupInputs baseRollupInputs) std::vector contract_leaves = calculate_contract_leaves(baseRollupInputs); - // std::array new_subtrees = calculate_new_subtrees(baseRollupInputs, contract_leaves); - // NT::fr contracts_tree_subroot = new_subtrees[0]; - // NT::fr commitments_tree_subroot = new_subtrees[1]; + // Perform merkle membership check with the provided sibling path up to the root + // Note - the subtree hasn't been created (i.e. it is empty) so you check that the sibling path corresponds to an + // empty tree + + // check for commitments/private_data + // next_available_leaf_index is at the leaf level. We need at the subtree level (say height 3). So divide by 8. + // (if leaf is at index x, its parent is at index floor(x/2)) + auto leafIndexAtSubtreeDepth = baseRollupInputs.start_private_data_tree_snapshot.next_available_leaf_index / + (NT::uint32(1) << COMMITMENTS_SUBTREE_DEPTH); + check_membership(EMPTY_COMMITMENTS_SUBTREE_ROOT, + leafIndexAtSubtreeDepth, + baseRollupInputs.new_commitments_subtree_sibling_path, + baseRollupInputs.start_private_data_tree_snapshot.root); + + // check for contracts + leafIndexAtSubtreeDepth = baseRollupInputs.start_contract_tree_snapshot.next_available_leaf_index / + (NT::uint32(1) << CONTRACTS_SUBTREE_DEPTH); + check_membership(EMPTY_CONTRACTS_SUBTREE_ROOT, + leafIndexAtSubtreeDepth, + baseRollupInputs.new_contracts_subtree_sibling_path, + baseRollupInputs.start_contract_tree_snapshot.root); + + std::array new_subtrees = calculate_new_subtrees(baseRollupInputs, contract_leaves); + NT::fr contracts_tree_subroot = new_subtrees[0]; + NT::fr commitments_tree_subroot = new_subtrees[1]; // NT::fr nullifiers_tree_subroot = new_subtrees[2]; + // Insert subtrees to the tree: + auto end_private_data_tree_snapshot = + insert_subtree_to_snapshot_tree(baseRollupInputs.new_commitments_subtree_sibling_path, + baseRollupInputs.start_private_data_tree_snapshot.next_available_leaf_index, + commitments_tree_subroot, + COMMITMENTS_SUBTREE_DEPTH); + + auto end_contract_tree_snapshot = + insert_subtree_to_snapshot_tree(baseRollupInputs.new_contracts_subtree_sibling_path, + baseRollupInputs.start_contract_tree_snapshot.next_available_leaf_index, + contracts_tree_subroot, + CONTRACTS_SUBTREE_DEPTH); + + // TODO: Nullifiers tree insertion + // Calculate the overall calldata hash NT::fr calldata_hash = calculate_calldata_hash(baseRollupInputs, contract_leaves); @@ -283,8 +345,12 @@ BaseRollupPublicInputs base_rollup_circuit(BaseRollupInputs baseRollupInputs) BaseRollupPublicInputs public_inputs = { .end_aggregation_object = aggregation_object, .constants = baseRollupInputs.constants, + .start_private_data_tree_snapshot = baseRollupInputs.start_private_data_tree_snapshot, + .end_private_data_tree_snapshot = end_private_data_tree_snapshot, .start_nullifier_tree_snapshot = mockNullifierStartSnapshot, // TODO: implement: .end_nullifier_tree_snapshot = mockNullifierEndSnapshot, // TODO: implement: + .start_contract_tree_snapshot = baseRollupInputs.start_contract_tree_snapshot, + .end_contract_tree_snapshot = end_contract_tree_snapshot, .calldata_hash = calldata_hash, }; return public_inputs; diff --git a/cpp/src/aztec3/constants.hpp b/cpp/src/aztec3/constants.hpp index da84a341..4bf07a6a 100644 --- a/cpp/src/aztec3/constants.hpp +++ b/cpp/src/aztec3/constants.hpp @@ -28,9 +28,9 @@ constexpr size_t KERNEL_OPTIONALLY_REVEALED_DATA_LENGTH = 4; constexpr size_t VK_TREE_HEIGHT = 3; constexpr size_t FUNCTION_TREE_HEIGHT = 4; -constexpr size_t CONTRACT_TREE_HEIGHT = 1; -constexpr size_t PRIVATE_DATA_TREE_HEIGHT = 2; -constexpr size_t NULLIFIER_TREE_HEIGHT = 2; +constexpr size_t CONTRACT_TREE_HEIGHT = 4; +constexpr size_t PRIVATE_DATA_TREE_HEIGHT = 8; +constexpr size_t NULLIFIER_TREE_HEIGHT = 8; constexpr size_t PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT = 8; constexpr size_t CONTRACT_TREE_ROOTS_TREE_HEIGHT = 8; diff --git a/ts/src/structs/__snapshots__/base_rollup.test.ts.snap b/ts/src/structs/__snapshots__/base_rollup.test.ts.snap index 3064ab0e..618692f1 100644 --- a/ts/src/structs/__snapshots__/base_rollup.test.ts.snap +++ b/ts/src/structs/__snapshots__/base_rollup.test.ts.snap @@ -115,7 +115,7 @@ portal_contract_address: 0x707070707070707070707070707070707070707 is_private: 1 proof: [ 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ] -vk: 0x12c240 +vk: 0x12ca00 vk_index: 42 vk_path: [ 0x1000 0x1001 0x1002 ] public_inputs: end: @@ -231,7 +231,7 @@ portal_contract_address: 0x707070707070707070707070707070707070707 is_private: 1 proof: [ 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 ] -vk: 0x134d80 +vk: 0x135540 vk_index: 42 vk_path: [ 0x1000 0x1001 0x1002 ] ] @@ -267,28 +267,28 @@ next_index: 1207 ] low_nullifier_membership_witness: [ leaf_index: 2000 -sibling_path: [ 0x2000 0x2001 ] +sibling_path: [ 0x2000 0x2001 0x2002 0x2003 0x2004 0x2005 0x2006 0x2007 ] leaf_index: 2001 -sibling_path: [ 0x2001 0x2002 ] +sibling_path: [ 0x2001 0x2002 0x2003 0x2004 0x2005 0x2006 0x2007 0x2008 ] leaf_index: 2002 -sibling_path: [ 0x2002 0x2003 ] +sibling_path: [ 0x2002 0x2003 0x2004 0x2005 0x2006 0x2007 0x2008 0x2009 ] leaf_index: 2003 -sibling_path: [ 0x2003 0x2004 ] +sibling_path: [ 0x2003 0x2004 0x2005 0x2006 0x2007 0x2008 0x2009 0x200a ] leaf_index: 2004 -sibling_path: [ 0x2004 0x2005 ] +sibling_path: [ 0x2004 0x2005 0x2006 0x2007 0x2008 0x2009 0x200a 0x200b ] leaf_index: 2005 -sibling_path: [ 0x2005 0x2006 ] +sibling_path: [ 0x2005 0x2006 0x2007 0x2008 0x2009 0x200a 0x200b 0x200c ] leaf_index: 2006 -sibling_path: [ 0x2006 0x2007 ] +sibling_path: [ 0x2006 0x2007 0x2008 0x2009 0x200a 0x200b 0x200c 0x200d ] leaf_index: 2007 -sibling_path: [ 0x2007 0x2008 ] +sibling_path: [ 0x2007 0x2008 0x2009 0x200a 0x200b 0x200c 0x200d 0x200e ] ] new_commitments_subtree_sibling_path: -[ 0x3000 0x3001 ] +[ 0x3000 0x3001 0x3002 0x3003 0x3004 0x3005 0x3006 0x3007 ] new_nullifiers_subtree_sibling_path: -[ 0x4000 0x4001 ] +[ 0x4000 0x4001 0x4002 0x4003 0x4004 0x4005 0x4006 0x4007 ] new_contracts_subtree_sibling_path: -[ 0x5000 ] +[ 0x5000 0x5001 0x5002 0x5003 ] historic_private_data_tree_root_membership_witnesses: [ leaf_index: 6000 sibling_path: [ 0x6000 0x6001 0x6002 0x6003 0x6004 0x6005 0x6006 0x6007 ] diff --git a/ts/src/structs/__snapshots__/kernel.test.ts.snap b/ts/src/structs/__snapshots__/kernel.test.ts.snap index 0ca8e604..9dca1b82 100644 --- a/ts/src/structs/__snapshots__/kernel.test.ts.snap +++ b/ts/src/structs/__snapshots__/kernel.test.ts.snap @@ -258,7 +258,7 @@ portal_contract_address: 0x808080808080808080808080808080808080808 is_private: 1 proof: [ 81 81 81 81 81 81 81 81 81 81 81 81 81 81 81 81 ] -vk: 0x12cd00 +vk: 0x12cd80 vk_index: 66 vk_path: [ 0x1000 0x1001 0x1002 ] @@ -435,14 +435,14 @@ portal_contract_address: 0x4 proof: [ 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 ] vk: -0x135740 +0x1357c0 function_leaf_membership_witness: leaf_index: 8241 sibling_path: [ 0x2031 0x2032 0x2033 0x2034 ] contract_leaf_membership_witness: leaf_index: 8225 -sibling_path: [ 0x2021 ] +sibling_path: [ 0x2021 0x2022 0x2023 0x2024 ] portal_contract_address: 0x4141414141414141414141414141414141414141 diff --git a/ts/src/structs/constants.ts b/ts/src/structs/constants.ts index 4b64732d..3693d3ec 100644 --- a/ts/src/structs/constants.ts +++ b/ts/src/structs/constants.ts @@ -25,9 +25,9 @@ export const KERNEL_OPTIONALLY_REVEALED_DATA_LENGTH = 4; export const VK_TREE_HEIGHT = 3; export const FUNCTION_TREE_HEIGHT = 4; -export const CONTRACT_TREE_HEIGHT = 1; -export const PRIVATE_DATA_TREE_HEIGHT = 2; -export const NULLIFIER_TREE_HEIGHT = 2; +export const CONTRACT_TREE_HEIGHT = 4; +export const PRIVATE_DATA_TREE_HEIGHT = 8; +export const NULLIFIER_TREE_HEIGHT = 8; export const PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT = 8; export const CONTRACT_TREE_ROOTS_TREE_HEIGHT = 8;