From 3cf9add85d386141c9422d105858b044ece97421 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Mon, 8 Apr 2024 18:18:19 +0000 Subject: [PATCH 01/15] Move public request validation to its own file. --- .../src/public_kernel_tail.nr | 86 +++--------------- .../crates/reset-kernel-lib/src/lib.nr | 4 +- .../public_validation_request_processor.nr | 91 +++++++++++++++++++ 3 files changed, 106 insertions(+), 75 deletions(-) create mode 100644 noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_validation_request_processor.nr diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr index 8240ae5d2d5..3b6419bc09d 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr @@ -1,16 +1,11 @@ use crate::common; -use dep::reset_kernel_lib::{ - NullifierReadRequestHints, NullifierNonExistentReadRequestHints, reset_non_existent_read_requests, - reset_read_requests -}; +use dep::reset_kernel_lib::{NullifierReadRequestHints, NullifierNonExistentReadRequestHints, PublicValidationRequestProcessor}; use dep::types::{ abis::{ kernel_circuit_public_inputs::{KernelCircuitPublicInputs, PublicKernelCircuitPublicInputsBuilder}, kernel_data::PublicKernelData, side_effect::SideEffectLinkedToNoteHash }, - constants::MAX_NEW_NULLIFIERS_PER_TX, - utils::{arrays::{array_length, array_merge, array_to_bounded_vec, assert_sorted_array}}, - hash::silo_nullifier, traits::is_empty + constants::MAX_NEW_NULLIFIERS_PER_TX, utils::{arrays::array_length} }; use dep::std::unsafe; @@ -38,81 +33,26 @@ impl PublicKernelTailCircuitPrivateInputs { ); } - fn validate_nullifier_read_requests(self, public_inputs: &mut PublicKernelCircuitPublicInputsBuilder) { - let end_non_revertible = self.previous_kernel.public_inputs.end_non_revertible; - let end = self.previous_kernel.public_inputs.end; - - let requests = self.previous_kernel.public_inputs.validation_requests.nullifier_read_requests; - - let pending_nullifiers = array_merge(end_non_revertible.new_nullifiers, end.new_nullifiers); - - let hints = self.nullifier_read_request_hints; - - let nullifier_tree_root = public_inputs.constants.historical_header.state.partial.nullifier_tree.root; - - let unverified_nullifier_read_requests = reset_read_requests( - requests, - pending_nullifiers, - hints.read_request_statuses, - hints.pending_read_hints, - hints.settled_read_hints, + pub fn public_kernel_tail(self) -> KernelCircuitPublicInputs { + let previous_public_inputs = self.previous_kernel.public_inputs; + let nullifier_tree_root = previous_public_inputs.constants.historical_header.state.partial.nullifier_tree.root; + let request_processor = PublicValidationRequestProcessor { + public_inputs: previous_public_inputs, + validation_requests: previous_public_inputs.validation_requests, + nullifier_read_request_hints: self.nullifier_read_request_hints, + nullifier_non_existent_read_request_hints: self.nullifier_non_existent_read_request_hints, nullifier_tree_root - ); - - assert( - unverified_nullifier_read_requests.len() == 0, "All nullifier read requests must be verified" - ); - } - - fn validate_nullifier_non_existent_read_requests(self, public_inputs: &mut PublicKernelCircuitPublicInputsBuilder) { - let end_non_revertible = self.previous_kernel.public_inputs.end_non_revertible; - let end = self.previous_kernel.public_inputs.end; - - // The values of the read requests here need to be siloed. - // Notice that it's not the case for regular read requests, which can be run between two kernel iterations, and will to be verified against unsiloed pending values. - let mut read_requests = self.previous_kernel.public_inputs.validation_requests.nullifier_non_existent_read_requests; - for i in 0..read_requests.len() { - let read_request = read_requests[i]; - if !is_empty(read_request) { - read_requests[i].value = silo_nullifier(read_request.contract_address, read_request.value); - } - } - - let nullifier_tree_root = public_inputs.constants.historical_header.state.partial.nullifier_tree.root; - - let hints = self.nullifier_non_existent_read_request_hints; + }; + request_processor.validate(); - let pending_nullifiers = array_merge(end_non_revertible.new_nullifiers, end.new_nullifiers); - assert_sorted_array( - pending_nullifiers, - hints.sorted_pending_values, - hints.sorted_pending_value_index_hints, - |a: SideEffectLinkedToNoteHash, b: SideEffectLinkedToNoteHash| a.value.lt(b.value) - ); - let sorted_pending_nullifiers = array_to_bounded_vec(hints.sorted_pending_values); - - reset_non_existent_read_requests( - read_requests, - hints.non_membership_hints, - nullifier_tree_root, - sorted_pending_nullifiers, - hints.next_pending_value_indices - ); - } + self.validate_inputs(); - pub fn public_kernel_tail(self) -> KernelCircuitPublicInputs { let mut public_inputs: PublicKernelCircuitPublicInputsBuilder = unsafe::zeroed(); - self.validate_inputs(); - self.propagate_revert_code(&mut public_inputs); common::initialize_emitted_end_values(self.previous_kernel, &mut public_inputs); - self.validate_nullifier_read_requests(&mut public_inputs); - - self.validate_nullifier_non_existent_read_requests(&mut public_inputs); - public_inputs.finish_tail() } } diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/lib.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/lib.nr index a156e40f1a6..8b207190f3a 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/lib.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/lib.nr @@ -1,12 +1,12 @@ -use non_existent_read_request_reset::reset_non_existent_read_requests; use nullifier_non_existent_read_request_reset::NullifierNonExistentReadRequestHints; use nullifier_read_request_reset::NullifierReadRequestHints; use private_validation_request_processor::PrivateValidationRequestProcessor; -use read_request_reset::reset_read_requests; +use public_validation_request_processor::PublicValidationRequestProcessor; mod non_existent_read_request_reset; mod nullifier_non_existent_read_request_reset; mod nullifier_read_request_reset; mod private_validation_request_processor; +mod public_validation_request_processor; mod read_request_reset; mod tests; diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_validation_request_processor.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_validation_request_processor.nr new file mode 100644 index 00000000000..3c0a98f4548 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_validation_request_processor.nr @@ -0,0 +1,91 @@ +use crate::{ + non_existent_read_request_reset::reset_non_existent_read_requests, + nullifier_read_request_reset::NullifierReadRequestHints, + nullifier_non_existent_read_request_reset::NullifierNonExistentReadRequestHints, + read_request_reset::reset_read_requests +}; +use dep::types::{ + abis::{ + kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, + side_effect::SideEffectLinkedToNoteHash, validation_requests::ValidationRequests +}, + hash::silo_nullifier, traits::is_empty, + utils::arrays::{array_merge, array_to_bounded_vec, assert_sorted_array} +}; + +struct PublicValidationRequestProcessor { + public_inputs: PublicKernelCircuitPublicInputs, + validation_requests: ValidationRequests, + nullifier_read_request_hints: NullifierReadRequestHints, + nullifier_non_existent_read_request_hints: NullifierNonExistentReadRequestHints, + nullifier_tree_root: Field, +} + +impl PublicValidationRequestProcessor { + pub fn validate(self) { + self.validate_nullifier_read_requests(); + self.validate_nullifier_non_existent_read_requests(); + } + + fn validate_nullifier_read_requests(self) { + let end_non_revertible = self.public_inputs.end_non_revertible; + let end = self.public_inputs.end; + + let requests = self.public_inputs.validation_requests.nullifier_read_requests; + + let pending_nullifiers = array_merge(end_non_revertible.new_nullifiers, end.new_nullifiers); + + let hints = self.nullifier_read_request_hints; + + let nullifier_tree_root = self.nullifier_tree_root; + + let unverified_nullifier_read_requests = reset_read_requests( + requests, + pending_nullifiers, + hints.read_request_statuses, + hints.pending_read_hints, + hints.settled_read_hints, + nullifier_tree_root + ); + + assert( + unverified_nullifier_read_requests.len() == 0, "All nullifier read requests must be verified" + ); + } + + fn validate_nullifier_non_existent_read_requests(self) { + let end_non_revertible = self.public_inputs.end_non_revertible; + let end = self.public_inputs.end; + + // The values of the read requests here need to be siloed. + // Notice that it's not the case for regular read requests, which can be run between two kernel iterations, and will to be verified against unsiloed pending values. + let mut read_requests = self.public_inputs.validation_requests.nullifier_non_existent_read_requests; + for i in 0..read_requests.len() { + let read_request = read_requests[i]; + if !is_empty(read_request) { + read_requests[i].value = silo_nullifier(read_request.contract_address, read_request.value); + } + } + + let nullifier_tree_root = self.nullifier_tree_root; + + let hints = self.nullifier_non_existent_read_request_hints; + + let pending_nullifiers = array_merge(end_non_revertible.new_nullifiers, end.new_nullifiers); + assert_sorted_array( + pending_nullifiers, + hints.sorted_pending_values, + hints.sorted_pending_value_index_hints, + |a: SideEffectLinkedToNoteHash, b: SideEffectLinkedToNoteHash| a.value.lt(b.value) + ); + let sorted_pending_nullifiers = array_to_bounded_vec(hints.sorted_pending_values); + + reset_non_existent_read_requests( + read_requests, + hints.non_membership_hints, + nullifier_tree_root, + sorted_pending_nullifiers, + hints.next_pending_value_indices + ); + } +} From d9760a76db133e82f7a3a7142b210ffededf37dc Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Wed, 10 Apr 2024 18:14:33 +0000 Subject: [PATCH 02/15] Validate public data reads. --- .../noir-protocol-circuits/Nargo.toml | 1 + .../src/private_kernel_tail.nr | 2 +- .../src/private_kernel_tail_to_public.nr | 2 +- .../src/public_kernel_tail.nr | 233 +++++++++++-- .../crates/reset-kernel-lib/src/lib.nr | 7 +- ...llifier_non_existent_read_request_reset.nr | 4 +- .../src/nullifier_read_request_reset.nr | 4 +- .../private_validation_request_processor.nr | 2 +- .../src/public_data_read_request_reset.nr | 9 + .../public_validation_request_processor.nr | 92 +++-- .../crates/reset-kernel-lib/src/reset.nr | 3 + .../src/reset/mutable_data_read_request.nr | 317 ++++++++++++++++++ .../non_existent_read_request.nr} | 2 +- .../read_request.nr} | 4 +- .../crates/reset-kernel-lib/src/tests.nr | 1 + .../nullifier_read_request_hints_builder.nr | 2 +- .../public_data_read_request_hints_builder.nr | 29 ++ .../crates/reset-kernel-lib/src/types.nr | 1 + .../src/types/public_data_hint.nr | 28 ++ .../crates/types/src/merkle_tree.nr | 4 +- .../types/src/merkle_tree/indexed_tree.nr | 2 + .../indexed_tree/check_valid_low_leaf.nr | 76 +++++ .../types/src/merkle_tree/membership.nr | 204 ++++++----- .../src/public_data_tree_leaf_preimage.nr | 16 +- .../crates/types/src/tests/fixture_builder.nr | 26 +- 25 files changed, 892 insertions(+), 179 deletions(-) create mode 100644 noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_data_read_request_reset.nr create mode 100644 noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset.nr create mode 100644 noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/mutable_data_read_request.nr rename noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/{non_existent_read_request_reset.nr => reset/non_existent_read_request.nr} (99%) rename noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/{read_request_reset.nr => reset/read_request.nr} (99%) create mode 100644 noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/public_data_read_request_hints_builder.nr create mode 100644 noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/types.nr create mode 100644 noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/types/public_data_hint.nr create mode 100644 noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/indexed_tree/check_valid_low_leaf.nr diff --git a/noir-projects/noir-protocol-circuits/Nargo.toml b/noir-projects/noir-protocol-circuits/Nargo.toml index d3f3c3d55b0..48cc2fc96f6 100644 --- a/noir-projects/noir-protocol-circuits/Nargo.toml +++ b/noir-projects/noir-protocol-circuits/Nargo.toml @@ -22,6 +22,7 @@ members = [ "crates/public-kernel-teardown-simulated", "crates/public-kernel-tail", "crates/public-kernel-tail-simulated", + "crates/reset-kernel-lib", "crates/rollup-lib", "crates/rollup-merge", "crates/rollup-base", diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr index 9c1d74fe688..2b7ad2cdab0 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr @@ -60,7 +60,7 @@ mod tests { use crate::private_kernel_tail::PrivateKernelTailCircuitPrivateInputs; use dep::reset_kernel_lib::{ tests::nullifier_read_request_hints_builder::NullifierReadRequestHintsBuilder, - read_request_reset::{PendingReadHint, ReadRequestState, ReadRequestStatus} + reset::read_request::{PendingReadHint, ReadRequestState, ReadRequestStatus} }; use dep::types::constants::{ MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr index e6a9c96be08..bc90e0aba77 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr @@ -60,7 +60,7 @@ mod tests { use crate::private_kernel_tail_to_public::PrivateKernelTailToPublicCircuitPrivateInputs; use dep::reset_kernel_lib::{ tests::nullifier_read_request_hints_builder::NullifierReadRequestHintsBuilder, - read_request_reset::{PendingReadHint, ReadRequestState, ReadRequestStatus} + reset::read_request::{PendingReadHint, ReadRequestState, ReadRequestStatus} }; use dep::types::constants::{ MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr index 3b6419bc09d..95cfed7a5ae 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr @@ -1,11 +1,15 @@ use crate::common; -use dep::reset_kernel_lib::{NullifierReadRequestHints, NullifierNonExistentReadRequestHints, PublicValidationRequestProcessor}; +use dep::reset_kernel_lib::{ + NullifierReadRequestHints, NullifierNonExistentReadRequestHints, PublicDataReadRequestHints, + PublicValidationRequestProcessor, PublicDataHint +}; use dep::types::{ abis::{ kernel_circuit_public_inputs::{KernelCircuitPublicInputs, PublicKernelCircuitPublicInputsBuilder}, kernel_data::PublicKernelData, side_effect::SideEffectLinkedToNoteHash }, - constants::MAX_NEW_NULLIFIERS_PER_TX, utils::{arrays::array_length} + constants::{MAX_NEW_NULLIFIERS_PER_TX, MAX_PUBLIC_DATA_READS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX}, + merkle_tree::conditionally_assert_check_membership, utils::{arrays::array_length} }; use dep::std::unsafe; @@ -13,6 +17,8 @@ struct PublicKernelTailCircuitPrivateInputs { previous_kernel: PublicKernelData, nullifier_read_request_hints: NullifierReadRequestHints, nullifier_non_existent_read_request_hints: NullifierNonExistentReadRequestHints, + public_data_read_request_hints: PublicDataReadRequestHints, + public_data_hints: [PublicDataHint; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX + MAX_PUBLIC_DATA_READS_PER_TX], } impl PublicKernelTailCircuitPrivateInputs { @@ -33,20 +39,50 @@ impl PublicKernelTailCircuitPrivateInputs { ); } + fn validate_public_data_hints(self) { + let public_data_hints = self.public_data_hints; + let public_data_tree_root = self.previous_kernel.public_inputs.constants.historical_header.state.partial.public_data_tree.root; + for i in 0..public_data_hints.len() { + let hint = public_data_hints[i]; + // We only need to check leaf_slot to decide if a (non-)membership check is required. + // It will fail if a PublicDataHint with 0 leaf_slot is used to verify a non-empty public read or write. + if hint.leaf_slot != 0 { + if hint.exists { + assert( + hint.value == hint.leaf_preimage.value, "Hinted public data value does not match the value in leaf preimage" + ); + } else { + assert(hint.value == 0, "Value must be 0 for non-existent public data"); + } + + conditionally_assert_check_membership( + hint.leaf_slot, + hint.exists, + hint.leaf_preimage, + hint.membership_witness, + public_data_tree_root + ); + } + } + } + pub fn public_kernel_tail(self) -> KernelCircuitPublicInputs { + self.validate_inputs(); + + self.validate_public_data_hints(); + let previous_public_inputs = self.previous_kernel.public_inputs; let nullifier_tree_root = previous_public_inputs.constants.historical_header.state.partial.nullifier_tree.root; - let request_processor = PublicValidationRequestProcessor { - public_inputs: previous_public_inputs, - validation_requests: previous_public_inputs.validation_requests, - nullifier_read_request_hints: self.nullifier_read_request_hints, - nullifier_non_existent_read_request_hints: self.nullifier_non_existent_read_request_hints, - nullifier_tree_root - }; + let request_processor = PublicValidationRequestProcessor::new( + previous_public_inputs, + self.nullifier_read_request_hints, + self.nullifier_non_existent_read_request_hints, + nullifier_tree_root, + self.public_data_read_request_hints, + self.public_data_hints + ); request_processor.validate(); - self.validate_inputs(); - let mut public_inputs: PublicKernelCircuitPublicInputsBuilder = unsafe::zeroed(); self.propagate_revert_code(&mut public_inputs); @@ -58,24 +94,29 @@ impl PublicKernelTailCircuitPrivateInputs { } mod tests { - use crate::{public_kernel_tail::PublicKernelTailCircuitPrivateInputs}; + use crate::public_kernel_tail::PublicKernelTailCircuitPrivateInputs; use dep::reset_kernel_lib::{ tests::{ nullifier_non_existent_read_request_hints_builder::NullifierNonExistentReadRequestHintsBuilder, - nullifier_read_request_hints_builder::NullifierReadRequestHintsBuilder + nullifier_read_request_hints_builder::NullifierReadRequestHintsBuilder, + public_data_read_request_hints_builder::PublicDataReadRequestHintsBuilder }, - read_request_reset::{PendingReadHint, ReadRequestState, ReadRequestStatus} + PublicDataHint, reset::read_request::{PendingReadHint, ReadRequestState, ReadRequestStatus} }; + use dep::std::unsafe; use dep::types::{ abis::{ kernel_circuit_public_inputs::{KernelCircuitPublicInputs, PublicKernelCircuitPublicInputsBuilder}, kernel_data::PublicKernelData, nullifier_leaf_preimage::NullifierLeafPreimage }, constants::{ - MAX_NEW_NULLIFIERS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, NULLIFIER_TREE_HEIGHT, - NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, NULLIFIER_SUBTREE_HEIGHT + MAX_NEW_NULLIFIERS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_PUBLIC_DATA_READS_PER_TX, + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, NULLIFIER_TREE_HEIGHT, + NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, NULLIFIER_SUBTREE_HEIGHT, PUBLIC_DATA_SUBTREE_HEIGHT, + PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH, PUBLIC_DATA_TREE_HEIGHT }, - hash::silo_nullifier, + hash::silo_nullifier, public_data_tree_leaf_preimage::PublicDataTreeLeafPreimage, + merkle_tree::membership::MembershipWitness, tests::{fixture_builder::FixtureBuilder, merkle_tree_utils::NonEmptyMerkleTree}, utils::arrays::array_merge }; @@ -92,11 +133,32 @@ mod tests { ) } + fn get_settled_public_data_leaves() -> [PublicDataTreeLeafPreimage; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX] { + let mut settled_public_data_leaves = [PublicDataTreeLeafPreimage::empty(); MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX]; + settled_public_data_leaves[0] = PublicDataTreeLeafPreimage { slot: 22, value: 200, next_slot: 33, next_index: 1 }; + settled_public_data_leaves[1] = PublicDataTreeLeafPreimage { slot: 33, value: 300, next_slot: 0, next_index: 0 }; + settled_public_data_leaves[2] = PublicDataTreeLeafPreimage { slot: 11, value: 100, next_slot: 22, next_index: 0 }; + settled_public_data_leaves + } + + fn build_public_data_tree() -> NonEmptyMerkleTree { + let settled_public_data_leaves = get_settled_public_data_leaves(); + NonEmptyMerkleTree::new( + settled_public_data_leaves.map(|preimage: PublicDataTreeLeafPreimage| preimage.hash()), + [0; PUBLIC_DATA_TREE_HEIGHT], + [0; PUBLIC_DATA_TREE_HEIGHT - PUBLIC_DATA_SUBTREE_HEIGHT], + [0; PUBLIC_DATA_SUBTREE_HEIGHT] + ) + } + struct PublicKernelTailCircuitPrivateInputsBuilder { previous_kernel: FixtureBuilder, previous_revertible: FixtureBuilder, nullifier_read_request_hints_builder: NullifierReadRequestHintsBuilder, nullifier_non_existent_read_request_hints_builder: NullifierNonExistentReadRequestHintsBuilder, + public_data_read_request_hints_builder: PublicDataReadRequestHintsBuilder, + public_data_hints: BoundedVec, + public_data_tree: NonEmptyMerkleTree, } impl PublicKernelTailCircuitPrivateInputsBuilder { @@ -109,7 +171,10 @@ mod tests { previous_kernel, previous_revertible, nullifier_read_request_hints_builder: NullifierReadRequestHintsBuilder::new(MAX_NULLIFIER_READ_REQUESTS_PER_TX), - nullifier_non_existent_read_request_hints_builder + nullifier_non_existent_read_request_hints_builder, + public_data_read_request_hints_builder: PublicDataReadRequestHintsBuilder::new(MAX_PUBLIC_DATA_READS_PER_TX), + public_data_hints: BoundedVec::new(), + public_data_tree: unsafe::zeroed() }; builder.set_nullifiers_for_non_existent_read_request_hints(); builder @@ -122,6 +187,13 @@ mod tests { *self } + pub fn with_public_data_tree(&mut self) -> Self { + let public_data_tree = build_public_data_tree(); + self.public_data_tree = public_data_tree; + self.previous_kernel.historical_header.state.partial.public_data_tree.root = public_data_tree.get_root(); + *self + } + pub fn add_nullifier(&mut self, unsiloed_nullifier: Field) { self.previous_kernel.add_nullifier(unsiloed_nullifier); self.sync_counters(); @@ -177,6 +249,38 @@ mod tests { self.nullifier_non_existent_read_request_hints_builder.add_value_read(siloed_nullifier); } + pub fn add_public_data_hint_for_settled_public_data(&mut self, leaf_index: u64) { + let leaf_preimage = get_settled_public_data_leaves()[leaf_index]; + let membership_witness = MembershipWitness { leaf_index: leaf_index as Field, sibling_path: self.public_data_tree.get_sibling_path(leaf_index) }; + let hint = PublicDataHint { + leaf_slot: leaf_preimage.slot, + value: leaf_preimage.value, + override_counter: 0, + exists: true, + membership_witness, + leaf_preimage + }; + self.public_data_hints.push(hint); + } + + pub fn add_public_data_hint_for_non_existent_public_data(&mut self, leaf_slot: Field, low_leaf_index: u64) { + let leaf_preimage = get_settled_public_data_leaves()[low_leaf_index]; + let membership_witness = MembershipWitness { + leaf_index: low_leaf_index as Field, + sibling_path: self.public_data_tree.get_sibling_path(low_leaf_index) + }; + let hint = PublicDataHint { leaf_slot, value: 0, override_counter: 0, exists: false, membership_witness, leaf_preimage }; + self.public_data_hints.push(hint); + } + + pub fn add_pending_public_data_read_request(&mut self, public_date_update_request_index: u64) { + let read_request_index = self.previous_kernel.add_read_request_for_pending_public_data(public_date_update_request_index); + let hint_index = self.public_data_read_request_hints_builder.pending_read_hints.len(); + let hint = PendingReadHint { read_request_index, pending_value_index: public_date_update_request_index }; + self.public_data_read_request_hints_builder.pending_read_hints.push(hint); + self.public_data_read_request_hints_builder.read_request_statuses[read_request_index] = ReadRequestStatus { state: ReadRequestState.PENDING, hint_index }; + } + fn sync_counters(&mut self) { let counter_non_revertible = self.previous_kernel.counter; let counter_revertible = self.previous_revertible.counter; @@ -194,7 +298,9 @@ mod tests { let kernel = PublicKernelTailCircuitPrivateInputs { previous_kernel, nullifier_read_request_hints: self.nullifier_read_request_hints_builder.to_hints(), - nullifier_non_existent_read_request_hints: self.nullifier_non_existent_read_request_hints_builder.to_hints() + nullifier_non_existent_read_request_hints: self.nullifier_non_existent_read_request_hints_builder.to_hints(), + public_data_read_request_hints: self.public_data_read_request_hints_builder.to_hints(), + public_data_hints: self.public_data_hints.storage }; kernel.public_kernel_tail() @@ -297,6 +403,95 @@ mod tests { builder.read_non_existent_nullifier(1); + builder.failed(); + } + + #[test] + unconstrained fn validate_public_data_hints() { + let mut builder = PublicKernelTailCircuitPrivateInputsBuilder::new().with_public_data_tree(); + + builder.add_public_data_hint_for_settled_public_data(1); + builder.add_public_data_hint_for_settled_public_data(0); + builder.add_public_data_hint_for_settled_public_data(2); + + builder.succeeded(); + } + + #[test(should_fail_with="Hinted public data value does not match the value in leaf preimage")] + unconstrained fn validate_public_data_hints_failed_mismatch_value() { + let mut builder = PublicKernelTailCircuitPrivateInputsBuilder::new().with_public_data_tree(); + + builder.add_public_data_hint_for_settled_public_data(1); + + let mut hint = builder.public_data_hints.pop(); + hint.value += 1; + builder.public_data_hints.push(hint); + + builder.failed(); + } + + #[test] + unconstrained fn validate_public_data_hints_uninitialized_value() { + let mut builder = PublicKernelTailCircuitPrivateInputsBuilder::new().with_public_data_tree(); + + builder.add_public_data_hint_for_non_existent_public_data(25, 0); + + builder.succeeded(); + } + + #[test(should_fail_with="Value must be 0 for non-existent public data")] + unconstrained fn validate_public_data_hints_failed_non_zero_uninitialized_value() { + let mut builder = PublicKernelTailCircuitPrivateInputsBuilder::new().with_public_data_tree(); + + builder.add_public_data_hint_for_non_existent_public_data(25, 0); + + let mut hint = builder.public_data_hints.pop(); + hint.value = 1; + builder.public_data_hints.push(hint); + + builder.failed(); + } + + #[test] + unconstrained fn pending_public_data_read_requests() { + let mut builder = PublicKernelTailCircuitPrivateInputsBuilder::new(); + + builder.previous_kernel.append_public_data_update_requests(3); + + builder.add_pending_public_data_read_request(1); + builder.add_pending_public_data_read_request(0); + builder.add_pending_public_data_read_request(2); + builder.succeeded(); } + + #[test(should_fail_with="Hinted slot of data write does not match read request")] + unconstrained fn pending_public_data_read_requests_failed_wrong_write_index() { + let mut builder = PublicKernelTailCircuitPrivateInputsBuilder::new(); + + builder.previous_kernel.append_public_data_update_requests(2); + + builder.add_pending_public_data_read_request(1); + + let mut hint = builder.public_data_read_request_hints_builder.pending_read_hints.pop(); + hint.pending_value_index += 1; + builder.public_data_read_request_hints_builder.pending_read_hints.push(hint); + + builder.failed(); + } + + #[test(should_fail_with="Hinted value of data write does not match read request")] + unconstrained fn pending_public_data_read_requests_failed_wrong_write_value() { + let mut builder = PublicKernelTailCircuitPrivateInputsBuilder::new(); + + builder.previous_kernel.append_public_data_update_requests(1); + + builder.add_pending_public_data_read_request(0); + + let mut public_data_write = builder.previous_kernel.public_data_update_requests.pop(); + public_data_write.new_value += 1; + builder.previous_kernel.public_data_update_requests.push(public_data_write); + + builder.failed(); + } } diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/lib.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/lib.nr index 8b207190f3a..8a7ffb5e38b 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/lib.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/lib.nr @@ -1,12 +1,15 @@ use nullifier_non_existent_read_request_reset::NullifierNonExistentReadRequestHints; use nullifier_read_request_reset::NullifierReadRequestHints; use private_validation_request_processor::PrivateValidationRequestProcessor; +use public_data_read_request_reset::PublicDataReadRequestHints; use public_validation_request_processor::PublicValidationRequestProcessor; +use types::public_data_hint::PublicDataHint; -mod non_existent_read_request_reset; mod nullifier_non_existent_read_request_reset; mod nullifier_read_request_reset; mod private_validation_request_processor; +mod public_data_read_request_reset; mod public_validation_request_processor; -mod read_request_reset; +mod reset; mod tests; +mod types; diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/nullifier_non_existent_read_request_reset.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/nullifier_non_existent_read_request_reset.nr index cc76145b18e..5f9f7548782 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/nullifier_non_existent_read_request_reset.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/nullifier_non_existent_read_request_reset.nr @@ -1,7 +1,7 @@ -use crate::non_existent_read_request_reset::{NonMembershipHint}; +use crate::reset::non_existent_read_request::NonMembershipHint; use dep::types::{ abis::{nullifier_leaf_preimage::NullifierLeafPreimage, side_effect::SideEffectLinkedToNoteHash}, - merkle_tree::{MembershipWitness}, + merkle_tree::MembershipWitness, constants::{MAX_NEW_NULLIFIERS_PER_TX, MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, NULLIFIER_TREE_HEIGHT} }; diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/nullifier_read_request_reset.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/nullifier_read_request_reset.nr index 6a122e57a2d..5caf1b2b7c1 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/nullifier_read_request_reset.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/nullifier_read_request_reset.nr @@ -1,5 +1,5 @@ // This will be moved to a separate Read Request Reset Circuit. -use crate::read_request_reset::{PendingReadHint, ReadRequestStatus, ReadValueHint, SettledReadHint}; +use crate::reset::read_request::{PendingReadHint, ReadRequestStatus, ReadValueHint, SettledReadHint}; use dep::std::unsafe; use dep::types::{ abis::{nullifier_leaf_preimage::NullifierLeafPreimage}, @@ -45,7 +45,7 @@ struct NullifierReadRequestHints { mod tests { use crate::nullifier_read_request_reset::NullifierSettledReadHint; - use crate::read_request_reset::{PendingReadHint, ReadRequestState, ReadRequestStatus, reset_read_requests}; + use crate::reset::read_request::{PendingReadHint, ReadRequestState, ReadRequestStatus, reset_read_requests}; use dep::types::{ address::AztecAddress, abis::{ diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/private_validation_request_processor.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/private_validation_request_processor.nr index 9f60134dd45..469a4d6d9bf 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/private_validation_request_processor.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/private_validation_request_processor.nr @@ -1,4 +1,4 @@ -use crate::{nullifier_read_request_reset::NullifierReadRequestHints, read_request_reset::reset_read_requests}; +use crate::{nullifier_read_request_reset::NullifierReadRequestHints, reset::read_request::reset_read_requests}; use dep::types::{ abis::{side_effect::{SideEffect, SideEffectLinkedToNoteHash}, validation_requests::ValidationRequests}, constants::{ diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_data_read_request_reset.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_data_read_request_reset.nr new file mode 100644 index 00000000000..d1ddafc40c1 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_data_read_request_reset.nr @@ -0,0 +1,9 @@ +use crate::reset::{mutable_data_read_request::SettledReadHint, read_request::{PendingReadHint, ReadRequestStatus}}; +use dep::types::constants::MAX_PUBLIC_DATA_READS_PER_TX; + +// The MAX_PUBLIC_DATA_READS_PER_TX for pending_read_hints and settled_read_hints can change if we create various circuits that deal with different number of reads. +struct PublicDataReadRequestHints { + read_request_statuses: [ReadRequestStatus; MAX_PUBLIC_DATA_READS_PER_TX], + pending_read_hints: [PendingReadHint; MAX_PUBLIC_DATA_READS_PER_TX], + settled_read_hints: [SettledReadHint; MAX_PUBLIC_DATA_READS_PER_TX], +} diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_validation_request_processor.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_validation_request_processor.nr index 3c0a98f4548..0a46a3cb16c 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_validation_request_processor.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_validation_request_processor.nr @@ -1,65 +1,91 @@ use crate::{ - non_existent_read_request_reset::reset_non_existent_read_requests, + reset::{ + non_existent_read_request::reset_non_existent_read_requests, + mutable_data_read_request::reset_mutable_data_read_requests, read_request::reset_read_requests +}, nullifier_read_request_reset::NullifierReadRequestHints, nullifier_non_existent_read_request_reset::NullifierNonExistentReadRequestHints, - read_request_reset::reset_read_requests + public_data_read_request_reset::PublicDataReadRequestHints, types::public_data_hint::PublicDataHint }; use dep::types::{ abis::{ kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, - side_effect::SideEffectLinkedToNoteHash, validation_requests::ValidationRequests + public_data_update_request::PublicDataUpdateRequest, side_effect::SideEffectLinkedToNoteHash, + validation_requests::ValidationRequests }, + constants::{MAX_NEW_NULLIFIERS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX}, hash::silo_nullifier, traits::is_empty, utils::arrays::{array_merge, array_to_bounded_vec, assert_sorted_array} }; -struct PublicValidationRequestProcessor { - public_inputs: PublicKernelCircuitPublicInputs, +struct PublicValidationRequestProcessor { validation_requests: ValidationRequests, + pending_nullifiers: [SideEffectLinkedToNoteHash; MAX_NEW_NULLIFIERS_PER_TX], + pending_public_data_writes: [PublicDataUpdateRequest; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], nullifier_read_request_hints: NullifierReadRequestHints, nullifier_non_existent_read_request_hints: NullifierNonExistentReadRequestHints, nullifier_tree_root: Field, + public_data_read_request_hints: PublicDataReadRequestHints, + public_data_hints: [PublicDataHint; N], } -impl PublicValidationRequestProcessor { +impl PublicValidationRequestProcessor { + pub fn new( + public_inputs: PublicKernelCircuitPublicInputs, + nullifier_read_request_hints: NullifierReadRequestHints, + nullifier_non_existent_read_request_hints: NullifierNonExistentReadRequestHints, + nullifier_tree_root: Field, + public_data_read_request_hints: PublicDataReadRequestHints, + public_data_hints: [PublicDataHint; N] + ) -> Self { + let end_non_revertible = public_inputs.end_non_revertible; + let end = public_inputs.end; + + let pending_nullifiers = array_merge(end_non_revertible.new_nullifiers, end.new_nullifiers); + + let pending_public_data_writes = array_merge( + end_non_revertible.public_data_update_requests, + end.public_data_update_requests + ); + + PublicValidationRequestProcessor { + validation_requests: public_inputs.validation_requests, + pending_nullifiers, + pending_public_data_writes, + nullifier_read_request_hints, + nullifier_non_existent_read_request_hints, + nullifier_tree_root, + public_data_read_request_hints, + public_data_hints + } + } + pub fn validate(self) { self.validate_nullifier_read_requests(); self.validate_nullifier_non_existent_read_requests(); + self.validate_public_data_read_requests(); } fn validate_nullifier_read_requests(self) { - let end_non_revertible = self.public_inputs.end_non_revertible; - let end = self.public_inputs.end; - - let requests = self.public_inputs.validation_requests.nullifier_read_requests; - - let pending_nullifiers = array_merge(end_non_revertible.new_nullifiers, end.new_nullifiers); - + let requests = self.validation_requests.nullifier_read_requests; let hints = self.nullifier_read_request_hints; - - let nullifier_tree_root = self.nullifier_tree_root; - let unverified_nullifier_read_requests = reset_read_requests( requests, - pending_nullifiers, + self.pending_nullifiers, hints.read_request_statuses, hints.pending_read_hints, hints.settled_read_hints, - nullifier_tree_root + self.nullifier_tree_root ); - assert( unverified_nullifier_read_requests.len() == 0, "All nullifier read requests must be verified" ); } fn validate_nullifier_non_existent_read_requests(self) { - let end_non_revertible = self.public_inputs.end_non_revertible; - let end = self.public_inputs.end; - // The values of the read requests here need to be siloed. // Notice that it's not the case for regular read requests, which can be run between two kernel iterations, and will to be verified against unsiloed pending values. - let mut read_requests = self.public_inputs.validation_requests.nullifier_non_existent_read_requests; + let mut read_requests = self.validation_requests.nullifier_non_existent_read_requests; for i in 0..read_requests.len() { let read_request = read_requests[i]; if !is_empty(read_request) { @@ -67,13 +93,10 @@ impl PublicValidationRequestProcessor { } } - let nullifier_tree_root = self.nullifier_tree_root; - let hints = self.nullifier_non_existent_read_request_hints; - let pending_nullifiers = array_merge(end_non_revertible.new_nullifiers, end.new_nullifiers); assert_sorted_array( - pending_nullifiers, + self.pending_nullifiers, hints.sorted_pending_values, hints.sorted_pending_value_index_hints, |a: SideEffectLinkedToNoteHash, b: SideEffectLinkedToNoteHash| a.value.lt(b.value) @@ -83,9 +106,22 @@ impl PublicValidationRequestProcessor { reset_non_existent_read_requests( read_requests, hints.non_membership_hints, - nullifier_tree_root, + self.nullifier_tree_root, sorted_pending_nullifiers, hints.next_pending_value_indices ); } + + fn validate_public_data_read_requests(self) { + let hints = self.public_data_read_request_hints; + + reset_mutable_data_read_requests( + self.validation_requests.public_data_reads, + hints.read_request_statuses, + self.pending_public_data_writes, + self.public_data_hints, + hints.pending_read_hints, + hints.settled_read_hints + ); + } } diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset.nr new file mode 100644 index 00000000000..8b98420b3cd --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset.nr @@ -0,0 +1,3 @@ +mod mutable_data_read_request; +mod non_existent_read_request; +mod read_request; diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/mutable_data_read_request.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/mutable_data_read_request.nr new file mode 100644 index 00000000000..e1b88a4c0c5 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/mutable_data_read_request.nr @@ -0,0 +1,317 @@ +use crate::reset::read_request::{PendingReadHint, ReadRequestState, ReadRequestStatus}; +use dep::types::{ + abis::{public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest}, + traits::{Empty, is_empty} +}; + +trait SettledDataHint { + fn leaf_slot(self) -> Field; + fn value(self) -> Field; + fn override_counter(self) -> u32; +} + +struct SettledReadHint { + read_request_index: u64, + settled_data_hint_index: u64, +} + +impl SettledReadHint { + pub fn nada(read_request_len: u64) -> Self { + SettledReadHint { read_request_index: read_request_len, settled_data_hint_index: 0 } + } +} + +fn validate_pending_read_requests( + read_requests: [PublicDataRead; READ_REQUEST_LEN], + data_writes: [PublicDataUpdateRequest; PENDING_VALUE_LEN], + hints: [PendingReadHint; NUM_PENDING_READS] +) { + for i in 0..NUM_PENDING_READS { + let read_request_index = hints[i].read_request_index; + if read_request_index != READ_REQUEST_LEN { + let read_request = read_requests[read_request_index]; + let pending_value = data_writes[hints[i].pending_value_index]; + assert( + read_request.leaf_slot.eq(pending_value.leaf_slot), "Hinted slot of data write does not match read request" + ); + assert( + read_request.value.eq(pending_value.new_value), "Hinted value of data write does not match read request" + ); + // TODO: Add counters and verify the following: + // assert( + // read_request.counter > pending_value.counter, "Read request counter must be greater than the counter of the data write" + // ); + // assert((read_request.counter < pending_value.next_counter) | (pending_value.next_counter == 0), "Read request counter must be less than the counter of the next data write"); + } + } +} + +fn validate_settled_read_requests( + read_requests: [PublicDataRead; READ_REQUEST_LEN], + settled_data_hints: [H; NUM_SETTLED_DATA_HINTS], + hints: [SettledReadHint; NUM_SETTLED_READS] +) where H: SettledDataHint { + for i in 0..NUM_SETTLED_READS { + let read_request_index = hints[i].read_request_index; + if read_request_index != READ_REQUEST_LEN { + let read_request = read_requests[read_request_index]; + let data_hint = settled_data_hints[hints[i].settled_data_hint_index]; + assert( + read_request.leaf_slot == data_hint.leaf_slot(), "Hinted slot does not match read request" + ); + assert(read_request.value == data_hint.value(), "Hinted value does not match read request"); + // TODO: Add counters and verify the following: + // assert((read_request.counter < data_hint.override_counter) | (data_hint.override_counter == 0), "Hinted leaf is overridden before the read request"); + } + } +} + +fn ensure_all_read_requests_are_verified( + read_requests: [PublicDataRead; READ_REQUEST_LEN], + read_request_statuses: [ReadRequestStatus; READ_REQUEST_LEN], + pending_read_hints: [PendingReadHint; NUM_PENDING_READS], + settled_read_hints: [SettledReadHint; NUM_SETTLED_READS] +) { + for i in 0..READ_REQUEST_LEN { + let read_request = read_requests[i]; + if !is_empty(read_request) { + let status = read_request_statuses[i]; + if status.state == ReadRequestState.PENDING { + assert( + pending_read_hints[status.hint_index].read_request_index == i, "Hinted pending read request does not match status" + ); + } else if status.state == ReadRequestState.SETTLED { + assert( + settled_read_hints[status.hint_index].read_request_index == i, "Hinted settled read request does not match status" + ); + } else { + assert(false, "Read request status must be PENDING or SETTLED"); + } + } + } +} + +pub fn reset_mutable_data_read_requests( + read_requests: [PublicDataRead; READ_REQUEST_LEN], + read_request_statuses: [ReadRequestStatus; READ_REQUEST_LEN], + data_writes: [PublicDataUpdateRequest; PENDING_VALUE_LEN], + settled_data_hints: [H; NUM_SETTLED_DATA_HINTS], + pending_read_hints: [PendingReadHint; NUM_PENDING_READS], + settled_read_hints: [SettledReadHint; NUM_SETTLED_READS] +) where H: SettledDataHint { + validate_pending_read_requests(read_requests, data_writes, pending_read_hints); + + validate_settled_read_requests(read_requests, settled_data_hints, settled_read_hints); + + ensure_all_read_requests_are_verified( + read_requests, + read_request_statuses, + pending_read_hints, + settled_read_hints + ); +} + +mod tests { + use crate::reset::{ + mutable_data_read_request::{ + ensure_all_read_requests_are_verified, reset_mutable_data_read_requests, SettledDataHint, + SettledReadHint, validate_pending_read_requests, validate_settled_read_requests + }, + read_request::{PendingReadHint, ReadRequestState, ReadRequestStatus} + }; + use dep::types::{abis::{public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest}}; + + struct TestDataHint { + leaf_slot: Field, + value: Field, + } + + impl SettledDataHint for TestDataHint { + fn leaf_slot(self) -> Field { + self.leaf_slot + } + + fn value(self) -> Field { + self.value + } + + fn override_counter(_self: Self) -> u32 { + 0 + } + } + + global data_writes = [ + PublicDataUpdateRequest { leaf_slot: 22, new_value: 200 }, + PublicDataUpdateRequest { leaf_slot: 11, new_value: 100 }, + PublicDataUpdateRequest { leaf_slot: 33, new_value: 300 }, + PublicDataUpdateRequest { leaf_slot: 44, new_value: 400 } + ]; + + global settled_data_hints = [ + TestDataHint { leaf_slot: 7, value: 70 }, + TestDataHint { leaf_slot: 6, value: 60 }, + TestDataHint { leaf_slot: 5, value: 50 }, + ]; + + fn create_pending_read_requests(data_write_indices: [u64; N]) -> ([PublicDataRead; N], [PendingReadHint; N]) { + let read_requests = data_write_indices.map( + |data_write_index: u64| PublicDataRead { leaf_slot: data_writes[data_write_index].leaf_slot, value: data_writes[data_write_index].new_value } + ); + let mut hints = BoundedVec::new(); + for i in 0..N { + hints.push(PendingReadHint { read_request_index: i, pending_value_index: data_write_indices[i] }); + } + (read_requests, hints.storage) + } + + fn create_settled_read_requests(settled_data_hint_indices: [u64; N]) -> ([PublicDataRead; N], [SettledReadHint; N]) { + let read_requests = settled_data_hint_indices.map( + |settled_data_hint_index: u64| PublicDataRead { leaf_slot: settled_data_hints[settled_data_hint_index].leaf_slot, value: settled_data_hints[settled_data_hint_index].value } + ); + let mut hints = BoundedVec::new(); + for i in 0..N { + hints.push( + SettledReadHint { read_request_index: i, settled_data_hint_index: settled_data_hint_indices[i] } + ); + } + (read_requests, hints.storage) + } + + #[test] + fn reset_pending_reads_succeeds() { + let (read_requests, hints) = create_pending_read_requests([2, 0, 1, 3]); + validate_pending_read_requests(read_requests, data_writes, hints); + } + + #[test] + fn reset_pending_reads_repeated_values() { + let (read_requests, hints) = create_pending_read_requests([1, 0, 0, 1]); + validate_pending_read_requests(read_requests, data_writes, hints); + } + + #[test] + fn reset_pending_reads_skips_nada() { + let read_requests = [PublicDataRead { leaf_slot: 88, value: 9999 }]; + let hints = [PendingReadHint::nada(1)]; + validate_pending_read_requests(read_requests, data_writes, hints); + } + + #[test(should_fail_with="Hinted slot of data write does not match read request")] + fn reset_pending_reads_wrong_slot_fails() { + let mut (read_requests, hints) = create_pending_read_requests([1]); + hints[0].pending_value_index = 0; + validate_pending_read_requests(read_requests, data_writes, hints); + } + + #[test(should_fail_with="Hinted value of data write does not match read request")] + fn reset_pending_reads_wrong_value_fails() { + let mut (read_requests, hints) = create_pending_read_requests([1]); + read_requests[0].value += 1; + validate_pending_read_requests(read_requests, data_writes, hints); + } + + #[test] + fn reset_settled_reads_succeeds() { + let (read_requests, hints) = create_settled_read_requests([2, 1, 0]); + validate_settled_read_requests(read_requests, settled_data_hints, hints); + } + + #[test] + fn reset_settled_reads_repeated_values() { + let (read_requests, hints) = create_settled_read_requests([1, 0, 1, 0]); + validate_settled_read_requests(read_requests, settled_data_hints, hints); + } + + #[test] + fn reset_settled_reads_skips_nada() { + let read_requests = [PublicDataRead { leaf_slot: 88, value: 9999 }]; + let hints = [SettledReadHint::nada(1)]; + validate_settled_read_requests(read_requests, settled_data_hints, hints); + } + + #[test(should_fail_with=""Hinted slot does not match read request")] + fn reset_settled_reads_wrong_slot_fails() { + let mut (read_requests, hints) = create_settled_read_requests([1]); + hints[0].settled_data_hint_index = 0; + validate_settled_read_requests(read_requests, settled_data_hints, hints); + } + + #[test(should_fail_with=""Hinted value does not match read request")] + fn reset_settled_reads_wrong_value_fails() { + let mut (read_requests, hints) = create_settled_read_requests([1]); + read_requests[0].value += 1; + validate_settled_read_requests(read_requests, settled_data_hints, hints); + } + + #[test] + fn ensure_all_read_requests_are_verified_succeeds() { + let mut (pending_read_requests, pending_read_hints) = create_pending_read_requests([1]); + let mut (settled_read_requests, settled_read_hints) = create_settled_read_requests([0, 1]); + let read_requests = [settled_read_requests[0], pending_read_requests[0], settled_read_requests[1]]; + pending_read_hints[0].read_request_index = 1; + settled_read_hints[1].read_request_index = 2; + + let statuses = [ + ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 0 }, + ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 0 }, + ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 1 } + ]; + + ensure_all_read_requests_are_verified(read_requests, statuses, pending_read_hints, settled_read_hints); + } + + #[test(should_fail_with="Hinted pending read request does not match status")] + fn ensure_all_read_requests_are_verified_wrong_pending_hint_index_fails() { + let (read_requests, hints) = create_pending_read_requests([0, 1]); + let statuses = [ + ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 0 }, + ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 0 } + ]; + ensure_all_read_requests_are_verified(read_requests, statuses, hints, []); + } + + #[test(should_fail_with="Hinted settled read request does not match status")] + fn ensure_all_read_requests_are_verified_wrong_settled_hint_index_fails() { + let (read_requests, hints) = create_settled_read_requests([0, 1]); + let statuses = [ + ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 0 }, + ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 0 } + ]; + ensure_all_read_requests_are_verified(read_requests, statuses, [], hints); + } + + #[test(should_fail_with="Read request status must be PENDING or SETTLED")] + fn ensure_all_read_requests_are_verified_wrong_status_fails() { + let (read_requests, hints) = create_settled_read_requests([0]); + let statuses = [ReadRequestStatus { state: ReadRequestState.NADA, hint_index: 0 }]; + ensure_all_read_requests_are_verified(read_requests, statuses, [], hints); + } + + #[test] + fn reset_mutable_data_read_requests_succeeds() { + let mut (pending_read_requests, pending_read_hints) = create_pending_read_requests([3, 1]); + let mut (settled_read_requests, settled_read_hints) = create_settled_read_requests([0, 1]); + let read_requests = [ + settled_read_requests[0], pending_read_requests[0], pending_read_requests[1], settled_read_requests[1] + ]; + pending_read_hints[0].read_request_index = 1; + pending_read_hints[1].read_request_index = 2; + settled_read_hints[1].read_request_index = 3; + + let statuses = [ + ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 0 }, + ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 0 }, + ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 1 }, + ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 1 } + ]; + + reset_mutable_data_read_requests( + read_requests, + statuses, + data_writes, + settled_data_hints, + pending_read_hints, + settled_read_hints + ); + } +} diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/non_existent_read_request_reset.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/non_existent_read_request.nr similarity index 99% rename from noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/non_existent_read_request_reset.nr rename to noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/non_existent_read_request.nr index 4beeee665ae..5cdd14d8480 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/non_existent_read_request_reset.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/non_existent_read_request.nr @@ -86,7 +86,7 @@ pub fn reset_non_existent_read_requests, + settled_read_hints: BoundedVec, +} + +impl PublicDataReadRequestHintsBuilder { + pub fn new(read_request_len: u64) -> Self { + PublicDataReadRequestHintsBuilder { + read_request_statuses: [ReadRequestStatus::empty(); MAX_PUBLIC_DATA_READS_PER_TX], + pending_read_hints: BoundedVec { storage: [PendingReadHint::nada(read_request_len); MAX_PUBLIC_DATA_READS_PER_TX], len: 0 }, + settled_read_hints: BoundedVec { storage: [SettledReadHint::nada(read_request_len); MAX_PUBLIC_DATA_READS_PER_TX], len: 0 } + } + } + + pub fn to_hints(self) -> PublicDataReadRequestHints { + PublicDataReadRequestHints { + read_request_statuses: self.read_request_statuses, + pending_read_hints: self.pending_read_hints.storage, + settled_read_hints: self.settled_read_hints.storage + } + } +} diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/types.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/types.nr new file mode 100644 index 00000000000..aa16f1fe678 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/types.nr @@ -0,0 +1 @@ +mod public_data_hint; diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/types/public_data_hint.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/types/public_data_hint.nr new file mode 100644 index 00000000000..5e86602f6e5 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/types/public_data_hint.nr @@ -0,0 +1,28 @@ +use crate::reset::{mutable_data_read_request::SettledDataHint}; +use dep::types::{ + constants::PUBLIC_DATA_TREE_HEIGHT, merkle_tree::MembershipWitness, + public_data_tree_leaf_preimage::PublicDataTreeLeafPreimage +}; + +struct PublicDataHint { + leaf_slot: Field, + value: Field, + override_counter: u32, + exists: bool, + membership_witness: MembershipWitness, + leaf_preimage: PublicDataTreeLeafPreimage, +} + +impl SettledDataHint for PublicDataHint { + fn leaf_slot(self) -> Field { + self.leaf_slot + } + + fn value(self) -> Field { + self.value + } + + fn override_counter(self) -> u32 { + self.override_counter + } +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree.nr b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree.nr index 67b23d3f449..9ef29b02628 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree.nr @@ -7,8 +7,8 @@ mod root; use leaf_preimage::{IndexedTreeLeafPreimage, LeafPreimage}; use membership::{ - assert_check_membership, assert_check_non_membership, check_membership, check_non_membership, - MembershipWitness + assert_check_membership, assert_check_non_membership, check_membership, + conditionally_assert_check_membership, MembershipWitness }; use merkle_tree::MerkleTree; use root::{calculate_empty_tree_root, calculate_subtree_root, root_from_sibling_path}; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/indexed_tree.nr b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/indexed_tree.nr index 6cfc75baaf6..1025c336661 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/indexed_tree.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/indexed_tree.nr @@ -1,3 +1,5 @@ +mod check_valid_low_leaf; + use crate::{ abis::{append_only_tree_snapshot::AppendOnlyTreeSnapshot}, merkle_tree::{ diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/indexed_tree/check_valid_low_leaf.nr b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/indexed_tree/check_valid_low_leaf.nr new file mode 100644 index 00000000000..77f685c978f --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/indexed_tree/check_valid_low_leaf.nr @@ -0,0 +1,76 @@ +use crate::merkle_tree::leaf_preimage::IndexedTreeLeafPreimage; + +pub fn assert_check_valid_low_leaf( + key: Field, + low_leaf_preimage: LEAF_PREIMAGE +) where LEAF_PREIMAGE: IndexedTreeLeafPreimage { + let low_key = low_leaf_preimage.get_key(); + let next_key = low_leaf_preimage.get_next_key(); + let is_empty_leaf = (low_key == 0) & (next_key == 0); + + assert(!is_empty_leaf, "Cannot check non membership against empty leaf"); + assert(low_key.lt(key), "Key is not greater than the low leaf"); + assert(key.lt(next_key) | (next_key == 0), "Key is not less than the next leaf"); +} + +mod tests { + use crate::{ + merkle_tree::{ + leaf_preimage::IndexedTreeLeafPreimage, + indexed_tree::check_valid_low_leaf::assert_check_valid_low_leaf + } + }; + + struct TestLeafPreimage { + value: Field, + next_value: Field, + } + + impl IndexedTreeLeafPreimage for TestLeafPreimage { + fn get_key(self) -> Field { + self.value + } + + fn get_next_key(self) -> Field { + self.next_value + } + + fn as_leaf(self) -> Field { + self.value + } + } + + #[test] + fn test_assert_check_valid_low_leaf() { + let key = 12; + let leaf = TestLeafPreimage { value: 11, next_value: 13 }; + assert_check_valid_low_leaf(key, leaf); + } + + #[test(should_fail_with="Cannot check non membership against empty leaf")] + fn test_assert_check_valid_low_leaf_failed_empty_leaf() { + let empty_leaf = TestLeafPreimage { value: 0, next_value: 0 }; + assert_check_valid_low_leaf(0, empty_leaf); + } + + #[test(should_fail_with="Key is not greater than the low leaf")] + fn test_assert_check_valid_low_leaf_failed_wrong_low_leaf() { + let key = 12; + let leaf = TestLeafPreimage { value: 13, next_value: 15 }; + assert_check_valid_low_leaf(key, leaf); + } + + #[test(should_fail_with="Key is not greater than the low leaf")] + fn test_assert_check_valid_low_leaf_failed_is_low_leaf() { + let key = 12; + let leaf = TestLeafPreimage { value: 12, next_value: 15 }; + assert_check_valid_low_leaf(key, leaf); + } + + #[test(should_fail_with="Key is not less than the next leaf")] + fn test_assert_check_valid_low_leaf_failed_wrong_next_key() { + let key = 12; + let leaf = TestLeafPreimage { value: 9, next_value: 11 }; + assert_check_valid_low_leaf(key, leaf); + } +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/membership.nr b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/membership.nr index 6fc8d91d13b..8b35865db7f 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/membership.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/membership.nr @@ -1,45 +1,32 @@ -use crate::{merkle_tree::{leaf_preimage::IndexedTreeLeafPreimage, root::root_from_sibling_path}}; +use crate::{ + merkle_tree::{ + leaf_preimage::IndexedTreeLeafPreimage, + indexed_tree::check_valid_low_leaf::assert_check_valid_low_leaf, root::root_from_sibling_path +} +}; struct MembershipWitness { leaf_index: Field, sibling_path: [Field; N] } -pub fn check_membership(leaf: Field, index: Field, sibling_path: [Field; N], root: Field) -> bool { +pub fn check_membership(leaf: Field, index: Field, sibling_path: [Field; TREE_HEIGHT], root: Field) -> bool { let calculated_root = root_from_sibling_path(leaf, index, sibling_path); calculated_root == root } -pub fn assert_check_membership(leaf: Field, index: Field, sibling_path: [Field; N], root: Field) { +pub fn assert_check_membership(leaf: Field, index: Field, sibling_path: [Field; TREE_HEIGHT], root: Field) { assert(check_membership(leaf, index, sibling_path, root), "membership check failed"); } -struct NonMembershipCheckErrorCodeEnum { - NADA: u64, - IS_EMPTY: u64, - NOT_EXISTS: u64, - NOT_GREATER_THAN_LOW: u64, - NOT_LESS_THAN_NEXT: u64, -} - -global NonMembershipCheckErrorCode = NonMembershipCheckErrorCodeEnum { - NADA: 0, - IS_EMPTY: 1, - NOT_EXISTS: 2, - NOT_GREATER_THAN_LOW: 3, - NOT_LESS_THAN_NEXT: 4, -}; - -fn check_non_membership_internal( +pub fn assert_check_non_membership( key: Field, low_leaf_preimage: LEAF_PREIMAGE, low_leaf_membership_witness: MembershipWitness, tree_root: Field -) -> u64 where +) where LEAF_PREIMAGE: IndexedTreeLeafPreimage { - let low_key = low_leaf_preimage.get_key(); - let next_key = low_leaf_preimage.get_next_key(); - let is_empty_leaf = (low_key == 0) & (next_key == 0); + assert_check_valid_low_leaf(key, low_leaf_preimage); let low_leaf_exists = check_membership( low_leaf_preimage.as_leaf(), @@ -47,52 +34,31 @@ fn check_non_membership_internal( low_leaf_membership_witness.sibling_path, tree_root ); - - if is_empty_leaf { - NonMembershipCheckErrorCode.IS_EMPTY - } else if !low_leaf_exists { - NonMembershipCheckErrorCode.NOT_EXISTS - } else if !low_key.lt(key) { - NonMembershipCheckErrorCode.NOT_GREATER_THAN_LOW - } else if !key.lt(next_key) & (next_key != 0) { - NonMembershipCheckErrorCode.NOT_LESS_THAN_NEXT - } else { - NonMembershipCheckErrorCode.NADA - } + assert(low_leaf_exists, "Low leaf does not exist"); } -pub fn check_non_membership( +// Prove either membership or non-membership depending on the value of `exists`. +// If `exists` == false, `key` is not in the tree, `leaf_preimage` and `membership_witness` are for the low leaf. +pub fn conditionally_assert_check_membership( key: Field, - low_leaf_preimage: LEAF_PREIMAGE, - low_leaf_membership_witness: MembershipWitness, - tree_root: Field -) -> bool where - LEAF_PREIMAGE: IndexedTreeLeafPreimage { - let error = check_non_membership_internal(key, low_leaf_preimage, low_leaf_membership_witness, tree_root); - error == NonMembershipCheckErrorCode.NADA -} - -pub fn assert_check_non_membership( - key: Field, - low_leaf_preimage: LEAF_PREIMAGE, - low_leaf_membership_witness: MembershipWitness, + exists: bool, + leaf_preimage: LEAF_PREIMAGE, + membership_witness: MembershipWitness, tree_root: Field ) where LEAF_PREIMAGE: IndexedTreeLeafPreimage { - let error = check_non_membership_internal(key, low_leaf_preimage, low_leaf_membership_witness, tree_root); - if error != NonMembershipCheckErrorCode.NADA { - assert( - error != NonMembershipCheckErrorCode.IS_EMPTY, "Cannot check non membership against empty leaf" - ); - assert(error != NonMembershipCheckErrorCode.NOT_EXISTS, "Low leaf does not exist"); - assert( - error != NonMembershipCheckErrorCode.NOT_GREATER_THAN_LOW, "Key is not greater than the low leaf" - ); - assert( - error != NonMembershipCheckErrorCode.NOT_LESS_THAN_NEXT, "Key is not less than the next leaf" - ); - assert(false, "Unknown error"); + if exists { + assert(key == leaf_preimage.get_key(), "Key does not match the key of the leaf preimage"); + } else { + assert_check_valid_low_leaf(key, leaf_preimage); } + + assert_check_membership( + leaf_preimage.as_leaf(), + membership_witness.leaf_index, + membership_witness.sibling_path, + tree_root + ); } mod tests { @@ -100,8 +66,8 @@ mod tests { merkle_tree::{ leaf_preimage::{IndexedTreeLeafPreimage, LeafPreimage}, membership::{ - assert_check_membership, assert_check_non_membership, check_membership, check_non_membership, - MembershipWitness + assert_check_membership, assert_check_non_membership, check_membership, + conditionally_assert_check_membership, MembershipWitness } }, tests::merkle_tree_utils::NonEmptyMerkleTree @@ -177,7 +143,7 @@ mod tests { ); } - fn check_non_membership_at_index(low_leaf_index: u64, leaf: Field) -> bool { + fn assert_check_non_membership_at_index(low_leaf_index: u64, key: Field) { let tree = build_tree(); let tree_root = tree.get_root(); let leaf_preimage = if low_leaf_index < leaf_preimages.len() { @@ -186,15 +152,15 @@ mod tests { TestLeafPreimage { value: 0, next_value: 0 } }; - check_non_membership( - leaf, + assert_check_non_membership( + key, leaf_preimage, MembershipWitness { leaf_index: low_leaf_index as Field, sibling_path: tree.get_sibling_path(low_leaf_index) } , tree_root - ) + ); } - fn assert_check_non_membership_at_index(low_leaf_index: u64, leaf: Field) { + fn conditionally_assert_check_membership_at_index(exists: bool, low_leaf_index: u64, key: Field) { let tree = build_tree(); let tree_root = tree.get_root(); let leaf_preimage = if low_leaf_index < leaf_preimages.len() { @@ -203,8 +169,9 @@ mod tests { TestLeafPreimage { value: 0, next_value: 0 } }; - assert_check_non_membership( - leaf, + conditionally_assert_check_membership( + key, + exists, leaf_preimage, MembershipWitness { leaf_index: low_leaf_index as Field, sibling_path: tree.get_sibling_path(low_leaf_index) } , tree_root @@ -261,80 +228,99 @@ mod tests { ); } - #[test] - fn test_check_non_membership() { - assert_eq(check_non_membership_at_index(0, 25), true); - } - #[test] fn test_assert_check_non_membership() { assert_check_non_membership_at_index(0, 25); } - #[test] - fn test_check_non_membership_greater_than_max() { - assert_eq(check_non_membership_at_index(1, 45), true); - } - #[test] fn test_assert_check_non_membership_greater_than_max() { assert_check_non_membership_at_index(1, 45); } - #[test] - fn test_check_non_membership_false_empty_leaf() { - assert_eq(check_non_membership_at_index(4, 25), false); - } - #[test(should_fail_with="Cannot check non membership against empty leaf")] fn test_assert_check_non_membership_failed_empty_leaf() { assert_check_non_membership_at_index(4, 25); } - #[test] - fn test_check_non_membership_false_wrong_low_leaf() { - assert_eq(check_non_membership_at_index(3, 25), false); - } - #[test(should_fail_with="Key is not greater than the low leaf")] fn test_assert_check_non_membership_failed_wrong_low_leaf() { assert_check_non_membership_at_index(3, 25); } - #[test] - fn test_check_non_membership_false_wrong_next_key() { - assert_eq(check_non_membership_at_index(2, 25), false); - } - #[test(should_fail_with="Key is not less than the next leaf")] fn test_assert_check_non_membership_failed_wrong_next_key() { assert_check_non_membership_at_index(2, 25); } - #[test] - fn test_check_non_membership_false_invalid_leaf() { + #[test(should_fail_with="Low leaf does not exist")] + fn test_assert_check_non_membership_failed_invalid_leaf() { let tree = build_tree(); let tree_root = tree.get_root(); let fake_leaf = TestLeafPreimage { value: 50, next_value: 60 }; - assert_eq( - check_non_membership( - 55, - fake_leaf, - MembershipWitness { leaf_index: 1, sibling_path: tree.get_sibling_path(1) } , - tree_root - ), false + assert_check_non_membership( + 55, + fake_leaf, + MembershipWitness { leaf_index: 1, sibling_path: tree.get_sibling_path(1) } , + tree_root ); } - #[test(should_fail_with="Low leaf does not exist")] - fn test_assert_check_non_membership_failed_invalid_leaf() { + #[test] + fn test_conditionally_assert_check_membership_exists() { + conditionally_assert_check_membership_at_index(true, 1, leaf_preimages[1].get_key()); + } + + #[test] + fn test_conditionally_assert_check_membership_not_exists() { + conditionally_assert_check_membership_at_index(false, 1, leaf_preimages[1].get_key() + 1); + } + + #[test(should_fail_with="Key does not match the key of the leaf preimage")] + fn test_conditionally_assert_check_membership_exists_value_mismatch() { + conditionally_assert_check_membership_at_index(true, 1, leaf_preimages[1].get_key() + 1); + } + + #[test(should_fail_with="Cannot check non membership against empty leaf")] + fn test_conditionally_assert_check_membership_failed_not_exists_empty_leaf() { + conditionally_assert_check_membership_at_index(false, 4, 1); + } + + #[test(should_fail_with="Key is not greater than the low leaf")] + fn test_conditionally_assert_check_membership_failed_not_exists_wrong_low_leaf() { + conditionally_assert_check_membership_at_index(false, 3, 25); + } + + #[test(should_fail_with="Key is not less than the next leaf")] + fn test_conditionally_assert_check_membership_failed_not_exists_wrong_next_key() { + conditionally_assert_check_membership_at_index(false, 2, 25); + } + + #[test(should_fail_with="membership check failed")] + fn test_conditionally_assert_check_membership_failed_exists_invalid_leaf() { let tree = build_tree(); let tree_root = tree.get_root(); + let fake_leaf = TestLeafPreimage { value: 50, next_value: 60 }; + let exists = true; + conditionally_assert_check_membership( + 50, + exists, + fake_leaf, + MembershipWitness { leaf_index: 1, sibling_path: tree.get_sibling_path(1) } , + tree_root + ); + } + #[test(should_fail_with="membership check failed")] + fn test_conditionally_assert_check_membership_failed_not_exists_invalid_leaf() { + let tree = build_tree(); + let tree_root = tree.get_root(); let fake_leaf = TestLeafPreimage { value: 50, next_value: 60 }; - assert_check_non_membership( + let exists = false; + conditionally_assert_check_membership( 55, + exists, fake_leaf, MembershipWitness { leaf_index: 1, sibling_path: tree.get_sibling_path(1) } , tree_root diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/public_data_tree_leaf_preimage.nr b/noir-projects/noir-protocol-circuits/crates/types/src/public_data_tree_leaf_preimage.nr index dcc84fe7026..992bbdecd18 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/public_data_tree_leaf_preimage.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/public_data_tree_leaf_preimage.nr @@ -1,4 +1,4 @@ -use crate::traits::{Empty, Hash}; +use crate::{merkle_tree::leaf_preimage::IndexedTreeLeafPreimage, traits::{Empty, Hash}}; struct PublicDataTreeLeafPreimage { slot : Field, @@ -28,6 +28,20 @@ impl Hash for PublicDataTreeLeafPreimage { } } +impl IndexedTreeLeafPreimage for PublicDataTreeLeafPreimage { + fn get_key(self) -> Field { + self.slot + } + + fn get_next_key(self) -> Field { + self.next_slot + } + + fn as_leaf(self) -> Field { + self.hash() + } +} + impl PublicDataTreeLeafPreimage { pub fn is_empty(self) -> bool { (self.slot == 0) & (self.value == 0) & (self.next_slot == 0) & (self.next_index == 0) diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr index 703b4bd6bfe..5cc6c44cbd9 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr @@ -256,17 +256,21 @@ impl FixtureBuilder { } } + pub fn add_public_data_update_request(&mut self, leaf_slot: Field, value: Field) { + let update_request = PublicDataUpdateRequest { leaf_slot, new_value: value }; + self.public_data_update_requests.push(update_request); + } + pub fn append_public_data_update_requests(&mut self, num_updates: u64) { let value_offset = self.public_data_update_requests.len(); for i in 0..MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX { if i < num_updates { - let update_request = PublicDataUpdateRequest { - // The default leaf index is its index + 23. - leaf_slot: (value_offset + i + 23) as Field, - // The default value is its index + 678. - new_value: (value_offset + i + 678) as Field - }; - self.public_data_update_requests.push(update_request); + // The default leaf index is its index + 23. + // The default value is its index + 678. + self.add_public_data_update_request( + (value_offset + i + 23) as Field, + (value_offset + i + 678) as Field + ); } } } @@ -315,6 +319,14 @@ impl FixtureBuilder { self.nullifier_non_existent_read_requests.push(read_request); } + pub fn add_read_request_for_pending_public_data(&mut self, public_date_update_request_index: u64) -> u64 { + let new_read_request_index = self.public_data_reads.len(); + let public_write = self.public_data_update_requests.get(public_date_update_request_index); + let read_request = PublicDataRead { leaf_slot: public_write.leaf_slot, value: public_write.new_value }; + self.public_data_reads.push(read_request); + new_read_request_index + } + pub fn set_encrypted_logs(&mut self, hash: Field, preimages_length: Field) { self.encrypted_logs_hash = hash; self.encrypted_log_preimages_length = preimages_length; From b5e53c176772486f33c872b971da08414c8c03ea Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Thu, 11 Apr 2024 16:48:54 +0000 Subject: [PATCH 03/15] Build hints in ts. --- .../src/core/libraries/ConstantsGen.sol | 1 + .../src/public_kernel_tail.nr | 35 ++-- .../src/public_data_read_request_reset.nr | 4 +- .../src/reset/mutable_data_read_request.nr | 20 +-- .../public_data_read_request_hints_builder.nr | 6 +- .../src/types/public_data_hint.nr | 5 +- .../crates/types/src/constants.nr | 3 + yarn-project/circuits.js/src/constants.gen.ts | 1 + .../circuits.js/src/hints/build_hints.test.ts | 9 +- .../circuits.js/src/hints/build_hints.ts | 8 +- .../src/hints/build_public_data_hints.test.ts | 123 ++++++++++++++ .../src/hints/build_public_data_hints.ts | 49 ++++++ ...ild_public_data_read_request_hints.test.ts | 150 ++++++++++++++++++ .../build_public_data_read_request_hints.ts | 45 ++++++ yarn-project/circuits.js/src/hints/index.ts | 3 +- yarn-project/circuits.js/src/index.ts | 1 + yarn-project/circuits.js/src/structs/index.ts | 2 + ...blic_kernel_tail_circuit_private_inputs.ts | 12 +- .../src/structs/membership_witness.ts | 2 +- .../non_existent_read_request_hints.ts | 2 +- .../src/structs/public_data_hint.ts | 47 ++++++ .../structs/public_data_read_request_hints.ts | 86 ++++++++++ .../src/structs/read_request_hints.ts | 10 +- .../structs/rollup/public_data_leaf/index.ts | 2 +- .../src/type_conversion.ts | 33 ++++ .../src/sequencer/hints_builder.ts | 122 +++++++------- .../src/sequencer/tail_phase_manager.ts | 44 ++++- 27 files changed, 700 insertions(+), 125 deletions(-) create mode 100644 yarn-project/circuits.js/src/hints/build_public_data_hints.test.ts create mode 100644 yarn-project/circuits.js/src/hints/build_public_data_hints.ts create mode 100644 yarn-project/circuits.js/src/hints/build_public_data_read_request_hints.test.ts create mode 100644 yarn-project/circuits.js/src/hints/build_public_data_read_request_hints.ts create mode 100644 yarn-project/circuits.js/src/structs/public_data_hint.ts create mode 100644 yarn-project/circuits.js/src/structs/public_data_read_request_hints.ts diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index c86086125bd..176b2f4a929 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -40,6 +40,7 @@ library Constants { uint256 internal constant MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX = 4; uint256 internal constant NUM_ENCRYPTED_LOGS_HASHES_PER_TX = 1; uint256 internal constant NUM_UNENCRYPTED_LOGS_HASHES_PER_TX = 1; + uint256 internal constant MAX_PUBLIC_DATA_HINTS = 64; uint256 internal constant NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP = 16; uint256 internal constant VK_TREE_HEIGHT = 3; uint256 internal constant FUNCTION_TREE_HEIGHT = 5; diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr index 95cfed7a5ae..2f75ae7e3ac 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr @@ -8,8 +8,9 @@ use dep::types::{ kernel_circuit_public_inputs::{KernelCircuitPublicInputs, PublicKernelCircuitPublicInputsBuilder}, kernel_data::PublicKernelData, side_effect::SideEffectLinkedToNoteHash }, - constants::{MAX_NEW_NULLIFIERS_PER_TX, MAX_PUBLIC_DATA_READS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX}, - merkle_tree::conditionally_assert_check_membership, utils::{arrays::array_length} + constants::MAX_PUBLIC_DATA_HINTS, + merkle_tree::{conditionally_assert_check_membership, MembershipWitness}, + utils::{arrays::array_length} }; use dep::std::unsafe; @@ -17,8 +18,8 @@ struct PublicKernelTailCircuitPrivateInputs { previous_kernel: PublicKernelData, nullifier_read_request_hints: NullifierReadRequestHints, nullifier_non_existent_read_request_hints: NullifierNonExistentReadRequestHints, + public_data_hints: [PublicDataHint; MAX_PUBLIC_DATA_HINTS], public_data_read_request_hints: PublicDataReadRequestHints, - public_data_hints: [PublicDataHint; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX + MAX_PUBLIC_DATA_READS_PER_TX], } impl PublicKernelTailCircuitPrivateInputs { @@ -47,7 +48,8 @@ impl PublicKernelTailCircuitPrivateInputs { // We only need to check leaf_slot to decide if a (non-)membership check is required. // It will fail if a PublicDataHint with 0 leaf_slot is used to verify a non-empty public read or write. if hint.leaf_slot != 0 { - if hint.exists { + let exists_in_tree = hint.leaf_slot == hint.leaf_preimage.slot; + if exists_in_tree { assert( hint.value == hint.leaf_preimage.value, "Hinted public data value does not match the value in leaf preimage" ); @@ -57,9 +59,9 @@ impl PublicKernelTailCircuitPrivateInputs { conditionally_assert_check_membership( hint.leaf_slot, - hint.exists, + exists_in_tree, hint.leaf_preimage, - hint.membership_witness, + MembershipWitness { leaf_index: hint.membership_witness.leaf_index, sibling_path: hint.membership_witness.sibling_path }, public_data_tree_root ); } @@ -107,16 +109,16 @@ mod tests { use dep::types::{ abis::{ kernel_circuit_public_inputs::{KernelCircuitPublicInputs, PublicKernelCircuitPublicInputsBuilder}, - kernel_data::PublicKernelData, nullifier_leaf_preimage::NullifierLeafPreimage + kernel_data::PublicKernelData, nullifier_leaf_preimage::NullifierLeafPreimage, + membership_witness::PublicDataMembershipWitness }, constants::{ - MAX_NEW_NULLIFIERS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_PUBLIC_DATA_READS_PER_TX, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, NULLIFIER_TREE_HEIGHT, + MAX_NEW_NULLIFIERS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_PUBLIC_DATA_HINTS, + MAX_PUBLIC_DATA_READS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, NULLIFIER_TREE_HEIGHT, NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, NULLIFIER_SUBTREE_HEIGHT, PUBLIC_DATA_SUBTREE_HEIGHT, PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH, PUBLIC_DATA_TREE_HEIGHT }, hash::silo_nullifier, public_data_tree_leaf_preimage::PublicDataTreeLeafPreimage, - merkle_tree::membership::MembershipWitness, tests::{fixture_builder::FixtureBuilder, merkle_tree_utils::NonEmptyMerkleTree}, utils::arrays::array_merge }; @@ -157,7 +159,7 @@ mod tests { nullifier_read_request_hints_builder: NullifierReadRequestHintsBuilder, nullifier_non_existent_read_request_hints_builder: NullifierNonExistentReadRequestHintsBuilder, public_data_read_request_hints_builder: PublicDataReadRequestHintsBuilder, - public_data_hints: BoundedVec, + public_data_hints: BoundedVec, public_data_tree: NonEmptyMerkleTree, } @@ -251,12 +253,11 @@ mod tests { pub fn add_public_data_hint_for_settled_public_data(&mut self, leaf_index: u64) { let leaf_preimage = get_settled_public_data_leaves()[leaf_index]; - let membership_witness = MembershipWitness { leaf_index: leaf_index as Field, sibling_path: self.public_data_tree.get_sibling_path(leaf_index) }; + let membership_witness = PublicDataMembershipWitness { leaf_index: leaf_index as Field, sibling_path: self.public_data_tree.get_sibling_path(leaf_index) }; let hint = PublicDataHint { leaf_slot: leaf_preimage.slot, value: leaf_preimage.value, override_counter: 0, - exists: true, membership_witness, leaf_preimage }; @@ -265,11 +266,11 @@ mod tests { pub fn add_public_data_hint_for_non_existent_public_data(&mut self, leaf_slot: Field, low_leaf_index: u64) { let leaf_preimage = get_settled_public_data_leaves()[low_leaf_index]; - let membership_witness = MembershipWitness { + let membership_witness = PublicDataMembershipWitness { leaf_index: low_leaf_index as Field, sibling_path: self.public_data_tree.get_sibling_path(low_leaf_index) }; - let hint = PublicDataHint { leaf_slot, value: 0, override_counter: 0, exists: false, membership_witness, leaf_preimage }; + let hint = PublicDataHint { leaf_slot, value: 0, override_counter: 0, membership_witness, leaf_preimage }; self.public_data_hints.push(hint); } @@ -299,8 +300,8 @@ mod tests { previous_kernel, nullifier_read_request_hints: self.nullifier_read_request_hints_builder.to_hints(), nullifier_non_existent_read_request_hints: self.nullifier_non_existent_read_request_hints_builder.to_hints(), - public_data_read_request_hints: self.public_data_read_request_hints_builder.to_hints(), - public_data_hints: self.public_data_hints.storage + public_data_hints: self.public_data_hints.storage, + public_data_read_request_hints: self.public_data_read_request_hints_builder.to_hints() }; kernel.public_kernel_tail() diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_data_read_request_reset.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_data_read_request_reset.nr index d1ddafc40c1..1524ad60544 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_data_read_request_reset.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_data_read_request_reset.nr @@ -1,9 +1,9 @@ -use crate::reset::{mutable_data_read_request::SettledReadHint, read_request::{PendingReadHint, ReadRequestStatus}}; +use crate::reset::{mutable_data_read_request::SettledDataReadHint, read_request::{PendingReadHint, ReadRequestStatus}}; use dep::types::constants::MAX_PUBLIC_DATA_READS_PER_TX; // The MAX_PUBLIC_DATA_READS_PER_TX for pending_read_hints and settled_read_hints can change if we create various circuits that deal with different number of reads. struct PublicDataReadRequestHints { read_request_statuses: [ReadRequestStatus; MAX_PUBLIC_DATA_READS_PER_TX], pending_read_hints: [PendingReadHint; MAX_PUBLIC_DATA_READS_PER_TX], - settled_read_hints: [SettledReadHint; MAX_PUBLIC_DATA_READS_PER_TX], + settled_read_hints: [SettledDataReadHint; MAX_PUBLIC_DATA_READS_PER_TX], } diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/mutable_data_read_request.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/mutable_data_read_request.nr index e1b88a4c0c5..13c3ffb4d4d 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/mutable_data_read_request.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/mutable_data_read_request.nr @@ -10,14 +10,14 @@ trait SettledDataHint { fn override_counter(self) -> u32; } -struct SettledReadHint { +struct SettledDataReadHint { read_request_index: u64, settled_data_hint_index: u64, } -impl SettledReadHint { +impl SettledDataReadHint { pub fn nada(read_request_len: u64) -> Self { - SettledReadHint { read_request_index: read_request_len, settled_data_hint_index: 0 } + SettledDataReadHint { read_request_index: read_request_len, settled_data_hint_index: 0 } } } @@ -49,7 +49,7 @@ fn validate_pending_read_requests( read_requests: [PublicDataRead; READ_REQUEST_LEN], settled_data_hints: [H; NUM_SETTLED_DATA_HINTS], - hints: [SettledReadHint; NUM_SETTLED_READS] + hints: [SettledDataReadHint; NUM_SETTLED_READS] ) where H: SettledDataHint { for i in 0..NUM_SETTLED_READS { let read_request_index = hints[i].read_request_index; @@ -70,7 +70,7 @@ fn ensure_all_read_requests_are_verified(settled_data_hint_indices: [u64; N]) -> ([PublicDataRead; N], [SettledReadHint; N]) { + fn create_settled_read_requests(settled_data_hint_indices: [u64; N]) -> ([PublicDataRead; N], [SettledDataReadHint; N]) { let read_requests = settled_data_hint_indices.map( |settled_data_hint_index: u64| PublicDataRead { leaf_slot: settled_data_hints[settled_data_hint_index].leaf_slot, value: settled_data_hints[settled_data_hint_index].value } ); let mut hints = BoundedVec::new(); for i in 0..N { hints.push( - SettledReadHint { read_request_index: i, settled_data_hint_index: settled_data_hint_indices[i] } + SettledDataReadHint { read_request_index: i, settled_data_hint_index: settled_data_hint_indices[i] } ); } (read_requests, hints.storage) @@ -225,7 +225,7 @@ mod tests { #[test] fn reset_settled_reads_skips_nada() { let read_requests = [PublicDataRead { leaf_slot: 88, value: 9999 }]; - let hints = [SettledReadHint::nada(1)]; + let hints = [SettledDataReadHint::nada(1)]; validate_settled_read_requests(read_requests, settled_data_hints, hints); } diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/public_data_read_request_hints_builder.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/public_data_read_request_hints_builder.nr index db0d85aec6a..a80b23febf4 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/public_data_read_request_hints_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/public_data_read_request_hints_builder.nr @@ -1,13 +1,13 @@ use crate::{ public_data_read_request_reset::PublicDataReadRequestHints, - reset::{mutable_data_read_request::SettledReadHint, read_request::{PendingReadHint, ReadRequestStatus}} + reset::{mutable_data_read_request::SettledDataReadHint, read_request::{PendingReadHint, ReadRequestStatus}} }; use dep::types::constants::MAX_PUBLIC_DATA_READS_PER_TX; struct PublicDataReadRequestHintsBuilder { read_request_statuses: [ReadRequestStatus; MAX_PUBLIC_DATA_READS_PER_TX], pending_read_hints: BoundedVec, - settled_read_hints: BoundedVec, + settled_read_hints: BoundedVec, } impl PublicDataReadRequestHintsBuilder { @@ -15,7 +15,7 @@ impl PublicDataReadRequestHintsBuilder { PublicDataReadRequestHintsBuilder { read_request_statuses: [ReadRequestStatus::empty(); MAX_PUBLIC_DATA_READS_PER_TX], pending_read_hints: BoundedVec { storage: [PendingReadHint::nada(read_request_len); MAX_PUBLIC_DATA_READS_PER_TX], len: 0 }, - settled_read_hints: BoundedVec { storage: [SettledReadHint::nada(read_request_len); MAX_PUBLIC_DATA_READS_PER_TX], len: 0 } + settled_read_hints: BoundedVec { storage: [SettledDataReadHint::nada(read_request_len); MAX_PUBLIC_DATA_READS_PER_TX], len: 0 } } } diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/types/public_data_hint.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/types/public_data_hint.nr index 5e86602f6e5..b9d9064dc61 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/types/public_data_hint.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/types/public_data_hint.nr @@ -1,6 +1,6 @@ use crate::reset::{mutable_data_read_request::SettledDataHint}; use dep::types::{ - constants::PUBLIC_DATA_TREE_HEIGHT, merkle_tree::MembershipWitness, + abis::membership_witness::PublicDataMembershipWitness, public_data_tree_leaf_preimage::PublicDataTreeLeafPreimage }; @@ -8,8 +8,7 @@ struct PublicDataHint { leaf_slot: Field, value: Field, override_counter: u32, - exists: bool, - membership_witness: MembershipWitness, + membership_witness: PublicDataMembershipWitness, // Should be MembershipWitness when we can handle generics when converting to ts types. leaf_preimage: PublicDataTreeLeafPreimage, } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index f89bbe8dfb0..2b79ba497c6 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -51,6 +51,9 @@ global NUM_ENCRYPTED_LOGS_HASHES_PER_TX: u64 = 1; global NUM_UNENCRYPTED_LOGS_HASHES_PER_TX: u64 = 1; // docs:end:constants +// KERNEL CIRCUIT PRIVATE INPUTS CONSTANTS +global MAX_PUBLIC_DATA_HINTS: u64 = 64; // MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX + MAX_PUBLIC_DATA_READS_PER_TX; + // ROLLUP CONTRACT CONSTANTS - constants used only in l1-contracts global NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP: u64 = 16; diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index 77e588276ed..94680ee5d57 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -26,6 +26,7 @@ export const MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX = 8; export const MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX = 4; export const NUM_ENCRYPTED_LOGS_HASHES_PER_TX = 1; export const NUM_UNENCRYPTED_LOGS_HASHES_PER_TX = 1; +export const MAX_PUBLIC_DATA_HINTS = 64; export const NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP = 16; export const VK_TREE_HEIGHT = 3; export const FUNCTION_TREE_HEIGHT = 5; diff --git a/yarn-project/circuits.js/src/hints/build_hints.test.ts b/yarn-project/circuits.js/src/hints/build_hints.test.ts index 7ac9ee39a52..5df210ca1e8 100644 --- a/yarn-project/circuits.js/src/hints/build_hints.test.ts +++ b/yarn-project/circuits.js/src/hints/build_hints.test.ts @@ -22,10 +22,8 @@ import { buildNullifierNonExistentReadRequestHints, buildNullifierReadRequestHin describe('buildNullifierReadRequestHints', () => { const contractAddress = AztecAddress.random(); const settledNullifierInnerValue = 99999; - const settledNullifierValue = makeNullifier(settledNullifierInnerValue).value; const oracle = { - getNullifierMembershipWitness: (value: Fr) => - value.equals(settledNullifierValue) ? ({ membershipWitness: {}, leafPreimage: {} } as any) : undefined, + getNullifierMembershipWitness: () => ({ membershipWitness: {}, leafPreimage: {} } as any), }; let nullifierReadRequests: Tuple; let nullifiers: Tuple; @@ -113,11 +111,6 @@ describe('buildNullifierReadRequestHints', () => { const hints = await buildHints(); expect(hints).toEqual(expectedHints); }); - - it('throws if reading an unknown nullifier', async () => { - nullifierReadRequests[0] = makeReadRequest(88888); - await expect(buildHints()).rejects.toThrow('Read request is reading an unknown nullifier value.'); - }); }); describe('buildNullifierNonExistentReadRequestHints', () => { diff --git a/yarn-project/circuits.js/src/hints/build_hints.ts b/yarn-project/circuits.js/src/hints/build_hints.ts index 1266082c2d0..302ed3a14f9 100644 --- a/yarn-project/circuits.js/src/hints/build_hints.ts +++ b/yarn-project/circuits.js/src/hints/build_hints.ts @@ -17,14 +17,14 @@ import { NullifierReadRequestHintsBuilder } from '../structs/read_request_hints. import { SideEffectLinkedToNoteHash } from '../structs/side_effects.js'; import { countAccumulatedItems } from '../utils/index.js'; -export interface NullifierMembershipWitnessWithPreimage { +interface NullifierMembershipWitnessWithPreimage { membershipWitness: MembershipWitness; leafPreimage: IndexedTreeLeafPreimage; } export async function buildNullifierReadRequestHints( oracle: { - getNullifierMembershipWitness(nullifier: Fr): Promise; + getNullifierMembershipWitness(nullifier: Fr): Promise; }, nullifierReadRequests: Tuple, nullifiers: Tuple, @@ -46,10 +46,6 @@ export async function buildNullifierReadRequestHints( builder.addPendingReadRequest(i, pendingValueIndex); } else { const membershipWitnessWithPreimage = await oracle.getNullifierMembershipWitness(value); - if (!membershipWitnessWithPreimage) { - throw new Error('Read request is reading an unknown nullifier value.'); - } - builder.addSettledReadRequest( i, membershipWitnessWithPreimage.membershipWitness, diff --git a/yarn-project/circuits.js/src/hints/build_public_data_hints.test.ts b/yarn-project/circuits.js/src/hints/build_public_data_hints.test.ts new file mode 100644 index 00000000000..a041d8fd32f --- /dev/null +++ b/yarn-project/circuits.js/src/hints/build_public_data_hints.test.ts @@ -0,0 +1,123 @@ +import { makeTuple } from '@aztec/foundation/array'; +import { Fr } from '@aztec/foundation/fields'; +import { type Tuple } from '@aztec/foundation/serialize'; + +import { + MAX_PUBLIC_DATA_HINTS, + MAX_PUBLIC_DATA_READS_PER_TX, + type MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, +} from '../constants.gen.js'; +import { PublicDataRead, PublicDataTreeLeafPreimage, PublicDataUpdateRequest } from '../structs/index.js'; +import { buildPublicDataHints } from './build_public_data_hints.js'; + +class ExpectedHint { + constructor(public leafSlot: number, public value: number, public matchOrLowLeafSlot: number) {} + + static empty() { + return new ExpectedHint(0, 0, 0); + } + + toExpectedObject() { + return expect.objectContaining({ + leafSlot: new Fr(this.leafSlot), + value: new Fr(this.value), + leafPreimage: expect.objectContaining({ slot: new Fr(this.matchOrLowLeafSlot) }), + }); + } +} + +describe('buildPublicDataHints', () => { + let publicDataReads: Tuple; + let publicDataUpdateRequests: Tuple; + let expectedHints: Tuple; + + const publicDataLeaves = [ + new PublicDataTreeLeafPreimage(new Fr(22), new Fr(200), new Fr(33), 0n), + new PublicDataTreeLeafPreimage(new Fr(11), new Fr(100), new Fr(22), 0n), + new PublicDataTreeLeafPreimage(new Fr(0), new Fr(0), new Fr(11), 0n), + ]; + + const makePublicDataRead = (leafSlot: number, value: number) => new PublicDataRead(new Fr(leafSlot), new Fr(value)); + const makePublicDataWrite = (leafSlot: number, value: number) => + new PublicDataUpdateRequest(new Fr(leafSlot), new Fr(value)); + + const oracle = { + getMatchOrLowPublicDataMembershipWitness: (leafSlot: bigint) => { + const leafPreimage = publicDataLeaves.find(l => l.slot.toBigInt() <= leafSlot); + return { membershipWitness: {}, leafPreimage } as any; + }, + }; + + const buildHints = () => buildPublicDataHints(oracle, publicDataReads, publicDataUpdateRequests); + + const buildAndCheckHints = async () => { + const hints = await buildHints(); + const partialHints = expectedHints.map(h => h.toExpectedObject()); + expect(hints).toEqual(partialHints); + }; + + beforeEach(() => { + publicDataReads = makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, PublicDataRead.empty); + publicDataUpdateRequests = makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, PublicDataUpdateRequest.empty); + expectedHints = makeTuple(MAX_PUBLIC_DATA_HINTS, ExpectedHint.empty); + }); + + it('returns empty hints', async () => { + await buildAndCheckHints(); + }); + + it('builds hints for reads for uninitialized slots', async () => { + publicDataReads[0] = makePublicDataRead(12, 0); + publicDataReads[1] = makePublicDataRead(39, 0); + expectedHints[0] = new ExpectedHint(12, 0, 11); + expectedHints[1] = new ExpectedHint(39, 0, 22); + + await buildAndCheckHints(); + }); + + it('builds hints for reads for initialized slots', async () => { + publicDataReads[0] = makePublicDataRead(22, 200); + publicDataReads[1] = makePublicDataRead(11, 100); + expectedHints[0] = new ExpectedHint(22, 200, 22); + expectedHints[1] = new ExpectedHint(11, 100, 11); + + await buildAndCheckHints(); + }); + + it('builds hints for writes to uninitialized slots', async () => { + publicDataUpdateRequests[0] = makePublicDataWrite(5, 500); + publicDataUpdateRequests[1] = makePublicDataWrite(17, 700); + expectedHints[0] = new ExpectedHint(5, 0, 0); + expectedHints[1] = new ExpectedHint(17, 0, 11); + + await buildAndCheckHints(); + }); + + it('builds hints for writes to initialized slots', async () => { + publicDataUpdateRequests[0] = makePublicDataWrite(11, 111); + publicDataUpdateRequests[1] = makePublicDataWrite(22, 222); + expectedHints[0] = new ExpectedHint(11, 100, 11); + expectedHints[1] = new ExpectedHint(22, 200, 22); + + await buildAndCheckHints(); + }); + + it('builds hints for mixed reads and writes', async () => { + publicDataReads[0] = makePublicDataRead(22, 200); + publicDataReads[1] = makePublicDataRead(12, 0); + publicDataReads[2] = makePublicDataRead(39, 0); + publicDataReads[3] = makePublicDataRead(11, 100); + publicDataUpdateRequests[0] = makePublicDataWrite(11, 111); + publicDataUpdateRequests[1] = makePublicDataWrite(5, 500); + publicDataUpdateRequests[2] = makePublicDataWrite(17, 700); + publicDataUpdateRequests[3] = makePublicDataWrite(22, 222); + expectedHints[0] = new ExpectedHint(22, 200, 22); + expectedHints[1] = new ExpectedHint(12, 0, 11); + expectedHints[2] = new ExpectedHint(39, 0, 22); + expectedHints[3] = new ExpectedHint(11, 100, 11); + expectedHints[4] = new ExpectedHint(5, 0, 0); + expectedHints[5] = new ExpectedHint(17, 0, 11); + + await buildAndCheckHints(); + }); +}); diff --git a/yarn-project/circuits.js/src/hints/build_public_data_hints.ts b/yarn-project/circuits.js/src/hints/build_public_data_hints.ts new file mode 100644 index 00000000000..22d69a520bb --- /dev/null +++ b/yarn-project/circuits.js/src/hints/build_public_data_hints.ts @@ -0,0 +1,49 @@ +import { padArrayEnd } from '@aztec/foundation/collection'; +import { Fr } from '@aztec/foundation/fields'; +import { type Tuple } from '@aztec/foundation/serialize'; + +import { + MAX_PUBLIC_DATA_HINTS, + type MAX_PUBLIC_DATA_READS_PER_TX, + type MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, + type PUBLIC_DATA_TREE_HEIGHT, +} from '../constants.gen.js'; +import { + type PublicDataRead, + type PublicDataTreeLeafPreimage, + type PublicDataUpdateRequest, +} from '../structs/index.js'; +import { type MembershipWitness } from '../structs/membership_witness.js'; +import { PublicDataHint } from '../structs/public_data_hint.js'; + +interface PublicDataMembershipWitnessWithPreimage { + membershipWitness: MembershipWitness; + leafPreimage: PublicDataTreeLeafPreimage; +} + +export async function buildPublicDataHints( + oracle: { + getMatchOrLowPublicDataMembershipWitness(leafSlot: bigint): Promise; + }, + publicDataReads: Tuple, + publicDataUpdateRequests: Tuple, +) { + const publicDataLeafSlotSet: Set = new Set(); + [...publicDataReads, ...publicDataUpdateRequests] + .filter(r => !r.isEmpty()) + .forEach(v => { + publicDataLeafSlotSet.add(v.leafSlot.toBigInt()); + }); + const uniquePublicDataLeafSlots = [...publicDataLeafSlotSet]; + + const hints: PublicDataHint[] = []; + for (let i = 0; i < uniquePublicDataLeafSlots.length; i++) { + const leafSlot = uniquePublicDataLeafSlots[i]; + const { membershipWitness, leafPreimage } = await oracle.getMatchOrLowPublicDataMembershipWitness(leafSlot); + const exists = leafPreimage.slot.toBigInt() === leafSlot; + const value = exists ? leafPreimage.value : Fr.ZERO; + hints.push(new PublicDataHint(new Fr(leafSlot), value, 0, membershipWitness, leafPreimage)); + } + + return padArrayEnd(hints, PublicDataHint.empty(), MAX_PUBLIC_DATA_HINTS); +} diff --git a/yarn-project/circuits.js/src/hints/build_public_data_read_request_hints.test.ts b/yarn-project/circuits.js/src/hints/build_public_data_read_request_hints.test.ts new file mode 100644 index 00000000000..b2bb83868eb --- /dev/null +++ b/yarn-project/circuits.js/src/hints/build_public_data_read_request_hints.test.ts @@ -0,0 +1,150 @@ +import { makeTuple } from '@aztec/foundation/array'; +import { padArrayEnd } from '@aztec/foundation/collection'; +import { Fr } from '@aztec/foundation/fields'; +import { type Tuple } from '@aztec/foundation/serialize'; + +import { + MAX_PUBLIC_DATA_HINTS, + MAX_PUBLIC_DATA_READS_PER_TX, + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, +} from '../constants.gen.js'; +import { + PendingReadHint, + PublicDataHint, + PublicDataRead, + PublicDataUpdateRequest, + ReadRequestStatus, + SettledDataReadHint, +} from '../structs/index.js'; +import { buildPublicDataReadRequestHints } from './build_public_data_read_request_hints.js'; + +describe('buildPublicDataReadRequestHints', () => { + let publicDataReads: Tuple; + let expectedStatuses: Tuple; + let expectedPendingHints: Tuple; + let expectedSettledHints: Tuple; + + const makePublicDataWrite = (leafSlot: number, value: number) => + new PublicDataUpdateRequest(new Fr(leafSlot), new Fr(value)); + const makePublicDataHint = (slot: number, value: number) => { + const hint = PublicDataHint.empty(); + hint.leafSlot = new Fr(slot); + hint.value = new Fr(value); + return hint; + }; + const makePublicDataRead = (leafSlot: number, value: number) => new PublicDataRead(new Fr(leafSlot), new Fr(value)); + const makePendingHint = (readRequestIndex: number, hintIndex: number) => + new PendingReadHint(readRequestIndex, hintIndex); + const makeSettledHint = (readRequestIndex: number, hintIndex: number) => + new SettledDataReadHint(readRequestIndex, hintIndex); + + const publicDataUpdateRequests = padArrayEnd( + [makePublicDataWrite(55, 5555), makePublicDataWrite(77, 7777), makePublicDataWrite(99, 9999)], + PublicDataUpdateRequest.empty(), + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, + ); + + const publicDataHints = padArrayEnd( + [ + makePublicDataHint(11, 100), + makePublicDataHint(22, 200), + makePublicDataHint(33, 300), + makePublicDataHint(55, 500), + makePublicDataHint(77, 0), + makePublicDataHint(99, 900), + ], + PublicDataHint.empty(), + MAX_PUBLIC_DATA_HINTS, + ); + + const buildHints = () => buildPublicDataReadRequestHints(publicDataReads, publicDataUpdateRequests, publicDataHints); + + const buildAndCheckHints = () => { + const hints = buildHints(); + expect(hints.readRequestStatuses).toEqual(expectedStatuses); + expect(hints.pendingReadHints).toEqual(expectedPendingHints); + expect(hints.settledReadHints).toEqual(expectedSettledHints); + }; + + beforeEach(() => { + publicDataReads = makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, PublicDataRead.empty); + expectedStatuses = makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, ReadRequestStatus.nada); + expectedPendingHints = makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, () => + PendingReadHint.nada(MAX_PUBLIC_DATA_READS_PER_TX), + ); + expectedSettledHints = makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, () => + SettledDataReadHint.nada(MAX_PUBLIC_DATA_READS_PER_TX), + ); + }); + + it('returns empty hints', () => { + buildAndCheckHints(); + }); + + it('builds hints for reading pending values', () => { + publicDataReads[0] = makePublicDataRead(77, 7777); + publicDataReads[1] = makePublicDataRead(99, 9999); + publicDataReads[2] = makePublicDataRead(55, 5555); + expectedStatuses[0] = ReadRequestStatus.pending(0); + expectedStatuses[1] = ReadRequestStatus.pending(1); + expectedStatuses[2] = ReadRequestStatus.pending(2); + expectedPendingHints[0] = makePendingHint(0, 1); + expectedPendingHints[1] = makePendingHint(1, 2); + expectedPendingHints[2] = makePendingHint(2, 0); + + buildAndCheckHints(); + }); + + it('builds hints for reading settled or uninitialized values', () => { + publicDataReads[0] = makePublicDataRead(33, 300); + publicDataReads[1] = makePublicDataRead(77, 0); + publicDataReads[2] = makePublicDataRead(55, 500); + publicDataReads[3] = makePublicDataRead(11, 100); + expectedStatuses[0] = ReadRequestStatus.settled(0); + expectedStatuses[1] = ReadRequestStatus.settled(1); + expectedStatuses[2] = ReadRequestStatus.settled(2); + expectedStatuses[3] = ReadRequestStatus.settled(3); + expectedSettledHints[0] = makeSettledHint(0, 2); + expectedSettledHints[1] = makeSettledHint(1, 4); + expectedSettledHints[2] = makeSettledHint(2, 3); + expectedSettledHints[3] = makeSettledHint(3, 0); + + buildAndCheckHints(); + }); + + it('builds hints for reading pending and settled values', () => { + publicDataReads[0] = makePublicDataRead(55, 500); + publicDataReads[1] = makePublicDataRead(55, 5555); + publicDataReads[2] = makePublicDataRead(77, 0); + publicDataReads[3] = makePublicDataRead(11, 100); + publicDataReads[4] = makePublicDataRead(99, 9999); + publicDataReads[5] = makePublicDataRead(77, 7777); + publicDataReads[6] = makePublicDataRead(11, 100); + expectedStatuses[0] = ReadRequestStatus.settled(0); + expectedStatuses[1] = ReadRequestStatus.pending(0); + expectedStatuses[2] = ReadRequestStatus.settled(1); + expectedStatuses[3] = ReadRequestStatus.settled(2); + expectedStatuses[4] = ReadRequestStatus.pending(1); + expectedStatuses[5] = ReadRequestStatus.pending(2); + expectedStatuses[6] = ReadRequestStatus.settled(3); + expectedPendingHints[0] = makePendingHint(1, 0); + expectedPendingHints[1] = makePendingHint(4, 2); + expectedPendingHints[2] = makePendingHint(5, 1); + expectedSettledHints[0] = makeSettledHint(0, 3); + expectedSettledHints[1] = makeSettledHint(2, 4); + expectedSettledHints[2] = makeSettledHint(3, 0); + expectedSettledHints[3] = makeSettledHint(6, 0); + + buildAndCheckHints(); + }); + + it('throws if reading unknown slot', () => { + publicDataReads[0] = makePublicDataRead(123, 100); + expect(() => buildHints()).toThrow('Cannot find a pending write or a data hint for the read request.'); + }); + + it('throws if reading unknown value', () => { + publicDataReads[0] = makePublicDataRead(11, 1111); + expect(() => buildHints()).toThrow('Value being read does not match existing public data or pending writes.'); + }); +}); diff --git a/yarn-project/circuits.js/src/hints/build_public_data_read_request_hints.ts b/yarn-project/circuits.js/src/hints/build_public_data_read_request_hints.ts new file mode 100644 index 00000000000..90531128d9a --- /dev/null +++ b/yarn-project/circuits.js/src/hints/build_public_data_read_request_hints.ts @@ -0,0 +1,45 @@ +import { type Tuple } from '@aztec/foundation/serialize'; + +import { + type MAX_PUBLIC_DATA_HINTS, + type MAX_PUBLIC_DATA_READS_PER_TX, + type MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, +} from '../constants.gen.js'; +import { + type PublicDataRead, + PublicDataReadRequestHintsBuilder, + type PublicDataUpdateRequest, +} from '../structs/index.js'; +import { type PublicDataHint } from '../structs/public_data_hint.js'; +import { countAccumulatedItems } from '../utils/index.js'; + +export function buildPublicDataReadRequestHints( + publicDataReads: Tuple, + publicDataUpdateRequests: Tuple, + publicDataHints: Tuple, +) { + const builder = new PublicDataReadRequestHintsBuilder(); + + const numReadRequests = countAccumulatedItems(publicDataReads); + for (let i = 0; i < numReadRequests; ++i) { + const rr = publicDataReads[i]; + // TODO: Add counters to reads and writes. + const writeIndex = publicDataUpdateRequests.findIndex( + w => w.leafSlot.equals(rr.leafSlot) && w.newValue.equals(rr.value), + ); + if (writeIndex !== -1) { + builder.addPendingReadRequest(i, writeIndex); + } else { + const hintIndex = publicDataHints.findIndex(h => h.leafSlot.equals(rr.leafSlot)); + if (hintIndex === -1) { + throw new Error('Cannot find a pending write or a data hint for the read request.'); + } + if (!publicDataHints[hintIndex].value.equals(rr.value)) { + throw new Error('Value being read does not match existing public data or pending writes.'); + } + builder.addSettledReadRequest(i, hintIndex); + } + } + + return builder.toHints(); +} diff --git a/yarn-project/circuits.js/src/hints/index.ts b/yarn-project/circuits.js/src/hints/index.ts index 476edce05e9..d9378ed85b5 100644 --- a/yarn-project/circuits.js/src/hints/index.ts +++ b/yarn-project/circuits.js/src/hints/index.ts @@ -1,2 +1,3 @@ export * from './build_hints.js'; -export * from '../utils/index.js'; +export * from './build_public_data_hints.js'; +export * from './build_public_data_read_request_hints.js'; diff --git a/yarn-project/circuits.js/src/index.ts b/yarn-project/circuits.js/src/index.ts index 3b6fdbcd0e6..d4c939ef836 100644 --- a/yarn-project/circuits.js/src/index.ts +++ b/yarn-project/circuits.js/src/index.ts @@ -6,3 +6,4 @@ export * from './interfaces/index.js'; export * from './keys/index.js'; export * from './structs/index.js'; export * from './types/index.js'; +export * from './utils/index.js'; diff --git a/yarn-project/circuits.js/src/structs/index.ts b/yarn-project/circuits.js/src/structs/index.ts index c59c4811e5b..da7d53bd4ed 100644 --- a/yarn-project/circuits.js/src/structs/index.ts +++ b/yarn-project/circuits.js/src/structs/index.ts @@ -44,7 +44,9 @@ export * from './proof.js'; export * from './public_call_request.js'; export * from './public_call_stack_item.js'; export * from './public_circuit_public_inputs.js'; +export * from './public_data_hint.js'; export * from './public_data_read_request.js'; +export * from './public_data_read_request_hints.js'; export * from './public_data_update_request.js'; export * from './read_request.js'; export * from './read_request_hints.js'; diff --git a/yarn-project/circuits.js/src/structs/kernel/public_kernel_tail_circuit_private_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/public_kernel_tail_circuit_private_inputs.ts index 073c0598861..0c760796c31 100644 --- a/yarn-project/circuits.js/src/structs/kernel/public_kernel_tail_circuit_private_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/public_kernel_tail_circuit_private_inputs.ts @@ -1,12 +1,12 @@ -import { serializeToBuffer } from '@aztec/foundation/serialize'; +import { type Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; +import { type MAX_PUBLIC_DATA_HINTS } from '../../constants.gen.js'; import { type NullifierNonExistentReadRequestHints } from '../non_existent_read_request_hints.js'; +import { type PublicDataHint } from '../public_data_hint.js'; +import { type PublicDataReadRequestHints } from '../public_data_read_request_hints.js'; import { type NullifierReadRequestHints } from '../read_request_hints.js'; import { type PublicKernelData } from './public_kernel_data.js'; -/** - * Inputs to the public kernel circuit. - */ export class PublicKernelTailCircuitPrivateInputs { constructor( /** @@ -21,6 +21,8 @@ export class PublicKernelTailCircuitPrivateInputs { * Contains hints for the nullifier non existent read requests. */ public readonly nullifierNonExistentReadRequestHints: NullifierNonExistentReadRequestHints, + public readonly publicDataHints: Tuple, + public readonly publicDataReadRequestHints: PublicDataReadRequestHints, ) {} toBuffer() { @@ -28,6 +30,8 @@ export class PublicKernelTailCircuitPrivateInputs { this.previousKernel, this.nullifierReadRequestHints, this.nullifierNonExistentReadRequestHints, + this.publicDataHints, + this.publicDataReadRequestHints, ); } } diff --git a/yarn-project/circuits.js/src/structs/membership_witness.ts b/yarn-project/circuits.js/src/structs/membership_witness.ts index db0457ef394..fd623300be1 100644 --- a/yarn-project/circuits.js/src/structs/membership_witness.ts +++ b/yarn-project/circuits.js/src/structs/membership_witness.ts @@ -49,7 +49,7 @@ export class MembershipWitness { * @param leafIndex - Index of the leaf in the Merkle tree. * @returns Membership witness with zero sibling path. */ - public static empty(pathSize: N, leafIndex: bigint): MembershipWitness { + public static empty(pathSize: N, leafIndex = 0n): MembershipWitness { const arr = Array(pathSize) .fill(0) .map(() => Fr.ZERO) as Tuple; diff --git a/yarn-project/circuits.js/src/structs/non_existent_read_request_hints.ts b/yarn-project/circuits.js/src/structs/non_existent_read_request_hints.ts index a459be8be34..57f7a7457b3 100644 --- a/yarn-project/circuits.js/src/structs/non_existent_read_request_hints.ts +++ b/yarn-project/circuits.js/src/structs/non_existent_read_request_hints.ts @@ -18,7 +18,7 @@ export class NonMembershipHint LEAF_PREIMAGE, ) { - return new NonMembershipHint(MembershipWitness.empty(treeHeight, 0n), makeEmptyLeafPreimage()); + return new NonMembershipHint(MembershipWitness.empty(treeHeight), makeEmptyLeafPreimage()); } static fromBuffer( diff --git a/yarn-project/circuits.js/src/structs/public_data_hint.ts b/yarn-project/circuits.js/src/structs/public_data_hint.ts new file mode 100644 index 00000000000..52d73a080f0 --- /dev/null +++ b/yarn-project/circuits.js/src/structs/public_data_hint.ts @@ -0,0 +1,47 @@ +import { Fr } from '@aztec/foundation/fields'; +import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; + +import { PUBLIC_DATA_TREE_HEIGHT } from '../constants.gen.js'; +import { MembershipWitness } from './membership_witness.js'; +import { PublicDataTreeLeafPreimage } from './rollup/public_data_leaf/index.js'; + +export class PublicDataHint { + constructor( + public leafSlot: Fr, + public value: Fr, + public overrideCounter: number, + public membershipWitness: MembershipWitness, + public leafPreimage: PublicDataTreeLeafPreimage, + ) {} + + static empty() { + return new PublicDataHint( + Fr.ZERO, + Fr.ZERO, + 0, + MembershipWitness.empty(PUBLIC_DATA_TREE_HEIGHT), + PublicDataTreeLeafPreimage.empty(), + ); + } + + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new PublicDataHint( + reader.readObject(Fr), + reader.readObject(Fr), + reader.readNumber(), + MembershipWitness.fromBuffer(reader, PUBLIC_DATA_TREE_HEIGHT), + reader.readObject(PublicDataTreeLeafPreimage), + ); + } + + toBuffer() { + return serializeToBuffer( + this.leafSlot, + this.value, + this.overrideCounter, + this.membershipWitness, + this.leafPreimage, + ); + } +} diff --git a/yarn-project/circuits.js/src/structs/public_data_read_request_hints.ts b/yarn-project/circuits.js/src/structs/public_data_read_request_hints.ts new file mode 100644 index 00000000000..f70804f1211 --- /dev/null +++ b/yarn-project/circuits.js/src/structs/public_data_read_request_hints.ts @@ -0,0 +1,86 @@ +import { makeTuple } from '@aztec/foundation/array'; +import { BufferReader, type Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; + +import { MAX_PUBLIC_DATA_READS_PER_TX } from '../constants.gen.js'; +import { PendingReadHint, ReadRequestState, ReadRequestStatus } from './read_request_hints.js'; + +export class SettledDataReadHint { + constructor(public readRequestIndex: number, public settledDataHintIndex: number) {} + + static nada(readRequestLen: number) { + return new SettledDataReadHint(readRequestLen, 0); + } + + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new SettledDataReadHint(reader.readNumber(), reader.readNumber()); + } + + toBuffer() { + return serializeToBuffer(this.readRequestIndex, this.settledDataHintIndex); + } +} + +export class PublicDataReadRequestHints { + constructor( + public readRequestStatuses: Tuple, + public pendingReadHints: Tuple, + public settledReadHints: Tuple, + ) {} + + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new PublicDataReadRequestHints( + reader.readArray(MAX_PUBLIC_DATA_READS_PER_TX, ReadRequestStatus), + reader.readArray(MAX_PUBLIC_DATA_READS_PER_TX, PendingReadHint), + reader.readArray(MAX_PUBLIC_DATA_READS_PER_TX, SettledDataReadHint), + ); + } + + toBuffer() { + return serializeToBuffer(this.readRequestStatuses, this.pendingReadHints, this.settledReadHints); + } +} + +export class PublicDataReadRequestHintsBuilder { + private hints: PublicDataReadRequestHints; + private numPendingReadHints = 0; + private numSettledReadHints = 0; + + constructor() { + this.hints = new PublicDataReadRequestHints( + makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, ReadRequestStatus.nada), + makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, () => PendingReadHint.nada(MAX_PUBLIC_DATA_READS_PER_TX)), + makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, () => SettledDataReadHint.nada(MAX_PUBLIC_DATA_READS_PER_TX)), + ); + } + + static empty() { + return new PublicDataReadRequestHintsBuilder().toHints(); + } + + addPendingReadRequest(readRequestIndex: number, publicDataWriteIndex: number) { + this.hints.readRequestStatuses[readRequestIndex] = new ReadRequestStatus( + ReadRequestState.PENDING, + this.numPendingReadHints, + ); + this.hints.pendingReadHints[this.numPendingReadHints] = new PendingReadHint(readRequestIndex, publicDataWriteIndex); + this.numPendingReadHints++; + } + + addSettledReadRequest(readRequestIndex: number, settledDataHintIndex: number) { + this.hints.readRequestStatuses[readRequestIndex] = new ReadRequestStatus( + ReadRequestState.SETTLED, + this.numSettledReadHints, + ); + this.hints.settledReadHints[this.numSettledReadHints] = new SettledDataReadHint( + readRequestIndex, + settledDataHintIndex, + ); + this.numSettledReadHints++; + } + + toHints() { + return this.hints; + } +} diff --git a/yarn-project/circuits.js/src/structs/read_request_hints.ts b/yarn-project/circuits.js/src/structs/read_request_hints.ts index 6e6439ec426..fd0be737614 100644 --- a/yarn-project/circuits.js/src/structs/read_request_hints.ts +++ b/yarn-project/circuits.js/src/structs/read_request_hints.ts @@ -19,6 +19,14 @@ export class ReadRequestStatus { return new ReadRequestStatus(ReadRequestState.NADA, 0); } + static pending(hintIndex: number) { + return new ReadRequestStatus(ReadRequestState.PENDING, hintIndex); + } + + static settled(hintIndex: number) { + return new ReadRequestStatus(ReadRequestState.SETTLED, hintIndex); + } + static fromBuffer(buffer: Buffer | BufferReader) { const reader = BufferReader.asReader(buffer); return new ReadRequestStatus(reader.readNumber(), reader.readNumber()); @@ -58,7 +66,7 @@ export class SettledReadHint LEAF_PREIMAGE, ) { - return new SettledReadHint(readRequestLen, MembershipWitness.empty(treeHeight, 0n), emptyLeafPreimage()); + return new SettledReadHint(readRequestLen, MembershipWitness.empty(treeHeight), emptyLeafPreimage()); } static fromBuffer( diff --git a/yarn-project/circuits.js/src/structs/rollup/public_data_leaf/index.ts b/yarn-project/circuits.js/src/structs/rollup/public_data_leaf/index.ts index 96a3eac57b9..5bf0cab55e2 100644 --- a/yarn-project/circuits.js/src/structs/rollup/public_data_leaf/index.ts +++ b/yarn-project/circuits.js/src/structs/rollup/public_data_leaf/index.ts @@ -64,7 +64,7 @@ export class PublicDataTreeLeafPreimage implements IndexedTreeLeafPreimage { return new PublicDataTreeLeafPreimage(Fr.ZERO, Fr.ZERO, Fr.ZERO, 0n); } - static fromBuffer(buffer: Buffer): PublicDataTreeLeafPreimage { + static fromBuffer(buffer: BufferReader | Buffer): PublicDataTreeLeafPreimage { const reader = BufferReader.asReader(buffer); const slot = Fr.fromBuffer(reader); const value = Fr.fromBuffer(reader); diff --git a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts index 667bbcf6a98..a4653feea7a 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -72,7 +72,9 @@ import { type PublicCallData, type PublicCallStackItem, type PublicCircuitPublicInputs, + type PublicDataHint, PublicDataRead, + type PublicDataReadRequestHints, type PublicDataTreeLeaf, type PublicDataTreeLeafPreimage, PublicDataUpdateRequest, @@ -89,6 +91,7 @@ import { type RootParityInputs, type RootRollupInputs, RootRollupPublicInputs, + type SettledDataReadHint, type SettledReadHint, SideEffect, SideEffectLinkedToNoteHash, @@ -164,8 +167,11 @@ import { import { type NullifierNonExistentReadRequestHints as NullifierNonExistentReadRequestHintsNoir, type NullifierNonMembershipHint as NullifierNonMembershipHintNoir, + type PublicDataHint as PublicDataHintNoir, + type PublicDataReadRequestHints as PublicDataReadRequestHintsNoir, type PublicDataUpdateRequest as PublicDataUpdateRequestNoir, type PublicKernelTailCircuitPrivateInputs as PublicKernelTailCircuitPrivateInputsNoir, + type SettledDataReadHint as SettledDataReadHintNoir, } from './types/public_kernel_tail_types.js'; import { type ArchiveRootMembershipWitness as ArchiveRootMembershipWitnessNoir, @@ -877,6 +883,13 @@ function mapPendingReadHintToNoir(hint: PendingReadHint): PendingReadHintNoir { }; } +function mapSettledDataReadHintToNoir(hint: SettledDataReadHint): SettledDataReadHintNoir { + return { + read_request_index: mapNumberToNoir(hint.readRequestIndex), + settled_data_hint_index: mapNumberToNoir(hint.settledDataHintIndex), + }; +} + function mapNullifierSettledReadHintToNoir( hint: SettledReadHint, ): NullifierSettledReadHintNoir { @@ -915,6 +928,24 @@ function mapNullifierNonExistentReadRequestHintsToNoir( }; } +function mapPublicDataHintToNoir(hint: PublicDataHint): PublicDataHintNoir { + return { + leaf_slot: mapFieldToNoir(hint.leafSlot), + value: mapFieldToNoir(hint.value), + override_counter: mapNumberToNoir(hint.overrideCounter), + membership_witness: mapPublicDataMembershipWitnessToNoir(hint.membershipWitness), + leaf_preimage: mapPublicDataTreePreimageToNoir(hint.leafPreimage), + }; +} + +function mapPublicDataReadRequestHintsToNoir(hints: PublicDataReadRequestHints): PublicDataReadRequestHintsNoir { + return { + read_request_statuses: mapTuple(hints.readRequestStatuses, mapReadRequestStatusToNoir), + pending_read_hints: mapTuple(hints.pendingReadHints, mapPendingReadHintToNoir), + settled_read_hints: mapTuple(hints.settledReadHints, mapSettledDataReadHintToNoir), + }; +} + function mapValidationRequestsToNoir(requests: ValidationRequests): ValidationRequestsNoir { return { for_rollup: mapRollupValidationRequestsToNoir(requests.forRollup), @@ -1326,6 +1357,8 @@ export function mapPublicKernelTailCircuitPrivateInputsToNoir( nullifier_non_existent_read_request_hints: mapNullifierNonExistentReadRequestHintsToNoir( inputs.nullifierNonExistentReadRequestHints, ), + public_data_hints: mapTuple(inputs.publicDataHints, mapPublicDataHintToNoir), + public_data_read_request_hints: mapPublicDataReadRequestHintsToNoir(inputs.publicDataReadRequestHints), }; } diff --git a/yarn-project/sequencer-client/src/sequencer/hints_builder.ts b/yarn-project/sequencer-client/src/sequencer/hints_builder.ts index b2a581d7696..5cc4988fd6f 100644 --- a/yarn-project/sequencer-client/src/sequencer/hints_builder.ts +++ b/yarn-project/sequencer-client/src/sequencer/hints_builder.ts @@ -1,65 +1,77 @@ import { MerkleTreeId } from '@aztec/circuit-types'; import { type Fr, - MAX_NEW_NULLIFIERS_PER_TX, + type MAX_NEW_NULLIFIERS_PER_TX, type MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, type MAX_NULLIFIER_READ_REQUESTS_PER_TX, - MAX_PUBLIC_DATA_READS_PER_TX, + type MAX_PUBLIC_DATA_HINTS, + type MAX_PUBLIC_DATA_READS_PER_TX, + type MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MembershipWitness, NULLIFIER_TREE_HEIGHT, PUBLIC_DATA_TREE_HEIGHT, + type PublicDataHint, type PublicDataRead, - PublicDataTreeLeafPreimage, + type PublicDataTreeLeafPreimage, + type PublicDataUpdateRequest, type ReadRequestContext, type SideEffectLinkedToNoteHash, buildNullifierNonExistentReadRequestHints, buildNullifierReadRequestHints, - mergeAccumulatedData, + buildPublicDataHints, + buildPublicDataReadRequestHints, } from '@aztec/circuits.js'; -import { makeTuple } from '@aztec/foundation/array'; import { type Tuple } from '@aztec/foundation/serialize'; -import { type MerkleTreeOperations } from '@aztec/world-state'; +import { type IndexedTreeId, type MerkleTreeOperations } from '@aztec/world-state'; export class HintsBuilder { constructor(private db: MerkleTreeOperations) {} getNullifierReadRequestHints( nullifierReadRequests: Tuple, - nullifiersNonRevertible: Tuple, - nullifiersRevertible: Tuple, + pendingNullifiers: Tuple, ) { - return buildNullifierReadRequestHints( - this, - nullifierReadRequests, - mergeAccumulatedData(MAX_NEW_NULLIFIERS_PER_TX, nullifiersNonRevertible, nullifiersRevertible), - ); + return buildNullifierReadRequestHints(this, nullifierReadRequests, pendingNullifiers); } getNullifierNonExistentReadRequestHints( nullifierNonExistentReadRequests: Tuple, - nullifiersNonRevertible: Tuple, - nullifiersRevertible: Tuple, + pendingNullifiers: Tuple, ) { - const pendingNullifiers = mergeAccumulatedData( - MAX_NEW_NULLIFIERS_PER_TX, - nullifiersNonRevertible, - nullifiersRevertible, - ); return buildNullifierNonExistentReadRequestHints(this, nullifierNonExistentReadRequests, pendingNullifiers); } + getPublicDataHints( + publicDataReads: Tuple, + publicDataUpdateRequests: Tuple, + ) { + return buildPublicDataHints(this, publicDataReads, publicDataUpdateRequests); + } + + getPublicDataReadRequestHints( + publicDataReads: Tuple, + publicDataUpdateRequests: Tuple, + publicDataHints: Tuple, + ) { + return buildPublicDataReadRequestHints(publicDataReads, publicDataUpdateRequests, publicDataHints); + } + async getNullifierMembershipWitness(nullifier: Fr) { const index = await this.db.findLeafIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBuffer()); if (index === undefined) { - return; + throw new Error(`Cannot find the leaf for nullifier ${nullifier.toBigInt()}.`); } - return this.getNullifierMembershipWitnessWithPreimage(index); + return this.getMembershipWitnessWithPreimage( + MerkleTreeId.NULLIFIER_TREE, + NULLIFIER_TREE_HEIGHT, + index, + ); } async getLowNullifierMembershipWitness(nullifier: Fr) { const res = await this.db.getPreviousValueIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBigInt()); - if (res === undefined) { + if (!res) { throw new Error(`Cannot find the low leaf for nullifier ${nullifier.toBigInt()}.`); } @@ -68,52 +80,40 @@ export class HintsBuilder { throw new Error(`Nullifier ${nullifier.toBigInt()} already exists in the tree.`); } - return this.getNullifierMembershipWitnessWithPreimage(index); - } - - private async getNullifierMembershipWitnessWithPreimage(index: bigint) { - const siblingPath = await this.db.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, index); - const membershipWitness = new MembershipWitness( + return this.getMembershipWitnessWithPreimage( + MerkleTreeId.NULLIFIER_TREE, NULLIFIER_TREE_HEIGHT, index, - siblingPath.toTuple(), ); + } - const leafPreimage = await this.db.getLeafPreimage(MerkleTreeId.NULLIFIER_TREE, index); - if (!leafPreimage) { - throw new Error(`Cannot find the leaf preimage at index ${index}.`); + async getMatchOrLowPublicDataMembershipWitness(leafSlot: bigint) { + const res = await this.db.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot); + if (!res) { + throw new Error(`Cannot find the previous value index for public data ${leafSlot}.`); } - return { membershipWitness, leafPreimage }; + const { membershipWitness, leafPreimage } = await this.getMembershipWitnessWithPreimage< + typeof PUBLIC_DATA_TREE_HEIGHT + >(MerkleTreeId.PUBLIC_DATA_TREE, PUBLIC_DATA_TREE_HEIGHT, res.index); + + // Should find a way to stop casting IndexedTreeLeafPreimage as PublicDataTreeLeafPreimage everywhere. + return { membershipWitness, leafPreimage: leafPreimage as PublicDataTreeLeafPreimage }; } - async getPublicDataReadsInfo(publicDataReads: PublicDataRead[]) { - const newPublicDataReadsWitnesses: Tuple< - MembershipWitness, - typeof MAX_PUBLIC_DATA_READS_PER_TX - > = makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, () => MembershipWitness.empty(PUBLIC_DATA_TREE_HEIGHT, 0n)); - - const newPublicDataReadsPreimages: Tuple = - makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, () => PublicDataTreeLeafPreimage.empty()); - - for (const i in publicDataReads) { - const leafSlot = publicDataReads[i].leafSlot.value; - const lowLeafResult = await this.db.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot); - if (!lowLeafResult) { - throw new Error(`Public data tree should have one initial leaf`); - } - const preimage = await this.db.getLeafPreimage(MerkleTreeId.PUBLIC_DATA_TREE, lowLeafResult.index); - const path = await this.db.getSiblingPath(MerkleTreeId.PUBLIC_DATA_TREE, lowLeafResult.index); - newPublicDataReadsWitnesses[i] = new MembershipWitness( - PUBLIC_DATA_TREE_HEIGHT, - BigInt(lowLeafResult.index), - path.toTuple(), - ); - newPublicDataReadsPreimages[i] = preimage! as PublicDataTreeLeafPreimage; + private async getMembershipWitnessWithPreimage( + treeId: IndexedTreeId, + treeHeight: TREE_HEIGHT, + index: bigint, + ) { + const siblingPath = await this.db.getSiblingPath(treeId, index); + const membershipWitness = new MembershipWitness(treeHeight, index, siblingPath.toTuple()); + + const leafPreimage = await this.db.getLeafPreimage(treeId, index); + if (!leafPreimage) { + throw new Error(`Cannot find the leaf preimage for tree ${treeId} at index ${index}.`); } - return { - newPublicDataReadsWitnesses, - newPublicDataReadsPreimages, - }; + + return { membershipWitness, leafPreimage }; } } diff --git a/yarn-project/sequencer-client/src/sequencer/tail_phase_manager.ts b/yarn-project/sequencer-client/src/sequencer/tail_phase_manager.ts index 748dca637cd..5f487aee305 100644 --- a/yarn-project/sequencer-client/src/sequencer/tail_phase_manager.ts +++ b/yarn-project/sequencer-client/src/sequencer/tail_phase_manager.ts @@ -5,6 +5,8 @@ import { type Header, type KernelCircuitPublicInputs, MAX_NEW_NOTE_HASHES_PER_TX, + MAX_NEW_NULLIFIERS_PER_TX, + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, type Proof, type PublicKernelCircuitPublicInputs, PublicKernelTailCircuitPrivateInputs, @@ -81,25 +83,55 @@ export class TailPhaseManager extends AbstractPhaseManager { previousOutput: PublicKernelCircuitPublicInputs, previousProof: Proof, ): Promise { + const inputs = await this.buildPrivateInputs(previousOutput, previousProof); + return this.publicKernel.publicKernelCircuitTail(inputs); + } + + private async buildPrivateInputs(previousOutput: PublicKernelCircuitPublicInputs, previousProof: Proof) { const previousKernel = this.getPreviousKernelData(previousOutput, previousProof); const { validationRequests, endNonRevertibleData, end } = previousOutput; - const nullifierReadRequestHints = await this.hintsBuilder.getNullifierReadRequestHints( - validationRequests.nullifierReadRequests, + + const pendingNullifiers = mergeAccumulatedData( + MAX_NEW_NULLIFIERS_PER_TX, endNonRevertibleData.newNullifiers, end.newNullifiers, ); + + const nullifierReadRequestHints = await this.hintsBuilder.getNullifierReadRequestHints( + validationRequests.nullifierReadRequests, + pendingNullifiers, + ); + const nullifierNonExistentReadRequestHints = await this.hintsBuilder.getNullifierNonExistentReadRequestHints( validationRequests.nullifierNonExistentReadRequests, - endNonRevertibleData.newNullifiers, - end.newNullifiers, + pendingNullifiers, + ); + + const pendingPublicDataWrites = mergeAccumulatedData( + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, + endNonRevertibleData.publicDataUpdateRequests, + end.publicDataUpdateRequests, + ); + + const publicDataHints = await this.hintsBuilder.getPublicDataHints( + validationRequests.publicDataReads, + pendingPublicDataWrites, + ); + + const publicDataReadRequestHints = this.hintsBuilder.getPublicDataReadRequestHints( + validationRequests.publicDataReads, + pendingPublicDataWrites, + publicDataHints, ); - const inputs = new PublicKernelTailCircuitPrivateInputs( + + return new PublicKernelTailCircuitPrivateInputs( previousKernel, nullifierReadRequestHints, nullifierNonExistentReadRequestHints, + publicDataHints, + publicDataReadRequestHints, ); - return this.publicKernel.publicKernelCircuitTail(inputs); } private sortNoteHashes(noteHashes: Tuple): Tuple { From ad686b52759d58318098ff43a4bc4591a8b76340 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Thu, 11 Apr 2024 17:21:11 +0000 Subject: [PATCH 04/15] Fix. --- yarn-project/pxe/src/kernel_prover/hints_builder.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn-project/pxe/src/kernel_prover/hints_builder.ts b/yarn-project/pxe/src/kernel_prover/hints_builder.ts index f57f1d8c7b4..dea4ae58b96 100644 --- a/yarn-project/pxe/src/kernel_prover/hints_builder.ts +++ b/yarn-project/pxe/src/kernel_prover/hints_builder.ts @@ -84,7 +84,7 @@ export class HintsBuilder { async getNullifierMembershipWitness(nullifier: Fr) { const res = await this.oracle.getNullifierMembershipWitness(nullifier); if (!res) { - return; + throw new Error(`Cannot find the leaf for nullifier ${nullifier.toBigInt()}.`); } const { index, siblingPath, leafPreimage } = res; From 434496297c63d60db0375a3d4e3942fe2a5cd15d Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Fri, 12 Apr 2024 11:30:55 +0000 Subject: [PATCH 05/15] Update mock data. --- yarn-project/circuit-types/src/mocks.ts | 24 +- .../src/sequencer/public_processor.test.ts | 307 ++++++++---------- 2 files changed, 154 insertions(+), 177 deletions(-) diff --git a/yarn-project/circuit-types/src/mocks.ts b/yarn-project/circuit-types/src/mocks.ts index 3f6c48c134f..75fbfd88bf0 100644 --- a/yarn-project/circuit-types/src/mocks.ts +++ b/yarn-project/circuit-types/src/mocks.ts @@ -5,6 +5,7 @@ import { PartialPrivateTailPublicInputsForPublic, PrivateKernelTailCircuitPublicInputs, Proof, + type PublicCallRequest, SideEffectLinkedToNoteHash, computeContractClassId, getContractClassFromArtifact, @@ -38,14 +39,21 @@ export const mockTx = ( hasLogs = false, numberOfNonRevertiblePublicCallRequests = MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX / 2, numberOfRevertiblePublicCallRequests = MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX / 2, + publicCallRequests = [], }: { hasLogs?: boolean; numberOfNonRevertiblePublicCallRequests?: number; numberOfRevertiblePublicCallRequests?: number; + publicCallRequests?: PublicCallRequest[]; } = {}, ) => { - const totalPublicCallRequests = numberOfNonRevertiblePublicCallRequests + numberOfRevertiblePublicCallRequests; - const publicCallRequests = times(totalPublicCallRequests, i => makePublicCallRequest(seed + 0x100 + i)); + const totalPublicCallRequests = + numberOfNonRevertiblePublicCallRequests + numberOfRevertiblePublicCallRequests || publicCallRequests.length; + if (publicCallRequests.length && publicCallRequests.length !== totalPublicCallRequests) { + throw new Error( + `Provided publicCallRequests does not match the required number of call requests. Expected ${totalPublicCallRequests}. Got ${publicCallRequests.length}`, + ); + } const isForPublic = totalPublicCallRequests > 0; const data = PrivateKernelTailCircuitPublicInputs.empty(); @@ -57,15 +65,19 @@ export const mockTx = ( data.forPublic.endNonRevertibleData.newNullifiers[0] = firstNullifier; - data.forPublic.end.publicCallStack = makeTuple(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, i => - i < numberOfRevertiblePublicCallRequests ? publicCallRequests[i].toCallRequest() : CallRequest.empty(), - ); + publicCallRequests = publicCallRequests.length + ? publicCallRequests.slice().sort((a, b) => b.callContext.sideEffectCounter - a.callContext.sideEffectCounter) + : times(totalPublicCallRequests, i => makePublicCallRequest(seed + 0x100 + i)); data.forPublic.endNonRevertibleData.publicCallStack = makeTuple(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, i => i < numberOfNonRevertiblePublicCallRequests - ? publicCallRequests[i + numberOfRevertiblePublicCallRequests].toCallRequest() + ? publicCallRequests[numberOfRevertiblePublicCallRequests + i].toCallRequest() : CallRequest.empty(), ); + + data.forPublic.end.publicCallStack = makeTuple(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, i => + i < numberOfRevertiblePublicCallRequests ? publicCallRequests[i].toCallRequest() : CallRequest.empty(), + ); } else { data.forRollup!.end.newNullifiers[0] = firstNullifier.value; } diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts index 567ec659e08..8f657d96009 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts @@ -1,22 +1,19 @@ import { type BlockProver, - EncryptedTxL2Logs, type FunctionCall, type ProcessedTx, PublicDataWrite, - SiblingPath, SimulationError, - Tx, + type Tx, UnencryptedFunctionL2Logs, - UnencryptedTxL2Logs, mockTx, toTxEffect, } from '@aztec/circuit-types'; import { ARGS_LENGTH, + AppendOnlyTreeSnapshot, type AztecAddress, CallContext, - CallRequest, ContractStorageUpdateRequest, EthAddress, Fr, @@ -24,25 +21,20 @@ import { GasSettings, GlobalVariables, Header, - MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PUBLIC_DATA_TREE_HEIGHT, - type PrivateKernelTailCircuitPublicInputs, + PartialStateReference, type Proof, type PublicCallRequest, - PublicDataUpdateRequest, + PublicDataTreeLeafPreimage, + StateReference, makeEmptyProof, } from '@aztec/circuits.js'; import { computePublicDataTreeLeafSlot } from '@aztec/circuits.js/hash'; -import { - fr, - makeAztecAddress, - makePrivateKernelTailCircuitPublicInputs, - makePublicCallRequest, - makeSelector, -} from '@aztec/circuits.js/testing'; -import { makeTuple } from '@aztec/foundation/array'; -import { arrayNonEmptyLength, padArrayEnd, times } from '@aztec/foundation/collection'; +import { fr, makeAztecAddress, makePublicCallRequest, makeSelector } from '@aztec/circuits.js/testing'; +import { arrayNonEmptyLength, padArrayEnd } from '@aztec/foundation/collection'; +import { pedersenHash } from '@aztec/foundation/crypto'; +import { openTmpStore } from '@aztec/kv-store/utils'; +import { type AppendOnlyTree, Pedersen, StandardTree, newTree } from '@aztec/merkle-tree'; import { type PublicExecution, type PublicExecutionResult, type PublicExecutor, WASMSimulator } from '@aztec/simulator'; import { type MerkleTreeOperations, type TreeInfo } from '@aztec/world-state'; @@ -152,17 +144,75 @@ describe('public_processor', () => { describe('with actual circuits', () => { let publicKernel: PublicKernelCircuitSimulator; + let publicDataTree: AppendOnlyTree; + let header = Header.empty(); + + const mockTxWithPartialState = ( + { + hasLogs = false, + numberOfNonRevertiblePublicCallRequests = 0, + numberOfRevertiblePublicCallRequests = 0, + publicCallRequests = [], + }: { + hasLogs?: boolean; + numberOfNonRevertiblePublicCallRequests?: number; + numberOfRevertiblePublicCallRequests?: number; + publicCallRequests?: PublicCallRequest[]; + } = {}, + seed = 1, + ) => { + const tx = mockTx(seed, { + hasLogs, + numberOfNonRevertiblePublicCallRequests, + numberOfRevertiblePublicCallRequests, + publicCallRequests, + }); + tx.data.constants.historicalHeader.state = header.state; + return tx; + }; + + beforeAll(async () => { + publicDataTree = await newTree( + StandardTree, + openTmpStore(), + new Pedersen(), + 'PublicData', + Fr, + PUBLIC_DATA_TREE_HEIGHT, + ); + // Add a default low leaf for the public data hints to be proved against. + const defaultLeaves = [new PublicDataTreeLeafPreimage(new Fr(1), new Fr(0), new Fr(0), 0n)].map(l => + pedersenHash(l.toHashInputs()), + ); + await publicDataTree.appendLeaves(defaultLeaves); + }); beforeEach(() => { - const path = times(PUBLIC_DATA_TREE_HEIGHT, i => Buffer.alloc(32, i)); - db.getSiblingPath.mockResolvedValue(new SiblingPath(PUBLIC_DATA_TREE_HEIGHT, path)); + const snap = new AppendOnlyTreeSnapshot( + Fr.fromBuffer(publicDataTree.getRoot(true)), + Number(publicDataTree.getNumLeaves(true)), + ); + header = new Header( + header.lastArchive, + header.contentCommitment, + new StateReference( + header.state.l1ToL2MessageTree, + new PartialStateReference(header.state.partial.noteHashTree, header.state.partial.nullifierTree, snap), + ), + header.globalVariables, + ); + + db.getSiblingPath.mockResolvedValue(publicDataTree.getSiblingPath(0n, false)); + db.getPreviousValueIndex.mockResolvedValue({ index: 0n, alreadyPresent: true }); + db.getLeafPreimage.mockResolvedValue(new PublicDataTreeLeafPreimage(new Fr(1), new Fr(0), new Fr(0), 0n)); + publicKernel = new RealPublicKernelCircuitSimulator(new WASMSimulator()); processor = new PublicProcessor( db, publicExecutor, publicKernel, GlobalVariables.empty(), - Header.empty(), + header, publicContractsDB, publicWorldStateDB, ); @@ -175,7 +225,9 @@ describe('public_processor', () => { }); it('runs a tx with enqueued public calls', async function () { - const tx = mockTx(1, { numberOfNonRevertiblePublicCallRequests: 0, numberOfRevertiblePublicCallRequests: 2 }); + const tx = mockTxWithPartialState({ + numberOfRevertiblePublicCallRequests: 2, + }); publicExecutor.simulate.mockImplementation(execution => { for (const request of tx.enqueuedPublicFunctionCalls) { @@ -201,7 +253,7 @@ describe('public_processor', () => { }); it('runs a tx with an enqueued public call with nested execution', async function () { - const tx = mockTx(1, { numberOfNonRevertiblePublicCallRequests: 0, numberOfRevertiblePublicCallRequests: 1 }); + const tx = mockTxWithPartialState({ numberOfRevertiblePublicCallRequests: 1 }); const callRequest = tx.enqueuedPublicFunctionCalls[0]; const publicExecutionResult = PublicExecutionResultBuilder.fromPublicCallRequest({ @@ -232,7 +284,7 @@ describe('public_processor', () => { it('does not attempt to overfill a block', async function () { const txs = Array.from([1, 2, 3], index => - mockTx(index, { numberOfNonRevertiblePublicCallRequests: 0, numberOfRevertiblePublicCallRequests: 1 }), + mockTxWithPartialState({ numberOfRevertiblePublicCallRequests: 1 }, index), ); let txCount = 0; @@ -264,7 +316,7 @@ describe('public_processor', () => { }); it('does not send a transaction to the prover if validation fails', async function () { - const tx = mockTx(1, { numberOfNonRevertiblePublicCallRequests: 0, numberOfRevertiblePublicCallRequests: 1 }); + const tx = mockTxWithPartialState({ numberOfRevertiblePublicCallRequests: 1 }); publicExecutor.simulate.mockImplementation(execution => { for (const request of tx.enqueuedPublicFunctionCalls) { @@ -292,40 +344,21 @@ describe('public_processor', () => { it('rolls back app logic db updates on failed public execution, but persists setup/teardown', async function () { const baseContractAddressSeed = 0x200; const baseContractAddress = makeAztecAddress(baseContractAddressSeed); - const callRequests: PublicCallRequest[] = [ + const publicCallRequests: PublicCallRequest[] = [ baseContractAddressSeed, baseContractAddressSeed, baseContractAddressSeed, ].map(makePublicCallRequest); - callRequests[0].callContext.sideEffectCounter = 2; - callRequests[1].callContext.sideEffectCounter = 3; - callRequests[2].callContext.sideEffectCounter = 4; - - const kernelOutput = makePrivateKernelTailCircuitPublicInputs(0x10); - kernelOutput.forPublic!.endNonRevertibleData.publicDataUpdateRequests = makeTuple( - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - PublicDataUpdateRequest.empty, - ); - kernelOutput.forPublic!.end.publicDataUpdateRequests = makeTuple( - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - PublicDataUpdateRequest.empty, - ); - - addKernelPublicCallStack(kernelOutput, { - setupCalls: [callRequests[0]], - appLogicCalls: [callRequests[2]], - teardownCall: callRequests[1], + publicCallRequests[0].callContext.sideEffectCounter = 2; + publicCallRequests[1].callContext.sideEffectCounter = 3; + publicCallRequests[2].callContext.sideEffectCounter = 4; + + const tx = mockTxWithPartialState({ + numberOfNonRevertiblePublicCallRequests: 2, + numberOfRevertiblePublicCallRequests: 1, + publicCallRequests, }); - const tx = new Tx( - kernelOutput, - proof, - EncryptedTxL2Logs.empty(), - UnencryptedTxL2Logs.empty(), - // reverse because `enqueuedPublicFunctions` expects the last element to be the front of the queue - callRequests.slice().reverse(), - ); - const contractSlotA = fr(0x100); const contractSlotB = fr(0x150); const contractSlotC = fr(0x200); @@ -334,16 +367,16 @@ describe('public_processor', () => { const simulatorResults: PublicExecutionResult[] = [ // Setup PublicExecutionResultBuilder.fromPublicCallRequest({ - request: callRequests[0], + request: publicCallRequests[0], contractStorageUpdateRequests: [new ContractStorageUpdateRequest(contractSlotA, fr(0x101))], }).build(), // App Logic PublicExecutionResultBuilder.fromPublicCallRequest({ - request: callRequests[2], + request: publicCallRequests[2], nestedExecutions: [ PublicExecutionResultBuilder.fromFunctionCall({ - from: callRequests[1].contractAddress, + from: publicCallRequests[1].contractAddress, tx: makeFunctionCall(baseContractAddress, makeSelector(5)), contractStorageUpdateRequests: [ new ContractStorageUpdateRequest(contractSlotA, fr(0x102)), @@ -351,7 +384,7 @@ describe('public_processor', () => { ], }).build(), PublicExecutionResultBuilder.fromFunctionCall({ - from: callRequests[1].contractAddress, + from: publicCallRequests[1].contractAddress, tx: makeFunctionCall(baseContractAddress, makeSelector(5)), revertReason: new SimulationError('Simulation Failed', []), }).build(), @@ -360,10 +393,10 @@ describe('public_processor', () => { // Teardown PublicExecutionResultBuilder.fromPublicCallRequest({ - request: callRequests[1], + request: publicCallRequests[1], nestedExecutions: [ PublicExecutionResultBuilder.fromFunctionCall({ - from: callRequests[1].contractAddress, + from: publicCallRequests[1].contractAddress, tx: makeFunctionCall(baseContractAddress, makeSelector(5)), contractStorageUpdateRequests: [new ContractStorageUpdateRequest(contractSlotC, fr(0x201))], }).build(), @@ -415,32 +448,21 @@ describe('public_processor', () => { it('fails a transaction that reverts in setup', async function () { const baseContractAddressSeed = 0x200; const baseContractAddress = makeAztecAddress(baseContractAddressSeed); - const callRequests: PublicCallRequest[] = [ + const publicCallRequests: PublicCallRequest[] = [ baseContractAddressSeed, baseContractAddressSeed, baseContractAddressSeed, ].map(makePublicCallRequest); - callRequests[0].callContext.sideEffectCounter = 2; - callRequests[1].callContext.sideEffectCounter = 3; - callRequests[2].callContext.sideEffectCounter = 4; - - const kernelOutput = makePrivateKernelTailCircuitPublicInputs(0x10); - - addKernelPublicCallStack(kernelOutput, { - setupCalls: [callRequests[0]], - appLogicCalls: [callRequests[2]], - teardownCall: callRequests[1], + publicCallRequests[0].callContext.sideEffectCounter = 2; + publicCallRequests[1].callContext.sideEffectCounter = 3; + publicCallRequests[2].callContext.sideEffectCounter = 4; + + const tx = mockTxWithPartialState({ + numberOfNonRevertiblePublicCallRequests: 2, + numberOfRevertiblePublicCallRequests: 1, + publicCallRequests, }); - const tx = new Tx( - kernelOutput, - proof, - EncryptedTxL2Logs.empty(), - UnencryptedTxL2Logs.empty(), - // reverse because `enqueuedPublicFunctions` expects the last element to be the front of the queue - callRequests.slice().reverse(), - ); - const contractSlotA = fr(0x100); const contractSlotB = fr(0x150); const contractSlotC = fr(0x200); @@ -449,11 +471,11 @@ describe('public_processor', () => { const simulatorResults: PublicExecutionResult[] = [ // Setup PublicExecutionResultBuilder.fromPublicCallRequest({ - request: callRequests[0], + request: publicCallRequests[0], contractStorageUpdateRequests: [new ContractStorageUpdateRequest(contractSlotA, fr(0x101))], nestedExecutions: [ PublicExecutionResultBuilder.fromFunctionCall({ - from: callRequests[1].contractAddress, + from: publicCallRequests[1].contractAddress, tx: makeFunctionCall(baseContractAddress, makeSelector(5)), contractStorageUpdateRequests: [ new ContractStorageUpdateRequest(contractSlotA, fr(0x102)), @@ -461,7 +483,7 @@ describe('public_processor', () => { ], }).build(), PublicExecutionResultBuilder.fromFunctionCall({ - from: callRequests[1].contractAddress, + from: publicCallRequests[1].contractAddress, tx: makeFunctionCall(baseContractAddress, makeSelector(5)), revertReason: new SimulationError('Simulation Failed', []), }).build(), @@ -470,15 +492,15 @@ describe('public_processor', () => { // App Logic PublicExecutionResultBuilder.fromPublicCallRequest({ - request: callRequests[2], + request: publicCallRequests[2], }).build(), // Teardown PublicExecutionResultBuilder.fromPublicCallRequest({ - request: callRequests[1], + request: publicCallRequests[1], nestedExecutions: [ PublicExecutionResultBuilder.fromFunctionCall({ - from: callRequests[1].contractAddress, + from: publicCallRequests[1].contractAddress, tx: makeFunctionCall(baseContractAddress, makeSelector(5)), contractStorageUpdateRequests: [new ContractStorageUpdateRequest(contractSlotC, fr(0x201))], }).build(), @@ -520,32 +542,21 @@ describe('public_processor', () => { it('fails a transaction that reverts in teardown', async function () { const baseContractAddressSeed = 0x200; const baseContractAddress = makeAztecAddress(baseContractAddressSeed); - const callRequests: PublicCallRequest[] = [ + const publicCallRequests: PublicCallRequest[] = [ baseContractAddressSeed, baseContractAddressSeed, baseContractAddressSeed, ].map(makePublicCallRequest); - callRequests[0].callContext.sideEffectCounter = 2; - callRequests[1].callContext.sideEffectCounter = 3; - callRequests[2].callContext.sideEffectCounter = 4; - - const kernelOutput = makePrivateKernelTailCircuitPublicInputs(0x10); - - addKernelPublicCallStack(kernelOutput, { - setupCalls: [callRequests[0]], - appLogicCalls: [callRequests[2]], - teardownCall: callRequests[1], + publicCallRequests[0].callContext.sideEffectCounter = 2; + publicCallRequests[1].callContext.sideEffectCounter = 3; + publicCallRequests[2].callContext.sideEffectCounter = 4; + + const tx = mockTxWithPartialState({ + numberOfNonRevertiblePublicCallRequests: 2, + numberOfRevertiblePublicCallRequests: 1, + publicCallRequests, }); - const tx = new Tx( - kernelOutput, - proof, - EncryptedTxL2Logs.empty(), - UnencryptedTxL2Logs.empty(), - // reverse because `enqueuedPublicFunctions` expects the last element to be the front of the queue - callRequests.slice().reverse(), - ); - const contractSlotA = fr(0x100); const contractSlotB = fr(0x150); const contractSlotC = fr(0x200); @@ -554,11 +565,11 @@ describe('public_processor', () => { const simulatorResults: PublicExecutionResult[] = [ // Setup PublicExecutionResultBuilder.fromPublicCallRequest({ - request: callRequests[0], + request: publicCallRequests[0], contractStorageUpdateRequests: [new ContractStorageUpdateRequest(contractSlotA, fr(0x101))], nestedExecutions: [ PublicExecutionResultBuilder.fromFunctionCall({ - from: callRequests[1].contractAddress, + from: publicCallRequests[1].contractAddress, tx: makeFunctionCall(baseContractAddress, makeSelector(5)), contractStorageUpdateRequests: [ new ContractStorageUpdateRequest(contractSlotA, fr(0x102)), @@ -570,20 +581,20 @@ describe('public_processor', () => { // App Logic PublicExecutionResultBuilder.fromPublicCallRequest({ - request: callRequests[2], + request: publicCallRequests[2], }).build(), // Teardown PublicExecutionResultBuilder.fromPublicCallRequest({ - request: callRequests[1], + request: publicCallRequests[1], nestedExecutions: [ PublicExecutionResultBuilder.fromFunctionCall({ - from: callRequests[1].contractAddress, + from: publicCallRequests[1].contractAddress, tx: makeFunctionCall(baseContractAddress, makeSelector(5)), revertReason: new SimulationError('Simulation Failed', []), }).build(), PublicExecutionResultBuilder.fromFunctionCall({ - from: callRequests[1].contractAddress, + from: publicCallRequests[1].contractAddress, tx: makeFunctionCall(baseContractAddress, makeSelector(5)), contractStorageUpdateRequests: [new ContractStorageUpdateRequest(contractSlotC, fr(0x201))], }).build(), @@ -624,42 +635,21 @@ describe('public_processor', () => { it('runs a tx with setup and teardown phases', async function () { const baseContractAddressSeed = 0x200; const baseContractAddress = makeAztecAddress(baseContractAddressSeed); - const callRequests: PublicCallRequest[] = [ + const publicCallRequests: PublicCallRequest[] = [ baseContractAddressSeed, baseContractAddressSeed, baseContractAddressSeed, ].map(makePublicCallRequest); - callRequests[0].callContext.sideEffectCounter = 2; - callRequests[1].callContext.sideEffectCounter = 3; - callRequests[2].callContext.sideEffectCounter = 4; - - const kernelOutput = makePrivateKernelTailCircuitPublicInputs(0x10); - kernelOutput.forPublic!.end.encryptedLogsHash = Fr.ZERO; - kernelOutput.forPublic!.end.unencryptedLogsHash = Fr.ZERO; - kernelOutput.forPublic!.endNonRevertibleData.publicDataUpdateRequests = makeTuple( - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - PublicDataUpdateRequest.empty, - ); - kernelOutput.forPublic!.end.publicDataUpdateRequests = makeTuple( - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - PublicDataUpdateRequest.empty, - ); - - addKernelPublicCallStack(kernelOutput, { - setupCalls: [callRequests[0]], - appLogicCalls: [callRequests[2]], - teardownCall: callRequests[1], + publicCallRequests[0].callContext.sideEffectCounter = 2; + publicCallRequests[1].callContext.sideEffectCounter = 3; + publicCallRequests[2].callContext.sideEffectCounter = 4; + + const tx = mockTxWithPartialState({ + numberOfNonRevertiblePublicCallRequests: 2, + numberOfRevertiblePublicCallRequests: 1, + publicCallRequests, }); - const tx = new Tx( - kernelOutput, - proof, - EncryptedTxL2Logs.empty(), - UnencryptedTxL2Logs.empty(), - // reverse because `enqueuedPublicFunctions` expects the last element to be the front of the queue - callRequests.slice().reverse(), - ); - // const baseContractAddress = makeAztecAddress(30); const contractSlotA = fr(0x100); const contractSlotB = fr(0x150); @@ -668,11 +658,11 @@ describe('public_processor', () => { let simulatorCallCount = 0; const simulatorResults: PublicExecutionResult[] = [ // Setup - PublicExecutionResultBuilder.fromPublicCallRequest({ request: callRequests[0] }).build(), + PublicExecutionResultBuilder.fromPublicCallRequest({ request: publicCallRequests[0] }).build(), // App Logic PublicExecutionResultBuilder.fromPublicCallRequest({ - request: callRequests[2], + request: publicCallRequests[2], contractStorageUpdateRequests: [ new ContractStorageUpdateRequest(contractSlotA, fr(0x101)), new ContractStorageUpdateRequest(contractSlotB, fr(0x151)), @@ -681,10 +671,10 @@ describe('public_processor', () => { // Teardown PublicExecutionResultBuilder.fromPublicCallRequest({ - request: callRequests[1], + request: publicCallRequests[1], nestedExecutions: [ PublicExecutionResultBuilder.fromFunctionCall({ - from: callRequests[1].contractAddress, + from: publicCallRequests[1].contractAddress, tx: makeFunctionCall(baseContractAddress, makeSelector(5)), contractStorageUpdateRequests: [ new ContractStorageUpdateRequest(contractSlotA, fr(0x101)), @@ -692,7 +682,7 @@ describe('public_processor', () => { ], }).build(), PublicExecutionResultBuilder.fromFunctionCall({ - from: callRequests[1].contractAddress, + from: publicCallRequests[1].contractAddress, tx: makeFunctionCall(baseContractAddress, makeSelector(5)), contractStorageUpdateRequests: [new ContractStorageUpdateRequest(contractSlotA, fr(0x102))], }).build(), @@ -867,28 +857,3 @@ const makeFunctionCall = ( selector = makeSelector(5), args = new Array(ARGS_LENGTH).fill(Fr.ZERO), ) => ({ to, functionData: new FunctionData(selector, false), args }); - -function addKernelPublicCallStack( - kernelOutput: PrivateKernelTailCircuitPublicInputs, - calls: { - setupCalls: PublicCallRequest[]; - appLogicCalls: PublicCallRequest[]; - teardownCall: PublicCallRequest; - }, -) { - // the first two calls are non-revertible - // the first is for setup, the second is for teardown - kernelOutput.forPublic!.endNonRevertibleData.publicCallStack = padArrayEnd( - // this is a stack, so the first item is the last call - // and callRequests is in the order of the calls - [calls.teardownCall.toCallRequest(), ...calls.setupCalls.map(c => c.toCallRequest())], - CallRequest.empty(), - MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, - ); - - kernelOutput.forPublic!.end.publicCallStack = padArrayEnd( - calls.appLogicCalls.map(c => c.toCallRequest()), - CallRequest.empty(), - MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, - ); -} From 2d1152a77780cc90d59a87ee838bd48159c48238 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Fri, 12 Apr 2024 18:23:11 +0000 Subject: [PATCH 06/15] Prove public data against current state. --- .../src/private_kernel_tail.nr | 9 +++ .../src/public_kernel_tail.nr | 55 ++++++++++++------- .../combined_accumulated_data.nr | 2 +- .../kernel_circuit_public_inputs.nr | 7 ++- ...te_kernel_circuit_public_inputs_builder.nr | 7 ++- ...ic_kernel_circuit_public_inputs_builder.nr | 21 +------ .../crates/types/src/tests/fixture_builder.nr | 13 ++++- .../kernel/kernel_circuit_public_inputs.ts | 7 +++ ...ivate_kernel_tail_circuit_public_inputs.ts | 3 + ...blic_kernel_tail_circuit_private_inputs.ts | 3 + .../circuits.js/src/tests/factories.ts | 2 + .../src/type_conversion.ts | 5 ++ .../src/sequencer/public_processor.test.ts | 21 +++---- .../src/sequencer/tail_phase_manager.ts | 3 + 14 files changed, 102 insertions(+), 56 deletions(-) diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr index d8bdb21cbb8..2989b989391 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr @@ -177,6 +177,15 @@ mod tests { } } + #[test] + unconstrained fn execution_succeeded() { + let mut builder = PrivateKernelTailInputsBuilder::new(); + let public_inputs = builder.execute(); + + assert(is_empty(public_inputs.start_state)); + assert(is_empty(public_inputs.end_state)); + } + #[test] unconstrained fn native_matching_one_read_request_to_commitment_works() { let mut builder = PrivateKernelTailInputsBuilder::new(); diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr index d87e3c25a14..29806a03f87 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr @@ -5,12 +5,12 @@ use dep::reset_kernel_lib::{ }; use dep::types::{ abis::{ - kernel_circuit_public_inputs::{KernelCircuitPublicInputs, PublicKernelCircuitPublicInputsBuilder}, - kernel_data::PublicKernelData, side_effect::SideEffectLinkedToNoteHash + accumulated_data::CombinedAccumulatedData, kernel_circuit_public_inputs::KernelCircuitPublicInputs, + kernel_data::PublicKernelData }, constants::MAX_PUBLIC_DATA_HINTS, merkle_tree::{conditionally_assert_check_membership, MembershipWitness}, - utils::{arrays::array_length} + partial_state_reference::PartialStateReference, utils::{arrays::array_length} }; struct PublicKernelTailCircuitPrivateInputs { @@ -19,13 +19,10 @@ struct PublicKernelTailCircuitPrivateInputs { nullifier_non_existent_read_request_hints: NullifierNonExistentReadRequestHints, public_data_hints: [PublicDataHint; MAX_PUBLIC_DATA_HINTS], public_data_read_request_hints: PublicDataReadRequestHints, + start_state: PartialStateReference, } impl PublicKernelTailCircuitPrivateInputs { - fn propagate_revert_code(self, public_inputs: &mut PublicKernelCircuitPublicInputsBuilder) { - public_inputs.revert_code = self.previous_kernel.public_inputs.revert_code; - } - fn validate_inputs(self) { let previous_public_inputs = self.previous_kernel.public_inputs; assert(previous_public_inputs.needs_setup() == false, "Previous kernel needs setup"); @@ -41,7 +38,7 @@ impl PublicKernelTailCircuitPrivateInputs { fn validate_public_data_hints(self) { let public_data_hints = self.public_data_hints; - let public_data_tree_root = self.previous_kernel.public_inputs.constants.historical_header.state.partial.public_data_tree.root; + let public_data_tree_root = self.start_state.public_data_tree.root; for i in 0..public_data_hints.len() { let hint = public_data_hints[i]; // We only need to check leaf_slot to decide if a (non-)membership check is required. @@ -67,6 +64,15 @@ impl PublicKernelTailCircuitPrivateInputs { } } + fn propagate_accumulated_data(self) -> CombinedAccumulatedData { + let previous_public_inputs = self.previous_kernel.public_inputs; + // TODO: Sort the combined data. + CombinedAccumulatedData::combine( + previous_public_inputs.end_non_revertible, + previous_public_inputs.end + ) + } + pub fn public_kernel_tail(self) -> KernelCircuitPublicInputs { self.validate_inputs(); @@ -84,13 +90,20 @@ impl PublicKernelTailCircuitPrivateInputs { ); request_processor.validate(); - let mut public_inputs = PublicKernelCircuitPublicInputsBuilder::empty(); + let end = self.propagate_accumulated_data(); - self.propagate_revert_code(&mut public_inputs); + // TODO: update public data tree root. + let end_state = self.start_state; - common::initialize_emitted_end_values(self.previous_kernel, &mut public_inputs); - - public_inputs.finish_tail() + KernelCircuitPublicInputs { + aggregation_object: previous_public_inputs.aggregation_object, + rollup_validation_requests: previous_public_inputs.validation_requests.for_rollup, + end, + constants: previous_public_inputs.constants, + start_state: self.start_state, + end_state, + revert_code: previous_public_inputs.revert_code + } } } @@ -106,9 +119,8 @@ mod tests { }; use dep::types::{ abis::{ - kernel_circuit_public_inputs::{KernelCircuitPublicInputs, PublicKernelCircuitPublicInputsBuilder}, - kernel_data::PublicKernelData, nullifier_leaf_preimage::NullifierLeafPreimage, - membership_witness::PublicDataMembershipWitness + kernel_circuit_public_inputs::KernelCircuitPublicInputs, kernel_data::PublicKernelData, + nullifier_leaf_preimage::NullifierLeafPreimage, membership_witness::PublicDataMembershipWitness }, constants::{ MAX_NEW_NULLIFIERS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_PUBLIC_DATA_HINTS, @@ -118,7 +130,7 @@ mod tests { }, hash::silo_nullifier, public_data_tree_leaf_preimage::PublicDataTreeLeafPreimage, tests::{fixture_builder::FixtureBuilder, merkle_tree_utils::NonEmptyMerkleTree}, - utils::arrays::array_merge + partial_state_reference::PartialStateReference, utils::arrays::array_merge }; fn build_nullifier_tree() -> NonEmptyMerkleTree { @@ -159,6 +171,7 @@ mod tests { public_data_read_request_hints_builder: PublicDataReadRequestHintsBuilder, public_data_hints: BoundedVec, public_data_tree: NonEmptyMerkleTree, + start_state: PartialStateReference, } impl PublicKernelTailCircuitPrivateInputsBuilder { @@ -174,7 +187,8 @@ mod tests { nullifier_non_existent_read_request_hints_builder, public_data_read_request_hints_builder: PublicDataReadRequestHintsBuilder::new(MAX_PUBLIC_DATA_READS_PER_TX), public_data_hints: BoundedVec::new(), - public_data_tree: NonEmptyMerkleTree::empty() + public_data_tree: NonEmptyMerkleTree::empty(), + start_state: PartialStateReference::empty() }; builder.set_nullifiers_for_non_existent_read_request_hints(); builder @@ -190,7 +204,7 @@ mod tests { pub fn with_public_data_tree(&mut self) -> Self { let public_data_tree = build_public_data_tree(); self.public_data_tree = public_data_tree; - self.previous_kernel.historical_header.state.partial.public_data_tree.root = public_data_tree.get_root(); + self.start_state.public_data_tree.root = public_data_tree.get_root(); *self } @@ -299,7 +313,8 @@ mod tests { nullifier_read_request_hints: self.nullifier_read_request_hints_builder.to_hints(), nullifier_non_existent_read_request_hints: self.nullifier_non_existent_read_request_hints_builder.to_hints(), public_data_hints: self.public_data_hints.storage, - public_data_read_request_hints: self.public_data_read_request_hints_builder.to_hints() + public_data_read_request_hints: self.public_data_read_request_hints_builder.to_hints(), + start_state: self.start_state }; kernel.public_kernel_tail() diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr index da9ad715af6..52d86ebb826 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr @@ -30,7 +30,7 @@ struct CombinedAccumulatedData { } impl CombinedAccumulatedData { - pub fn recombine(non_revertible: PublicAccumulatedData, revertible: PublicAccumulatedData) -> Self { + pub fn combine(non_revertible: PublicAccumulatedData, revertible: PublicAccumulatedData) -> Self { CombinedAccumulatedData { new_note_hashes: array_merge(non_revertible.new_note_hashes, revertible.new_note_hashes).map(|n: SideEffect| n.value), new_nullifiers: array_merge(non_revertible.new_nullifiers, revertible.new_nullifiers).map(|n: SideEffectLinkedToNoteHash| n.value), diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/kernel_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/kernel_circuit_public_inputs.nr index b15b68d2365..c688e3f3558 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/kernel_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/kernel_circuit_public_inputs.nr @@ -1,6 +1,9 @@ -use crate::abis::{ +use crate::{ + abis::{ accumulated_data::CombinedAccumulatedData, combined_constant_data::CombinedConstantData, validation_requests::RollupValidationRequests +}, + partial_state_reference::PartialStateReference }; use crate::mocked::AggregationObject; @@ -9,5 +12,7 @@ struct KernelCircuitPublicInputs { rollup_validation_requests: RollupValidationRequests, end: CombinedAccumulatedData, constants: CombinedConstantData, + start_state: PartialStateReference, + end_state: PartialStateReference, revert_code: u8, } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs_builder.nr index 5aa04bfc44f..c2982c13e6c 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs_builder.nr @@ -8,8 +8,7 @@ use crate::{ }, validation_requests::validation_requests_builder::ValidationRequestsBuilder }, -mocked::AggregationObject, -traits::Empty + mocked::AggregationObject, partial_state_reference::PartialStateReference, traits::Empty }; struct PrivateKernelCircuitPublicInputsBuilder { @@ -37,6 +36,8 @@ impl PrivateKernelCircuitPublicInputsBuilder { rollup_validation_requests: self.validation_requests.to_rollup(), end: self.end.to_combined(), constants: self.constants, + start_state: PartialStateReference::empty(), + end_state: PartialStateReference::empty(), revert_code: 0 } } @@ -65,4 +66,4 @@ impl Empty for PrivateKernelCircuitPublicInputsBuilder { constants: CombinedConstantData::empty(), } } -} \ No newline at end of file +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr index 6d3dc6fefc4..5a0ff151e9b 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr @@ -2,14 +2,10 @@ use crate::{ abis::{ accumulated_data::{CombinedAccumulatedData, PublicAccumulatedDataBuilder}, combined_constant_data::CombinedConstantData, - kernel_circuit_public_inputs::{ - kernel_circuit_public_inputs::KernelCircuitPublicInputs, - public_kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs -}, + kernel_circuit_public_inputs::{public_kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs}, validation_requests::ValidationRequestsBuilder }, -mocked::AggregationObject, -traits::Empty + mocked::AggregationObject, traits::Empty }; struct PublicKernelCircuitPublicInputsBuilder { @@ -35,17 +31,6 @@ impl PublicKernelCircuitPublicInputsBuilder { revert_code: self.revert_code } } - - pub fn finish_tail(self) -> KernelCircuitPublicInputs { - KernelCircuitPublicInputs { - aggregation_object: self.aggregation_object, - rollup_validation_requests: self.validation_requests.to_rollup(), - // TODO: Sort by counters. - end: CombinedAccumulatedData::recombine(self.end_non_revertible.finish(), self.end.finish()), - constants: self.constants, - revert_code: self.revert_code - } - } } impl Empty for PublicKernelCircuitPublicInputsBuilder { @@ -59,4 +44,4 @@ impl Empty for PublicKernelCircuitPublicInputsBuilder { revert_code: 0 as u8, } } -} \ No newline at end of file +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr index 69f91e06593..7f363c3be46 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr @@ -24,7 +24,8 @@ use crate::{ VK_TREE_HEIGHT }, hash::silo_nullifier, header::Header, mocked::{AggregationObject, Proof, VerificationKey}, - tests::fixtures, transaction::tx_context::TxContext, traits::Empty + partial_state_reference::PartialStateReference, tests::fixtures, transaction::tx_context::TxContext, + traits::Empty }; struct FixtureBuilder { @@ -67,6 +68,10 @@ struct FixtureBuilder { // Counters. min_revertible_side_effect_counter: u32, counter: u32, + + // States. + start_state: PartialStateReference, + end_state: PartialStateReference, } impl FixtureBuilder { @@ -101,6 +106,8 @@ impl FixtureBuilder { revert_code: 0, min_revertible_side_effect_counter: 0, counter: 0, + start_state: PartialStateReference::empty(), + end_state: PartialStateReference::empty(), gas_used: GasUsed::empty(), gas_settings: GasSettings::empty() } @@ -231,6 +238,8 @@ impl FixtureBuilder { rollup_validation_requests, end, constants, + start_state: self.start_state, + end_state: self.end_state, revert_code: self.revert_code } } @@ -431,6 +440,8 @@ impl Empty for FixtureBuilder { revert_code: 0, min_revertible_side_effect_counter: 0, counter: 0, + start_state: PartialStateReference::empty(), + end_state: PartialStateReference::empty(), gas_settings: GasSettings::empty(), gas_used: GasUsed::empty(), } diff --git a/yarn-project/circuits.js/src/structs/kernel/kernel_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/kernel_circuit_public_inputs.ts index cb59c58b76d..9dafbec6bd9 100644 --- a/yarn-project/circuits.js/src/structs/kernel/kernel_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/kernel_circuit_public_inputs.ts @@ -1,6 +1,7 @@ import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { AggregationObject } from '../aggregation_object.js'; +import { PartialStateReference } from '../partial_state_reference.js'; import { RevertCode } from '../revert_code.js'; import { RollupValidationRequests } from '../rollup_validation_requests.js'; import { CombinedAccumulatedData } from './combined_accumulated_data.js'; @@ -28,6 +29,8 @@ export class KernelCircuitPublicInputs { * Data which is not modified by the circuits. */ public constants: CombinedConstantData, + public startState: PartialStateReference, + public endState: PartialStateReference, /** * Flag indicating whether the transaction reverted. */ @@ -60,6 +63,8 @@ export class KernelCircuitPublicInputs { reader.readObject(RollupValidationRequests), reader.readObject(CombinedAccumulatedData), reader.readObject(CombinedConstantData), + reader.readObject(PartialStateReference), + reader.readObject(PartialStateReference), reader.readObject(RevertCode), ); } @@ -70,6 +75,8 @@ export class KernelCircuitPublicInputs { RollupValidationRequests.empty(), CombinedAccumulatedData.empty(), CombinedConstantData.empty(), + PartialStateReference.empty(), + PartialStateReference.empty(), RevertCode.OK, ); } diff --git a/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_public_inputs.ts index cc7ac7fb8b4..4bc5bfa262c 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_public_inputs.ts @@ -3,6 +3,7 @@ import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { MAX_NEW_NULLIFIERS_PER_TX } from '../../constants.gen.js'; import { countAccumulatedItems, mergeAccumulatedData } from '../../utils/index.js'; import { AggregationObject } from '../aggregation_object.js'; +import { PartialStateReference } from '../partial_state_reference.js'; import { RevertCode } from '../revert_code.js'; import { RollupValidationRequests } from '../rollup_validation_requests.js'; import { ValidationRequests } from '../validation_requests.js'; @@ -135,6 +136,8 @@ export class PrivateKernelTailCircuitPublicInputs { this.forRollup.rollupValidationRequests, this.forRollup.end, this.constants, + PartialStateReference.empty(), + PartialStateReference.empty(), this.revertCode, ); } diff --git a/yarn-project/circuits.js/src/structs/kernel/public_kernel_tail_circuit_private_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/public_kernel_tail_circuit_private_inputs.ts index 0c760796c31..c7c310ecbb1 100644 --- a/yarn-project/circuits.js/src/structs/kernel/public_kernel_tail_circuit_private_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/public_kernel_tail_circuit_private_inputs.ts @@ -2,6 +2,7 @@ import { type Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; import { type MAX_PUBLIC_DATA_HINTS } from '../../constants.gen.js'; import { type NullifierNonExistentReadRequestHints } from '../non_existent_read_request_hints.js'; +import { type PartialStateReference } from '../partial_state_reference.js'; import { type PublicDataHint } from '../public_data_hint.js'; import { type PublicDataReadRequestHints } from '../public_data_read_request_hints.js'; import { type NullifierReadRequestHints } from '../read_request_hints.js'; @@ -23,6 +24,7 @@ export class PublicKernelTailCircuitPrivateInputs { public readonly nullifierNonExistentReadRequestHints: NullifierNonExistentReadRequestHints, public readonly publicDataHints: Tuple, public readonly publicDataReadRequestHints: PublicDataReadRequestHints, + public readonly startState: PartialStateReference, ) {} toBuffer() { @@ -32,6 +34,7 @@ export class PublicKernelTailCircuitPrivateInputs { this.nullifierNonExistentReadRequestHints, this.publicDataHints, this.publicDataReadRequestHints, + this.startState, ); } } diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index 753c7ca0db4..a78263d30a5 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -537,6 +537,8 @@ export function makeKernelCircuitPublicInputs(seed = 1, fullAccumulatedData = tr makeRollupValidationRequests(seed), makeCombinedAccumulatedData(seed, fullAccumulatedData), makeConstantData(seed + 0x100), + makePartialStateReference(seed + 0x200), + makePartialStateReference(seed + 0x200), RevertCode.OK, ); } diff --git a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts index 8cf2dddf9af..c7ab649f010 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -1249,6 +1249,8 @@ export function mapKernelCircuitPublicInputsFromNoir(inputs: KernelCircuitPublic mapRollupValidationRequestsFromNoir(inputs.rollup_validation_requests), mapCombinedAccumulatedDataFromNoir(inputs.end), mapCombinedConstantDataFromNoir(inputs.constants), + mapPartialStateReferenceFromNoir(inputs.start_state), + mapPartialStateReferenceFromNoir(inputs.end_state), mapRevertCodeFromNoir(inputs.revert_code), ); } @@ -1259,6 +1261,8 @@ export function mapKernelCircuitPublicInputsToNoir(inputs: KernelCircuitPublicIn rollup_validation_requests: mapRollupValidationRequestsToNoir(inputs.rollupValidationRequests), constants: mapCombinedConstantDataToNoir(inputs.constants), end: mapCombinedAccumulatedDataToNoir(inputs.end), + start_state: mapPartialStateReferenceToNoir(inputs.startState), + end_state: mapPartialStateReferenceToNoir(inputs.endState), revert_code: mapRevertCodeToNoir(inputs.revertCode), }; } @@ -1429,6 +1433,7 @@ export function mapPublicKernelTailCircuitPrivateInputsToNoir( ), public_data_hints: mapTuple(inputs.publicDataHints, mapPublicDataHintToNoir), public_data_read_request_hints: mapPublicDataReadRequestHintsToNoir(inputs.publicDataReadRequestHints), + start_state: mapPartialStateReferenceToNoir(inputs.startState), }; } diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts index 8f657d96009..aa721064412 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts @@ -145,7 +145,6 @@ describe('public_processor', () => { describe('with actual circuits', () => { let publicKernel: PublicKernelCircuitSimulator; let publicDataTree: AppendOnlyTree; - let header = Header.empty(); const mockTxWithPartialState = ( { @@ -161,14 +160,12 @@ describe('public_processor', () => { } = {}, seed = 1, ) => { - const tx = mockTx(seed, { + return mockTx(seed, { hasLogs, numberOfNonRevertiblePublicCallRequests, numberOfRevertiblePublicCallRequests, publicCallRequests, }); - tx.data.constants.historicalHeader.state = header.state; - return tx; }; beforeAll(async () => { @@ -192,16 +189,16 @@ describe('public_processor', () => { Fr.fromBuffer(publicDataTree.getRoot(true)), Number(publicDataTree.getNumLeaves(true)), ); - header = new Header( - header.lastArchive, - header.contentCommitment, - new StateReference( - header.state.l1ToL2MessageTree, - new PartialStateReference(header.state.partial.noteHashTree, header.state.partial.nullifierTree, snap), - ), - header.globalVariables, + + const header = Header.empty(); + const stateReference = new StateReference( + header.state.l1ToL2MessageTree, + new PartialStateReference(header.state.partial.noteHashTree, header.state.partial.nullifierTree, snap), ); + // Clone the whole state because somewhere down the line something is changing the public data root in header. + header.state = StateReference.fromBuffer(stateReference.toBuffer()); + db.getStateReference.mockResolvedValue(stateReference); db.getSiblingPath.mockResolvedValue(publicDataTree.getSiblingPath(0n, false)); db.getPreviousValueIndex.mockResolvedValue({ index: 0n, alreadyPresent: true }); db.getLeafPreimage.mockResolvedValue(new PublicDataTreeLeafPreimage(new Fr(1), new Fr(0), new Fr(0), 0n)); diff --git a/yarn-project/sequencer-client/src/sequencer/tail_phase_manager.ts b/yarn-project/sequencer-client/src/sequencer/tail_phase_manager.ts index ff26db04ef4..ffda5a3982f 100644 --- a/yarn-project/sequencer-client/src/sequencer/tail_phase_manager.ts +++ b/yarn-project/sequencer-client/src/sequencer/tail_phase_manager.ts @@ -125,12 +125,15 @@ export class TailPhaseManager extends AbstractPhaseManager { publicDataHints, ); + const currentState = await this.db.getStateReference(); + return new PublicKernelTailCircuitPrivateInputs( previousKernel, nullifierReadRequestHints, nullifierNonExistentReadRequestHints, publicDataHints, publicDataReadRequestHints, + currentState.partial, ); } From fe1bce6edcdd484f8eed3bf539b41bb584cf2a27 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Fri, 12 Apr 2024 19:51:30 +0000 Subject: [PATCH 07/15] Allow all-zero low leaf. --- .../src/reset/non_existent_read_request.nr | 16 ------ .../rollup-lib/src/base/base_rollup_inputs.nr | 51 ++----------------- .../indexed_tree/check_valid_low_leaf.nr | 14 ++--- .../types/src/merkle_tree/membership.nr | 10 ---- .../src/sequencer/public_processor.test.ts | 11 ++-- 5 files changed, 15 insertions(+), 87 deletions(-) diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/non_existent_read_request.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/non_existent_read_request.nr index 5cdd14d8480..afb50e68ce5 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/non_existent_read_request.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/non_existent_read_request.nr @@ -236,22 +236,6 @@ mod tests { ); } - #[test(should_fail_with="Cannot check non membership against empty leaf")] - fn test_reset_non_existent_read_requests_empty_leaf_failed() { - let read_requests = [ReadRequestContext { value: 10, counter: 50, contract_address: AztecAddress::zero() }]; - let (non_membership_hints, root) = get_non_membership_hints([0]); - let mut hint = non_membership_hints[0]; - hint.low_leaf_preimage = TestLeafPreimage { value: 0, next_value: 0 }; - let next_pending_value_indices = [1]; - reset_non_existent_read_requests( - read_requests, - [hint], - root, - sorted_pending_values, - next_pending_value_indices - ); - } - #[test(should_fail_with="Low leaf does not exist")] fn test_reset_non_existent_read_requests_invalid_preimage_failed() { let read_requests = [ReadRequestContext { value: 10, counter: 50, contract_address: AztecAddress::zero() }]; diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr index a9e9e772f59..1e725b9309a 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr @@ -178,16 +178,10 @@ impl BaseRollupInputs { } fn validate_and_process_public_state(self) -> AppendOnlyTreeSnapshot { - // TODO(#2521) - data read validation should happen against the current state of the tx and not the start state. - // Blocks all interesting usecases that read and write to the same public state in the same tx. - // https://aztecprotocol.slack.com/archives/C02M7VC7TN0/p1695809629015719?thread_ts=1695653252.007339&cid=C02M7VC7TN0 - - // Process public data reads and public data update requests for left input - // validate_public_data_reads( - // self.start_public_data_tree_root, - // self.kernel_data[0].public_inputs.end.public_data_reads, - // 0, - // self.new_public_data_reads_sibling_paths); + let kernel_state = self.kernel_data.public_inputs.end_state; + if !kernel_state.public_data_tree.eq(AppendOnlyTreeSnapshot::zero()) { + assert(kernel_state.public_data_tree.eq(self.start.public_data_tree), "Mismatch start state"); + } let end_public_data_tree_snapshot = insert_public_data_update_requests( self.start.public_data_tree, @@ -318,43 +312,6 @@ fn insert_public_data_update_requests( ) } -fn validate_public_data_reads( - tree_root: Field, - public_data_reads: [PublicDataRead; MAX_PUBLIC_DATA_READS_PER_TX], - public_data_reads_preimages: [PublicDataTreeLeafPreimage; MAX_PUBLIC_DATA_READS_PER_TX], - public_data_reads_witnesses: [PublicDataMembershipWitness; MAX_PUBLIC_DATA_READS_PER_TX] -) { - for i in 0..MAX_PUBLIC_DATA_READS_PER_TX { - let read = public_data_reads[i]; - let low_preimage = public_data_reads_preimages[i]; - let witness = public_data_reads_witnesses[i]; - - let is_low_empty = low_preimage.is_empty(); - let is_exact = low_preimage.slot == read.leaf_slot; - - let is_less_than_slot = full_field_less_than(low_preimage.slot, read.leaf_slot); - let is_next_greater_than = full_field_less_than(read.leaf_slot, low_preimage.next_slot); - let is_in_range = is_less_than_slot - & (is_next_greater_than | ((low_preimage.next_index == 0) & (low_preimage.next_slot == 0))); - - if (!read.is_empty()) { - assert(!is_low_empty, "public data read is not empty but low preimage is empty"); - if is_in_range { - assert_eq(read.value, 0, "low leaf for public data read is in range but value is not zero"); - } else { - assert(is_exact, "low leaf for public data read is invalid"); - assert_eq(read.value, low_preimage.value, "low leaf for public data has different value"); - } - assert_check_membership( - low_preimage.hash(), - witness.leaf_index, - witness.sibling_path, - tree_root - ); - } - } -} - #[test] fn consistent_not_hash_subtree_width() { assert_eq( diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/indexed_tree/check_valid_low_leaf.nr b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/indexed_tree/check_valid_low_leaf.nr index 77f685c978f..01b4136bded 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/indexed_tree/check_valid_low_leaf.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/indexed_tree/check_valid_low_leaf.nr @@ -6,9 +6,7 @@ pub fn assert_check_valid_low_leaf( ) where LEAF_PREIMAGE: IndexedTreeLeafPreimage { let low_key = low_leaf_preimage.get_key(); let next_key = low_leaf_preimage.get_next_key(); - let is_empty_leaf = (low_key == 0) & (next_key == 0); - assert(!is_empty_leaf, "Cannot check non membership against empty leaf"); assert(low_key.lt(key), "Key is not greater than the low leaf"); assert(key.lt(next_key) | (next_key == 0), "Key is not less than the next leaf"); } @@ -47,10 +45,14 @@ mod tests { assert_check_valid_low_leaf(key, leaf); } - #[test(should_fail_with="Cannot check non membership against empty leaf")] - fn test_assert_check_valid_low_leaf_failed_empty_leaf() { - let empty_leaf = TestLeafPreimage { value: 0, next_value: 0 }; - assert_check_valid_low_leaf(0, empty_leaf); + #[test] + fn test_assert_check_empty_low_leaf() { + // An all-zero low leaf should be valid. It could be used as the first dummy leaf in a tree. + // It's not possible to prove against an empty leaf at an uninitialized index. + // The membership check will fail because the leaf value hash(0, 0) is not 0. + let key = 12; + let leaf = TestLeafPreimage { value: 0, next_value: 0 }; + assert_check_valid_low_leaf(key, leaf); } #[test(should_fail_with="Key is not greater than the low leaf")] diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/membership.nr b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/membership.nr index 7d2a3e5d543..d549f269984 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/membership.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/membership.nr @@ -248,11 +248,6 @@ mod tests { assert_check_non_membership_at_index(1, 45); } - #[test(should_fail_with="Cannot check non membership against empty leaf")] - fn test_assert_check_non_membership_failed_empty_leaf() { - assert_check_non_membership_at_index(4, 25); - } - #[test(should_fail_with="Key is not greater than the low leaf")] fn test_assert_check_non_membership_failed_wrong_low_leaf() { assert_check_non_membership_at_index(3, 25); @@ -292,11 +287,6 @@ mod tests { conditionally_assert_check_membership_at_index(true, 1, leaf_preimages[1].get_key() + 1); } - #[test(should_fail_with="Cannot check non membership against empty leaf")] - fn test_conditionally_assert_check_membership_failed_not_exists_empty_leaf() { - conditionally_assert_check_membership_at_index(false, 4, 1); - } - #[test(should_fail_with="Key is not greater than the low leaf")] fn test_conditionally_assert_check_membership_failed_not_exists_wrong_low_leaf() { conditionally_assert_check_membership_at_index(false, 3, 25); diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts index aa721064412..bc9c12a1ce0 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts @@ -32,7 +32,6 @@ import { import { computePublicDataTreeLeafSlot } from '@aztec/circuits.js/hash'; import { fr, makeAztecAddress, makePublicCallRequest, makeSelector } from '@aztec/circuits.js/testing'; import { arrayNonEmptyLength, padArrayEnd } from '@aztec/foundation/collection'; -import { pedersenHash } from '@aztec/foundation/crypto'; import { openTmpStore } from '@aztec/kv-store/utils'; import { type AppendOnlyTree, Pedersen, StandardTree, newTree } from '@aztec/merkle-tree'; import { type PublicExecution, type PublicExecutionResult, type PublicExecutor, WASMSimulator } from '@aztec/simulator'; @@ -176,12 +175,8 @@ describe('public_processor', () => { 'PublicData', Fr, PUBLIC_DATA_TREE_HEIGHT, + 1, // Add a default low leaf for the public data hints to be proved against. ); - // Add a default low leaf for the public data hints to be proved against. - const defaultLeaves = [new PublicDataTreeLeafPreimage(new Fr(1), new Fr(0), new Fr(0), 0n)].map(l => - pedersenHash(l.toHashInputs()), - ); - await publicDataTree.appendLeaves(defaultLeaves); }); beforeEach(() => { @@ -195,13 +190,13 @@ describe('public_processor', () => { header.state.l1ToL2MessageTree, new PartialStateReference(header.state.partial.noteHashTree, header.state.partial.nullifierTree, snap), ); - // Clone the whole state because somewhere down the line something is changing the public data root in header. + // Clone the whole state because somewhere down the line (AbstractPhaseManager) the public data root is modified in the referenced header directly :/ header.state = StateReference.fromBuffer(stateReference.toBuffer()); db.getStateReference.mockResolvedValue(stateReference); db.getSiblingPath.mockResolvedValue(publicDataTree.getSiblingPath(0n, false)); db.getPreviousValueIndex.mockResolvedValue({ index: 0n, alreadyPresent: true }); - db.getLeafPreimage.mockResolvedValue(new PublicDataTreeLeafPreimage(new Fr(1), new Fr(0), new Fr(0), 0n)); + db.getLeafPreimage.mockResolvedValue(new PublicDataTreeLeafPreimage(new Fr(0), new Fr(0), new Fr(0), 0n)); publicKernel = new RealPublicKernelCircuitSimulator(new WASMSimulator()); processor = new PublicProcessor( From 6ad22e946197c82e4732486b09a2df99f49ed86a Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Sun, 14 Apr 2024 13:52:59 +0000 Subject: [PATCH 08/15] Silo storage slot with correct address. --- .../src/structs/contract_storage_read.ts | 5 +- .../contract_storage_update_request.ts | 4 +- .../src/sequencer/abstract_phase_manager.ts | 22 +-------- .../src/sequencer/public_processor.test.ts | 48 ++++++++++++------- .../simulator/src/public/execution.ts | 16 ++----- .../simulator/src/public/index.test.ts | 5 ++ .../simulator/src/public/state_actions.ts | 2 + .../src/public/transitional_adaptors.ts | 4 +- 8 files changed, 53 insertions(+), 53 deletions(-) diff --git a/yarn-project/circuits.js/src/structs/contract_storage_read.ts b/yarn-project/circuits.js/src/structs/contract_storage_read.ts index 2c376a1d3f5..52d708f0ef1 100644 --- a/yarn-project/circuits.js/src/structs/contract_storage_read.ts +++ b/yarn-project/circuits.js/src/structs/contract_storage_read.ts @@ -1,3 +1,4 @@ +import { type AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; @@ -24,6 +25,7 @@ export class ContractStorageRead { * Note: Not serialized */ public readonly sideEffectCounter?: number, + public contractAddress?: AztecAddress, // TODO: Should not be optional. This is a temporary hack to silo the storage slot with the correct address for nested executions. ) {} static from(args: { @@ -39,8 +41,9 @@ export class ContractStorageRead { * Optional side effect counter tracking position of this event in tx execution. */ sideEffectCounter?: number; + contractAddress?: AztecAddress; }) { - return new ContractStorageRead(args.storageSlot, args.currentValue, args.sideEffectCounter); + return new ContractStorageRead(args.storageSlot, args.currentValue, args.sideEffectCounter, args.contractAddress); } toBuffer() { diff --git a/yarn-project/circuits.js/src/structs/contract_storage_update_request.ts b/yarn-project/circuits.js/src/structs/contract_storage_update_request.ts index 8508fa8c7b8..378279d55bb 100644 --- a/yarn-project/circuits.js/src/structs/contract_storage_update_request.ts +++ b/yarn-project/circuits.js/src/structs/contract_storage_update_request.ts @@ -1,3 +1,4 @@ +import { type AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { type FieldsOf } from '@aztec/foundation/types'; @@ -24,6 +25,7 @@ export class ContractStorageUpdateRequest { * Optional side effect counter tracking position of this event in tx execution. */ public readonly sideEffectCounter?: number, + public contractAddress?: AztecAddress, // TODO: Should not be optional. This is a temporary hack to silo the storage slot with the correct address for nested executions. ) {} toBuffer() { @@ -50,7 +52,7 @@ export class ContractStorageUpdateRequest { * @returns The array. */ static getFields(fields: FieldsOf) { - return [fields.storageSlot, fields.newValue, fields.sideEffectCounter] as const; + return [fields.storageSlot, fields.newValue, fields.sideEffectCounter, fields.contractAddress] as const; } static empty() { diff --git a/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts b/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts index ca12297b5fa..b8f6fc109b5 100644 --- a/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts +++ b/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts @@ -500,29 +500,9 @@ function patchPublicStorageActionOrdering( // so the returned result will be a subset of the public kernel output. const simPublicDataReads = collectPublicDataReads(execResult); - // verify that each read is in the kernel output - for (const read of simPublicDataReads) { - if (!publicDataReads.find(item => item.equals(read))) { - throw new Error( - `Public data reads from simulator do not match those from public kernel.\nFrom simulator: ${simPublicDataReads - .map(p => p.toFriendlyJSON()) - .join(', ')}\nFrom public kernel: ${publicDataReads.map(i => i.toFriendlyJSON()).join(', ')}`, - ); - } - } const simPublicDataUpdateRequests = collectPublicDataUpdateRequests(execResult); - for (const update of simPublicDataUpdateRequests) { - if (!publicDataUpdateRequests.find(item => item.equals(update))) { - throw new Error( - `Public data update requests from simulator do not match those from public kernel.\nFrom simulator: ${simPublicDataUpdateRequests - .map(p => p.toFriendlyJSON()) - .join(', ')}\nFrom public kernel revertible: ${publicDataUpdateRequests - .map(i => i.toFriendlyJSON()) - .join(', ')}`, - ); - } - } + // We only want to reorder the items from the public inputs of the // most recently processed top/enqueued call. diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts index bc9c12a1ce0..21e1794d517 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts @@ -360,7 +360,9 @@ describe('public_processor', () => { // Setup PublicExecutionResultBuilder.fromPublicCallRequest({ request: publicCallRequests[0], - contractStorageUpdateRequests: [new ContractStorageUpdateRequest(contractSlotA, fr(0x101))], + contractStorageUpdateRequests: [ + new ContractStorageUpdateRequest(contractSlotA, fr(0x101), 11, baseContractAddress), + ], }).build(), // App Logic @@ -371,8 +373,8 @@ describe('public_processor', () => { from: publicCallRequests[1].contractAddress, tx: makeFunctionCall(baseContractAddress, makeSelector(5)), contractStorageUpdateRequests: [ - new ContractStorageUpdateRequest(contractSlotA, fr(0x102)), - new ContractStorageUpdateRequest(contractSlotB, fr(0x151)), + new ContractStorageUpdateRequest(contractSlotA, fr(0x102), 13, baseContractAddress), + new ContractStorageUpdateRequest(contractSlotB, fr(0x151), 14, baseContractAddress), ], }).build(), PublicExecutionResultBuilder.fromFunctionCall({ @@ -390,7 +392,9 @@ describe('public_processor', () => { PublicExecutionResultBuilder.fromFunctionCall({ from: publicCallRequests[1].contractAddress, tx: makeFunctionCall(baseContractAddress, makeSelector(5)), - contractStorageUpdateRequests: [new ContractStorageUpdateRequest(contractSlotC, fr(0x201))], + contractStorageUpdateRequests: [ + new ContractStorageUpdateRequest(contractSlotC, fr(0x201), 12, baseContractAddress), + ], }).build(), ], }).build(), @@ -464,14 +468,16 @@ describe('public_processor', () => { // Setup PublicExecutionResultBuilder.fromPublicCallRequest({ request: publicCallRequests[0], - contractStorageUpdateRequests: [new ContractStorageUpdateRequest(contractSlotA, fr(0x101))], + contractStorageUpdateRequests: [ + new ContractStorageUpdateRequest(contractSlotA, fr(0x101), 11, baseContractAddress), + ], nestedExecutions: [ PublicExecutionResultBuilder.fromFunctionCall({ from: publicCallRequests[1].contractAddress, tx: makeFunctionCall(baseContractAddress, makeSelector(5)), contractStorageUpdateRequests: [ - new ContractStorageUpdateRequest(contractSlotA, fr(0x102)), - new ContractStorageUpdateRequest(contractSlotB, fr(0x151)), + new ContractStorageUpdateRequest(contractSlotA, fr(0x102), 12, baseContractAddress), + new ContractStorageUpdateRequest(contractSlotB, fr(0x151), 13, baseContractAddress), ], }).build(), PublicExecutionResultBuilder.fromFunctionCall({ @@ -494,7 +500,9 @@ describe('public_processor', () => { PublicExecutionResultBuilder.fromFunctionCall({ from: publicCallRequests[1].contractAddress, tx: makeFunctionCall(baseContractAddress, makeSelector(5)), - contractStorageUpdateRequests: [new ContractStorageUpdateRequest(contractSlotC, fr(0x201))], + contractStorageUpdateRequests: [ + new ContractStorageUpdateRequest(contractSlotC, fr(0x201), 14, baseContractAddress), + ], }).build(), ], }).build(), @@ -558,14 +566,16 @@ describe('public_processor', () => { // Setup PublicExecutionResultBuilder.fromPublicCallRequest({ request: publicCallRequests[0], - contractStorageUpdateRequests: [new ContractStorageUpdateRequest(contractSlotA, fr(0x101))], + contractStorageUpdateRequests: [ + new ContractStorageUpdateRequest(contractSlotA, fr(0x101), 11, baseContractAddress), + ], nestedExecutions: [ PublicExecutionResultBuilder.fromFunctionCall({ from: publicCallRequests[1].contractAddress, tx: makeFunctionCall(baseContractAddress, makeSelector(5)), contractStorageUpdateRequests: [ - new ContractStorageUpdateRequest(contractSlotA, fr(0x102)), - new ContractStorageUpdateRequest(contractSlotB, fr(0x151)), + new ContractStorageUpdateRequest(contractSlotA, fr(0x102), 12, baseContractAddress), + new ContractStorageUpdateRequest(contractSlotB, fr(0x151), 13, baseContractAddress), ], }).build(), ], @@ -588,7 +598,9 @@ describe('public_processor', () => { PublicExecutionResultBuilder.fromFunctionCall({ from: publicCallRequests[1].contractAddress, tx: makeFunctionCall(baseContractAddress, makeSelector(5)), - contractStorageUpdateRequests: [new ContractStorageUpdateRequest(contractSlotC, fr(0x201))], + contractStorageUpdateRequests: [ + new ContractStorageUpdateRequest(contractSlotC, fr(0x201), 14, baseContractAddress), + ], }).build(), ], }).build(), @@ -656,8 +668,8 @@ describe('public_processor', () => { PublicExecutionResultBuilder.fromPublicCallRequest({ request: publicCallRequests[2], contractStorageUpdateRequests: [ - new ContractStorageUpdateRequest(contractSlotA, fr(0x101)), - new ContractStorageUpdateRequest(contractSlotB, fr(0x151)), + new ContractStorageUpdateRequest(contractSlotA, fr(0x101), 14, baseContractAddress), + new ContractStorageUpdateRequest(contractSlotB, fr(0x151), 15, baseContractAddress), ], }).build(), @@ -669,14 +681,16 @@ describe('public_processor', () => { from: publicCallRequests[1].contractAddress, tx: makeFunctionCall(baseContractAddress, makeSelector(5)), contractStorageUpdateRequests: [ - new ContractStorageUpdateRequest(contractSlotA, fr(0x101)), - new ContractStorageUpdateRequest(contractSlotC, fr(0x201)), + new ContractStorageUpdateRequest(contractSlotA, fr(0x101), 11, baseContractAddress), + new ContractStorageUpdateRequest(contractSlotC, fr(0x201), 12, baseContractAddress), ], }).build(), PublicExecutionResultBuilder.fromFunctionCall({ from: publicCallRequests[1].contractAddress, tx: makeFunctionCall(baseContractAddress, makeSelector(5)), - contractStorageUpdateRequests: [new ContractStorageUpdateRequest(contractSlotA, fr(0x102))], + contractStorageUpdateRequests: [ + new ContractStorageUpdateRequest(contractSlotA, fr(0x102), 13, baseContractAddress), + ], }).build(), ], }).build(), diff --git a/yarn-project/simulator/src/public/execution.ts b/yarn-project/simulator/src/public/execution.ts index 96ac9e84e97..be9a8fc6f1b 100644 --- a/yarn-project/simulator/src/public/execution.ts +++ b/yarn-project/simulator/src/public/execution.ts @@ -1,6 +1,5 @@ import { type SimulationError, type UnencryptedFunctionL2Logs } from '@aztec/circuit-types'; import { - type AztecAddress, type ContractStorageRead, type ContractStorageUpdateRequest, type Fr, @@ -81,10 +80,8 @@ export function isPublicExecutionResult( */ export function collectPublicDataReads(execResult: PublicExecutionResult): PublicDataRead[] { // HACK(#1622): part of temporary hack - may be able to remove this function after public state ordering is fixed - const contractAddress = execResult.execution.callContext.storageContractAddress; - const thisExecPublicDataReads = execResult.contractStorageReads.map(read => - contractStorageReadToPublicDataRead(read, contractAddress), + contractStorageReadToPublicDataRead(read), ); const unsorted = [ ...thisExecPublicDataReads, @@ -101,10 +98,8 @@ export function collectPublicDataReads(execResult: PublicExecutionResult): Publi */ export function collectPublicDataUpdateRequests(execResult: PublicExecutionResult): PublicDataUpdateRequest[] { // HACK(#1622): part of temporary hack - may be able to remove this function after public state ordering is fixed - const contractAddress = execResult.execution.callContext.storageContractAddress; - const thisExecPublicDataUpdateRequests = execResult.contractStorageUpdateRequests.map(update => - contractStorageUpdateRequestToPublicDataUpdateRequest(update, contractAddress), + contractStorageUpdateRequestToPublicDataUpdateRequest(update), ); const unsorted = [ ...thisExecPublicDataUpdateRequests, @@ -119,9 +114,9 @@ export function collectPublicDataUpdateRequests(execResult: PublicExecutionResul * @param contractAddress - the contract address of the read * @returns The public data read. */ -function contractStorageReadToPublicDataRead(read: ContractStorageRead, contractAddress: AztecAddress): PublicDataRead { +function contractStorageReadToPublicDataRead(read: ContractStorageRead): PublicDataRead { return new PublicDataRead( - computePublicDataTreeLeafSlot(contractAddress, read.storageSlot), + computePublicDataTreeLeafSlot(read.contractAddress!, read.storageSlot), computePublicDataTreeValue(read.currentValue), read.sideEffectCounter!, ); @@ -135,10 +130,9 @@ function contractStorageReadToPublicDataRead(read: ContractStorageRead, contract */ function contractStorageUpdateRequestToPublicDataUpdateRequest( update: ContractStorageUpdateRequest, - contractAddress: AztecAddress, ): PublicDataUpdateRequest { return new PublicDataUpdateRequest( - computePublicDataTreeLeafSlot(contractAddress, update.storageSlot), + computePublicDataTreeLeafSlot(update.contractAddress!, update.storageSlot), computePublicDataTreeValue(update.newValue), update.sideEffectCounter!, ); diff --git a/yarn-project/simulator/src/public/index.test.ts b/yarn-project/simulator/src/public/index.test.ts index d309a73f5e6..24eb9639cb2 100644 --- a/yarn-project/simulator/src/public/index.test.ts +++ b/yarn-project/simulator/src/public/index.test.ts @@ -142,11 +142,13 @@ describe('ACIR public execution simulator', () => { // There should be 2 storage updates, one for the recipient's balance and one for the total supply expect(result.contractStorageUpdateRequests).toEqual([ { + contractAddress, storageSlot: recipientBalanceStorageSlot, newValue: expectedBalance, sideEffectCounter: 3, }, { + contractAddress, storageSlot: totalSupplyStorageSlot, newValue: expectedTotalSupply, sideEffectCounter: 4, @@ -159,6 +161,7 @@ describe('ACIR public execution simulator', () => { // the updates expect(result.contractStorageReads).toEqual([ { + contractAddress, storageSlot: isMinterStorageSlot, currentValue: isMinter, sideEffectCounter: 0, @@ -217,11 +220,13 @@ describe('ACIR public execution simulator', () => { expect(result.contractStorageUpdateRequests).toEqual([ { + contractAddress, storageSlot: senderStorageSlot, newValue: expectedSenderBalance, sideEffectCounter: 1, // 1 read (sender balance) }, { + contractAddress, storageSlot: recipientStorageSlot, newValue: expectedRecipientBalance, sideEffectCounter: 3, // 1 read (sender balance), 1 write (new sender balance), 1 read (recipient balance) diff --git a/yarn-project/simulator/src/public/state_actions.ts b/yarn-project/simulator/src/public/state_actions.ts index a4b63c54a60..cd25d82f669 100644 --- a/yarn-project/simulator/src/public/state_actions.ts +++ b/yarn-project/simulator/src/public/state_actions.ts @@ -83,6 +83,7 @@ export class ContractStorageActionsCollector { public collect(): [ContractStorageRead[], ContractStorageUpdateRequest[]] { const reads = Array.from(this.contractStorageReads.entries()).map(([slot, valueAndCounter]) => ContractStorageRead.from({ + contractAddress: this.address, storageSlot: new Fr(slot), ...valueAndCounter, }), @@ -90,6 +91,7 @@ export class ContractStorageActionsCollector { const updateRequests = Array.from(this.contractStorageUpdateRequests.entries()).map(([slot, valuesAndCounter]) => ContractStorageUpdateRequest.from({ + contractAddress: this.address, storageSlot: new Fr(slot), ...valuesAndCounter, }), diff --git a/yarn-project/simulator/src/public/transitional_adaptors.ts b/yarn-project/simulator/src/public/transitional_adaptors.ts index 567852b124e..72f19836bf5 100644 --- a/yarn-project/simulator/src/public/transitional_adaptors.ts +++ b/yarn-project/simulator/src/public/transitional_adaptors.ts @@ -108,10 +108,10 @@ export async function convertAvmResults( const execution = executionContext.execution; const contractStorageReads: ContractStorageRead[] = newWorldState.storageReads.map( - read => new ContractStorageRead(read.slot, read.value, read.counter.toNumber()), + read => new ContractStorageRead(read.slot, read.value, read.counter.toNumber(), read.storageAddress), ); const contractStorageUpdateRequests: ContractStorageUpdateRequest[] = newWorldState.storageWrites.map( - write => new ContractStorageUpdateRequest(write.slot, write.value, write.counter.toNumber()), + write => new ContractStorageUpdateRequest(write.slot, write.value, write.counter.toNumber(), write.storageAddress), ); // We need to write the storage updates to the DB, because that's what the ACVM expects. // Assumes the updates are in the right order. From f86ce260df7b9418c83068cf57dbb583f1f6ede7 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Mon, 15 Apr 2024 09:09:37 +0000 Subject: [PATCH 09/15] Prove nullifier (non-)membership against latest root. --- .../crates/public-kernel-lib/src/public_kernel_tail.nr | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr index 29806a03f87..ec9d61f96ae 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr @@ -79,12 +79,11 @@ impl PublicKernelTailCircuitPrivateInputs { self.validate_public_data_hints(); let previous_public_inputs = self.previous_kernel.public_inputs; - let nullifier_tree_root = previous_public_inputs.constants.historical_header.state.partial.nullifier_tree.root; let request_processor = PublicValidationRequestProcessor::new( previous_public_inputs, self.nullifier_read_request_hints, self.nullifier_non_existent_read_request_hints, - nullifier_tree_root, + self.start_state.nullifier_tree.root, self.public_data_read_request_hints, self.public_data_hints ); @@ -196,8 +195,10 @@ mod tests { pub fn with_nullifier_tree(&mut self) -> Self { let nullifier_tree = build_nullifier_tree(); - self.previous_kernel.historical_header.state.partial.nullifier_tree.root = nullifier_tree.get_root(); self.nullifier_non_existent_read_request_hints_builder.set_nullifier_tree(nullifier_tree); + let tree_root = nullifier_tree.get_root(); + self.start_state.nullifier_tree.root = tree_root; + self.previous_kernel.historical_header.state.partial.nullifier_tree.root = tree_root; *self } From c4ff2450ca0529315c2683a049cf501a5e3a8736 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Mon, 15 Apr 2024 09:45:33 +0000 Subject: [PATCH 10/15] Fixes. --- .../rollup-lib/src/base/base_rollup_inputs.nr | 22 ++++++++++++++----- .../circuits.js/src/tests/factories.ts | 6 +++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr index 1e725b9309a..db3a8cddfb0 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr @@ -29,7 +29,7 @@ use dep::types::{ }, mocked::{AggregationObject, Proof}, partial_state_reference::PartialStateReference, public_data_tree_leaf::PublicDataTreeLeaf, - public_data_tree_leaf_preimage::PublicDataTreeLeafPreimage, + public_data_tree_leaf_preimage::PublicDataTreeLeafPreimage, traits::is_empty, utils::{field::{full_field_less_than, full_field_greater_than}, uint256::U256} }; @@ -66,6 +66,8 @@ impl BaseRollupInputs { == self.constants.global_variables.version, "kernel version does not match the rollup version" ); + self.validate_kernel_start_state(); + let rollup_validation_requests = self.kernel_data.public_inputs.rollup_validation_requests; // Verify the max block number @@ -177,12 +179,22 @@ impl BaseRollupInputs { calculate_subtree_root(leaves.map(|leaf:NullifierLeafPreimage| leaf.hash())) } - fn validate_and_process_public_state(self) -> AppendOnlyTreeSnapshot { - let kernel_state = self.kernel_data.public_inputs.end_state; - if !kernel_state.public_data_tree.eq(AppendOnlyTreeSnapshot::zero()) { - assert(kernel_state.public_data_tree.eq(self.start.public_data_tree), "Mismatch start state"); + fn validate_kernel_start_state(self) { + let kernel_state = self.kernel_data.public_inputs.start_state; + if !is_empty(kernel_state) { + assert( + kernel_state.note_hash_tree.eq(self.start.note_hash_tree), "Mismatch start state for note hash tree" + ); + assert( + kernel_state.nullifier_tree.eq(self.start.nullifier_tree), "Mismatch start state for nullifier tree" + ); + assert( + kernel_state.public_data_tree.eq(self.start.public_data_tree), "Mismatch start state for public data tree" + ); } + } + fn validate_and_process_public_state(self) -> AppendOnlyTreeSnapshot { let end_public_data_tree_snapshot = insert_public_data_update_requests( self.start.public_data_tree, self.kernel_data.public_inputs.end.public_data_update_requests.map( diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index 5c5d036e6e7..ba38ad27a04 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -57,6 +57,7 @@ import { MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, + MAX_PUBLIC_DATA_HINTS, MAX_PUBLIC_DATA_READS_PER_CALL, MAX_PUBLIC_DATA_READS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, @@ -98,7 +99,9 @@ import { PublicCallRequest, PublicCallStackItem, PublicCircuitPublicInputs, + PublicDataHint, PublicDataRead, + PublicDataReadRequestHintsBuilder, PublicDataTreeLeaf, PublicDataTreeLeafPreimage, PublicDataUpdateRequest, @@ -805,6 +808,9 @@ export function makePublicKernelTailCircuitPrivateInputs(seed = 1): PublicKernel makePublicKernelData(seed), NullifierReadRequestHintsBuilder.empty(), NullifierNonExistentReadRequestHintsBuilder.empty(), + makeTuple(MAX_PUBLIC_DATA_HINTS, PublicDataHint.empty, seed + 0x100), + PublicDataReadRequestHintsBuilder.empty(), + makePartialStateReference(seed + 0x200), ); } From c78aa16f39deded1945f0a4f2ec93952e848422a Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Mon, 15 Apr 2024 11:08:33 +0000 Subject: [PATCH 11/15] Fix formatting. --- yarn-project/simulator/src/public/tail_phase_manager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn-project/simulator/src/public/tail_phase_manager.ts b/yarn-project/simulator/src/public/tail_phase_manager.ts index 6ae351c8d96..548647b95b2 100644 --- a/yarn-project/simulator/src/public/tail_phase_manager.ts +++ b/yarn-project/simulator/src/public/tail_phase_manager.ts @@ -89,7 +89,7 @@ export class TailPhaseManager extends AbstractPhaseManager { private async simulate( previousOutput: PublicKernelCircuitPublicInputs, previousProof: Proof, -): Promise<[PublicKernelTailCircuitPrivateInputs, KernelCircuitPublicInputs]> { + ): Promise<[PublicKernelTailCircuitPrivateInputs, KernelCircuitPublicInputs]> { const inputs = await this.buildPrivateInputs(previousOutput, previousProof); return [inputs, await this.publicKernel.publicKernelCircuitTail(inputs)]; } From 92b4589f66603bde1e0ee8022a4a82bfb3fa78eb Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Mon, 15 Apr 2024 14:34:14 +0000 Subject: [PATCH 12/15] Update names. --- .../src/public_data_read_request_reset.nr | 6 +- .../public_validation_request_processor.nr | 2 +- .../src/reset/mutable_data_read_request.nr | 127 +++++++++--------- .../public_data_read_request_hints_builder.nr | 8 +- .../src/types/public_data_hint.nr | 4 +- ...ild_public_data_read_request_hints.test.ts | 30 ++--- .../build_public_data_read_request_hints.ts | 2 +- .../structs/public_data_read_request_hints.ts | 30 ++--- .../src/type_conversion.ts | 10 +- 9 files changed, 111 insertions(+), 108 deletions(-) diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_data_read_request_reset.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_data_read_request_reset.nr index 1524ad60544..7c6b6634074 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_data_read_request_reset.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_data_read_request_reset.nr @@ -1,9 +1,9 @@ -use crate::reset::{mutable_data_read_request::SettledDataReadHint, read_request::{PendingReadHint, ReadRequestStatus}}; +use crate::reset::{mutable_data_read_request::LeafDataReadHint, read_request::{PendingReadHint, ReadRequestStatus}}; use dep::types::constants::MAX_PUBLIC_DATA_READS_PER_TX; -// The MAX_PUBLIC_DATA_READS_PER_TX for pending_read_hints and settled_read_hints can change if we create various circuits that deal with different number of reads. +// The MAX_PUBLIC_DATA_READS_PER_TX for pending_read_hints and leaf_data_read_hints can change if we create various circuits that deal with different number of reads. struct PublicDataReadRequestHints { read_request_statuses: [ReadRequestStatus; MAX_PUBLIC_DATA_READS_PER_TX], pending_read_hints: [PendingReadHint; MAX_PUBLIC_DATA_READS_PER_TX], - settled_read_hints: [SettledDataReadHint; MAX_PUBLIC_DATA_READS_PER_TX], + leaf_data_read_hints: [LeafDataReadHint; MAX_PUBLIC_DATA_READS_PER_TX], } diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_validation_request_processor.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_validation_request_processor.nr index 0a46a3cb16c..4a74f99fd5b 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_validation_request_processor.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_validation_request_processor.nr @@ -121,7 +121,7 @@ impl PublicValidationRequestProcessor { self.pending_public_data_writes, self.public_data_hints, hints.pending_read_hints, - hints.settled_read_hints + hints.leaf_data_read_hints ); } } diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/mutable_data_read_request.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/mutable_data_read_request.nr index 13c3ffb4d4d..a86ab40f20d 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/mutable_data_read_request.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/mutable_data_read_request.nr @@ -4,20 +4,20 @@ use dep::types::{ traits::{Empty, is_empty} }; -trait SettledDataHint { +trait LeafDataHint { fn leaf_slot(self) -> Field; fn value(self) -> Field; fn override_counter(self) -> u32; } -struct SettledDataReadHint { +struct LeafDataReadHint { read_request_index: u64, - settled_data_hint_index: u64, + data_hint_index: u64, } -impl SettledDataReadHint { +impl LeafDataReadHint { pub fn nada(read_request_len: u64) -> Self { - SettledDataReadHint { read_request_index: read_request_len, settled_data_hint_index: 0 } + LeafDataReadHint { read_request_index: read_request_len, data_hint_index: 0 } } } @@ -46,16 +46,16 @@ fn validate_pending_read_requests( +fn validate_leaf_data_read_requests( read_requests: [PublicDataRead; READ_REQUEST_LEN], - settled_data_hints: [H; NUM_SETTLED_DATA_HINTS], - hints: [SettledDataReadHint; NUM_SETTLED_READS] -) where H: SettledDataHint { - for i in 0..NUM_SETTLED_READS { + leaf_data_hints: [H; NUM_LEAF_DATA_HINTS], + hints: [LeafDataReadHint; NUM_LEAF_DATA_READS] +) where H: LeafDataHint { + for i in 0..NUM_LEAF_DATA_READS { let read_request_index = hints[i].read_request_index; if read_request_index != READ_REQUEST_LEN { let read_request = read_requests[read_request_index]; - let data_hint = settled_data_hints[hints[i].settled_data_hint_index]; + let data_hint = leaf_data_hints[hints[i].data_hint_index]; assert( read_request.leaf_slot == data_hint.leaf_slot(), "Hinted slot does not match read request" ); @@ -66,11 +66,11 @@ fn validate_settled_read_requests( +fn ensure_all_read_requests_are_verified( read_requests: [PublicDataRead; READ_REQUEST_LEN], read_request_statuses: [ReadRequestStatus; READ_REQUEST_LEN], pending_read_hints: [PendingReadHint; NUM_PENDING_READS], - settled_read_hints: [SettledDataReadHint; NUM_SETTLED_READS] + leaf_data_read_hints: [LeafDataReadHint; NUM_LEAF_DATA_READS] ) { for i in 0..READ_REQUEST_LEN { let read_request = read_requests[i]; @@ -82,7 +82,7 @@ fn ensure_all_read_requests_are_verified( +pub fn reset_mutable_data_read_requests( read_requests: [PublicDataRead; READ_REQUEST_LEN], read_request_statuses: [ReadRequestStatus; READ_REQUEST_LEN], data_writes: [PublicDataUpdateRequest; PENDING_VALUE_LEN], - settled_data_hints: [H; NUM_SETTLED_DATA_HINTS], + leaf_data_hints: [H; NUM_LEAF_DATA_HINTS], pending_read_hints: [PendingReadHint; NUM_PENDING_READS], - settled_read_hints: [SettledDataReadHint; NUM_SETTLED_READS] -) where H: SettledDataHint { + leaf_data_read_hints: [LeafDataReadHint; NUM_LEAF_DATA_READS] +) where H: LeafDataHint { validate_pending_read_requests(read_requests, data_writes, pending_read_hints); - validate_settled_read_requests(read_requests, settled_data_hints, settled_read_hints); + validate_leaf_data_read_requests(read_requests, leaf_data_hints, leaf_data_read_hints); ensure_all_read_requests_are_verified( read_requests, read_request_statuses, pending_read_hints, - settled_read_hints + leaf_data_read_hints ); } mod tests { use crate::reset::{ mutable_data_read_request::{ - ensure_all_read_requests_are_verified, reset_mutable_data_read_requests, SettledDataHint, - SettledDataReadHint, validate_pending_read_requests, validate_settled_read_requests + ensure_all_read_requests_are_verified, reset_mutable_data_read_requests, LeafDataHint, + LeafDataReadHint, validate_pending_read_requests, validate_leaf_data_read_requests }, read_request::{PendingReadHint, ReadRequestState, ReadRequestStatus} }; use dep::types::{abis::{public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest}}; - struct TestDataHint { + struct TestLeafDataHint { leaf_slot: Field, value: Field, } - impl SettledDataHint for TestDataHint { + impl LeafDataHint for TestLeafDataHint { fn leaf_slot(self) -> Field { self.leaf_slot } @@ -147,10 +147,10 @@ mod tests { PublicDataUpdateRequest { leaf_slot: 44, new_value: 400 } ]; - global settled_data_hints = [ - TestDataHint { leaf_slot: 7, value: 70 }, - TestDataHint { leaf_slot: 6, value: 60 }, - TestDataHint { leaf_slot: 5, value: 50 }, + global leaf_data_hints = [ + TestLeafDataHint { leaf_slot: 7, value: 70 }, + TestLeafDataHint { leaf_slot: 6, value: 60 }, + TestLeafDataHint { leaf_slot: 5, value: 50 }, ]; fn create_pending_read_requests(data_write_indices: [u64; N]) -> ([PublicDataRead; N], [PendingReadHint; N]) { @@ -164,15 +164,13 @@ mod tests { (read_requests, hints.storage) } - fn create_settled_read_requests(settled_data_hint_indices: [u64; N]) -> ([PublicDataRead; N], [SettledDataReadHint; N]) { - let read_requests = settled_data_hint_indices.map( - |settled_data_hint_index: u64| PublicDataRead { leaf_slot: settled_data_hints[settled_data_hint_index].leaf_slot, value: settled_data_hints[settled_data_hint_index].value } + fn create_leaf_data_read_requests(data_hint_indices: [u64; N]) -> ([PublicDataRead; N], [LeafDataReadHint; N]) { + let read_requests = data_hint_indices.map( + |data_hint_index: u64| PublicDataRead { leaf_slot: leaf_data_hints[data_hint_index].leaf_slot, value: leaf_data_hints[data_hint_index].value } ); let mut hints = BoundedVec::new(); for i in 0..N { - hints.push( - SettledDataReadHint { read_request_index: i, settled_data_hint_index: settled_data_hint_indices[i] } - ); + hints.push(LeafDataReadHint { read_request_index: i, data_hint_index: data_hint_indices[i] }); } (read_requests, hints.storage) } @@ -211,45 +209,45 @@ mod tests { } #[test] - fn reset_settled_reads_succeeds() { - let (read_requests, hints) = create_settled_read_requests([2, 1, 0]); - validate_settled_read_requests(read_requests, settled_data_hints, hints); + fn reset_leaf_data_reads_succeeds() { + let (read_requests, hints) = create_leaf_data_read_requests([2, 1, 0]); + validate_leaf_data_read_requests(read_requests, leaf_data_hints, hints); } #[test] - fn reset_settled_reads_repeated_values() { - let (read_requests, hints) = create_settled_read_requests([1, 0, 1, 0]); - validate_settled_read_requests(read_requests, settled_data_hints, hints); + fn reset_leaf_data_reads_repeated_values() { + let (read_requests, hints) = create_leaf_data_read_requests([1, 0, 1, 0]); + validate_leaf_data_read_requests(read_requests, leaf_data_hints, hints); } #[test] - fn reset_settled_reads_skips_nada() { + fn reset_leaf_data_reads_skips_nada() { let read_requests = [PublicDataRead { leaf_slot: 88, value: 9999 }]; - let hints = [SettledDataReadHint::nada(1)]; - validate_settled_read_requests(read_requests, settled_data_hints, hints); + let hints = [LeafDataReadHint::nada(1)]; + validate_leaf_data_read_requests(read_requests, leaf_data_hints, hints); } #[test(should_fail_with=""Hinted slot does not match read request")] - fn reset_settled_reads_wrong_slot_fails() { - let mut (read_requests, hints) = create_settled_read_requests([1]); - hints[0].settled_data_hint_index = 0; - validate_settled_read_requests(read_requests, settled_data_hints, hints); + fn reset_leaf_reads_wrong_slot_fails() { + let mut (read_requests, hints) = create_leaf_data_read_requests([1]); + hints[0].data_hint_index = 0; + validate_leaf_data_read_requests(read_requests, leaf_data_hints, hints); } #[test(should_fail_with=""Hinted value does not match read request")] - fn reset_settled_reads_wrong_value_fails() { - let mut (read_requests, hints) = create_settled_read_requests([1]); + fn reset_leaf_reads_wrong_value_fails() { + let mut (read_requests, hints) = create_leaf_data_read_requests([1]); read_requests[0].value += 1; - validate_settled_read_requests(read_requests, settled_data_hints, hints); + validate_leaf_data_read_requests(read_requests, leaf_data_hints, hints); } #[test] fn ensure_all_read_requests_are_verified_succeeds() { let mut (pending_read_requests, pending_read_hints) = create_pending_read_requests([1]); - let mut (settled_read_requests, settled_read_hints) = create_settled_read_requests([0, 1]); - let read_requests = [settled_read_requests[0], pending_read_requests[0], settled_read_requests[1]]; + let mut (leaf_read_requests, leaf_data_read_hints) = create_leaf_data_read_requests([0, 1]); + let read_requests = [leaf_read_requests[0], pending_read_requests[0], leaf_read_requests[1]]; pending_read_hints[0].read_request_index = 1; - settled_read_hints[1].read_request_index = 2; + leaf_data_read_hints[1].read_request_index = 2; let statuses = [ ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 0 }, @@ -257,7 +255,12 @@ mod tests { ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 1 } ]; - ensure_all_read_requests_are_verified(read_requests, statuses, pending_read_hints, settled_read_hints); + ensure_all_read_requests_are_verified( + read_requests, + statuses, + pending_read_hints, + leaf_data_read_hints + ); } #[test(should_fail_with="Hinted pending read request does not match status")] @@ -271,8 +274,8 @@ mod tests { } #[test(should_fail_with="Hinted settled read request does not match status")] - fn ensure_all_read_requests_are_verified_wrong_settled_hint_index_fails() { - let (read_requests, hints) = create_settled_read_requests([0, 1]); + fn ensure_all_read_requests_are_verified_wrong_leaf_hint_index_fails() { + let (read_requests, hints) = create_leaf_data_read_requests([0, 1]); let statuses = [ ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 0 }, ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 0 } @@ -282,7 +285,7 @@ mod tests { #[test(should_fail_with="Read request status must be PENDING or SETTLED")] fn ensure_all_read_requests_are_verified_wrong_status_fails() { - let (read_requests, hints) = create_settled_read_requests([0]); + let (read_requests, hints) = create_leaf_data_read_requests([0]); let statuses = [ReadRequestStatus { state: ReadRequestState.NADA, hint_index: 0 }]; ensure_all_read_requests_are_verified(read_requests, statuses, [], hints); } @@ -290,13 +293,13 @@ mod tests { #[test] fn reset_mutable_data_read_requests_succeeds() { let mut (pending_read_requests, pending_read_hints) = create_pending_read_requests([3, 1]); - let mut (settled_read_requests, settled_read_hints) = create_settled_read_requests([0, 1]); + let mut (leaf_read_requests, leaf_data_read_hints) = create_leaf_data_read_requests([0, 1]); let read_requests = [ - settled_read_requests[0], pending_read_requests[0], pending_read_requests[1], settled_read_requests[1] + leaf_read_requests[0], pending_read_requests[0], pending_read_requests[1], leaf_read_requests[1] ]; pending_read_hints[0].read_request_index = 1; pending_read_hints[1].read_request_index = 2; - settled_read_hints[1].read_request_index = 3; + leaf_data_read_hints[1].read_request_index = 3; let statuses = [ ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 0 }, @@ -309,9 +312,9 @@ mod tests { read_requests, statuses, data_writes, - settled_data_hints, + leaf_data_hints, pending_read_hints, - settled_read_hints + leaf_data_read_hints ); } } diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/public_data_read_request_hints_builder.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/public_data_read_request_hints_builder.nr index a80b23febf4..d22a0c1e7f1 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/public_data_read_request_hints_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/public_data_read_request_hints_builder.nr @@ -1,13 +1,13 @@ use crate::{ public_data_read_request_reset::PublicDataReadRequestHints, - reset::{mutable_data_read_request::SettledDataReadHint, read_request::{PendingReadHint, ReadRequestStatus}} + reset::{mutable_data_read_request::LeafDataReadHint, read_request::{PendingReadHint, ReadRequestStatus}} }; use dep::types::constants::MAX_PUBLIC_DATA_READS_PER_TX; struct PublicDataReadRequestHintsBuilder { read_request_statuses: [ReadRequestStatus; MAX_PUBLIC_DATA_READS_PER_TX], pending_read_hints: BoundedVec, - settled_read_hints: BoundedVec, + leaf_data_read_hints: BoundedVec, } impl PublicDataReadRequestHintsBuilder { @@ -15,7 +15,7 @@ impl PublicDataReadRequestHintsBuilder { PublicDataReadRequestHintsBuilder { read_request_statuses: [ReadRequestStatus::empty(); MAX_PUBLIC_DATA_READS_PER_TX], pending_read_hints: BoundedVec { storage: [PendingReadHint::nada(read_request_len); MAX_PUBLIC_DATA_READS_PER_TX], len: 0 }, - settled_read_hints: BoundedVec { storage: [SettledDataReadHint::nada(read_request_len); MAX_PUBLIC_DATA_READS_PER_TX], len: 0 } + leaf_data_read_hints: BoundedVec { storage: [LeafDataReadHint::nada(read_request_len); MAX_PUBLIC_DATA_READS_PER_TX], len: 0 } } } @@ -23,7 +23,7 @@ impl PublicDataReadRequestHintsBuilder { PublicDataReadRequestHints { read_request_statuses: self.read_request_statuses, pending_read_hints: self.pending_read_hints.storage, - settled_read_hints: self.settled_read_hints.storage + leaf_data_read_hints: self.leaf_data_read_hints.storage } } } diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/types/public_data_hint.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/types/public_data_hint.nr index b9d9064dc61..28a3eb74cb0 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/types/public_data_hint.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/types/public_data_hint.nr @@ -1,4 +1,4 @@ -use crate::reset::{mutable_data_read_request::SettledDataHint}; +use crate::reset::{mutable_data_read_request::LeafDataHint}; use dep::types::{ abis::membership_witness::PublicDataMembershipWitness, public_data_tree_leaf_preimage::PublicDataTreeLeafPreimage @@ -12,7 +12,7 @@ struct PublicDataHint { leaf_preimage: PublicDataTreeLeafPreimage, } -impl SettledDataHint for PublicDataHint { +impl LeafDataHint for PublicDataHint { fn leaf_slot(self) -> Field { self.leaf_slot } diff --git a/yarn-project/circuits.js/src/hints/build_public_data_read_request_hints.test.ts b/yarn-project/circuits.js/src/hints/build_public_data_read_request_hints.test.ts index b2bb83868eb..164256ede3e 100644 --- a/yarn-project/circuits.js/src/hints/build_public_data_read_request_hints.test.ts +++ b/yarn-project/circuits.js/src/hints/build_public_data_read_request_hints.test.ts @@ -9,12 +9,12 @@ import { MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, } from '../constants.gen.js'; import { + LeafDataReadHint, PendingReadHint, PublicDataHint, PublicDataRead, PublicDataUpdateRequest, ReadRequestStatus, - SettledDataReadHint, } from '../structs/index.js'; import { buildPublicDataReadRequestHints } from './build_public_data_read_request_hints.js'; @@ -22,7 +22,7 @@ describe('buildPublicDataReadRequestHints', () => { let publicDataReads: Tuple; let expectedStatuses: Tuple; let expectedPendingHints: Tuple; - let expectedSettledHints: Tuple; + let expectedLeafDataHints: Tuple; const makePublicDataWrite = (leafSlot: number, value: number) => new PublicDataUpdateRequest(new Fr(leafSlot), new Fr(value)); @@ -35,8 +35,8 @@ describe('buildPublicDataReadRequestHints', () => { const makePublicDataRead = (leafSlot: number, value: number) => new PublicDataRead(new Fr(leafSlot), new Fr(value)); const makePendingHint = (readRequestIndex: number, hintIndex: number) => new PendingReadHint(readRequestIndex, hintIndex); - const makeSettledHint = (readRequestIndex: number, hintIndex: number) => - new SettledDataReadHint(readRequestIndex, hintIndex); + const makeLeafDataHint = (readRequestIndex: number, hintIndex: number) => + new LeafDataReadHint(readRequestIndex, hintIndex); const publicDataUpdateRequests = padArrayEnd( [makePublicDataWrite(55, 5555), makePublicDataWrite(77, 7777), makePublicDataWrite(99, 9999)], @@ -63,7 +63,7 @@ describe('buildPublicDataReadRequestHints', () => { const hints = buildHints(); expect(hints.readRequestStatuses).toEqual(expectedStatuses); expect(hints.pendingReadHints).toEqual(expectedPendingHints); - expect(hints.settledReadHints).toEqual(expectedSettledHints); + expect(hints.leafDataReadHints).toEqual(expectedLeafDataHints); }; beforeEach(() => { @@ -72,8 +72,8 @@ describe('buildPublicDataReadRequestHints', () => { expectedPendingHints = makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, () => PendingReadHint.nada(MAX_PUBLIC_DATA_READS_PER_TX), ); - expectedSettledHints = makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, () => - SettledDataReadHint.nada(MAX_PUBLIC_DATA_READS_PER_TX), + expectedLeafDataHints = makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, () => + LeafDataReadHint.nada(MAX_PUBLIC_DATA_READS_PER_TX), ); }); @@ -104,10 +104,10 @@ describe('buildPublicDataReadRequestHints', () => { expectedStatuses[1] = ReadRequestStatus.settled(1); expectedStatuses[2] = ReadRequestStatus.settled(2); expectedStatuses[3] = ReadRequestStatus.settled(3); - expectedSettledHints[0] = makeSettledHint(0, 2); - expectedSettledHints[1] = makeSettledHint(1, 4); - expectedSettledHints[2] = makeSettledHint(2, 3); - expectedSettledHints[3] = makeSettledHint(3, 0); + expectedLeafDataHints[0] = makeLeafDataHint(0, 2); + expectedLeafDataHints[1] = makeLeafDataHint(1, 4); + expectedLeafDataHints[2] = makeLeafDataHint(2, 3); + expectedLeafDataHints[3] = makeLeafDataHint(3, 0); buildAndCheckHints(); }); @@ -130,10 +130,10 @@ describe('buildPublicDataReadRequestHints', () => { expectedPendingHints[0] = makePendingHint(1, 0); expectedPendingHints[1] = makePendingHint(4, 2); expectedPendingHints[2] = makePendingHint(5, 1); - expectedSettledHints[0] = makeSettledHint(0, 3); - expectedSettledHints[1] = makeSettledHint(2, 4); - expectedSettledHints[2] = makeSettledHint(3, 0); - expectedSettledHints[3] = makeSettledHint(6, 0); + expectedLeafDataHints[0] = makeLeafDataHint(0, 3); + expectedLeafDataHints[1] = makeLeafDataHint(2, 4); + expectedLeafDataHints[2] = makeLeafDataHint(3, 0); + expectedLeafDataHints[3] = makeLeafDataHint(6, 0); buildAndCheckHints(); }); diff --git a/yarn-project/circuits.js/src/hints/build_public_data_read_request_hints.ts b/yarn-project/circuits.js/src/hints/build_public_data_read_request_hints.ts index 90531128d9a..4f7b15f312b 100644 --- a/yarn-project/circuits.js/src/hints/build_public_data_read_request_hints.ts +++ b/yarn-project/circuits.js/src/hints/build_public_data_read_request_hints.ts @@ -37,7 +37,7 @@ export function buildPublicDataReadRequestHints( if (!publicDataHints[hintIndex].value.equals(rr.value)) { throw new Error('Value being read does not match existing public data or pending writes.'); } - builder.addSettledReadRequest(i, hintIndex); + builder.addLeafDataReadRequest(i, hintIndex); } } diff --git a/yarn-project/circuits.js/src/structs/public_data_read_request_hints.ts b/yarn-project/circuits.js/src/structs/public_data_read_request_hints.ts index f70804f1211..8c6b324d63f 100644 --- a/yarn-project/circuits.js/src/structs/public_data_read_request_hints.ts +++ b/yarn-project/circuits.js/src/structs/public_data_read_request_hints.ts @@ -4,20 +4,20 @@ import { BufferReader, type Tuple, serializeToBuffer } from '@aztec/foundation/s import { MAX_PUBLIC_DATA_READS_PER_TX } from '../constants.gen.js'; import { PendingReadHint, ReadRequestState, ReadRequestStatus } from './read_request_hints.js'; -export class SettledDataReadHint { - constructor(public readRequestIndex: number, public settledDataHintIndex: number) {} +export class LeafDataReadHint { + constructor(public readRequestIndex: number, public dataHintIndex: number) {} static nada(readRequestLen: number) { - return new SettledDataReadHint(readRequestLen, 0); + return new LeafDataReadHint(readRequestLen, 0); } static fromBuffer(buffer: Buffer | BufferReader) { const reader = BufferReader.asReader(buffer); - return new SettledDataReadHint(reader.readNumber(), reader.readNumber()); + return new LeafDataReadHint(reader.readNumber(), reader.readNumber()); } toBuffer() { - return serializeToBuffer(this.readRequestIndex, this.settledDataHintIndex); + return serializeToBuffer(this.readRequestIndex, this.dataHintIndex); } } @@ -25,7 +25,7 @@ export class PublicDataReadRequestHints { constructor( public readRequestStatuses: Tuple, public pendingReadHints: Tuple, - public settledReadHints: Tuple, + public leafDataReadHints: Tuple, ) {} static fromBuffer(buffer: Buffer | BufferReader) { @@ -33,25 +33,25 @@ export class PublicDataReadRequestHints { return new PublicDataReadRequestHints( reader.readArray(MAX_PUBLIC_DATA_READS_PER_TX, ReadRequestStatus), reader.readArray(MAX_PUBLIC_DATA_READS_PER_TX, PendingReadHint), - reader.readArray(MAX_PUBLIC_DATA_READS_PER_TX, SettledDataReadHint), + reader.readArray(MAX_PUBLIC_DATA_READS_PER_TX, LeafDataReadHint), ); } toBuffer() { - return serializeToBuffer(this.readRequestStatuses, this.pendingReadHints, this.settledReadHints); + return serializeToBuffer(this.readRequestStatuses, this.pendingReadHints, this.leafDataReadHints); } } export class PublicDataReadRequestHintsBuilder { private hints: PublicDataReadRequestHints; private numPendingReadHints = 0; - private numSettledReadHints = 0; + private numLeafDataReadHints = 0; constructor() { this.hints = new PublicDataReadRequestHints( makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, ReadRequestStatus.nada), makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, () => PendingReadHint.nada(MAX_PUBLIC_DATA_READS_PER_TX)), - makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, () => SettledDataReadHint.nada(MAX_PUBLIC_DATA_READS_PER_TX)), + makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, () => LeafDataReadHint.nada(MAX_PUBLIC_DATA_READS_PER_TX)), ); } @@ -68,16 +68,16 @@ export class PublicDataReadRequestHintsBuilder { this.numPendingReadHints++; } - addSettledReadRequest(readRequestIndex: number, settledDataHintIndex: number) { + addLeafDataReadRequest(readRequestIndex: number, leafDataDataHintIndex: number) { this.hints.readRequestStatuses[readRequestIndex] = new ReadRequestStatus( ReadRequestState.SETTLED, - this.numSettledReadHints, + this.numLeafDataReadHints, ); - this.hints.settledReadHints[this.numSettledReadHints] = new SettledDataReadHint( + this.hints.leafDataReadHints[this.numLeafDataReadHints] = new LeafDataReadHint( readRequestIndex, - settledDataHintIndex, + leafDataDataHintIndex, ); - this.numSettledReadHints++; + this.numLeafDataReadHints++; } toHints() { diff --git a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts index c7ab649f010..80409a0fafd 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -31,6 +31,7 @@ import { KernelCircuitPublicInputs, type KernelData, type L2ToL1Message, + type LeafDataReadHint, MAX_NEW_L2_TO_L1_MSGS_PER_TX, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, @@ -95,7 +96,6 @@ import { type RootParityInputs, type RootRollupInputs, RootRollupPublicInputs, - type SettledDataReadHint, type SettledReadHint, SideEffect, SideEffectLinkedToNoteHash, @@ -173,13 +173,13 @@ import { type StorageUpdateRequest as StorageUpdateRequestNoir, } from './types/public_kernel_setup_types.js'; import { + type LeafDataReadHint as LeafDataReadHintNoir, type NullifierNonExistentReadRequestHints as NullifierNonExistentReadRequestHintsNoir, type NullifierNonMembershipHint as NullifierNonMembershipHintNoir, type PublicDataHint as PublicDataHintNoir, type PublicDataReadRequestHints as PublicDataReadRequestHintsNoir, type PublicDataUpdateRequest as PublicDataUpdateRequestNoir, type PublicKernelTailCircuitPrivateInputs as PublicKernelTailCircuitPrivateInputsNoir, - type SettledDataReadHint as SettledDataReadHintNoir, } from './types/public_kernel_tail_types.js'; import { type ArchiveRootMembershipWitness as ArchiveRootMembershipWitnessNoir, @@ -929,10 +929,10 @@ function mapPendingReadHintToNoir(hint: PendingReadHint): PendingReadHintNoir { }; } -function mapSettledDataReadHintToNoir(hint: SettledDataReadHint): SettledDataReadHintNoir { +function mapLeafDataReadHintToNoir(hint: LeafDataReadHint): LeafDataReadHintNoir { return { read_request_index: mapNumberToNoir(hint.readRequestIndex), - settled_data_hint_index: mapNumberToNoir(hint.settledDataHintIndex), + data_hint_index: mapNumberToNoir(hint.dataHintIndex), }; } @@ -988,7 +988,7 @@ function mapPublicDataReadRequestHintsToNoir(hints: PublicDataReadRequestHints): return { read_request_statuses: mapTuple(hints.readRequestStatuses, mapReadRequestStatusToNoir), pending_read_hints: mapTuple(hints.pendingReadHints, mapPendingReadHintToNoir), - settled_read_hints: mapTuple(hints.settledReadHints, mapSettledDataReadHintToNoir), + leaf_data_read_hints: mapTuple(hints.leafDataReadHints, mapLeafDataReadHintToNoir), }; } From f9a85f58d1588b9b1519109b871686f130095d2b Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Mon, 15 Apr 2024 14:34:33 +0000 Subject: [PATCH 13/15] Fix. --- .../src/structs/kernel/kernel_circuit_public_inputs.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/yarn-project/circuits.js/src/structs/kernel/kernel_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/kernel_circuit_public_inputs.ts index 9dafbec6bd9..0c92a421833 100644 --- a/yarn-project/circuits.js/src/structs/kernel/kernel_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/kernel_circuit_public_inputs.ts @@ -47,6 +47,8 @@ export class KernelCircuitPublicInputs { this.rollupValidationRequests, this.end, this.constants, + this.startState, + this.endState, this.revertCode, ); } From f44354aa7681e43a40587e3b78b1b694bf55f112 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Tue, 16 Apr 2024 12:52:57 +0000 Subject: [PATCH 14/15] Remove end state from kernel circuit public inputs. --- .../src/private_kernel_tail.nr | 1 - .../crates/public-kernel-lib/src/common.nr | 27 ++++++++++++++++++- .../src/public_kernel_tail.nr | 4 --- .../kernel_circuit_public_inputs.nr | 1 - ...te_kernel_circuit_public_inputs_builder.nr | 1 - .../crates/types/src/tests/fixture_builder.nr | 4 --- .../kernel/kernel_circuit_public_inputs.ts | 4 --- ...ivate_kernel_tail_circuit_public_inputs.ts | 1 - .../circuits.js/src/tests/factories.ts | 1 - .../src/type_conversion.ts | 2 -- 10 files changed, 26 insertions(+), 20 deletions(-) diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr index 2989b989391..551605f4426 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr @@ -183,7 +183,6 @@ mod tests { let public_inputs = builder.execute(); assert(is_empty(public_inputs.start_state)); - assert(is_empty(public_inputs.end_state)); } #[test] diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr index 1008e0c0f49..9edab82d251 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr @@ -186,7 +186,7 @@ pub fn update_public_end_non_revertible_values( propagate_new_nullifiers_non_revertible(public_call, circuit_outputs); propagate_new_note_hashes_non_revertible(public_call, circuit_outputs); - propagate_new_l2_to_l1_messages(public_call, circuit_outputs); + propagate_new_l2_to_l1_messages_non_revertible(public_call, circuit_outputs); propagate_valid_non_revertible_public_data_update_requests(public_call, circuit_outputs); } @@ -399,6 +399,31 @@ fn propagate_new_nullifiers( circuit_outputs.end.new_nullifiers.extend_from_bounded_vec(siloed_new_nullifiers); } +fn propagate_new_l2_to_l1_messages_non_revertible( + public_call: PublicCallData, + public_inputs: &mut PublicKernelCircuitPublicInputsBuilder +) { + // new l2 to l1 messages + let public_call_public_inputs = public_call.call_stack_item.public_inputs; + let storage_contract_address = public_call_public_inputs.call_context.storage_contract_address; + + let new_l2_to_l1_msgs = public_call_public_inputs.new_l2_to_l1_msgs; + let mut new_l2_to_l1_msgs_to_insert : BoundedVec = BoundedVec::new(); + for i in 0..MAX_NEW_L2_TO_L1_MSGS_PER_CALL { + let msg = new_l2_to_l1_msgs[i]; + if !is_empty(msg) { + let new_l2_to_l1_msgs = compute_l2_to_l1_hash( + storage_contract_address, + public_inputs.constants.tx_context.version, + public_inputs.constants.tx_context.chain_id, + msg + ); + new_l2_to_l1_msgs_to_insert.push(new_l2_to_l1_msgs) + } + } + public_inputs.end_non_revertible.new_l2_to_l1_msgs.extend_from_bounded_vec(new_l2_to_l1_msgs_to_insert); +} + fn propagate_new_l2_to_l1_messages(public_call: PublicCallData, public_inputs: &mut PublicKernelCircuitPublicInputsBuilder) { // new l2 to l1 messages let public_call_public_inputs = public_call.call_stack_item.public_inputs; diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr index ec9d61f96ae..d84e309b6a9 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr @@ -91,16 +91,12 @@ impl PublicKernelTailCircuitPrivateInputs { let end = self.propagate_accumulated_data(); - // TODO: update public data tree root. - let end_state = self.start_state; - KernelCircuitPublicInputs { aggregation_object: previous_public_inputs.aggregation_object, rollup_validation_requests: previous_public_inputs.validation_requests.for_rollup, end, constants: previous_public_inputs.constants, start_state: self.start_state, - end_state, revert_code: previous_public_inputs.revert_code } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/kernel_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/kernel_circuit_public_inputs.nr index c688e3f3558..41100691cbc 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/kernel_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/kernel_circuit_public_inputs.nr @@ -13,6 +13,5 @@ struct KernelCircuitPublicInputs { end: CombinedAccumulatedData, constants: CombinedConstantData, start_state: PartialStateReference, - end_state: PartialStateReference, revert_code: u8, } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs_builder.nr index c2982c13e6c..b4fc5217621 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs_builder.nr @@ -37,7 +37,6 @@ impl PrivateKernelCircuitPublicInputsBuilder { end: self.end.to_combined(), constants: self.constants, start_state: PartialStateReference::empty(), - end_state: PartialStateReference::empty(), revert_code: 0 } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr index 7f363c3be46..4b8903ca571 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr @@ -71,7 +71,6 @@ struct FixtureBuilder { // States. start_state: PartialStateReference, - end_state: PartialStateReference, } impl FixtureBuilder { @@ -107,7 +106,6 @@ impl FixtureBuilder { min_revertible_side_effect_counter: 0, counter: 0, start_state: PartialStateReference::empty(), - end_state: PartialStateReference::empty(), gas_used: GasUsed::empty(), gas_settings: GasSettings::empty() } @@ -239,7 +237,6 @@ impl FixtureBuilder { end, constants, start_state: self.start_state, - end_state: self.end_state, revert_code: self.revert_code } } @@ -441,7 +438,6 @@ impl Empty for FixtureBuilder { min_revertible_side_effect_counter: 0, counter: 0, start_state: PartialStateReference::empty(), - end_state: PartialStateReference::empty(), gas_settings: GasSettings::empty(), gas_used: GasUsed::empty(), } diff --git a/yarn-project/circuits.js/src/structs/kernel/kernel_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/kernel_circuit_public_inputs.ts index 0c92a421833..84637a61f91 100644 --- a/yarn-project/circuits.js/src/structs/kernel/kernel_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/kernel_circuit_public_inputs.ts @@ -30,7 +30,6 @@ export class KernelCircuitPublicInputs { */ public constants: CombinedConstantData, public startState: PartialStateReference, - public endState: PartialStateReference, /** * Flag indicating whether the transaction reverted. */ @@ -48,7 +47,6 @@ export class KernelCircuitPublicInputs { this.end, this.constants, this.startState, - this.endState, this.revertCode, ); } @@ -66,7 +64,6 @@ export class KernelCircuitPublicInputs { reader.readObject(CombinedAccumulatedData), reader.readObject(CombinedConstantData), reader.readObject(PartialStateReference), - reader.readObject(PartialStateReference), reader.readObject(RevertCode), ); } @@ -78,7 +75,6 @@ export class KernelCircuitPublicInputs { CombinedAccumulatedData.empty(), CombinedConstantData.empty(), PartialStateReference.empty(), - PartialStateReference.empty(), RevertCode.OK, ); } diff --git a/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_public_inputs.ts index 4bc5bfa262c..f064b5ee6ec 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_public_inputs.ts @@ -137,7 +137,6 @@ export class PrivateKernelTailCircuitPublicInputs { this.forRollup.end, this.constants, PartialStateReference.empty(), - PartialStateReference.empty(), this.revertCode, ); } diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index ba38ad27a04..ccc3df8d078 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -544,7 +544,6 @@ export function makeKernelCircuitPublicInputs(seed = 1, fullAccumulatedData = tr makeCombinedAccumulatedData(seed, fullAccumulatedData), makeConstantData(seed + 0x100), makePartialStateReference(seed + 0x200), - makePartialStateReference(seed + 0x200), RevertCode.OK, ); } diff --git a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts index 80409a0fafd..81592e332ce 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -1250,7 +1250,6 @@ export function mapKernelCircuitPublicInputsFromNoir(inputs: KernelCircuitPublic mapCombinedAccumulatedDataFromNoir(inputs.end), mapCombinedConstantDataFromNoir(inputs.constants), mapPartialStateReferenceFromNoir(inputs.start_state), - mapPartialStateReferenceFromNoir(inputs.end_state), mapRevertCodeFromNoir(inputs.revert_code), ); } @@ -1262,7 +1261,6 @@ export function mapKernelCircuitPublicInputsToNoir(inputs: KernelCircuitPublicIn constants: mapCombinedConstantDataToNoir(inputs.constants), end: mapCombinedAccumulatedDataToNoir(inputs.end), start_state: mapPartialStateReferenceToNoir(inputs.startState), - end_state: mapPartialStateReferenceToNoir(inputs.endState), revert_code: mapRevertCodeToNoir(inputs.revertCode), }; } From 0ee2eaa805252b5d7d652367e14fe54c6665d786 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Wed, 17 Apr 2024 09:05:15 +0000 Subject: [PATCH 15/15] Stop propagating public data reads in tail. --- .../crates/public-kernel-lib/src/common.nr | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr index 7e6477c6f9a..61ea76033e5 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr @@ -79,11 +79,8 @@ pub fn initialize_emitted_end_values( circuit_outputs.end_non_revertible.encrypted_logs_hash = start_non_revertible.encrypted_logs_hash; circuit_outputs.end_non_revertible.encrypted_log_preimages_length = start_non_revertible.encrypted_log_preimages_length; - // TODO - should be propagated only in initialize_end_values() and clear them in the tail circuit. The - // max_block_number must be propagated to the rollup however as a RollupValidationRequest. let start = previous_kernel.public_inputs.validation_requests; circuit_outputs.validation_requests.max_block_number = start.for_rollup.max_block_number; - circuit_outputs.validation_requests.public_data_reads = array_to_bounded_vec(start.public_data_reads); } // Initialises the circuit outputs with the end state of the previous iteration. @@ -110,6 +107,7 @@ pub fn initialize_end_values( circuit_outputs.validation_requests.max_block_number = previous_kernel.public_inputs.validation_requests.for_rollup.max_block_number; circuit_outputs.validation_requests.nullifier_read_requests = array_to_bounded_vec(start.nullifier_read_requests); circuit_outputs.validation_requests.nullifier_non_existent_read_requests = array_to_bounded_vec(start.nullifier_non_existent_read_requests); + circuit_outputs.validation_requests.public_data_reads = array_to_bounded_vec(start.public_data_reads); } fn perform_static_call_checks(public_call: PublicCallData) {