From 007585b421ad6ec3c984435a590a083c45ec85d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Fri, 6 Dec 2024 21:53:12 +0000 Subject: [PATCH 1/4] Move collapse tests into that file --- .../aztec/src/utils/collapse_array.nr | 133 +++++++++++++++++- noir-projects/aztec-nr/aztec/src/utils/mod.nr | 1 - .../aztec-nr/aztec/src/utils/test.nr | 127 ----------------- 3 files changed, 132 insertions(+), 129 deletions(-) delete mode 100644 noir-projects/aztec-nr/aztec/src/utils/test.nr diff --git a/noir-projects/aztec-nr/aztec/src/utils/collapse_array.nr b/noir-projects/aztec-nr/aztec/src/utils/collapse_array.nr index ff5bc2adb82..122ada4dbbc 100644 --- a/noir-projects/aztec-nr/aztec/src/utils/collapse_array.nr +++ b/noir-projects/aztec-nr/aztec/src/utils/collapse_array.nr @@ -17,7 +17,7 @@ where collapsed } -pub(crate) fn verify_collapse_hints( +fn verify_collapse_hints( input: [Option; N], collapsed: BoundedVec, collapsed_to_input_index_mapping: BoundedVec, @@ -102,3 +102,134 @@ unconstrained fn get_collapse_hints( (collapsed, collapsed_to_input_index_mapping) } + +mod test { + use super::{collapse_array, verify_collapse_hints}; + + #[test] + unconstrained fn collapse_empty_array() { + let original: [Option; 2] = [Option::none(), Option::none()]; + let collapsed = collapse_array(original); + + assert_eq(collapsed.len(), 0); + } + + #[test] + unconstrained fn collapse_non_sparse_array() { + let original = [Option::some(7), Option::some(3), Option::none()]; + let collapsed = collapse_array(original); + + assert_eq(collapsed.len(), 2); + assert_eq(collapsed.get(0), 7); + assert_eq(collapsed.get(1), 3); + } + + #[test] + unconstrained fn collapse_sparse_array() { + let original = [Option::some(7), Option::none(), Option::some(3)]; + let collapsed = collapse_array(original); + + assert_eq(collapsed.len(), 2); + assert_eq(collapsed.get(0), 7); + assert_eq(collapsed.get(1), 3); + } + + #[test] + unconstrained fn collapse_array_front_padding() { + let original = + [Option::none(), Option::none(), Option::some(7), Option::none(), Option::some(3)]; + let collapsed = collapse_array(original); + + assert_eq(collapsed.len(), 2); + assert_eq(collapsed.get(0), 7); + assert_eq(collapsed.get(1), 3); + } + + #[test] + unconstrained fn collapse_array_back_padding() { + let original = + [Option::some(7), Option::none(), Option::some(3), Option::none(), Option::none()]; + let collapsed = collapse_array(original); + + assert_eq(collapsed.len(), 2); + assert_eq(collapsed.get(0), 7); + assert_eq(collapsed.get(1), 3); + } + + #[test] + unconstrained fn verify_collapse_hints_good_hints() { + let original = [Option::some(7), Option::none(), Option::some(3)]; + let collapsed = BoundedVec::from_array([7, 3]); + let collapsed_to_input_index_mapping = BoundedVec::from_array([0, 2]); + + verify_collapse_hints(original, collapsed, collapsed_to_input_index_mapping); + } + + #[test(should_fail_with = "Wrong collapsed vec length")] + unconstrained fn verify_collapse_hints_wrong_length() { + let original = [Option::some(7), Option::none(), Option::some(3)]; + let collapsed = BoundedVec::from_array([7]); + let collapsed_to_input_index_mapping = BoundedVec::from_array([0]); + + verify_collapse_hints(original, collapsed, collapsed_to_input_index_mapping); + } + + #[test(should_fail_with = "Collapse hint vec length mismatch")] + unconstrained fn verify_collapse_hints_hint_length_mismatch() { + let original = [Option::some(7), Option::none(), Option::some(3)]; + let collapsed = BoundedVec::from_array([7, 3]); + let collapsed_to_input_index_mapping = BoundedVec::from_array([0]); + + verify_collapse_hints(original, collapsed, collapsed_to_input_index_mapping); + } + + #[test(should_fail_with = "Out of bounds index hint")] + unconstrained fn verify_collapse_hints_out_of_bounds_index_hint() { + let original = [Option::some(7), Option::none(), Option::some(3)]; + let collapsed = BoundedVec::from_array([7, 3]); + let collapsed_to_input_index_mapping = BoundedVec::from_array([0, 5]); + + verify_collapse_hints(original, collapsed, collapsed_to_input_index_mapping); + } + + #[test(should_fail)] + unconstrained fn verify_collapse_hints_hint_to_none() { + let original = [Option::some(7), Option::none(), Option::some(3)]; + let collapsed = BoundedVec::from_array([7, 0]); + let collapsed_to_input_index_mapping = BoundedVec::from_array([0, 1]); + + verify_collapse_hints(original, collapsed, collapsed_to_input_index_mapping); + } + + #[test(should_fail_with = "Wrong collapsed vec content")] + unconstrained fn verify_collapse_hints_wrong_vec_content() { + let original = [Option::some(7), Option::none(), Option::some(3)]; + let collapsed = BoundedVec::from_array([7, 42]); + let collapsed_to_input_index_mapping = BoundedVec::from_array([0, 2]); + + verify_collapse_hints(original, collapsed, collapsed_to_input_index_mapping); + } + + #[test(should_fail_with = "Wrong collapsed vec order")] + unconstrained fn verify_collapse_hints_wrong_vec_order() { + let original = [Option::some(7), Option::none(), Option::some(3)]; + let collapsed = BoundedVec::from_array([3, 7]); + let collapsed_to_input_index_mapping = BoundedVec::from_array([2, 0]); + + verify_collapse_hints(original, collapsed, collapsed_to_input_index_mapping); + } + + #[test(should_fail_with = "Dirty collapsed vec storage")] + unconstrained fn verify_collapse_hints_dirty_storage() { + let original = [Option::some(7), Option::none(), Option::some(3)]; + + let mut collapsed: BoundedVec = BoundedVec::from_array([7, 3]); + // We have to use the unchecked setter as we're knowingly writing past the length, breaking its invariants. + collapsed.set_unchecked(2, 1); + + let collapsed_to_input_index_mapping = BoundedVec::from_array([0, 2]); + + verify_collapse_hints(original, collapsed, collapsed_to_input_index_mapping); + } + +} \ No newline at end of file diff --git a/noir-projects/aztec-nr/aztec/src/utils/mod.nr b/noir-projects/aztec-nr/aztec/src/utils/mod.nr index d7abdd8234f..68190aeb9c6 100644 --- a/noir-projects/aztec-nr/aztec/src/utils/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/utils/mod.nr @@ -2,7 +2,6 @@ pub mod bytes; pub mod collapse_array; pub mod comparison; pub mod point; -pub mod test; pub mod to_bytes; pub use crate::utils::bytes::{bytes_to_fields, fields_to_bytes}; diff --git a/noir-projects/aztec-nr/aztec/src/utils/test.nr b/noir-projects/aztec-nr/aztec/src/utils/test.nr deleted file mode 100644 index 644a6baeafe..00000000000 --- a/noir-projects/aztec-nr/aztec/src/utils/test.nr +++ /dev/null @@ -1,127 +0,0 @@ -use super::collapse_array::{collapse_array, verify_collapse_hints}; - -#[test] -unconstrained fn collapse_empty_array() { - let original: [Option; 2] = [Option::none(), Option::none()]; - let collapsed = collapse_array(original); - - assert_eq(collapsed.len(), 0); -} - -#[test] -unconstrained fn collapse_non_sparse_array() { - let original = [Option::some(7), Option::some(3), Option::none()]; - let collapsed = collapse_array(original); - - assert_eq(collapsed.len(), 2); - assert_eq(collapsed.get(0), 7); - assert_eq(collapsed.get(1), 3); -} - -#[test] -unconstrained fn collapse_sparse_array() { - let original = [Option::some(7), Option::none(), Option::some(3)]; - let collapsed = collapse_array(original); - - assert_eq(collapsed.len(), 2); - assert_eq(collapsed.get(0), 7); - assert_eq(collapsed.get(1), 3); -} - -#[test] -unconstrained fn collapse_array_front_padding() { - let original = - [Option::none(), Option::none(), Option::some(7), Option::none(), Option::some(3)]; - let collapsed = collapse_array(original); - - assert_eq(collapsed.len(), 2); - assert_eq(collapsed.get(0), 7); - assert_eq(collapsed.get(1), 3); -} - -#[test] -unconstrained fn collapse_array_back_padding() { - let original = - [Option::some(7), Option::none(), Option::some(3), Option::none(), Option::none()]; - let collapsed = collapse_array(original); - - assert_eq(collapsed.len(), 2); - assert_eq(collapsed.get(0), 7); - assert_eq(collapsed.get(1), 3); -} - -#[test] -unconstrained fn verify_collapse_hints_good_hints() { - let original = [Option::some(7), Option::none(), Option::some(3)]; - let collapsed = BoundedVec::from_array([7, 3]); - let collapsed_to_input_index_mapping = BoundedVec::from_array([0, 2]); - - verify_collapse_hints(original, collapsed, collapsed_to_input_index_mapping); -} - -#[test(should_fail_with = "Wrong collapsed vec length")] -unconstrained fn verify_collapse_hints_wrong_length() { - let original = [Option::some(7), Option::none(), Option::some(3)]; - let collapsed = BoundedVec::from_array([7]); - let collapsed_to_input_index_mapping = BoundedVec::from_array([0]); - - verify_collapse_hints(original, collapsed, collapsed_to_input_index_mapping); -} - -#[test(should_fail_with = "Collapse hint vec length mismatch")] -unconstrained fn verify_collapse_hints_hint_length_mismatch() { - let original = [Option::some(7), Option::none(), Option::some(3)]; - let collapsed = BoundedVec::from_array([7, 3]); - let collapsed_to_input_index_mapping = BoundedVec::from_array([0]); - - verify_collapse_hints(original, collapsed, collapsed_to_input_index_mapping); -} - -#[test(should_fail_with = "Out of bounds index hint")] -unconstrained fn verify_collapse_hints_out_of_bounds_index_hint() { - let original = [Option::some(7), Option::none(), Option::some(3)]; - let collapsed = BoundedVec::from_array([7, 3]); - let collapsed_to_input_index_mapping = BoundedVec::from_array([0, 5]); - - verify_collapse_hints(original, collapsed, collapsed_to_input_index_mapping); -} - -#[test(should_fail)] -unconstrained fn verify_collapse_hints_hint_to_none() { - let original = [Option::some(7), Option::none(), Option::some(3)]; - let collapsed = BoundedVec::from_array([7, 0]); - let collapsed_to_input_index_mapping = BoundedVec::from_array([0, 1]); - - verify_collapse_hints(original, collapsed, collapsed_to_input_index_mapping); -} - -#[test(should_fail_with = "Wrong collapsed vec content")] -unconstrained fn verify_collapse_hints_wrong_vec_content() { - let original = [Option::some(7), Option::none(), Option::some(3)]; - let collapsed = BoundedVec::from_array([7, 42]); - let collapsed_to_input_index_mapping = BoundedVec::from_array([0, 2]); - - verify_collapse_hints(original, collapsed, collapsed_to_input_index_mapping); -} - -#[test(should_fail_with = "Wrong collapsed vec order")] -unconstrained fn verify_collapse_hints_wrong_vec_order() { - let original = [Option::some(7), Option::none(), Option::some(3)]; - let collapsed = BoundedVec::from_array([3, 7]); - let collapsed_to_input_index_mapping = BoundedVec::from_array([2, 0]); - - verify_collapse_hints(original, collapsed, collapsed_to_input_index_mapping); -} - -#[test(should_fail_with = "Dirty collapsed vec storage")] -unconstrained fn verify_collapse_hints_dirty_storage() { - let original = [Option::some(7), Option::none(), Option::some(3)]; - - let mut collapsed: BoundedVec = BoundedVec::from_array([7, 3]); - // We have to use the unchecked setter as we're knowingly writing past the length, breaking its invariants. - collapsed.set_unchecked(2, 1); - - let collapsed_to_input_index_mapping = BoundedVec::from_array([0, 2]); - - verify_collapse_hints(original, collapsed, collapsed_to_input_index_mapping); -} From 00b07632173b57e5186efe8dd5dba53064ea882a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Mon, 9 Dec 2024 20:54:52 +0000 Subject: [PATCH 2/4] Add subaray --- .../aztec/src/keys/point_to_symmetric_key.nr | 17 +++--- .../aztec/src/note/note_getter/mod.nr | 2 +- .../aztec-nr/aztec/src/note/utils.nr | 13 ++-- .../oracle/get_l1_to_l2_membership_witness.nr | 7 +-- .../src/oracle/get_membership_witness.nr | 8 +-- .../get_nullifier_membership_witness.nr | 16 ++--- .../src/oracle/get_public_data_witness.nr | 11 +--- .../aztec-nr/aztec/src/oracle/notes.nr | 13 ++-- .../{collapse_array.nr => array/collapse.nr} | 32 +++++----- .../aztec-nr/aztec/src/utils/array/mod.nr | 5 ++ .../aztec/src/utils/array/subarray.nr | 61 +++++++++++++++++++ noir-projects/aztec-nr/aztec/src/utils/mod.nr | 3 +- .../src/auth_oracle.nr | 9 ++- .../crates/types/src/address/aztec_address.nr | 6 -- .../crates/types/src/address/eth_address.nr | 7 +-- .../crates/types/src/header.nr | 31 ++++------ .../crates/types/src/state_reference.nr | 14 ++--- .../crates/types/src/utils/arrays.nr | 15 +++++ .../crates/types/src/utils/mod.nr | 21 ------- 19 files changed, 158 insertions(+), 133 deletions(-) rename noir-projects/aztec-nr/aztec/src/utils/{collapse_array.nr => array/collapse.nr} (92%) create mode 100644 noir-projects/aztec-nr/aztec/src/utils/array/mod.nr create mode 100644 noir-projects/aztec-nr/aztec/src/utils/array/subarray.nr diff --git a/noir-projects/aztec-nr/aztec/src/keys/point_to_symmetric_key.nr b/noir-projects/aztec-nr/aztec/src/keys/point_to_symmetric_key.nr index f1ad2b43938..5f2fbfb911e 100644 --- a/noir-projects/aztec-nr/aztec/src/keys/point_to_symmetric_key.nr +++ b/noir-projects/aztec-nr/aztec/src/keys/point_to_symmetric_key.nr @@ -1,18 +1,19 @@ use crate::utils::point::point_to_bytes; -use dep::protocol_types::{ - constants::GENERATOR_INDEX__SYMMETRIC_KEY, point::Point, scalar::Scalar, utils::arr_copy_slice, -}; +use dep::protocol_types::{constants::GENERATOR_INDEX__SYMMETRIC_KEY, point::Point, scalar::Scalar}; use std::{embedded_curve_ops::multi_scalar_mul, hash::sha256}; // TODO(#5726): This function is called deriveAESSecret in TS. I don't like point_to_symmetric_key name much since // point is not the only input of the function. Unify naming with TS once we have a better name. pub fn point_to_symmetric_key(secret: Scalar, point: Point) -> [u8; 32] { - let shared_secret: Point = multi_scalar_mul([point], [secret]); - let shared_secret = point_to_bytes(shared_secret); - let mut shared_secret_bytes_with_separator = [0 as u8; 33]; - shared_secret_bytes_with_separator = - arr_copy_slice(shared_secret, shared_secret_bytes_with_separator, 0); + let shared_secret = point_to_bytes(multi_scalar_mul([point], [secret])); + + let mut shared_secret_bytes_with_separator: [u8; 33] = std::mem::zeroed(); + for i in 0..shared_secret.len() { + shared_secret_bytes_with_separator[i] = shared_secret[i]; + } + shared_secret_bytes_with_separator[32] = GENERATOR_INDEX__SYMMETRIC_KEY; + sha256(shared_secret_bytes_with_separator) } 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 99efea10032..c79c2e18730 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 @@ -141,7 +141,7 @@ where let filter_args = options.filter_args; let filtered_notes = filter_fn(opt_notes, filter_args); - let notes = crate::utils::collapse_array(filtered_notes); + let notes = crate::utils::array::collapse(filtered_notes); let mut note_hashes: BoundedVec = BoundedVec::new(); diff --git a/noir-projects/aztec-nr/aztec/src/note/utils.nr b/noir-projects/aztec-nr/aztec/src/note/utils.nr index 6f3031f0384..184d70c8f2b 100644 --- a/noir-projects/aztec-nr/aztec/src/note/utils.nr +++ b/noir-projects/aztec-nr/aztec/src/note/utils.nr @@ -1,15 +1,12 @@ use crate::{ context::PrivateContext, note::{note_header::NoteHeader, note_interface::{NoteInterface, NullifiableNote}}, + utils::array, }; -use dep::protocol_types::{ - hash::{ - compute_siloed_note_hash as compute_siloed_note_hash, - compute_siloed_nullifier as compute_siloed_nullifier_from_preimage, - compute_unique_note_hash, - }, - utils::arr_copy_slice, +use dep::protocol_types::hash::{ + compute_siloed_note_hash as compute_siloed_note_hash, + compute_siloed_nullifier as compute_siloed_nullifier_from_preimage, compute_unique_note_hash, }; pub fn compute_siloed_nullifier( @@ -128,7 +125,7 @@ pub unconstrained fn compute_note_hash_and_optionally_a_nullifier + NullifiableNote, { - let mut note = deserialize_content(arr_copy_slice(serialized_note, [0; N], 0)); + let mut note = deserialize_content(array::subarray(serialized_note, 0)); note.set_header(note_header); let note_hash = note.compute_note_hash(); diff --git a/noir-projects/aztec-nr/aztec/src/oracle/get_l1_to_l2_membership_witness.nr b/noir-projects/aztec-nr/aztec/src/oracle/get_l1_to_l2_membership_witness.nr index 313791269c4..d648f7f2b12 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/get_l1_to_l2_membership_witness.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/get_l1_to_l2_membership_witness.nr @@ -1,6 +1,5 @@ -use dep::protocol_types::{ - address::AztecAddress, constants::L1_TO_L2_MSG_TREE_HEIGHT, utils::arr_copy_slice, -}; +use crate::utils::array; +use dep::protocol_types::{address::AztecAddress, constants::L1_TO_L2_MSG_TREE_HEIGHT}; /// Returns the leaf index and sibling path of an entry in the L1 to L2 messaging tree, which can then be used to prove /// its existence. @@ -12,7 +11,7 @@ pub unconstrained fn get_l1_to_l2_membership_witness( let returned_message = get_l1_to_l2_membership_witness_oracle(contract_address, message_hash, secret); let leaf_index = returned_message[0]; - let sibling_path = arr_copy_slice(returned_message, [0; L1_TO_L2_MSG_TREE_HEIGHT], 1); + let sibling_path = array::subarray(returned_message, 1); (leaf_index, sibling_path) } diff --git a/noir-projects/aztec-nr/aztec/src/oracle/get_membership_witness.nr b/noir-projects/aztec-nr/aztec/src/oracle/get_membership_witness.nr index 02f8a0267cc..7a6a28b385b 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/get_membership_witness.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/get_membership_witness.nr @@ -1,7 +1,5 @@ -use dep::protocol_types::{ - constants::{ARCHIVE_HEIGHT, NOTE_HASH_TREE_HEIGHT}, - utils::arr_copy_slice, -}; +use crate::utils::array; +use dep::protocol_types::constants::{ARCHIVE_HEIGHT, NOTE_HASH_TREE_HEIGHT}; global NOTE_HASH_TREE_ID: Field = 1; global ARCHIVE_TREE_ID: Field = 4; @@ -31,7 +29,7 @@ pub unconstrained fn get_membership_witness( leaf_value: Field, ) -> MembershipWitness { let fields: [Field; M] = get_membership_witness_oracle(block_number, tree_id, leaf_value); - MembershipWitness { index: fields[0], path: arr_copy_slice(fields, [0; N], 1) } + MembershipWitness { index: fields[0], path: array::subarray(fields, 1) } } // Note: get_nullifier_membership_witness function is implemented in get_nullifier_membership_witness.nr diff --git a/noir-projects/aztec-nr/aztec/src/oracle/get_nullifier_membership_witness.nr b/noir-projects/aztec-nr/aztec/src/oracle/get_nullifier_membership_witness.nr index e5f87124753..d41ac58cf14 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/get_nullifier_membership_witness.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/get_nullifier_membership_witness.nr @@ -1,7 +1,6 @@ +use crate::utils::array; use dep::protocol_types::{ - abis::nullifier_leaf_preimage::{NULLIFIER_LEAF_PREIMAGE_LENGTH, NullifierLeafPreimage}, - constants::NULLIFIER_TREE_HEIGHT, - utils::arr_copy_slice, + abis::nullifier_leaf_preimage::NullifierLeafPreimage, constants::NULLIFIER_TREE_HEIGHT, }; // INDEX_LENGTH + NULLIFIER_LEAF_PREIMAGE_LENGTH + NULLIFIER_TREE_HEIGHT @@ -15,15 +14,12 @@ pub struct NullifierMembershipWitness { impl NullifierMembershipWitness { pub fn deserialize(fields: [Field; NULLIFIER_MEMBERSHIP_WITNESS]) -> Self { - let leaf_preimage_fields = arr_copy_slice(fields, [0; NULLIFIER_LEAF_PREIMAGE_LENGTH], 1); + let serialized_leaf_preimage = array::subarray(fields, 1); + Self { index: fields[0], - leaf_preimage: NullifierLeafPreimage::deserialize(leaf_preimage_fields), - path: arr_copy_slice( - fields, - [0; NULLIFIER_TREE_HEIGHT], - 1 + NULLIFIER_LEAF_PREIMAGE_LENGTH, - ), + leaf_preimage: NullifierLeafPreimage::deserialize(serialized_leaf_preimage), + path: array::subarray(fields, 1 + serialized_leaf_preimage.len()), } } } diff --git a/noir-projects/aztec-nr/aztec/src/oracle/get_public_data_witness.nr b/noir-projects/aztec-nr/aztec/src/oracle/get_public_data_witness.nr index 517a8e2d59a..07879b4fd3e 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/get_public_data_witness.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/get_public_data_witness.nr @@ -1,6 +1,5 @@ -use dep::protocol_types::{ - constants::PUBLIC_DATA_TREE_HEIGHT, data::PublicDataTreeLeafPreimage, utils::arr_copy_slice, -}; +use crate::utils::array; +use dep::protocol_types::{constants::PUBLIC_DATA_TREE_HEIGHT, data::PublicDataTreeLeafPreimage}; global LEAF_PREIMAGE_LENGTH: u32 = 4; global PUBLIC_DATA_WITNESS: u32 = 45; @@ -30,10 +29,6 @@ pub unconstrained fn get_public_data_witness( next_index: fields[3] as u32, next_slot: fields[4], }, - path: arr_copy_slice( - fields, - [0; PUBLIC_DATA_TREE_HEIGHT], - 1 + LEAF_PREIMAGE_LENGTH, - ), + path: array::subarray(fields, 1 + LEAF_PREIMAGE_LENGTH), } } diff --git a/noir-projects/aztec-nr/aztec/src/oracle/notes.nr b/noir-projects/aztec-nr/aztec/src/oracle/notes.nr index 737f69d20f4..6d2cdab8f83 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/notes.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/notes.nr @@ -1,9 +1,8 @@ -use crate::note::{note_header::NoteHeader, note_interface::NoteInterface}; +use crate::{note::{note_header::NoteHeader, note_interface::NoteInterface}, utils::array}; use dep::protocol_types::{ address::AztecAddress, indexed_tagging_secret::{INDEXED_TAGGING_SECRET_LENGTH, IndexedTaggingSecret}, - utils::arr_copy_slice, }; /// Notifies the simulator that a note has been created, so that it can be returned in future read requests in the same @@ -181,12 +180,14 @@ where let return_header_length: u32 = 2; // num_notes & contract_address. let extra_preimage_length: u32 = 2; // nonce & note_hash_counter. let read_offset: u32 = return_header_length + i * (N + extra_preimage_length); + let nonce = fields[read_offset]; let note_hash_counter = fields[read_offset + 1] as u32; - let header = NoteHeader { contract_address, nonce, storage_slot, note_hash_counter }; - let serialized_note = arr_copy_slice(fields, [0; N], read_offset + 2); - let mut note = Note::deserialize_content(serialized_note); - note.set_header(header); + let note_content = array::subarray(fields, read_offset + 2); + + let mut note = Note::deserialize_content(note_content); + note.set_header(NoteHeader { contract_address, nonce, storage_slot, note_hash_counter }); + placeholder_opt_notes[i] = Option::some(note); }; } diff --git a/noir-projects/aztec-nr/aztec/src/utils/collapse_array.nr b/noir-projects/aztec-nr/aztec/src/utils/array/collapse.nr similarity index 92% rename from noir-projects/aztec-nr/aztec/src/utils/collapse_array.nr rename to noir-projects/aztec-nr/aztec/src/utils/array/collapse.nr index 122ada4dbbc..22ac88aeb33 100644 --- a/noir-projects/aztec-nr/aztec/src/utils/collapse_array.nr +++ b/noir-projects/aztec-nr/aztec/src/utils/array/collapse.nr @@ -1,9 +1,11 @@ -// 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 -// collapsed: [3, 1] -pub fn collapse_array(input: [Option; N]) -> BoundedVec +/// Collapses an array of `Option`s with sparse `Some` values into a `BoundedVec`, essentially unwrapping the `Option`s +/// and removing the `None` values. +/// +/// For example, given: +/// `input: [some(3), none(), some(1)]` +/// this returns +/// `collapsed: [3, 1]` +pub fn collapse(input: [Option; N]) -> BoundedVec where T: Eq, { @@ -104,12 +106,12 @@ unconstrained fn get_collapse_hints( } mod test { - use super::{collapse_array, verify_collapse_hints}; + use super::{collapse, verify_collapse_hints}; #[test] unconstrained fn collapse_empty_array() { let original: [Option; 2] = [Option::none(), Option::none()]; - let collapsed = collapse_array(original); + let collapsed = collapse(original); assert_eq(collapsed.len(), 0); } @@ -117,7 +119,7 @@ mod test { #[test] unconstrained fn collapse_non_sparse_array() { let original = [Option::some(7), Option::some(3), Option::none()]; - let collapsed = collapse_array(original); + let collapsed = collapse(original); assert_eq(collapsed.len(), 2); assert_eq(collapsed.get(0), 7); @@ -127,7 +129,7 @@ mod test { #[test] unconstrained fn collapse_sparse_array() { let original = [Option::some(7), Option::none(), Option::some(3)]; - let collapsed = collapse_array(original); + let collapsed = collapse(original); assert_eq(collapsed.len(), 2); assert_eq(collapsed.get(0), 7); @@ -135,10 +137,10 @@ mod test { } #[test] - unconstrained fn collapse_array_front_padding() { + unconstrained fn collapse_front_padding() { let original = [Option::none(), Option::none(), Option::some(7), Option::none(), Option::some(3)]; - let collapsed = collapse_array(original); + let collapsed = collapse(original); assert_eq(collapsed.len(), 2); assert_eq(collapsed.get(0), 7); @@ -146,10 +148,10 @@ mod test { } #[test] - unconstrained fn collapse_array_back_padding() { + unconstrained fn collapse_back_padding() { let original = [Option::some(7), Option::none(), Option::some(3), Option::none(), Option::none()]; - let collapsed = collapse_array(original); + let collapsed = collapse(original); assert_eq(collapsed.len(), 2); assert_eq(collapsed.get(0), 7); @@ -232,4 +234,4 @@ mod test { verify_collapse_hints(original, collapsed, collapsed_to_input_index_mapping); } -} \ No newline at end of file +} diff --git a/noir-projects/aztec-nr/aztec/src/utils/array/mod.nr b/noir-projects/aztec-nr/aztec/src/utils/array/mod.nr new file mode 100644 index 00000000000..832615e787c --- /dev/null +++ b/noir-projects/aztec-nr/aztec/src/utils/array/mod.nr @@ -0,0 +1,5 @@ +mod collapse; +mod subarray; + +pub use collapse::collapse; +pub use subarray::subarray; diff --git a/noir-projects/aztec-nr/aztec/src/utils/array/subarray.nr b/noir-projects/aztec-nr/aztec/src/utils/array/subarray.nr new file mode 100644 index 00000000000..4e450d55cba --- /dev/null +++ b/noir-projects/aztec-nr/aztec/src/utils/array/subarray.nr @@ -0,0 +1,61 @@ +use std::static_assert; + +/// Returns `DST_LEN` elements from a source array, starting at `offset`. `DST_LEN` must be large enough to hold all of +/// the elements past `offset`. +/// +/// Example: +/// ``` +/// let foo: [Field; 2] = subarray([1, 2, 3, 4, 5], 2); +/// assert_eq(foo, [3, 4]); +/// ``` +pub fn subarray( + src: [Field; SRC_LEN], + offset: u32, +) -> [Field; DST_LEN] { + static_assert(offset + DST_LEN <= SRC_LEN, "offset too large"); + + let mut dst: [Field; DST_LEN] = std::mem::zeroed(); + for i in 0..DST_LEN { + dst[i] = src[i + offset]; + } + + dst +} + +mod test { + use super::subarray; + + #[test] + unconstrained fn subarray_into_empty() { + // In all of these cases we're setting DST_LEN to be 0, so we always get back an emtpy array. + assert_eq(subarray([], 0), []); + assert_eq(subarray([1, 2, 3, 4, 5], 0), []); + assert_eq(subarray([1, 2, 3, 4, 5], 2), []); + } + + #[test] + unconstrained fn subarray_complete() { + assert_eq(subarray([], 0), []); + assert_eq(subarray([1, 2, 3, 4, 5], 0), [1, 2, 3, 4, 5]); + } + + #[test] + unconstrained fn subarray_different_end_sizes() { + // We implicitly select how many values to read in the size of the return array + assert_eq(subarray([1, 2, 3, 4, 5], 1), [2, 3, 4, 5]); + assert_eq(subarray([1, 2, 3, 4, 5], 1), [2, 3, 4]); + assert_eq(subarray([1, 2, 3, 4, 5], 1), [2, 3]); + assert_eq(subarray([1, 2, 3, 4, 5], 1), [2]); + } + + #[test(should_fail)] + unconstrained fn subarray_offset_too_large() { + // With an offset of 1 we can only request up to 4 elements + let _: [_; 5] = subarray([1, 2, 3, 4, 5], 1); + } + + #[test(should_fail)] + unconstrained fn subarray_bad_return_value() { + assert_eq(subarray([1, 2, 3, 4, 5], 1), [3, 3, 4, 5]); + } +} diff --git a/noir-projects/aztec-nr/aztec/src/utils/mod.nr b/noir-projects/aztec-nr/aztec/src/utils/mod.nr index 68190aeb9c6..92ce0a09344 100644 --- a/noir-projects/aztec-nr/aztec/src/utils/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/utils/mod.nr @@ -1,8 +1,7 @@ pub mod bytes; -pub mod collapse_array; +pub mod array; pub mod comparison; pub mod point; pub mod to_bytes; pub use crate::utils::bytes::{bytes_to_fields, fields_to_bytes}; -pub use crate::utils::collapse_array::collapse_array; diff --git a/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/auth_oracle.nr b/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/auth_oracle.nr index 063720d28e1..53e883aca57 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/auth_oracle.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/auth_oracle.nr @@ -1,8 +1,7 @@ use dep::authwit::auth_witness; -use dep::aztec::protocol_types::{ - address::PartialAddress, - public_keys::{PUBLIC_KEYS_LENGTH, PublicKeys}, - utils::arr_copy_slice, +use dep::aztec::{ + protocol_types::{address::PartialAddress, public_keys::{PUBLIC_KEYS_LENGTH, PublicKeys}}, + utils::array, }; pub struct AuthWitness { @@ -18,7 +17,7 @@ impl AuthWitness { signature[i] = values[i + PUBLIC_KEYS_LENGTH] as u8; } Self { - keys: PublicKeys::deserialize(arr_copy_slice(values, [0; PUBLIC_KEYS_LENGTH], 0)), + keys: PublicKeys::deserialize(array::subarray(values, 0)), signature, partial_address: PartialAddress::from_field(values[76]), } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/address/aztec_address.nr b/noir-projects/noir-protocol-circuits/crates/types/src/address/aztec_address.nr index f66f0418fe7..e8751bf5220 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/address/aztec_address.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/address/aztec_address.nr @@ -12,7 +12,6 @@ use crate::{ merkle_tree::membership::MembershipWitness, public_keys::{IvpkM, NpkM, OvpkM, PublicKeys, TpkM}, traits::{Deserialize, Empty, FromField, Serialize, ToField}, - utils, }; // We do below because `use crate::point::Point;` does not work @@ -148,11 +147,6 @@ impl AztecAddress { pub fn assert_is_zero(self) { assert(self.to_field() == 0); } - - pub fn conditional_assign(predicate: bool, lhs: Self, rhs: Self) -> Self { - let result = utils::conditional_assign(predicate, rhs.to_field(), lhs.to_field()); - Self { inner: result } - } } #[test] diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/address/eth_address.nr b/noir-projects/noir-protocol-circuits/crates/types/src/address/eth_address.nr index 465ae83c61e..56b8e2d7d91 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/address/eth_address.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/address/eth_address.nr @@ -1,4 +1,4 @@ -use crate::{constants::ETH_ADDRESS_LENGTH, traits::{Deserialize, Empty, Serialize, ToField}, utils}; +use crate::{constants::ETH_ADDRESS_LENGTH, traits::{Deserialize, Empty, Serialize, ToField}}; pub struct EthAddress { inner: Field, @@ -51,9 +51,4 @@ impl EthAddress { pub fn assert_is_zero(self) { assert(self.to_field() == 0); } - - pub fn conditional_assign(predicate: bool, lhs: Self, rhs: Self) -> Self { - let result = utils::conditional_assign(predicate, rhs.to_field(), lhs.to_field()); - Self { inner: result } - } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/header.nr b/noir-projects/noir-protocol-circuits/crates/types/src/header.nr index 5817cdb7e18..f99f66f0021 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/header.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/header.nr @@ -1,17 +1,11 @@ use crate::{ - abis::{ - append_only_tree_snapshot::{APPEND_ONLY_TREE_SNAPSHOT_LENGTH, AppendOnlyTreeSnapshot}, - global_variables::GlobalVariables, - }, - constants::{ - CONTENT_COMMITMENT_LENGTH, GENERATOR_INDEX__BLOCK_HASH, GLOBAL_VARIABLES_LENGTH, - HEADER_LENGTH, STATE_REFERENCE_LENGTH, - }, + abis::{append_only_tree_snapshot::AppendOnlyTreeSnapshot, global_variables::GlobalVariables}, + constants::{GENERATOR_INDEX__BLOCK_HASH, HEADER_LENGTH}, content_commitment::ContentCommitment, hash::poseidon2_hash_with_separator, state_reference::StateReference, traits::{Deserialize, Empty, Hash, Serialize}, - utils::arr_copy_slice, + utils::arrays::subarray, }; // docs:start:header @@ -54,20 +48,17 @@ impl Deserialize for Header { fn deserialize(serialized: [Field; HEADER_LENGTH]) -> Self { let mut offset = 0; - let last_archive_fields = - arr_copy_slice(serialized, [0; APPEND_ONLY_TREE_SNAPSHOT_LENGTH], offset); - offset = offset + APPEND_ONLY_TREE_SNAPSHOT_LENGTH; + let last_archive_fields = subarray(serialized, offset); + offset = offset + last_archive_fields.len(); - let content_commitment_fields = - arr_copy_slice(serialized, [0; CONTENT_COMMITMENT_LENGTH], offset); - offset = offset + CONTENT_COMMITMENT_LENGTH; + let content_commitment_fields = subarray(serialized, offset); + offset = offset + content_commitment_fields.len(); - let state_fields = arr_copy_slice(serialized, [0; STATE_REFERENCE_LENGTH], offset); - offset = offset + STATE_REFERENCE_LENGTH; + let state_fields = subarray(serialized, offset); + offset = offset + state_fields.len(); - let global_variables_fields = - arr_copy_slice(serialized, [0; GLOBAL_VARIABLES_LENGTH], offset); - offset = offset + GLOBAL_VARIABLES_LENGTH; + let global_variables_fields = subarray(serialized, offset); + offset = offset + global_variables_fields.len(); let total_fees = serialized[offset]; offset = offset + 1; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/state_reference.nr b/noir-projects/noir-protocol-circuits/crates/types/src/state_reference.nr index 2af97314c02..1e96e52a37c 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/state_reference.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/state_reference.nr @@ -1,10 +1,10 @@ use crate::{ - abis::append_only_tree_snapshot::{APPEND_ONLY_TREE_SNAPSHOT_LENGTH, AppendOnlyTreeSnapshot}, - constants::{PARTIAL_STATE_REFERENCE_LENGTH, STATE_REFERENCE_LENGTH}, + abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot, + constants::STATE_REFERENCE_LENGTH, partial_state_reference::PartialStateReference, traits::{Deserialize, Empty, Serialize}, - utils::arr_copy_slice, }; +use super::utils::arrays::subarray; pub struct StateReference { pub l1_to_l2_message_tree: AppendOnlyTreeSnapshot, @@ -32,12 +32,10 @@ impl Deserialize for StateReference { fn deserialize(serialized: [Field; STATE_REFERENCE_LENGTH]) -> StateReference { let mut offset = 0; - let l1_to_l2_message_tree_fields = - arr_copy_slice(serialized, [0; APPEND_ONLY_TREE_SNAPSHOT_LENGTH], offset); - offset = offset + APPEND_ONLY_TREE_SNAPSHOT_LENGTH; + let l1_to_l2_message_tree_fields = subarray(serialized, offset); + offset = offset + l1_to_l2_message_tree_fields.len(); - let partial_fields = - arr_copy_slice(serialized, [0; PARTIAL_STATE_REFERENCE_LENGTH], offset); + let partial_fields = subarray(serialized, offset); StateReference { l1_to_l2_message_tree: AppendOnlyTreeSnapshot::deserialize( diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays.nr b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays.nr index 41d609572b7..2ce727236e3 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays.nr @@ -40,6 +40,21 @@ pub use get_sorted_result::{get_sorted_result, SortedResult}; pub use sort_by_counter::{sort_by_counter_asc, sort_by_counter_desc}; use crate::traits::{Empty, is_empty}; +use std::static_assert; + +pub fn subarray( + src: [Field; SRC_LEN], + offset: u32, +) -> [Field; DST_LEN] { + static_assert(offset + DST_LEN <= SRC_LEN, "offset too large"); + + let mut dst: [Field; DST_LEN] = std::mem::zeroed(); + for i in 0..DST_LEN { + dst[i] = src[i + offset]; + } + + dst +} pub fn array_to_bounded_vec(array: [T; N]) -> BoundedVec where diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/utils/mod.nr b/noir-projects/noir-protocol-circuits/crates/types/src/utils/mod.nr index 113da583999..d88d62eb507 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/utils/mod.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/utils/mod.nr @@ -6,24 +6,3 @@ pub mod arrays; pub mod field; pub mod reader; pub mod uint256; - -// if predicate == true then return lhs, else return rhs -pub fn conditional_assign(predicate: bool, lhs: Field, rhs: Field) -> Field { - if predicate { - lhs - } else { - rhs - } -} - -pub fn arr_copy_slice( - src: [T; N], - mut dst: [T; M], - offset: u32, -) -> [T; M] { - let iterator_len = if N > M { M } else { N }; - for i in 0..iterator_len { - dst[i] = src[i + offset]; - } - dst -} From b846b7ff18f0947763786caa5ab59cb55b80ffdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Tue, 10 Dec 2024 10:35:25 -0300 Subject: [PATCH 3/4] Update noir-projects/aztec-nr/aztec/src/utils/array/subarray.nr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jan Beneš --- noir-projects/aztec-nr/aztec/src/utils/array/subarray.nr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/noir-projects/aztec-nr/aztec/src/utils/array/subarray.nr b/noir-projects/aztec-nr/aztec/src/utils/array/subarray.nr index 4e450d55cba..27b2e58bf8f 100644 --- a/noir-projects/aztec-nr/aztec/src/utils/array/subarray.nr +++ b/noir-projects/aztec-nr/aztec/src/utils/array/subarray.nr @@ -27,7 +27,7 @@ mod test { #[test] unconstrained fn subarray_into_empty() { - // In all of these cases we're setting DST_LEN to be 0, so we always get back an emtpy array. + // In all of these cases we're setting DST_LEN to be 0, so we always get back an empty array. assert_eq(subarray([], 0), []); assert_eq(subarray([1, 2, 3, 4, 5], 0), []); assert_eq(subarray([1, 2, 3, 4, 5], 2), []); From cd44f1c57002617fe314d8f9708bb5c136d52c5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Tue, 10 Dec 2024 14:22:35 +0000 Subject: [PATCH 4/4] Make asserts runtime --- noir-projects/aztec-nr/aztec/src/utils/array/subarray.nr | 6 ++---- .../noir-protocol-circuits/crates/types/src/utils/arrays.nr | 3 +-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/utils/array/subarray.nr b/noir-projects/aztec-nr/aztec/src/utils/array/subarray.nr index 27b2e58bf8f..fc4b7567185 100644 --- a/noir-projects/aztec-nr/aztec/src/utils/array/subarray.nr +++ b/noir-projects/aztec-nr/aztec/src/utils/array/subarray.nr @@ -1,5 +1,3 @@ -use std::static_assert; - /// Returns `DST_LEN` elements from a source array, starting at `offset`. `DST_LEN` must be large enough to hold all of /// the elements past `offset`. /// @@ -12,7 +10,7 @@ pub fn subarray( src: [Field; SRC_LEN], offset: u32, ) -> [Field; DST_LEN] { - static_assert(offset + DST_LEN <= SRC_LEN, "offset too large"); + assert(offset + DST_LEN <= SRC_LEN, "offset too large"); let mut dst: [Field; DST_LEN] = std::mem::zeroed(); for i in 0..DST_LEN { @@ -27,7 +25,7 @@ mod test { #[test] unconstrained fn subarray_into_empty() { - // In all of these cases we're setting DST_LEN to be 0, so we always get back an empty array. + // In all of these cases we're setting DST_LEN to be 0, so we always get back an emtpy array. assert_eq(subarray([], 0), []); assert_eq(subarray([1, 2, 3, 4, 5], 0), []); assert_eq(subarray([1, 2, 3, 4, 5], 2), []); diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays.nr b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays.nr index 2ce727236e3..97d90406a7d 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays.nr @@ -40,13 +40,12 @@ pub use get_sorted_result::{get_sorted_result, SortedResult}; pub use sort_by_counter::{sort_by_counter_asc, sort_by_counter_desc}; use crate::traits::{Empty, is_empty}; -use std::static_assert; pub fn subarray( src: [Field; SRC_LEN], offset: u32, ) -> [Field; DST_LEN] { - static_assert(offset + DST_LEN <= SRC_LEN, "offset too large"); + assert(offset + DST_LEN <= SRC_LEN, "offset too large"); let mut dst: [Field; DST_LEN] = std::mem::zeroed(); for i in 0..DST_LEN {