From 4ecf747df02f7b58c3a715b0b087ecd24bc9d174 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Tue, 27 Aug 2024 20:22:14 +0000 Subject: [PATCH 1/3] Fix some instances of missing unsafe blocks --- .../aztec/src/history/note_inclusion.nr | 10 +++-- .../aztec/src/history/nullifier_inclusion.nr | 22 +++++----- .../src/history/nullifier_non_inclusion.nr | 31 +++++++------- .../aztec/src/history/public_storage.nr | 37 +++++++++------- .../aztec-nr/aztec/src/keys/getters/mod.nr | 4 +- .../aztec/src/note/note_getter/mod.nr | 16 +++++-- .../aztec-nr/aztec/src/oracle/header.nr | 8 +++- .../src/oracle/key_validation_request.nr | 6 ++- .../aztec-nr/aztec/src/oracle/keys.nr | 8 +--- .../aztec/src/state_vars/private_mutable.nr | 10 +++-- .../shared_mutable/shared_mutable.nr | 25 +++++------ .../aztec/src/test/mocks/mock_note.nr | 4 +- noir-projects/aztec-nr/aztec/src/utils/mod.nr | 42 +++++++++++-------- 13 files changed, 125 insertions(+), 98 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr index d5779411b6ba..6dc078e986b0 100644 --- a/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr +++ b/noir-projects/aztec-nr/aztec/src/history/note_inclusion.nr @@ -12,13 +12,15 @@ trait ProveNoteInclusion { impl ProveNoteInclusion for Header { fn prove_note_inclusion(self, note: Note) where Note: NoteInterface { - // 1) Compute note_hash let note_hash = compute_note_hash_for_nullify(note); - // 2) Get the membership witness of the note in the note hash tree - let witness = get_note_hash_membership_witness(self.global_variables.block_number as u32, note_hash); + let witness = unsafe { + get_note_hash_membership_witness(self.global_variables.block_number as u32, note_hash) + }; - // 3) Prove that the commitment is in the note hash tree + // Note inclusion is fairly straightforward, since all we need to prove is that a note exists in the note tree - + // we don't even care _where_ in the tree it is stored. This is because entries in the note hash tree are + // unique. assert_eq( self.state.partial.note_hash_tree.root, root_from_sibling_path(note_hash, witness.index, witness.path), "Proving note inclusion failed" ); diff --git a/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr index 612db617c9c6..4c9b89788d13 100644 --- a/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr +++ b/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr @@ -13,21 +13,21 @@ trait ProveNullifierInclusion { impl ProveNullifierInclusion for Header { fn prove_nullifier_inclusion(self, nullifier: Field) { // 1) Get the membership witness of the nullifier - let witness = get_nullifier_membership_witness(self.global_variables.block_number as u32, nullifier); + let witness = unsafe { + get_nullifier_membership_witness(self.global_variables.block_number as u32, nullifier) + }; - // 2) Check that the witness we obtained matches the nullifier - assert(witness.leaf_preimage.nullifier == nullifier, "Nullifier does not match value in witness"); - - // 3) Compute the nullifier tree leaf - let nullifier_leaf = witness.leaf_preimage.hash(); - - // 4) Prove that the nullifier is in the nullifier tree + // 2) First we prove that the tree leaf in the witness is present in the nullifier tree. This is expected to be + // the leaf that contains the nullifier we're proving inclusion for. assert( self.state.partial.nullifier_tree.root - == root_from_sibling_path(nullifier_leaf, witness.index, witness.path), "Proving nullifier inclusion failed" + == root_from_sibling_path(witness.leaf_preimage.hash(), witness.index, witness.path), "Proving nullifier inclusion failed" ); - // --> Now we have traversed the trees all the way up to archive root and verified that the nullifier - // was included in the nullifier tree. + + // 3) Then we simply check that the value in the leaf is the expected one. Note that we don't need to perform + // any checks on the rest of the values in the leaf preimage (the next index or next nullifier), since all we + // care about is showing that the tree contains an entry with the expected nullifier. + assert(witness.leaf_preimage.nullifier == nullifier, "Nullifier does not match value in witness"); } } diff --git a/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr index 786edb3c2b8b..5238ca99c50a 100644 --- a/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr +++ b/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr @@ -12,30 +12,31 @@ trait ProveNullifierNonInclusion { impl ProveNullifierNonInclusion for Header { fn prove_nullifier_non_inclusion(self, nullifier: Field) { // 1) Get the membership witness of a low nullifier of the nullifier - let witness = get_low_nullifier_membership_witness(self.global_variables.block_number as u32, nullifier); - - // 2) Prove that the nullifier is not included in the nullifier tree - - // 2.a) Compute the low nullifier leaf and prove that it is in the nullifier tree - let low_nullifier_leaf = witness.leaf_preimage.hash(); + let witness = unsafe { + get_low_nullifier_membership_witness(self.global_variables.block_number as u32, nullifier) + }; + + // 2) First we prove that the tree leaf in the witness is present in the nullifier tree. This is expected to be + // the 'low leaf', i.e. the leaf that would come immediately before the nullifier's leaf, if the nullifier were + // to be in the tree. + let low_nullifier_leaf = witness.leaf_preimage; assert( self.state.partial.nullifier_tree.root - == root_from_sibling_path(low_nullifier_leaf, witness.index, witness.path), "Proving nullifier non-inclusion failed: Could not prove low nullifier inclusion" + == root_from_sibling_path(low_nullifier_leaf.hash(), witness.index, witness.path), "Proving nullifier non-inclusion failed: Could not prove low nullifier inclusion" ); - // 2.b) Prove that the low nullifier is smaller than the nullifier + // 3) Prove that the low leaf is indeed smaller than the nullifier assert( - full_field_less_than(witness.leaf_preimage.nullifier, nullifier), "Proving nullifier non-inclusion failed: low_nullifier.value < nullifier.value check failed" + full_field_less_than(low_nullifier_leaf.nullifier, nullifier), "Proving nullifier non-inclusion failed: low_nullifier.value < nullifier.value check failed" ); - // 2.c) Prove that the low nullifier is pointing "over" the nullifier to prove that the nullifier is not - // included in the nullifier tree (or to 0 if the to-be-inserted nullifier is the largest of all) + // 4) Prove that the low leaf is pointing "over" the nullifier, which means that the nullifier is not included + // in the nullifier tree, since if it were it'd need to be between the low leaf and the next leaf. Note the + // special case in which the low leaf is the largest of all entries, in which case there's no 'next' entry. assert( - full_field_greater_than(witness.leaf_preimage.next_nullifier, nullifier) - | (witness.leaf_preimage.next_index == 0), "Proving nullifier non-inclusion failed: low_nullifier.next_value > nullifier.value check failed" + full_field_greater_than(low_nullifier_leaf.next_nullifier, nullifier) + | (low_nullifier_leaf.next_index == 0), "Proving nullifier non-inclusion failed: low_nullifier.next_value > nullifier.value check failed" ); - // --> Now we have traversed the trees all the way up to archive root and verified that the nullifier - // was not yet included in the nullifier tree. } } diff --git a/noir-projects/aztec-nr/aztec/src/history/public_storage.nr b/noir-projects/aztec-nr/aztec/src/history/public_storage.nr index 07356cbd2522..b1d833824fcc 100644 --- a/noir-projects/aztec-nr/aztec/src/history/public_storage.nr +++ b/noir-projects/aztec-nr/aztec/src/history/public_storage.nr @@ -12,24 +12,36 @@ trait PublicStorageHistoricalRead { impl PublicStorageHistoricalRead for Header { fn public_storage_historical_read(self, storage_slot: Field, contract_address: AztecAddress) -> Field { - // 1) Compute the leaf slot by siloing the storage slot with the contract address + // 1) Compute the leaf index by siloing the storage slot with the contract address let public_data_tree_index = poseidon2_hash_with_separator( [contract_address.to_field(), storage_slot], GENERATOR_INDEX__PUBLIC_LEAF_INDEX ); - // 2) Get the membership witness of the slot - let witness = get_public_data_witness( - self.global_variables.block_number as u32, - public_data_tree_index + // 2) Get the membership witness for the tree index. + let witness = unsafe { + get_public_data_witness( + self.global_variables.block_number as u32, + public_data_tree_index + ) + }; + + // 3) The witness is made up of two parts: the preimage of the leaf and the proof that it exists in the tree. + // We first prove that the witness is indeed valid for the public data tree, i.e. that the preimage is of a + // value present in the tree. Note that `hash` returns not just the hash of the value but also the metadata + // (slot, next index and next slot). + assert( + self.state.partial.public_data_tree.root + == root_from_sibling_path(witness.leaf_preimage.hash(), witness.index, witness.path), "Proving public value inclusion failed" ); - // 3) Extract the value from the witness leaf and check that the storage slot is correct + // 4) Now that we know the preimage is valid, we determine the value that's represented by this tree entry. Here + // we have two scenarios: + // 1. The tree entry is initialized, and the value is the same as the one in the witness + // 2. The entry was never initialized, and the value is default zero (the default) + // The code below is based on the same checks in `validate_public_data_reads` in `base_rollup_inputs`. let preimage = witness.leaf_preimage; - // Here we have two cases. Code based on same checks in `validate_public_data_reads` in `base_rollup_inputs` - // 1. The value is the same as the one in the witness - // 2. The value was never initialized and is zero let is_less_than_slot = full_field_less_than(preimage.slot, public_data_tree_index); let is_next_greater_than = full_field_less_than(public_data_tree_index, preimage.next_slot); let is_max = ((preimage.next_index == 0) & (preimage.next_slot == 0)); @@ -42,13 +54,6 @@ impl PublicStorageHistoricalRead for Header { preimage.value }; - // 4) Prove that the leaf exists in the public data tree. Note that `hash` returns not just the hash of the value - // but also the metadata (slot, next index and next slot). - assert( - self.state.partial.public_data_tree.root - == root_from_sibling_path(preimage.hash(), witness.index, witness.path), "Proving public value inclusion failed" - ); - value } } diff --git a/noir-projects/aztec-nr/aztec/src/keys/getters/mod.nr b/noir-projects/aztec-nr/aztec/src/keys/getters/mod.nr index dc1af573af1b..ca4ceb86db72 100644 --- a/noir-projects/aztec-nr/aztec/src/keys/getters/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/keys/getters/mod.nr @@ -24,9 +24,7 @@ global KEY_REGISTRY_UPDATE_BLOCKS = 5; global KEY_REGISTRY_STORAGE_SLOT = 1; -// A helper function since requesting nsk_app is very common -// TODO(#6543) -pub fn get_nsk_app(npk_m_hash: Field) -> Field { +unconstrained pub fn get_nsk_app(npk_m_hash: Field) -> Field { get_key_validation_request(npk_m_hash, NULLIFIER_INDEX).sk_app } diff --git a/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr b/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr index 576d05a08854..847b89f9cf8e 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr @@ -14,7 +14,7 @@ fn extract_property_value_from_selector( serialized_note: [Field; N], selector: PropertySelector ) -> Field { - // Selectors use PropertySelectors in order to locate note properties inside the serialized note. + // Selectors use PropertySelectors in order to locate note properties inside the serialized note. // This allows easier packing and custom (de)serialization schemas. A note property is located // inside the serialized note using the index inside the array, a byte offset and a length. let value = serialized_note[selector.index].to_be_bytes(32); @@ -93,13 +93,17 @@ pub fn get_note( context: &mut PrivateContext, storage_slot: Field ) -> (Note, Field) where Note: NoteInterface { - let note = get_note_internal(storage_slot); + let note = unsafe { + get_note_internal(storage_slot) + }; + // Constraining that we got a valid note from the oracle is fairly straightforward: all we need to do is check that + // the metadata is correct, and that the note exists. check_note_header(*context, storage_slot, note); let note_hash_for_read_request = compute_note_hash_for_read_request(note); - context.push_note_hash_read_request(note_hash_for_read_request); + (note, note_hash_for_read_request) } @@ -108,8 +112,12 @@ pub fn get_notes( storage_slot: Field, options: NoteGetterOptions ) -> (BoundedVec, BoundedVec) where Note: NoteInterface + Eq { - let opt_notes = get_notes_internal(storage_slot, options); + let opt_notes = unsafe { + get_notes_internal(storage_slot, options) + }; + // We apply the constraints in a separate function instead of inlining them here to make testing that these checks + // correctly reject bad notes. constrain_get_notes_internal(context, storage_slot, opt_notes, options) } diff --git a/noir-projects/aztec-nr/aztec/src/oracle/header.nr b/noir-projects/aztec-nr/aztec/src/oracle/header.nr index da388b948ddc..444419ccec40 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/header.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/header.nr @@ -34,7 +34,9 @@ pub fn get_header_at(block_number: u32, context: PrivateContext) -> Header { ); // 3) Get the header hint of a given block from an oracle - let historical = get_header_at_internal(block_number); + let historical = unsafe { + get_header_at_internal(block_number) + }; // 4) We make sure that the header hint we received from the oracle exists in the state tree and is the actual header // at the desired block number @@ -60,7 +62,9 @@ fn constrain_get_header_at_internal( let block_hash = header_hint.hash(); // 2) Get the membership witness of the block in the archive tree - let witness = get_archive_membership_witness(last_archive_block_number, block_hash); + let witness = unsafe { + get_archive_membership_witness(last_archive_block_number, block_hash) + }; // 3) Check that the block is in the archive (i.e. the witness is valid) assert( diff --git a/noir-projects/aztec-nr/aztec/src/oracle/key_validation_request.nr b/noir-projects/aztec-nr/aztec/src/oracle/key_validation_request.nr index d36d8128bdfd..2a9eb412c9c3 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/key_validation_request.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/key_validation_request.nr @@ -14,7 +14,9 @@ unconstrained fn get_key_validation_request_internal( KeyValidationRequest::deserialize(result) } -pub fn get_key_validation_request(pk_m_hash: Field, key_index: Field) -> KeyValidationRequest { +unconstrained pub fn get_key_validation_request( + pk_m_hash: Field, + key_index: Field +) -> KeyValidationRequest { get_key_validation_request_internal(pk_m_hash, key_index) } - diff --git a/noir-projects/aztec-nr/aztec/src/oracle/keys.nr b/noir-projects/aztec-nr/aztec/src/oracle/keys.nr index 0c4f3c5f5795..de41594fbf94 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/keys.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/keys.nr @@ -4,12 +4,8 @@ use dep::protocol_types::{address::{AztecAddress, PartialAddress}, point::Point} #[oracle(getPublicKeysAndPartialAddress)] unconstrained fn get_public_keys_and_partial_address_oracle(_address: AztecAddress) -> [Field; 13] {} -unconstrained fn get_public_keys_and_partial_address_oracle_wrapper(address: AztecAddress) -> [Field; 13] { - get_public_keys_and_partial_address_oracle(address) -} - -pub fn get_public_keys_and_partial_address(address: AztecAddress) -> (PublicKeys, PartialAddress) { - let result = get_public_keys_and_partial_address_oracle_wrapper(address); +unconstrained pub fn get_public_keys_and_partial_address(address: AztecAddress) -> (PublicKeys, PartialAddress) { + let result = get_public_keys_and_partial_address_oracle(address); let keys = PublicKeys { npk_m: NpkM { inner: Point { x: result[0], y: result[1], is_infinite: result[2] as bool } }, diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr index b054ae17c8bc..dcd219d9ad28 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr @@ -70,13 +70,15 @@ impl PrivateMutable where Note: NoteInter // docs:end:replace pub fn initialize_or_replace(self, note: &mut Note) -> NoteEmission { - let is_initialized = check_nullifier_exists(self.compute_initialization_nullifier()); + let is_initialized = unsafe { + check_nullifier_exists(self.compute_initialization_nullifier()) + }; - // check_nullifier_exists() is an unconstrained function - we can constrain a true value by providing an - // inclusion proof of the nullifier, but cannot constrain a false value since a non-inclusion proof would only + // check_nullifier_exists() is an unconstrained function - we can constrain a true value by providing an + // inclusion proof of the nullifier, but cannot constrain a false value since a non-inclusion proof would only // be valid if done in public. // Ultimately, this is not an issue ginen that we'll either: - // - initialize the state variable, which would fail if it was already initialized due to the duplicate + // - initialize the state variable, which would fail if it was already initialized due to the duplicate // nullifier, or // - replace the current value, which would fail if it was not initialized since we wouldn't be able to produce // an inclusion proof for the current note diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/shared_mutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/shared_mutable.nr index 71cd7ba2a2bc..f49978dd0692 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/shared_mutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/shared_mutable.nr @@ -107,27 +107,28 @@ impl SharedMutable for MockNote { 4135 } - fn compute_nullifier(self, context: &mut PrivateContext, note_hash_for_nullify: Field) -> Field { + fn compute_nullifier(_self: Self, _context: &mut PrivateContext, note_hash_for_nullify: Field) -> Field { // We don't use any kind of secret here since this is only a mock note and having it here would make tests // more cumbersome poseidon2_hash_with_separator([note_hash_for_nullify], GENERATOR_INDEX__NOTE_NULLIFIER as Field) @@ -85,7 +85,7 @@ impl NoteInterface for MockNote { impl Eq for MockNote { fn eq(self, other: Self) -> bool { - (self.header == other.header) & + (self.header == other.header) & (self.value == other.value) } } diff --git a/noir-projects/aztec-nr/aztec/src/utils/mod.nr b/noir-projects/aztec-nr/aztec/src/utils/mod.nr index 6d79c195f334..0ac8b51e7bfb 100644 --- a/noir-projects/aztec-nr/aztec/src/utils/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/utils/mod.nr @@ -6,14 +6,36 @@ mod point; // Collapses an array of Options with sparse Some values into a BoundedVec, essentially unwrapping the Options and // removing the None values. For example, given: // input: [some(3), none(), some(1)] -// this returns +// this returns // collapsed: [3, 1] pub fn collapse(input: [Option; N]) -> BoundedVec where T: Eq { - let (collapsed, collapsed_to_input_index_mapping) = get_collapse_hints(input); + // Computing the collpased BoundedVec would result in a very large number of constraints, since we'd need to loop + // over the input array and conditionally write to a dynamic vec index, which is a very unfriendly pattern to the + // proving backend. + // Instead, we use an unconstrained function to produce the final collapsed array, along with some hints, and then + // verify that the input and collapsed arrays are equivalent. + let (collapsed, collapsed_to_input_index_mapping) = unsafe { + get_collapse_hints(input) + }; + verify_collapse_hints(input, collapsed, collapsed_to_input_index_mapping); collapsed } +unconstrained fn get_collapse_hints(input: [Option; N]) -> (BoundedVec, BoundedVec) { + let mut collapsed: BoundedVec = BoundedVec::new(); + let mut collapsed_to_input_index_mapping: BoundedVec = BoundedVec::new(); + + for i in 0..N { + if input[i].is_some() { + collapsed.push(input[i].unwrap_unchecked()); + collapsed_to_input_index_mapping.push(i); + } + } + + (collapsed, collapsed_to_input_index_mapping) +} + fn verify_collapse_hints( input: [Option; N], collapsed: BoundedVec, @@ -32,7 +54,7 @@ fn verify_collapse_hints( assert_eq(count, collapsed.len(), "Wrong collapsed vec length"); // Then we check that all elements exist in the original array, and are in the same order. To do this we use the - // auxiliary collapsed_to_input_index_mapping array, which at index n contains the index in the input array that + // auxiliary collapsed_to_input_index_mapping array, which at index n contains the index in the input array that // corresponds to the collapsed entry at index n. // Example: // - input: [some(3), none(), some(1)] @@ -69,17 +91,3 @@ fn verify_collapse_hints( // - the number of elements in the collapsed array is the same as in the input array. // Therefore, the collapsed array is correct. } - -unconstrained fn get_collapse_hints(input: [Option; N]) -> (BoundedVec, BoundedVec) { - let mut collapsed: BoundedVec = BoundedVec::new(); - let mut collapsed_to_input_index_mapping: BoundedVec = BoundedVec::new(); - - for i in 0..N { - if input[i].is_some() { - collapsed.push(input[i].unwrap_unchecked()); - collapsed_to_input_index_mapping.push(i); - } - } - - (collapsed, collapsed_to_input_index_mapping) -} From 950c510809e64abda97d77e0c692de408a845ac5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Tue, 27 Aug 2024 23:50:22 +0000 Subject: [PATCH 2/3] Add clarifying comment --- .../aztec-nr/aztec/src/oracle/get_contract_instance.nr | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/oracle/get_contract_instance.nr b/noir-projects/aztec-nr/aztec/src/oracle/get_contract_instance.nr index 84a017a5ea0f..f9fcad78f385 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/get_contract_instance.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/get_contract_instance.nr @@ -19,8 +19,13 @@ unconstrained pub fn get_contract_instance_internal_avm(address: AztecAddress) - } pub fn get_contract_instance(address: AztecAddress) -> ContractInstance { - let instance = ContractInstance::deserialize(get_contract_instance_internal(address)); - assert(instance.to_address().eq(address)); + let instance = unsafe { + ContractInstance::deserialize(get_contract_instance_internal(address)) + }; + // The to_address function combines all values in the instance object to produce an address, so by checking that we + // get the expected address we validate the entire struct. + assert_eq(instance.to_address(), address); + instance } From d829bfb1fc3db6519dd32d9b707a1f2cbf45d340 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Fri, 6 Sep 2024 20:46:03 +0000 Subject: [PATCH 3/3] Fix comment --- noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr b/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr index e502eeb73529..25d66fe899d1 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr @@ -103,8 +103,8 @@ pub fn get_notes( get_notes_internal(storage_slot, options) }; - // We apply the constraints in a separate function instead of inlining them here to make testing that these checks - // correctly reject bad notes. + // We apply the constraints in a separate function instead of inlining them here to make it easier to test that + // these checks correctly reject bad notes. constrain_get_notes_internal(context, storage_slot, opt_notes, options) }