diff --git a/circuits/cpp/src/aztec3/circuits/abis/rollup/root/root_rollup_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/rollup/root/root_rollup_inputs.hpp index e094762490cc..8e387b38eebe 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/rollup/root/root_rollup_inputs.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/rollup/root/root_rollup_inputs.hpp @@ -27,10 +27,13 @@ template struct RootRollupInputs { std::array new_historic_contract_tree_root_sibling_path; // TODO(sean): is this going to be here? - std::array new_l1_to_l2_messages; - std::array new_l1_to_l2_message_tree_root_sibling_path; + std::array l1_to_l2_messages; + std::array new_l1_to_l2_message_tree_root_sibling_path; std::array new_historic_l1_to_l2_message_roots_tree_sibling_path; + AppendOnlyTreeSnapshot start_l1_to_l2_message_tree_snapshot; + AppendOnlyTreeSnapshot start_historic_tree_l1_to_l2_message_tree_roots_snapshot; + bool operator==(RootRollupInputs const&) const = default; }; @@ -41,7 +44,7 @@ template void read(uint8_t const*& it, RootRollupInputs& obj read(it, obj.previous_rollup_data); read(it, obj.new_historic_private_data_tree_root_sibling_path); read(it, obj.new_historic_contract_tree_root_sibling_path); - read(it, obj.new_l1_to_l2_messages); + read(it, obj.l1_to_l2_messages); read(it, obj.new_l1_to_l2_message_tree_root_sibling_path); read(it, obj.new_historic_l1_to_l2_message_roots_tree_sibling_path); }; @@ -53,7 +56,7 @@ template void write(std::vector& buf, RootRollupInputs std::ostream& operator<<(std::ostream& os, RootRollupInp << "new_historic_private_data_tree_roots: " << obj.new_historic_private_data_tree_root_sibling_path << "\n" << "new_historic_contract_tree_roots: " << obj.new_historic_contract_tree_root_sibling_path << "\n" - << "new_l1_to_l2_messages: " << obj.new_l1_to_l2_messages << "\n" + << "new_l1_to_l2_messages: " << obj.l1_to_l2_messages << "\n" << "new_l1_to_l2_message_tree_root_sibling_path: " << obj.new_l1_to_l2_message_tree_root_sibling_path << "\n" << "new_historic_l1_to_l2_message_roots_tree_sibling_path: " diff --git a/circuits/cpp/src/aztec3/circuits/abis/rollup/root/root_rollup_public_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/rollup/root/root_rollup_public_inputs.hpp index f5b47628259c..23d320d6eb2a 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/rollup/root/root_rollup_public_inputs.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/rollup/root/root_rollup_public_inputs.hpp @@ -40,6 +40,7 @@ template struct RootRollupPublicInputs { AppendOnlyTreeSnapshot end_tree_of_historic_l1_tol2_messages_tree_roots_snapshot; std::array calldata_hash; + std::array l1_to_l2_messages_hash; bool operator==(RootRollupPublicInputs const&) const = default; }; @@ -64,6 +65,7 @@ template void read(uint8_t const*& it, RootRollupPublicInputs void write(std::vector& buf, RootRollupPublicInputs const& obj) @@ -86,6 +88,7 @@ template void write(std::vector& buf, RootRollupPublicIn write(buf, obj.start_tree_of_historic_l1_to_l2_messages_tree_roots_snapshot); write(buf, obj.end_tree_of_historic_l1_tol2_messages_tree_roots_snapshot); write(buf, obj.calldata_hash); + write(buf, obj.l1_to_l2_messages_hash); }; template std::ostream& operator<<(std::ostream& os, RootRollupPublicInputs const& obj) @@ -111,7 +114,9 @@ template std::ostream& operator<<(std::ostream& os, RootRollupPub << obj.start_tree_of_historic_l1_to_l2_messages_tree_roots_snapshot << "\n" << "end_tree_of_historic_l1_tol2_messages_tree_roots_snapshot: " << obj.end_tree_of_historic_l1_tol2_messages_tree_roots_snapshot << "\n" - << "calldata_hash: " << obj.calldata_hash << "\n"; + << "calldata_hash: " << obj.calldata_hash << "\n" + << "l1_to_l2_messages_hash: " << obj.l1_to_l2_messages_hash << "\n"; + ; }; } // namespace aztec3::circuits::abis \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/rollup/root/init.hpp b/circuits/cpp/src/aztec3/circuits/rollup/root/init.hpp index 5b8776ca2cd2..5bff569cf681 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/root/init.hpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/root/init.hpp @@ -27,4 +27,6 @@ using RootRollupPublicInputs = abis::RootRollupPublicInputs; using Aggregator = aztec3::circuits::recursion::Aggregator; +using MerkleTree = stdlib::merkle_tree::MemoryTree; + } // namespace aztec3::circuits::rollup::native_root_rollup \ No newline at end of file diff --git a/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp b/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp index 75e07a4ee29e..547c312b161f 100644 --- a/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp +++ b/circuits/cpp/src/aztec3/circuits/rollup/root/native_root_rollup_circuit.cpp @@ -26,6 +26,40 @@ namespace aztec3::circuits::rollup::native_root_rollup { // Access Native types through NT namespace +const NT::fr EMPTY_L1_TO_L2_MESSAGES_SUBTREE_ROOT = MerkleTree(L1_TO_L2_MSG_SUBTREE_DEPTH).root(); + +// TODO: turn this into generic function that can be used by other rollups +NT::fr calculate_subtree(std::array leaves) +{ + MerkleTree merkle_tree = MerkleTree(L1_TO_L2_MSG_SUBTREE_DEPTH); + + // Compute the merkle root of a contract subtree + // Contracts subtree + for (size_t i = 0; i < NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP; i++) { + merkle_tree.update_element(i, leaves[i]); + } + return merkle_tree.root(); +} + +// TODO: move helper functions here to components +std::array compute_messages_hash(std::array leaves) +{ + std::vector messages_hash_input_bytes_vec(leaves.begin(), leaves.end()); + auto h = sha256::sha256(messages_hash_input_bytes_vec); + + std::array buf_1, buf_2; + for (uint8_t i = 0; i < 16; i++) { + buf_1[i] = 0; + buf_1[16 + i] = h[i]; + buf_2[i] = 0; + buf_2[16 + i] = h[i + 16]; + } + auto high = fr::serialize_from_buffer(buf_1.data()); + auto low = fr::serialize_from_buffer(buf_2.data()); + + return { high, low }; +} + RootRollupPublicInputs root_rollup_circuit(DummyComposer& composer, RootRollupInputs const& rootRollupInputs) { // TODO: Verify the previous rollup proofs @@ -59,6 +93,29 @@ RootRollupPublicInputs root_rollup_circuit(DummyComposer& composer, RootRollupIn right.end_contract_tree_snapshot.root, 0); + // Check correct l1 to l2 tree given + + // Compute subtree inserting l1 to l2 messages + auto l1_to_l2_subtree_root = calculate_subtree(rootRollupInputs.l1_to_l2_messages); + + // Insert subtree into the l1 to l2 data tree + auto new_root = + components::insert_subtree_to_snapshot_tree(composer, + rootRollupInputs.start_l1_to_l2_message_tree_snapshot, + rootRollupInputs.new_l1_to_l2_message_tree_root_sibling_path, + EMPTY_L1_TO_L2_MESSAGES_SUBTREE_ROOT, + l1_to_l2_subtree_root, + L1_TO_L2_MSG_SUBTREE_INCLUSION_CHECK_DEPTH); + + // Update the historic l1 to l2 data tree + auto end_l1_to_l2_data_tree_snapshot = components::insert_subtree_to_snapshot_tree( + composer, + rootRollupInputs.start_historic_tree_l1_to_l2_message_tree_roots_snapshot, + rootRollupInputs.new_historic_private_data_tree_root_sibling_path, + fr::zero(), + new_root.root, + 0); + RootRollupPublicInputs public_inputs = { .end_aggregation_object = aggregation_object, .start_private_data_tree_snapshot = left.start_private_data_tree_snapshot, @@ -74,6 +131,7 @@ RootRollupPublicInputs root_rollup_circuit(DummyComposer& composer, RootRollupIn left.constants.start_tree_of_historic_contract_tree_roots_snapshot, .end_tree_of_historic_contract_tree_roots_snapshot = end_tree_of_historic_contract_tree_roots_snapshot, .calldata_hash = components::compute_calldata_hash(rootRollupInputs.previous_rollup_data), + .l1_to_l2_messages_hash = compute_messages_hash(rootRollupInputs.l1_to_l2_messages) }; return public_inputs; diff --git a/circuits/cpp/src/aztec3/constants.hpp b/circuits/cpp/src/aztec3/constants.hpp index 5952b5937e98..ebef725f4982 100644 --- a/circuits/cpp/src/aztec3/constants.hpp +++ b/circuits/cpp/src/aztec3/constants.hpp @@ -43,8 +43,8 @@ constexpr size_t PRIVATE_DATA_SUBTREE_INCLUSION_CHECK_DEPTH = NULLIFIER_TREE_HEI constexpr size_t NULLIFIER_SUBTREE_DEPTH = 3; constexpr size_t NULLIFIER_SUBTREE_INCLUSION_CHECK_DEPTH = NULLIFIER_TREE_HEIGHT - NULLIFIER_SUBTREE_DEPTH; -constexpr size_t L2_MSG_SUBTREE_DEPTH = 3; -constexpr size_t L2_MSG_SUBTREE_INCLUSION_CHECK_DEPTH = L1_TO_L2_MSG_TREE_HEIGHT - L2_MSG_SUBTREE_DEPTH; +constexpr size_t L1_TO_L2_MSG_SUBTREE_DEPTH = 4; +constexpr size_t L1_TO_L2_MSG_SUBTREE_INCLUSION_CHECK_DEPTH = L1_TO_L2_MSG_TREE_HEIGHT - L1_TO_L2_MSG_SUBTREE_DEPTH; constexpr size_t PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT = 8; constexpr size_t CONTRACT_TREE_ROOTS_TREE_HEIGHT = 8; diff --git a/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts b/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts index 28bc52a595ff..4f9dc30e6a9a 100644 --- a/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts +++ b/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts @@ -4,6 +4,7 @@ import { serializeToBuffer } from '../../utils/serialize.js'; import { AppendOnlyTreeSnapshot } from './append_only_tree_snapshot.js'; import { CONTRACT_TREE_ROOTS_TREE_HEIGHT, + L1_TO_L2_MESSAGES_ROOTS_TREE_HEIGHT, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT, } from '../constants.js'; @@ -16,13 +17,15 @@ export class RootRollupInputs { public newHistoricPrivateDataTreeRootSiblingPath: Fr[], public newHistoricContractDataTreeRootSiblingPath: Fr[], - - // TODO: Work out when writing the circuits if i will need to include both the normal and historic paths here + public newL1ToL2MessageTreeRootSiblingPath: Fr[], public newHistoricL1ToL2MessageTreeRootSiblingPath: Fr[], public newL1ToL2Messages: Fr[], ) { assertLength(this, 'newHistoricPrivateDataTreeRootSiblingPath', PRIVATE_DATA_TREE_ROOTS_TREE_HEIGHT); assertLength(this, 'newHistoricContractDataTreeRootSiblingPath', CONTRACT_TREE_ROOTS_TREE_HEIGHT); + // TODO: the height of this could be wrong + assertLength(this, 'newL1ToL2MessageTreeRootSiblingPath', L1_TO_L2_MESSAGES_ROOTS_TREE_HEIGHT); + assertLength(this, 'newHistoricL1ToL2MessageTreeRootSiblingPath', L1_TO_L2_MESSAGES_ROOTS_TREE_HEIGHT); assertLength(this, 'newL1ToL2Messages', NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP); } @@ -31,6 +34,8 @@ export class RootRollupInputs { this.previousRollupData, this.newHistoricPrivateDataTreeRootSiblingPath, this.newHistoricContractDataTreeRootSiblingPath, + this.newL1ToL2MessageTreeRootSiblingPath, + this.newHistoricL1ToL2MessageTreeRootSiblingPath, this.newL1ToL2Messages, ); } @@ -44,7 +49,8 @@ export class RootRollupInputs { fields.previousRollupData, fields.newHistoricPrivateDataTreeRootSiblingPath, fields.newHistoricContractDataTreeRootSiblingPath, - fields.newHistoricContractDataTreeRootSiblingPath, + fields.newL1ToL2MessageTreeRootSiblingPath, + fields.newHistoricL1ToL2MessageTreeRootSiblingPath, fields.newL1ToL2Messages, ] as const; } @@ -79,6 +85,7 @@ export class RootRollupPublicInputs { public endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot: AppendOnlyTreeSnapshot, public calldataHash: [Fr, Fr], + public l1ToL2MessagesHash: [Fr, Fr], ) {} static getFields(fields: FieldsOf) { @@ -99,6 +106,7 @@ export class RootRollupPublicInputs { fields.startTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, fields.endTreeOfHistoricL1ToL2MessageTreeRootsSnapshot, fields.calldataHash, + fields.l1ToL2MessagesHash, ] as const; } @@ -129,6 +137,7 @@ export class RootRollupPublicInputs { reader.readObject(AppendOnlyTreeSnapshot), reader.readObject(AppendOnlyTreeSnapshot), [reader.readFr(), reader.readFr()], + [reader.readFr(), reader.readFr()], ); } }