diff --git a/yarn-project/circuits.js/src/structs/index.ts b/yarn-project/circuits.js/src/structs/index.ts index 9fcbec1dc46..fc9305a85a6 100644 --- a/yarn-project/circuits.js/src/structs/index.ts +++ b/yarn-project/circuits.js/src/structs/index.ts @@ -30,6 +30,7 @@ export * from './rollup/previous_rollup_data.js'; export * from './rollup/root_rollup.js'; export * from './shared.js'; export * from './side_effects.js'; +export * from './rollup/state_diff_hints.js'; export * from './tx_context.js'; export * from './tx_request.js'; export * from './verification_key.js'; diff --git a/yarn-project/circuits.js/src/structs/rollup/base_rollup.ts b/yarn-project/circuits.js/src/structs/rollup/base_rollup.ts index 680f00e6696..3707c39d105 100644 --- a/yarn-project/circuits.js/src/structs/rollup/base_rollup.ts +++ b/yarn-project/circuits.js/src/structs/rollup/base_rollup.ts @@ -3,14 +3,8 @@ import { BufferReader, Tuple } from '@aztec/foundation/serialize'; import { ARCHIVE_HEIGHT, - CONTRACT_SUBTREE_SIBLING_PATH_LENGTH, - MAX_NEW_NULLIFIERS_PER_TX, MAX_PUBLIC_DATA_READS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH, - NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, - NULLIFIER_TREE_HEIGHT, - PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH, PUBLIC_DATA_TREE_HEIGHT, } from '../../constants.gen.js'; import { FieldsOf } from '../../utils/jsUtils.js'; @@ -23,6 +17,7 @@ import { UInt32 } from '../shared.js'; import { AppendOnlyTreeSnapshot } from './append_only_tree_snapshot.js'; import { NullifierLeaf, NullifierLeafPreimage } from './nullifier_leaf/index.js'; import { PublicDataTreeLeaf, PublicDataTreeLeafPreimage } from './public_data_leaf/index.js'; +import { StateDiffHints } from './state_diff_hints.js'; export { NullifierLeaf, NullifierLeafPreimage, PublicDataTreeLeaf, PublicDataTreeLeafPreimage }; @@ -93,48 +88,13 @@ export class ConstantRollupData { */ export class BaseRollupInputs { constructor( - /** - * Data of the 2 kernels that preceded this base rollup circuit. - */ + /** Data of the 2 kernels that preceded this base rollup circuit. */ public kernelData: PreviousKernelData, - /** - * Partial state reference at the start of the rollup. - */ + /** Partial state reference at the start of the rollup. */ public start: PartialStateReference, - /** - * The nullifiers to be inserted in the tree, sorted high to low. - */ - public sortedNewNullifiers: Tuple, - /** - * The indexes of the sorted nullifiers to the original ones. - */ - public sortedNewNullifiersIndexes: Tuple, - /** - * The nullifiers which need to be updated to perform the batch insertion of the new nullifiers. - * See `StandardIndexedTree.batchInsert` function for more details. - */ - public lowNullifierLeafPreimages: Tuple, - /** - * Membership witnesses for the nullifiers which need to be updated to perform the batch insertion of the new - * nullifiers. - */ - public lowNullifierMembershipWitness: Tuple< - MembershipWitness, - typeof MAX_NEW_NULLIFIERS_PER_TX - >, + /** Hints used while proving state diff validity. */ + public stateDiffHints: StateDiffHints, - /** - * Sibling path "pointing to" where the new commitments subtree should be inserted into the note hash tree. - */ - public newCommitmentsSubtreeSiblingPath: Tuple, - /** - * Sibling path "pointing to" where the new nullifiers subtree should be inserted into the nullifier tree. - */ - public newNullifiersSubtreeSiblingPath: Tuple, - /** - * Sibling path "pointing to" where the new contracts subtree should be inserted into the contract tree. - */ - public newContractsSubtreeSiblingPath: Tuple, /** * The public data writes to be inserted in the tree, sorted high slot to low slot. */ @@ -161,11 +121,6 @@ export class BaseRollupInputs { typeof MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX >, - /** - * Sibling path "pointing to" where the new public data subtree should be inserted into the public data tree. - */ - public publicDataWritesSubtreeSiblingPath: Tuple, - /** * Preimages of leaves which are to be read by the public data reads. */ @@ -197,18 +152,11 @@ export class BaseRollupInputs { return [ fields.kernelData, fields.start, - fields.sortedNewNullifiers, - fields.sortedNewNullifiersIndexes, - fields.lowNullifierLeafPreimages, - fields.lowNullifierMembershipWitness, - fields.newCommitmentsSubtreeSiblingPath, - fields.newNullifiersSubtreeSiblingPath, - fields.newContractsSubtreeSiblingPath, + fields.stateDiffHints, fields.sortedPublicDataWrites, fields.sortedPublicDataWritesIndexes, fields.lowPublicDataWritesPreimages, fields.lowPublicDataWritesMembershipWitnesses, - fields.publicDataWritesSubtreeSiblingPath, fields.publicDataReadsPreimages, fields.publicDataReadsMembershipWitnesses, fields.archiveRootMembershipWitness, diff --git a/yarn-project/circuits.js/src/structs/rollup/state_diff_hints.ts b/yarn-project/circuits.js/src/structs/rollup/state_diff_hints.ts new file mode 100644 index 00000000000..59189c42b63 --- /dev/null +++ b/yarn-project/circuits.js/src/structs/rollup/state_diff_hints.ts @@ -0,0 +1,81 @@ +import { Fr } from '@aztec/foundation/fields'; +import { Tuple } from '@aztec/foundation/serialize'; +import { FieldsOf } from '@aztec/foundation/types'; + +import { + CONTRACT_SUBTREE_SIBLING_PATH_LENGTH, + MAX_NEW_NULLIFIERS_PER_TX, + NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH, + NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, + NULLIFIER_TREE_HEIGHT, + PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH, +} from '../../constants.gen.js'; +import { serializeToBuffer } from '../../utils/serialize.js'; +import { MembershipWitness } from '../membership_witness.js'; +import { NullifierLeafPreimage } from './nullifier_leaf/index.js'; + +/** + * Hints used while proving state diff validity. + */ +export class StateDiffHints { + constructor( + /** + * The nullifiers which need to be updated to perform the batch insertion of the new nullifiers. + * See `StandardIndexedTree.batchInsert` function for more details. + */ + public nullifierPredecessorPreimages: Tuple, + /** + * Membership witnesses for the nullifiers which need to be updated to perform the batch insertion of the new + * nullifiers. + */ + public nullifierPredecessorMembershipWitnesses: Tuple< + MembershipWitness, + typeof MAX_NEW_NULLIFIERS_PER_TX + >, + /** + * The nullifiers to be inserted in the tree, sorted high to low. + */ + public sortedNullifiers: Tuple, + /** + * The indexes of the sorted nullifiers to the original ones. + */ + public sortedNullifierIndexes: Tuple, + /** + * Sibling path "pointing to" where the new note hash subtree should be inserted into the note hash tree. + */ + public noteHashSubtreeSiblingPath: Tuple, + /** + * Sibling path "pointing to" where the new nullifiers subtree should be inserted into the nullifier tree. + */ + public nullifierSubtreeSiblingPath: Tuple, + /** + * Sibling path "pointing to" where the new contracts subtree should be inserted into the contract tree. + */ + public contractSubtreeSiblingPath: Tuple, + /** + * Sibling path "pointing to" where the new public data subtree should be inserted into the public data tree. + */ + public publicDataSiblingPath: Tuple, + ) {} + + static from(fields: FieldsOf): StateDiffHints { + return new StateDiffHints(...StateDiffHints.getFields(fields)); + } + + static getFields(fields: FieldsOf) { + return [ + fields.nullifierPredecessorPreimages, + fields.nullifierPredecessorMembershipWitnesses, + fields.sortedNullifiers, + fields.sortedNullifierIndexes, + fields.noteHashSubtreeSiblingPath, + fields.nullifierSubtreeSiblingPath, + fields.contractSubtreeSiblingPath, + fields.publicDataSiblingPath, + ] as const; + } + + toBuffer(): Buffer { + return serializeToBuffer(...StateDiffHints.getFields(this)); + } +} diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index e1f640c79bb..8139fe46c28 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -91,6 +91,7 @@ import { RootRollupPublicInputs, SideEffect, SideEffectLinkedToNoteHash, + StateDiffHints, StateReference, TxContext, TxRequest, @@ -941,33 +942,58 @@ export function makePublicDataTreeLeafPreimage(seed = 0): PublicDataTreeLeafPrei } /** - * Makes arbitrary base rollup inputs. - * @param seed - The seed to use for generating the base rollup inputs. - * @returns A base rollup inputs. + * Creates an instance of StateDiffHints with arbitrary values based on the provided seed. + * @param seed - The seed to use for generating the hints. + * @returns A StateDiffHints object. */ -export function makeBaseRollupInputs(seed = 0): BaseRollupInputs { - const kernelData = makePreviousKernelData(seed); - - const start = makePartialStateReference(seed + 0x100); - - const lowNullifierLeafPreimages = makeTuple( +export function makeStateDiffHints(seed = 1): StateDiffHints { + const nullifierPredecessorPreimages = makeTuple( MAX_NEW_NULLIFIERS_PER_TX, x => new NullifierLeafPreimage(fr(x), fr(x + 0x100), BigInt(x + 0x200)), seed + 0x1000, ); - const lowNullifierMembershipWitness = makeTuple( + const nullifierPredecessorMembershipWitnesses = makeTuple( MAX_NEW_NULLIFIERS_PER_TX, x => makeMembershipWitness(NULLIFIER_TREE_HEIGHT, x), seed + 0x2000, ); - const newCommitmentsSubtreeSiblingPath = makeTuple(NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH, fr, seed + 0x3000); - const newNullifiersSubtreeSiblingPath = makeTuple(NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, fr, seed + 0x4000); - const newContractsSubtreeSiblingPath = makeTuple(CONTRACT_SUBTREE_SIBLING_PATH_LENGTH, fr, seed + 0x5000); + const sortedNullifiers = makeTuple(MAX_NEW_NULLIFIERS_PER_TX, fr, seed + 0x3000); + + const sortedNullifierIndexes = makeTuple(MAX_NEW_NULLIFIERS_PER_TX, i => i, seed + 0x4000); + + const noteHashSubtreeSiblingPath = makeTuple(NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH, fr, seed + 0x5000); + + const nullifierSubtreeSiblingPath = makeTuple(NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, fr, seed + 0x6000); - const sortedNewNullifiers = makeTuple(MAX_NEW_NULLIFIERS_PER_TX, fr, seed + 0x6000); - const sortedNewNullifiersIndexes = makeTuple(MAX_NEW_NULLIFIERS_PER_TX, i => i, seed + 0x7000); + const contractSubtreeSiblingPath = makeTuple(CONTRACT_SUBTREE_SIBLING_PATH_LENGTH, fr, seed + 0x7000); + + const publicDataSiblingPath = makeTuple(PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH, fr, 0x8000); + + return new StateDiffHints( + nullifierPredecessorPreimages, + nullifierPredecessorMembershipWitnesses, + sortedNullifiers, + sortedNullifierIndexes, + noteHashSubtreeSiblingPath, + nullifierSubtreeSiblingPath, + contractSubtreeSiblingPath, + publicDataSiblingPath, + ); +} + +/** + * Makes arbitrary base rollup inputs. + * @param seed - The seed to use for generating the base rollup inputs. + * @returns A base rollup inputs. + */ +export function makeBaseRollupInputs(seed = 0): BaseRollupInputs { + const kernelData = makePreviousKernelData(seed); + + const start = makePartialStateReference(seed + 0x100); + + const stateDiffHints = makeStateDiffHints(seed + 0x600); const sortedPublicDataWrites = makeTuple( MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, @@ -989,8 +1015,6 @@ export function makeBaseRollupInputs(seed = 0): BaseRollupInputs { seed + 0x8400, ); - const publicDataWritesSubtreeSiblingPath = makeTuple(PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH, fr, 0x8600); - const publicDataReadsPreimages = makeTuple( MAX_PUBLIC_DATA_READS_PER_TX, makePublicDataTreeLeafPreimage, @@ -1009,19 +1033,12 @@ export function makeBaseRollupInputs(seed = 0): BaseRollupInputs { return BaseRollupInputs.from({ kernelData, - lowNullifierMembershipWitness, start, - sortedNewNullifiers, - sortedNewNullifiersIndexes, - lowNullifierLeafPreimages, - newCommitmentsSubtreeSiblingPath, - newNullifiersSubtreeSiblingPath, - newContractsSubtreeSiblingPath, + stateDiffHints, sortedPublicDataWrites, sortedPublicDataWritesIndexes, lowPublicDataWritesPreimages, lowPublicDataWritesMembershipWitnesses, - publicDataWritesSubtreeSiblingPath, publicDataReadsPreimages, publicDataReadsMembershipWitnesses, archiveRootMembershipWitness, diff --git a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/base.nr b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/base.nr index 8e8b06724c9..26987302495 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/base.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/base.nr @@ -1,4 +1,5 @@ mod base_rollup_inputs; +mod state_diff_hints; use base_rollup_inputs::BaseRollupInputs; use crate::abis::base_or_merge_rollup_public_inputs::BaseOrMergeRollupPublicInputs; diff --git a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/base/base_rollup_inputs.nr b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/base/base_rollup_inputs.nr index 9e12bbd4a22..9699f07a24b 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/base/base_rollup_inputs.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/base/base_rollup_inputs.nr @@ -1,6 +1,7 @@ use crate::abis::public_data_tree_leaf::{PublicDataTreeLeaf, PublicDataTreeLeafPreimage}; use crate::abis::constant_rollup_data::ConstantRollupData; use crate::abis::base_or_merge_rollup_public_inputs::{BaseOrMergeRollupPublicInputs, BASE_ROLLUP_TYPE}; +use crate::base::state_diff_hints::StateDiffHints; use crate::merkle_tree::{calculate_subtree, calculate_empty_tree_root}; use crate::components; use dep::types::utils::uint256::U256; @@ -40,23 +41,14 @@ struct BaseRollupInputs { kernel_data: PreviousKernelData, start: PartialStateReference, - sorted_new_nullifiers: [Field; MAX_NEW_NULLIFIERS_PER_TX], - sorted_new_nullifiers_indexes: [u32; MAX_NEW_NULLIFIERS_PER_TX], - low_nullifier_leaf_preimages: [NullifierLeafPreimage; MAX_NEW_NULLIFIERS_PER_TX], - low_nullifier_membership_witness: [NullifierMembershipWitness; MAX_NEW_NULLIFIERS_PER_TX], - - // For inserting the new subtrees into their respective trees: - // Note: the insertion leaf index can be derived from the above snapshots' `next_available_leaf_index` values. - new_commitments_subtree_sibling_path: [Field; NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH], - new_nullifiers_subtree_sibling_path: [Field; NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH], - public_data_writes_subtree_sibling_path: [Field; PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH], - new_contracts_subtree_sibling_path: [Field; CONTRACT_SUBTREE_SIBLING_PATH_LENGTH], + state_diff_hints: StateDiffHints, + // TODO: The following 6 values are eventually going to be nuked from here. See discussion: + // https://aztecprotocol.slack.com/archives/C060PU5R327/p1701965354071269 sorted_public_data_writes: [PublicDataTreeLeaf; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], sorted_public_data_writes_indexes: [u32; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], low_public_data_writes_preimages: [PublicDataTreeLeafPreimage; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], low_public_data_writes_witnesses: [PublicDataMembershipWitness; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], - public_data_reads_preimages: [PublicDataTreeLeafPreimage; MAX_PUBLIC_DATA_READS_PER_TX], public_data_reads_witnesses: [PublicDataMembershipWitness; MAX_PUBLIC_DATA_READS_PER_TX], @@ -86,7 +78,7 @@ impl BaseRollupInputs { let end_note_hash_tree_snapshot = components::insert_subtree_to_snapshot_tree( self.start.note_hash_tree, - self.new_commitments_subtree_sibling_path, + self.state_diff_hints.note_hash_subtree_sibling_path, empty_commitments_subtree_root, commitments_tree_subroot, NOTE_HASH_SUBTREE_HEIGHT as u8, @@ -96,7 +88,7 @@ impl BaseRollupInputs { let empty_contracts_subtree_root = calculate_empty_tree_root(CONTRACT_SUBTREE_HEIGHT); let end_contract_tree_snapshot = components::insert_subtree_to_snapshot_tree( self.start.contract_tree, - self.new_contracts_subtree_sibling_path, + self.state_diff_hints.contract_subtree_sibling_path, empty_contracts_subtree_root, contracts_tree_subroot, CONTRACT_SUBTREE_HEIGHT as u8, @@ -171,11 +163,11 @@ impl BaseRollupInputs { crate::indexed_tree::batch_insert( self.start.nullifier_tree, self.kernel_data.public_inputs.end.new_nullifiers.map(|nullifier: SideEffectLinkedToNoteHash| nullifier.value), - self.sorted_new_nullifiers, - self.sorted_new_nullifiers_indexes, - self.new_nullifiers_subtree_sibling_path, - self.low_nullifier_leaf_preimages, - self.low_nullifier_membership_witness.map(|witness: NullifierMembershipWitness| { + self.state_diff_hints.sorted_nullifiers, + self.state_diff_hints.sorted_nullifier_indexes, + self.state_diff_hints.nullifier_subtree_sibling_path, + self.state_diff_hints.nullifier_predecessor_preimages, + self.state_diff_hints.nullifier_predecessor_membership_witnesses.map(|witness: NullifierMembershipWitness| { MembershipWitness { leaf_index: witness.leaf_index, sibling_path: witness.sibling_path, @@ -241,7 +233,7 @@ impl BaseRollupInputs { self.sorted_public_data_writes_indexes, self.low_public_data_writes_preimages, self.low_public_data_writes_witnesses, - self.public_data_writes_subtree_sibling_path, + self.state_diff_hints.public_data_sibling_path, ); end_public_data_tree_snapshot @@ -556,11 +548,14 @@ fn test_u256_greater_than() { mod tests { use crate::{ - base::base_rollup_inputs::{ - CALL_DATA_HASH_FULL_FIELDS, - CALL_DATA_HASH_LOG_FIELDS, - BaseRollupInputs, - full_field_less_than, + base::{ + base_rollup_inputs::{ + CALL_DATA_HASH_FULL_FIELDS, + CALL_DATA_HASH_LOG_FIELDS, + BaseRollupInputs, + full_field_less_than, + }, + state_diff_hints::StateDiffHints, }, merkle_tree::{calculate_subtree, calculate_empty_tree_root}, abis::base_or_merge_rollup_public_inputs::BaseOrMergeRollupPublicInputs, @@ -767,21 +762,21 @@ mod tests { [Field; MAX_NEW_NULLIFIERS_PER_TX], [u32; MAX_NEW_NULLIFIERS_PER_TX], ) { - let mut low_nullifier_leaf_preimages: [NullifierLeafPreimage; MAX_NEW_NULLIFIERS_PER_TX] = dep::std::unsafe::zeroed(); + let mut nullifier_predecessor_preimages: [NullifierLeafPreimage; MAX_NEW_NULLIFIERS_PER_TX] = dep::std::unsafe::zeroed(); let mut low_nullifier_membership_witness: [NullifierMembershipWitness; MAX_NEW_NULLIFIERS_PER_TX] = dep::std::unsafe::zeroed(); let sorted_new_nullifier_tuples = sort_high_to_low(self.new_nullifiers.storage.map(|insertion: NullifierInsertion| insertion.value), full_field_less_than); - let mut sorted_new_nullifiers = [0; MAX_NEW_NULLIFIERS_PER_TX]; - let mut sorted_new_nullifiers_indexes = [0; MAX_NEW_NULLIFIERS_PER_TX]; + let mut sorted_nullifiers = [0; MAX_NEW_NULLIFIERS_PER_TX]; + let mut sorted_nullifiers_indexes = [0; MAX_NEW_NULLIFIERS_PER_TX]; for i in 0..MAX_NEW_NULLIFIERS_PER_TX { if (i as u32) < (MAX_NEW_NULLIFIERS_PER_TEST as u32) { - sorted_new_nullifiers[i] = sorted_new_nullifier_tuples[i].value; - sorted_new_nullifiers_indexes[i] = sorted_new_nullifier_tuples[i].original_index; + sorted_nullifiers[i] = sorted_new_nullifier_tuples[i].value; + sorted_nullifiers_indexes[i] = sorted_new_nullifier_tuples[i].original_index; } else { - sorted_new_nullifiers[i] = 0; - sorted_new_nullifiers_indexes[i] = i as u32; + sorted_nullifiers[i] = 0; + sorted_nullifiers_indexes[i] = i as u32; } } @@ -798,7 +793,7 @@ mod tests { kernel_data.public_inputs.end.new_nullifiers[original_index].value = new_nullifier; let mut low_preimage = pre_existing_nullifiers[low_index]; - low_nullifier_leaf_preimages[i] = low_preimage; + nullifier_predecessor_preimages[i] = low_preimage; low_nullifier_membership_witness[i] = NullifierMembershipWitness { leaf_index: low_index as Field, sibling_path: nullifier_tree.get_sibling_path(low_index as Field) @@ -812,7 +807,7 @@ mod tests { } } - (low_nullifier_leaf_preimages, low_nullifier_membership_witness, sorted_new_nullifiers, sorted_new_nullifiers_indexes) + (nullifier_predecessor_preimages, low_nullifier_membership_witness, sorted_nullifiers, sorted_nullifiers_indexes) } fn build_inputs(mut self) -> BaseRollupInputs { @@ -823,7 +818,7 @@ mod tests { root: start_note_hash_tree.get_root(), next_available_leaf_index: start_note_hash_tree.get_next_available_index() as u32, }; - let new_commitments_subtree_sibling_path = BaseRollupInputsBuilder::extract_subtree_sibling_path(start_note_hash_tree.get_sibling_path(self.pre_existing_notes.len()), [0; NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH]); + let note_hash_subtree_sibling_path = BaseRollupInputsBuilder::extract_subtree_sibling_path(start_note_hash_tree.get_sibling_path(self.pre_existing_notes.len()), [0; NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH]); let mut start_nullifier_tree = NonEmptyMerkleTree::new( self.pre_existing_nullifiers.map(|preimage: NullifierLeafPreimage| preimage.hash()), @@ -842,7 +837,7 @@ mod tests { root: start_contract_tree.get_root(), next_available_leaf_index: start_contract_tree.get_next_available_index() as u32, }; - let new_contracts_subtree_sibling_path = BaseRollupInputsBuilder::extract_subtree_sibling_path(start_contract_tree.get_sibling_path(self.pre_existing_contracts.len()), [0; CONTRACT_SUBTREE_SIBLING_PATH_LENGTH]); + let contract_subtree_sibling_path = BaseRollupInputsBuilder::extract_subtree_sibling_path(start_contract_tree.get_sibling_path(self.pre_existing_contracts.len()), [0; CONTRACT_SUBTREE_SIBLING_PATH_LENGTH]); let mut start_public_data_tree = NonEmptyMerkleTree::new( self.pre_existing_public_data.map(|preimage: PublicDataTreeLeafPreimage| preimage.hash()), @@ -862,16 +857,16 @@ mod tests { }; let ( - low_nullifier_leaf_preimages, - low_nullifier_membership_witness, - sorted_new_nullifiers, - sorted_new_nullifiers_indexes + nullifier_predecessor_preimages, + nullifier_predecessor_membership_witnesses, + sorted_nullifiers, + sorted_nullifier_indexes ) = self.update_nullifier_tree_with_new_leaves(&mut start_nullifier_tree, &mut kernel_data, start_nullifier_tree_snapshot); - let new_nullifiers_subtree_sibling_path = BaseRollupInputsBuilder::extract_subtree_sibling_path(start_nullifier_tree.get_sibling_path(self.pre_existing_nullifiers.len()), [0; NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH]); + let nullifier_subtree_sibling_path = BaseRollupInputsBuilder::extract_subtree_sibling_path(start_nullifier_tree.get_sibling_path(self.pre_existing_nullifiers.len()), [0; NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH]); let ( - public_data_writes_subtree_sibling_path, + public_data_sibling_path, sorted_public_data_writes, sorted_public_data_writes_indexes, low_public_data_writes_preimages, @@ -894,20 +889,21 @@ mod tests { public_data_tree: start_public_data_tree_snapshot }; + let state_diff_hints = StateDiffHints { + nullifier_predecessor_preimages, + nullifier_predecessor_membership_witnesses, + sorted_nullifiers, + sorted_nullifier_indexes, + note_hash_subtree_sibling_path, + nullifier_subtree_sibling_path, + contract_subtree_sibling_path, + public_data_sibling_path, + }; + BaseRollupInputs { - kernel_data: kernel_data, + kernel_data, start, - - sorted_new_nullifiers, - sorted_new_nullifiers_indexes, - - low_nullifier_leaf_preimages, - low_nullifier_membership_witness, - - new_commitments_subtree_sibling_path, - new_nullifiers_subtree_sibling_path, - public_data_writes_subtree_sibling_path, - new_contracts_subtree_sibling_path, + state_diff_hints, sorted_public_data_writes, sorted_public_data_writes_indexes, diff --git a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/base/state_diff_hints.nr b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/base/state_diff_hints.nr new file mode 100644 index 00000000000..9aeb4bdfceb --- /dev/null +++ b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/base/state_diff_hints.nr @@ -0,0 +1,29 @@ +use dep::types::{ + abis::{ + membership_witness::NullifierMembershipWitness, + nullifier_leaf_preimage::NullifierLeafPreimage, + }, + constants::{ + MAX_NEW_NULLIFIERS_PER_TX, + NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH, + NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, + CONTRACT_SUBTREE_SIBLING_PATH_LENGTH, + PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH, + }, +}; + +struct StateDiffHints { + nullifier_predecessor_preimages: [NullifierLeafPreimage; MAX_NEW_NULLIFIERS_PER_TX], + nullifier_predecessor_membership_witnesses: [NullifierMembershipWitness; MAX_NEW_NULLIFIERS_PER_TX], + + sorted_nullifiers: [Field; MAX_NEW_NULLIFIERS_PER_TX], + sorted_nullifier_indexes: [u32; MAX_NEW_NULLIFIERS_PER_TX], + + // For inserting the new subtrees into their respective trees: + // Note: the insertion leaf index can be derived from the snapshots' `next_available_leaf_index` values (tree + // snapshots of the relevant trees are stored in partial state reference). + note_hash_subtree_sibling_path: [Field; NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH], + nullifier_subtree_sibling_path: [Field; NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH], + contract_subtree_sibling_path: [Field; CONTRACT_SUBTREE_SIBLING_PATH_LENGTH], + public_data_sibling_path: [Field; PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH], +} diff --git a/yarn-project/noir-protocol-circuits/src/type_conversion.ts b/yarn-project/noir-protocol-circuits/src/type_conversion.ts index a785b99338b..907ac9dbed4 100644 --- a/yarn-project/noir-protocol-circuits/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits/src/type_conversion.ts @@ -67,6 +67,7 @@ import { RootRollupPublicInputs, SideEffect, SideEffectLinkedToNoteHash, + StateDiffHints, StateReference, TxContext, TxRequest, @@ -129,6 +130,7 @@ import { PublicDataMembershipWitness as PublicDataMembershipWitnessNoir, PublicDataTreeLeaf as PublicDataTreeLeafNoir, PublicDataTreeLeafPreimage as PublicDataTreeLeafPreimageNoir, + StateDiffHints as StateDiffHintsNoir, } from './types/rollup_base_types.js'; import { MergeRollupInputs as MergeRollupInputsNoir } from './types/rollup_merge_types.js'; import { @@ -1450,6 +1452,27 @@ export function mapPartialStateReferenceToNoir( }; } +/** + * Maps state diff hints to a noir state diff hints. + * @param hints - The state diff hints. + * @returns The noir state diff hints. + */ +export function mapStateDiffHintsToNoir(hints: StateDiffHints): StateDiffHintsNoir { + return { + nullifier_predecessor_preimages: mapTuple(hints.nullifierPredecessorPreimages, mapNullifierLeafPreimageToNoir), + nullifier_predecessor_membership_witnesses: mapTuple( + hints.nullifierPredecessorMembershipWitnesses, + mapNullifierMembershipWitnessToNoir, + ), + sorted_nullifiers: mapTuple(hints.sortedNullifiers, mapFieldToNoir), + sorted_nullifier_indexes: mapTuple(hints.sortedNullifierIndexes, (index: number) => mapNumberToNoir(index)), + note_hash_subtree_sibling_path: mapTuple(hints.noteHashSubtreeSiblingPath, mapFieldToNoir), + nullifier_subtree_sibling_path: mapTuple(hints.nullifierSubtreeSiblingPath, mapFieldToNoir), + contract_subtree_sibling_path: mapTuple(hints.contractSubtreeSiblingPath, mapFieldToNoir), + public_data_sibling_path: mapTuple(hints.publicDataSiblingPath, mapFieldToNoir), + }; +} + /** * Maps the inputs to the base rollup to noir. * @param input - The circuits.js base rollup inputs. @@ -1459,19 +1482,7 @@ export function mapBaseRollupInputsToNoir(inputs: BaseRollupInputs): BaseRollupI return { kernel_data: mapPreviousKernelDataToNoir(inputs.kernelData), start: mapPartialStateReferenceToNoir(inputs.start), - sorted_new_nullifiers: mapTuple(inputs.sortedNewNullifiers, mapFieldToNoir), - sorted_new_nullifiers_indexes: mapTuple(inputs.sortedNewNullifiersIndexes, (index: number) => - mapNumberToNoir(index), - ), - low_nullifier_leaf_preimages: mapTuple(inputs.lowNullifierLeafPreimages, mapNullifierLeafPreimageToNoir), - low_nullifier_membership_witness: mapTuple( - inputs.lowNullifierMembershipWitness, - mapNullifierMembershipWitnessToNoir, - ), - new_commitments_subtree_sibling_path: mapTuple(inputs.newCommitmentsSubtreeSiblingPath, mapFieldToNoir), - new_nullifiers_subtree_sibling_path: mapTuple(inputs.newNullifiersSubtreeSiblingPath, mapFieldToNoir), - public_data_writes_subtree_sibling_path: mapTuple(inputs.publicDataWritesSubtreeSiblingPath, mapFieldToNoir), - new_contracts_subtree_sibling_path: mapTuple(inputs.newContractsSubtreeSiblingPath, mapFieldToNoir), + state_diff_hints: mapStateDiffHintsToNoir(inputs.stateDiffHints), sorted_public_data_writes: mapTuple(inputs.sortedPublicDataWrites, mapPublicDataTreeLeafToNoir), diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts index a7915099304..1e46f17c933 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -36,6 +36,7 @@ import { RootRollupPublicInputs, SideEffect, SideEffectLinkedToNoteHash, + StateDiffHints, StateReference, VK_TREE_HEIGHT, VerificationKey, @@ -645,22 +646,22 @@ export class SoloBlockBuilder implements BlockBuilder { ); // Get the subtree sibling paths for the circuit - const newCommitmentsSubtreeSiblingPathArray = await this.getSubtreeSiblingPath( + const noteHashSubtreeSiblingPathArray = await this.getSubtreeSiblingPath( MerkleTreeId.NOTE_HASH_TREE, NOTE_HASH_SUBTREE_HEIGHT, ); - const newCommitmentsSubtreeSiblingPath = makeTuple(NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH, i => - i < newCommitmentsSubtreeSiblingPathArray.length ? newCommitmentsSubtreeSiblingPathArray[i] : Fr.ZERO, + const noteHashSubtreeSiblingPath = makeTuple(NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH, i => + i < noteHashSubtreeSiblingPathArray.length ? noteHashSubtreeSiblingPathArray[i] : Fr.ZERO, ); - const newContractsSubtreeSiblingPathArray = await this.getSubtreeSiblingPath( + const contractSubtreeSiblingPathArray = await this.getSubtreeSiblingPath( MerkleTreeId.CONTRACT_TREE, CONTRACT_SUBTREE_HEIGHT, ); - const newContractsSubtreeSiblingPath = makeTuple(CONTRACT_SUBTREE_SIBLING_PATH_LENGTH, i => - i < newContractsSubtreeSiblingPathArray.length ? newContractsSubtreeSiblingPathArray[i] : Fr.ZERO, + const contractSubtreeSiblingPath = makeTuple(CONTRACT_SUBTREE_SIBLING_PATH_LENGTH, i => + i < contractSubtreeSiblingPathArray.length ? contractSubtreeSiblingPathArray[i] : Fr.ZERO, ); // Update the contract and note hash trees with the new items being inserted to get the new roots @@ -697,47 +698,53 @@ export class SoloBlockBuilder implements BlockBuilder { } // Extract witness objects from returned data - const lowNullifierMembershipWitnesses: MembershipWitness[] = + const nullifierPredecessorMembershipWitnessesWithoutPadding: MembershipWitness[] = nullifierWitnessLeaves.map(l => MembershipWitness.fromBufferArray(l.index, assertLength(l.siblingPath.toBufferArray(), NULLIFIER_TREE_HEIGHT)), ); - const newNullifiersSubtreeSiblingPathArray = newNullifiersSubtreeSiblingPath.toFieldArray(); + const nullifierSubtreeSiblingPathArray = newNullifiersSubtreeSiblingPath.toFieldArray(); - return BaseRollupInputs.from({ - constants, - start, - sortedPublicDataWrites: txPublicDataUpdateRequestInfo.sortedPublicDataWrites, - sortedPublicDataWritesIndexes: txPublicDataUpdateRequestInfo.sortedPublicDataWritesIndexes, - lowPublicDataWritesPreimages: txPublicDataUpdateRequestInfo.lowPublicDataWritesPreimages, - lowPublicDataWritesMembershipWitnesses: txPublicDataUpdateRequestInfo.lowPublicDataWritesMembershipWitnesses, - publicDataWritesSubtreeSiblingPath: txPublicDataUpdateRequestInfo.newPublicDataSubtreeSiblingPath, - - sortedNewNullifiers: makeTuple(MAX_NEW_NULLIFIERS_PER_TX, i => Fr.fromBuffer(sortedNewNullifiers[i])), - sortedNewNullifiersIndexes: makeTuple(MAX_NEW_NULLIFIERS_PER_TX, i => sortedNewLeavesIndexes[i]), - newCommitmentsSubtreeSiblingPath, - newContractsSubtreeSiblingPath, - - newNullifiersSubtreeSiblingPath: makeTuple(NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, i => - i < newNullifiersSubtreeSiblingPathArray.length ? newNullifiersSubtreeSiblingPathArray[i] : Fr.ZERO, - ), - - publicDataReadsPreimages: txPublicDataReadsInfo.newPublicDataReadsPreimages, + const nullifierSubtreeSiblingPath = makeTuple(NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, i => + i < nullifierSubtreeSiblingPathArray.length ? nullifierSubtreeSiblingPathArray[i] : Fr.ZERO, + ); - publicDataReadsMembershipWitnesses: txPublicDataReadsInfo.newPublicDataReadsWitnesses, + const publicDataSiblingPath = txPublicDataUpdateRequestInfo.newPublicDataSubtreeSiblingPath; - lowNullifierLeafPreimages: makeTuple(MAX_NEW_NULLIFIERS_PER_TX, i => + const stateDiffHints = StateDiffHints.from({ + nullifierPredecessorPreimages: makeTuple(MAX_NEW_NULLIFIERS_PER_TX, i => i < nullifierWitnessLeaves.length ? (nullifierWitnessLeaves[i].leafPreimage as NullifierLeafPreimage) : NullifierLeafPreimage.empty(), ), - lowNullifierMembershipWitness: makeTuple(MAX_NEW_NULLIFIERS_PER_TX, i => - i < lowNullifierMembershipWitnesses.length - ? lowNullifierMembershipWitnesses[i] + nullifierPredecessorMembershipWitnesses: makeTuple(MAX_NEW_NULLIFIERS_PER_TX, i => + i < nullifierPredecessorMembershipWitnessesWithoutPadding.length + ? nullifierPredecessorMembershipWitnessesWithoutPadding[i] : this.makeEmptyMembershipWitness(NULLIFIER_TREE_HEIGHT), ), + sortedNullifiers: makeTuple(MAX_NEW_NULLIFIERS_PER_TX, i => Fr.fromBuffer(sortedNewNullifiers[i])), + sortedNullifierIndexes: makeTuple(MAX_NEW_NULLIFIERS_PER_TX, i => sortedNewLeavesIndexes[i]), + noteHashSubtreeSiblingPath, + nullifierSubtreeSiblingPath, + contractSubtreeSiblingPath, + publicDataSiblingPath, + }); + + return BaseRollupInputs.from({ kernelData: this.getKernelDataFor(tx), + start, + stateDiffHints, + + sortedPublicDataWrites: txPublicDataUpdateRequestInfo.sortedPublicDataWrites, + sortedPublicDataWritesIndexes: txPublicDataUpdateRequestInfo.sortedPublicDataWritesIndexes, + lowPublicDataWritesPreimages: txPublicDataUpdateRequestInfo.lowPublicDataWritesPreimages, + lowPublicDataWritesMembershipWitnesses: txPublicDataUpdateRequestInfo.lowPublicDataWritesMembershipWitnesses, + publicDataReadsPreimages: txPublicDataReadsInfo.newPublicDataReadsPreimages, + publicDataReadsMembershipWitnesses: txPublicDataReadsInfo.newPublicDataReadsWitnesses, + archiveRootMembershipWitness: await this.getHistoricalTreesMembershipWitnessFor(tx), + + constants, }); }