From ddf9fa27679afe856eacfd591369361c3830ff27 Mon Sep 17 00:00:00 2001 From: benesjan Date: Tue, 21 Jan 2025 02:27:39 +0000 Subject: [PATCH 01/12] feat: packing note content --- .../aztec-nr/aztec/src/macros/mod.nr | 18 ++++---- .../aztec-nr/aztec/src/macros/notes/mod.nr | 46 +++++++++---------- .../aztec-nr/aztec/src/note/discovery/mod.nr | 24 ++++------ .../aztec-nr/aztec/src/note/lifecycle.nr | 2 +- .../aztec/src/note/note_getter/mod.nr | 2 +- .../aztec-nr/aztec/src/note/note_interface.nr | 4 +- .../aztec-nr/aztec/src/note/utils.nr | 4 +- .../aztec-nr/aztec/src/oracle/notes.nr | 2 +- .../src/test/helpers/test_environment.nr | 2 +- .../aztec/src/test/mocks/mock_note.nr | 4 +- .../ecdsa_public_key_note/src/lib.nr | 6 +-- 11 files changed, 55 insertions(+), 59 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/mod.nr index 2f951652348c..d3e721e074d6 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/mod.nr @@ -138,7 +138,7 @@ comptime fn generate_compute_note_hash_and_optionally_a_nullifier() -> Quoted { if_statements_list = if_statements_list.push_back( quote { $if_or_else_if note_type_id == $typ::get_note_type_id() { - aztec::note::utils::compute_note_hash_and_optionally_a_nullifier($typ::deserialize_content, note_header, compute_nullifier, serialized_note) + aztec::note::utils::compute_note_hash_and_optionally_a_nullifier($typ::unpack_content, note_header, compute_nullifier, serialized_note) } }, ); @@ -184,14 +184,14 @@ comptime fn generate_process_log() -> Quoted { // A typical implementation of the lambda looks something like this: // ``` - // |serialized_note_content: BoundedVec, note_header: NoteHeader, note_type_id: Field| { + // |packed_note_content: BoundedVec, note_header: NoteHeader, note_type_id: Field| { // let hashes = if note_type_id == MyNoteType::get_note_type_id() { - // assert(serialized_note_content.len() == MY_NOTE_TYPE_SERIALIZATION_LENGTH); + // assert(packed_note_content.len() == MY_NOTE_TYPE_SERIALIZATION_LENGTH); // dep::aztec::note::utils::compute_note_hash_and_optionally_a_nullifier( - // MyNoteType::deserialize_content, + // MyNoteType::unpack_content, // note_header, // true, - // serialized_note_content.storage(), + // packed_note_content.storage(), // ) // } else { // panic(f"Unknown note type id {note_type_id}") @@ -224,17 +224,17 @@ comptime fn generate_process_log() -> Quoted { if_note_type_id_match_statements_list = if_note_type_id_match_statements_list.push_back( quote { $if_or_else_if note_type_id == $typ::get_note_type_id() { - // As an extra safety check we make sure that the serialized_note_content bounded vec has the + // As an extra safety check we make sure that the packed_note_content bounded vec has the // expected length, to avoid scenarios in which compute_note_hash_and_optionally_a_nullifier // silently trims the end if the log were to be longer. let expected_len = $serialized_note_length; - let actual_len = serialized_note_content.len(); + let actual_len = packed_note_content.len(); assert( actual_len == expected_len, f"Expected note content of length {expected_len} but got {actual_len} for note type id {note_type_id}" ); - aztec::note::utils::compute_note_hash_and_optionally_a_nullifier($typ::deserialize_content, note_header, true, serialized_note_content.storage()) + aztec::note::utils::compute_note_hash_and_optionally_a_nullifier($typ::unpack_content, note_header, true, packed_note_content.storage()) } }, ); @@ -256,7 +256,7 @@ comptime fn generate_process_log() -> Quoted { unique_note_hashes_in_tx, first_nullifier_in_tx, recipient, - |serialized_note_content: BoundedVec, note_header, note_type_id| { + |packed_note_content: BoundedVec, note_header, note_type_id| { let hashes = $if_note_type_id_match_statements else { panic(f"Unknown note type id {note_type_id}") diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index 5cec843fd44c..208106d3138e 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -8,7 +8,7 @@ use std::{ comptime global NOTE_HEADER_TYPE: Type = type_of(NoteHeader::empty()); -/// A map from note type to (note_struct_definition, serialized_note_length, note_type_id, fields). +/// A map from note type to (note_struct_definition, note_packed_len, note_type_id, fields). /// `fields` is an array of tuples where each tuple contains the name of the field/struct member (e.g. `amount` /// in `TokenNote`), the index of where the serialized member starts in the serialized note and a flag indicating /// whether the field is nullable or not. @@ -38,11 +38,11 @@ comptime fn get_next_note_type_id() -> Field { /// ... /// } /// -/// fn deserialize_content(serialized_content: [Field; N]) -> Self { +/// fn unpack_content(packed_content: [Field; N]) -> Self { /// ... /// } /// -/// fn serialize_content(self) -> [Field; N] { +/// fn pack_content(self) -> [Field; N] { /// ... /// } /// @@ -86,10 +86,10 @@ comptime fn generate_note_interface( let content_fields = content_fields_list.join(quote {,}); let content_len = content_fields_list.len(); - let (deserialized_content, _) = generate_deserialize_from_fields( + let (unpacked_content, _) = generate_deserialize_from_fields( quote {}, typ, - quote { serialized_content }, // "serialized_content" is argument of NoteInterface::deserialize_content + quote { packed_content }, // "packed_content" is argument of NoteInterface::deserialize_content 0, quote {header}, quote { aztec::note::note_header::NoteHeader::empty() }, @@ -114,11 +114,11 @@ comptime fn generate_note_interface( ( quote { impl aztec::note::note_interface::NoteInterface<$content_len> for $name { - fn deserialize_content(serialized_content: [Field; $content_len]) -> Self { - $deserialized_content + fn unpack_content(packed_content: [Field; $content_len]) -> Self { + $unpacked_content } - fn serialize_content(self) -> [Field; $content_len] { + fn pack_content(self) -> [Field; $content_len] { $content_aux_vars [$content_fields] } @@ -356,10 +356,10 @@ comptime fn generate_multi_scalar_mul( /// log_plaintext[32 + i] = note_type_id_bytes[i]; /// } /// -/// let serialized_note = [npk_m_hash as Field, randomness as Field]; +/// let packed_note_content = [npk_m_hash as Field, randomness as Field]; /// -/// for i in 0..serialized_note.len() { -/// let bytes: [u8; 32] = serialized_note[i].to_be_bytes(); +/// for i in 0..packed_note_content.len() { +/// let bytes: [u8; 32] = packed_note_content[i].to_be_bytes(); /// for j in 0..32 { /// log_plaintext[64 + i * 32 + j] = bytes[j]; /// } @@ -510,10 +510,10 @@ comptime fn get_setup_log_plaintext_body( } $aux_vars_for_serialization - let serialized_note = [$fields]; + let packed_note_content = [$fields]; - for i in 0..serialized_note.len() { - let bytes: [u8; 32] = serialized_note[i].to_be_bytes(); + for i in 0..packed_note_content.len() { + let bytes: [u8; 32] = packed_note_content[i].to_be_bytes(); for j in 0..32 { log_plaintext[64 + i * 32 + j] = bytes[j]; } @@ -793,11 +793,11 @@ comptime fn generate_partial_note_impl( } } -/// Registers a note struct `note` with the given `note_serialized_len`, `note_type_id`, `fixed_fields` and +/// Registers a note struct `note` with the given `note_packed_len`, `note_type_id`, `fixed_fields` and /// `nullable_fields` in the global `NOTES` map. comptime fn register_note( note: StructDefinition, - note_serialized_len: u32, + note_packed_len: u32, note_type_id: Field, fixed_fields: [(Quoted, Type, u32)], nullable_fields: [(Quoted, Type, u32)], @@ -812,7 +812,7 @@ comptime fn register_note( fields = fields.push_back((name, index, true)); } - NOTES.insert(note.as_type(), (note, note_serialized_len, note_type_id, fields)); + NOTES.insert(note.as_type(), (note, note_packed_len, note_type_id, fields)); } /// Separates note struct members into fixed and nullable ones. It also stores the index of where each struct member @@ -876,7 +876,7 @@ pub comptime fn partial_note(s: StructDefinition, nullable_fields: [Quoted]) -> generate_setup_payload(s, indexed_fixed_fields, indexed_nullable_fields); let (finalization_payload_impl, finalization_payload_name) = generate_finalization_payload(s, indexed_fixed_fields, indexed_nullable_fields); - let (note_interface_impl, note_serialized_len) = generate_note_interface( + let (note_interface_impl, note_packed_len) = generate_note_interface( s, note_type_id, indexed_fixed_fields, @@ -886,7 +886,7 @@ pub comptime fn partial_note(s: StructDefinition, nullable_fields: [Quoted]) -> generate_partial_note_impl(s, setup_payload_name, finalization_payload_name); register_note( s, - note_serialized_len, + note_packed_len, note_type_id, indexed_fixed_fields, indexed_nullable_fields, @@ -915,7 +915,7 @@ pub comptime fn note(s: StructDefinition) -> Quoted { let note_properties = generate_note_properties(s); let note_type_id = get_next_note_type_id(); - let (note_interface_impl, note_serialized_len) = generate_note_interface( + let (note_interface_impl, note_packed_len) = generate_note_interface( s, note_type_id, indexed_fixed_fields, @@ -923,7 +923,7 @@ pub comptime fn note(s: StructDefinition) -> Quoted { ); register_note( s, - note_serialized_len, + note_packed_len, note_type_id, indexed_fixed_fields, indexed_nullable_fields, @@ -952,7 +952,7 @@ pub comptime fn note_custom_interface(s: StructDefinition) -> Quoted { ); let name = s.name(); - let note_serialized_len = note_interface_impl + let note_packed_len = note_interface_impl .expect(f"Note {name} must implement NoteInterface trait") .trait_generic_args()[0] .as_constant() @@ -961,7 +961,7 @@ pub comptime fn note_custom_interface(s: StructDefinition) -> Quoted { let (indexed_fixed_fields, indexed_nullable_fields) = index_note_fields(s, &[]); register_note( s, - note_serialized_len, + note_packed_len, note_type_id, indexed_fixed_fields, indexed_nullable_fields, diff --git a/noir-projects/aztec-nr/aztec/src/note/discovery/mod.nr b/noir-projects/aztec-nr/aztec/src/note/discovery/mod.nr index 1f0c0316832f..ddbcd80e9de9 100644 --- a/noir-projects/aztec-nr/aztec/src/note/discovery/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/note/discovery/mod.nr @@ -30,14 +30,14 @@ pub struct NoteHashesAndNullifier { /// note in the contract given their contents. A typical implementation of such a function would look like this: /// /// ``` -/// |serialized_note_content, note_header, note_type_id| { +/// |packed_note_content, note_header, note_type_id| { /// let hashes = if note_type_id == MyNoteType::get_note_type_id() { -/// assert(serialized_note_content.len() == MY_NOTE_TYPE_SERIALIZATION_LENGTH); +/// assert(packed_note_content.len() == MY_NOTE_TYPE_SERIALIZATION_LENGTH); /// dep::aztec::note::utils::compute_note_hash_and_optionally_a_nullifier( -/// MyNoteType::deserialize_content, +/// MyNoteType::unpack_content, /// note_header, /// true, -/// serialized_note_content.storage(), +/// packed_note_content.storage(), /// ) /// } else { /// panic(f"Unknown note type id {note_type_id}") @@ -59,7 +59,7 @@ pub unconstrained fn do_process_log( recipient: AztecAddress, compute_note_hash_and_nullifier: fn[Env](BoundedVec, NoteHeader, Field) -> Option, ) { - let (storage_slot, note_type_id, serialized_note_content) = + let (storage_slot, note_type_id, packed_note_content) = destructure_log_plaintext(log_plaintext); // We need to find the note's nonce, which is the one that results in one of the unique note hashes from tx_hash @@ -71,12 +71,8 @@ pub unconstrained fn do_process_log( let header = NoteHeader::new(context.this_address(), candidate_nonce, storage_slot); // TODO(#11157): handle failed note_hash_and_nullifier computation - let hashes = compute_note_hash_and_nullifier( - serialized_note_content, - header, - note_type_id, - ) - .unwrap(); + let hashes = + compute_note_hash_and_nullifier(packed_note_content, header, note_type_id).unwrap(); if hashes.unique_note_hash == expected_unique_note_hash { // TODO(#10726): push these into a vec to deliver all at once instead of having one oracle call per note @@ -86,7 +82,7 @@ pub unconstrained fn do_process_log( context.this_address(), // TODO(#10727): allow other contracts to deliver notes storage_slot, candidate_nonce, - serialized_note_content, + packed_note_content, hashes.note_hash, hashes.inner_nullifier, tx_hash, @@ -117,9 +113,9 @@ unconstrained fn destructure_log_plaintext( let storage_slot = log_plaintext.get(0); let note_type_id = log_plaintext.get(1); - let serialized_note_content = array::subbvec(log_plaintext, NOTE_LOG_RESERVED_FIELDS); + let packed_note_content = array::subbvec(log_plaintext, NOTE_LOG_RESERVED_FIELDS); - (storage_slot, note_type_id, serialized_note_content) + (storage_slot, note_type_id, packed_note_content) } fn for_each_in_bounded_vec( diff --git a/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr b/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr index d284a8e90fcf..460531601bce 100644 --- a/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr +++ b/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr @@ -22,7 +22,7 @@ where note.set_header(header); let note_hash = note.compute_note_hash(); - let serialized_note = Note::serialize_content(*note); + let serialized_note = Note::pack_content(*note); notify_created_note( storage_slot, Note::get_note_type_id(), 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 02f94ef64c36..ee654c014963 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 @@ -154,7 +154,7 @@ where for i in 0..options.limit { if i < notes.len() { let note = notes.get_unchecked(i); - let fields = note.serialize_content(); + let fields = note.pack_content(); check_note_header(*context, storage_slot, note); check_note_fields(fields, options.selects); if i != 0 { diff --git a/noir-projects/aztec-nr/aztec/src/note/note_interface.nr b/noir-projects/aztec-nr/aztec/src/note/note_interface.nr index 6f264fc4df20..94ed825f9863 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_interface.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_interface.nr @@ -38,9 +38,9 @@ pub trait NullifiableNote { // docs:start:note_interface // Autogenerated by the #[note] macro pub trait NoteInterface { - fn serialize_content(self) -> [Field; N]; + fn pack_content(self) -> [Field; N]; - fn deserialize_content(fields: [Field; N]) -> Self; + fn unpack_content(fields: [Field; N]) -> Self; fn get_header(self) -> NoteHeader; diff --git a/noir-projects/aztec-nr/aztec/src/note/utils.nr b/noir-projects/aztec-nr/aztec/src/note/utils.nr index 55c5870d0ff6..9f69c5987bbc 100644 --- a/noir-projects/aztec-nr/aztec/src/note/utils.nr +++ b/noir-projects/aztec-nr/aztec/src/note/utils.nr @@ -117,7 +117,7 @@ where } pub unconstrained fn compute_note_hash_and_optionally_a_nullifier( - deserialize_content: fn([Field; N]) -> T, + unpack_content: fn([Field; N]) -> T, note_header: NoteHeader, compute_nullifier: bool, serialized_note: [Field; S], @@ -125,7 +125,7 @@ pub unconstrained fn compute_note_hash_and_optionally_a_nullifier + NullifiableNote, { - let mut note = deserialize_content(array::subarray(serialized_note, 0)); + let mut note = unpack_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/notes.nr b/noir-projects/aztec-nr/aztec/src/oracle/notes.nr index 642e1281915b..7465b24fd17f 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/notes.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/notes.nr @@ -200,7 +200,7 @@ where let note_hash_counter = fields[read_offset + 1] as u32; let note_content = array::subarray(fields, read_offset + 2); - let mut note = Note::deserialize_content(note_content); + let mut note = Note::unpack_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/test/helpers/test_environment.nr b/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr index 1ab5a63f8631..e52b857b5f11 100644 --- a/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr +++ b/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr @@ -148,7 +148,7 @@ impl TestEnvironment { let header = NoteHeader { contract_address, storage_slot, nonce: 0, note_hash_counter }; note.set_header(header); let note_hash = note.compute_note_hash(); - let serialized_note = Note::serialize_content(*note); + let serialized_note = Note::pack_content(*note); notify_created_note( storage_slot, Note::get_note_type_id(), diff --git a/noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr b/noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr index b28c49a5ba8f..9f96a0489d72 100644 --- a/noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr +++ b/noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr @@ -47,11 +47,11 @@ impl NullifiableNote for MockNote { } impl NoteInterface for MockNote { - fn serialize_content(self) -> [Field; MOCK_NOTE_LENGTH] { + fn pack_content(self) -> [Field; MOCK_NOTE_LENGTH] { [self.value] } - fn deserialize_content(fields: [Field; MOCK_NOTE_LENGTH]) -> Self { + fn unpack_content(fields: [Field; MOCK_NOTE_LENGTH]) -> Self { Self { value: fields[0], header: NoteHeader::empty() } } diff --git a/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr b/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr index b560bbacb687..ab5cf216d6fd 100644 --- a/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr +++ b/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr @@ -27,7 +27,7 @@ impl NoteInterface for EcdsaPublicKeyNote { // [2] = y[0..31] // [3] = y[31] // [4] = owner - fn serialize_content(self) -> [Field; ECDSA_PUBLIC_KEY_NOTE_LEN] { + fn pack_content(self) -> [Field; ECDSA_PUBLIC_KEY_NOTE_LEN] { let mut x: Field = 0; let mut y: Field = 0; let mut mul: Field = 1; @@ -47,7 +47,7 @@ impl NoteInterface for EcdsaPublicKeyNote { } // Cannot use the automatic deserialization for the aforementioned reasons - fn deserialize_content(serialized_note: [Field; ECDSA_PUBLIC_KEY_NOTE_LEN]) -> EcdsaPublicKeyNote { + fn unpack_content(serialized_note: [Field; ECDSA_PUBLIC_KEY_NOTE_LEN]) -> EcdsaPublicKeyNote { let mut x: [u8; 32] = [0; 32]; let mut y: [u8; 32] = [0; 32]; @@ -80,7 +80,7 @@ impl NoteInterface for EcdsaPublicKeyNote { } fn compute_note_hash(self) -> Field { - let serialized = self.serialize_content(); + let serialized = self.pack_content(); std::embedded_curve_ops::multi_scalar_mul( [Gx_1, Gx_2, Gy_1, Gy_2, G_owner, G_slot], [ From dadeb8e1dcc1fa22bb58022cca6054731966ae75 Mon Sep 17 00:00:00 2001 From: benesjan Date: Thu, 23 Jan 2025 19:48:29 +0000 Subject: [PATCH 02/12] naming fixes --- .../aztec-nr/aztec/src/macros/mod.nr | 12 ++++---- .../aztec-nr/aztec/src/macros/notes/mod.nr | 4 +-- .../aztec-nr/aztec/src/note/lifecycle.nr | 4 +-- .../aztec/src/note/note_getter/mod.nr | 12 ++++---- .../aztec-nr/aztec/src/note/utils.nr | 4 +-- .../aztec-nr/aztec/src/oracle/notes.nr | 10 +++---- .../src/test/helpers/test_environment.nr | 4 +-- .../ecdsa_public_key_note/src/lib.nr | 28 +++++++++---------- yarn-project/pxe/src/database/note_dao.ts | 4 +-- .../simulator/src/client/pick_notes.ts | 8 +++--- 10 files changed, 45 insertions(+), 45 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/mod.nr index d3e721e074d6..981b6dc11557 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/mod.nr @@ -112,10 +112,10 @@ comptime fn generate_contract_interface(m: Module) -> Quoted { } comptime fn generate_compute_note_hash_and_optionally_a_nullifier() -> Quoted { - let mut max_note_length: u32 = 0; + let mut max_note_content_length: u32 = 0; let notes = NOTES.entries(); let body = if notes.len() > 0 { - max_note_length = notes.fold( + max_note_content_length = notes.fold( 0, |acc, (_, (_, len, _, _)): (Type, (StructDefinition, u32, Field, [(Quoted, u32, bool)]))| { if len > acc { @@ -138,7 +138,7 @@ comptime fn generate_compute_note_hash_and_optionally_a_nullifier() -> Quoted { if_statements_list = if_statements_list.push_back( quote { $if_or_else_if note_type_id == $typ::get_note_type_id() { - aztec::note::utils::compute_note_hash_and_optionally_a_nullifier($typ::unpack_content, note_header, compute_nullifier, serialized_note) + aztec::note::utils::compute_note_hash_and_optionally_a_nullifier($typ::unpack_content, note_header, compute_nullifier, packed_note_content) } }, ); @@ -166,7 +166,7 @@ comptime fn generate_compute_note_hash_and_optionally_a_nullifier() -> Quoted { storage_slot: Field, note_type_id: Field, compute_nullifier: bool, - serialized_note: [Field; $max_note_length], + packed_note_content: [Field; $max_note_content_length], ) -> pub [Field; 4] { $body } @@ -213,7 +213,7 @@ comptime fn generate_process_log() -> Quoted { let mut if_note_type_id_match_statements_list = &[]; for i in 0..notes.len() { - let (typ, (_, serialized_note_length, _, _)) = notes[i]; + let (typ, (_, packed_note_content_length, _, _)) = notes[i]; let if_or_else_if = if i == 0 { quote { if } @@ -227,7 +227,7 @@ comptime fn generate_process_log() -> Quoted { // As an extra safety check we make sure that the packed_note_content bounded vec has the // expected length, to avoid scenarios in which compute_note_hash_and_optionally_a_nullifier // silently trims the end if the log were to be longer. - let expected_len = $serialized_note_length; + let expected_len = $packed_note_content_length; let actual_len = packed_note_content.len(); assert( actual_len == expected_len, diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index 208106d3138e..488a43b6aac6 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -10,7 +10,7 @@ comptime global NOTE_HEADER_TYPE: Type = type_of(NoteHeader::empty()); /// A map from note type to (note_struct_definition, note_packed_len, note_type_id, fields). /// `fields` is an array of tuples where each tuple contains the name of the field/struct member (e.g. `amount` -/// in `TokenNote`), the index of where the serialized member starts in the serialized note and a flag indicating +/// in `TokenNote`), the index of where the packed member starts in the packed note and a flag indicating /// whether the field is nullable or not. pub comptime mut global NOTES: UHashMap> = UHashMap::default(); @@ -31,7 +31,7 @@ comptime fn get_next_note_type_id() -> Field { } /// Generates default `NoteInterface` implementation for a given note struct `s` and returns it as quote along with -/// the length of the serialized note. +/// the length of the packed note. /// /// impl NoteInterface for NoteStruct { /// fn to_be_bytes(self, storage_slot: Field) -> [u8; N * 32 + 64] { diff --git a/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr b/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr index 460531601bce..2359e7a9c64f 100644 --- a/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr +++ b/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr @@ -22,11 +22,11 @@ where note.set_header(header); let note_hash = note.compute_note_hash(); - let serialized_note = Note::pack_content(*note); + let packed_note_content = Note::pack_content(*note); notify_created_note( storage_slot, Note::get_note_type_id(), - serialized_note, + packed_note_content, note_hash, note_hash_counter, ); 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 ee654c014963..75481c9d036a 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 @@ -17,13 +17,13 @@ pub use crate::note::constants::MAX_NOTES_PER_PAGE; mod test; fn extract_property_value_from_selector( - serialized_note: [Field; N], + packed_note_content: [Field; N], selector: PropertySelector, ) -> Field { // 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: [u8; 32] = serialized_note[selector.index].to_be_bytes(); + let value: [u8; 32] = packed_note_content[selector.index].to_be_bytes(); let offset = selector.offset; let length = selector.length; let mut value_field = 0 as Field; @@ -47,14 +47,14 @@ where assert(header.storage_slot == storage_slot, "Mismatch note header storage slot."); } -fn check_note_fields( - serialized_note: [Field; N], +fn check_note_content( + packed_note_content: [Field; N], selects: BoundedVec, N>, ) { for i in 0..selects.len() { let select = selects.get_unchecked(i).unwrap_unchecked(); let value_field = - extract_property_value_from_selector(serialized_note, select.property_selector); + extract_property_value_from_selector(packed_note_content, select.property_selector); assert( compare(value_field, select.comparator, select.value.to_field()), @@ -156,7 +156,7 @@ where let note = notes.get_unchecked(i); let fields = note.pack_content(); check_note_header(*context, storage_slot, note); - check_note_fields(fields, options.selects); + check_note_content(fields, options.selects); if i != 0 { check_notes_order(prev_fields, fields, options.sorts); } diff --git a/noir-projects/aztec-nr/aztec/src/note/utils.nr b/noir-projects/aztec-nr/aztec/src/note/utils.nr index 9f69c5987bbc..730540ec0210 100644 --- a/noir-projects/aztec-nr/aztec/src/note/utils.nr +++ b/noir-projects/aztec-nr/aztec/src/note/utils.nr @@ -120,12 +120,12 @@ pub unconstrained fn compute_note_hash_and_optionally_a_nullifier T, note_header: NoteHeader, compute_nullifier: bool, - serialized_note: [Field; S], + packed_note_content: [Field; S], ) -> [Field; 4] where T: NoteInterface + NullifiableNote, { - let mut note = unpack_content(array::subarray(serialized_note, 0)); + let mut note = unpack_content(array::subarray(packed_note_content, 0)); note.set_header(note_header); let note_hash = note.compute_note_hash(); diff --git a/noir-projects/aztec-nr/aztec/src/oracle/notes.nr b/noir-projects/aztec-nr/aztec/src/oracle/notes.nr index 7465b24fd17f..f1d779c43c49 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/notes.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/notes.nr @@ -10,7 +10,7 @@ use dep::protocol_types::{ pub fn notify_created_note( storage_slot: Field, note_type_id: Field, - serialized_note: [Field; N], + packed_note_content: [Field; N], note_hash: Field, counter: u32, ) { @@ -20,7 +20,7 @@ pub fn notify_created_note( notify_created_note_oracle_wrapper( storage_slot, note_type_id, - serialized_note, + packed_note_content, note_hash, counter, ) @@ -45,14 +45,14 @@ pub fn notify_created_nullifier(nullifier: Field) { unconstrained fn notify_created_note_oracle_wrapper( storage_slot: Field, note_type_id: Field, - serialized_note: [Field; N], + packed_note_content: [Field; N], note_hash: Field, counter: u32, ) { let _ = notify_created_note_oracle( storage_slot, note_type_id, - serialized_note, + packed_note_content, note_hash, counter, ); @@ -62,7 +62,7 @@ unconstrained fn notify_created_note_oracle_wrapper( unconstrained fn notify_created_note_oracle( _storage_slot: Field, _note_type_id: Field, - _serialized_note: [Field; N], + _packed_note_content: [Field; N], _note_hash: Field, _counter: u32, ) -> Field {} diff --git a/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr b/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr index e52b857b5f11..d5e494cc5a7e 100644 --- a/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr +++ b/noir-projects/aztec-nr/aztec/src/test/helpers/test_environment.nr @@ -148,11 +148,11 @@ impl TestEnvironment { let header = NoteHeader { contract_address, storage_slot, nonce: 0, note_hash_counter }; note.set_header(header); let note_hash = note.compute_note_hash(); - let serialized_note = Note::pack_content(*note); + let packed_content = Note::pack_content(*note); notify_created_note( storage_slot, Note::get_note_type_id(), - serialized_note, + packed_content, note_hash, note_hash_counter, ); diff --git a/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr b/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr index ab5cf216d6fd..d86b4a76161d 100644 --- a/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr +++ b/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr @@ -21,7 +21,7 @@ pub struct EcdsaPublicKeyNote { } impl NoteInterface for EcdsaPublicKeyNote { - // Cannot use the automatic serialization since x and y don't fit. Serialize the note as 5 fields where: + // Cannot use the automatic packing since x and y don't fit. Serialize the note as 5 fields where: // [0] = x[0..31] (upper bound excluded) // [1] = x[31] // [2] = y[0..31] @@ -46,24 +46,24 @@ impl NoteInterface for EcdsaPublicKeyNote { [x, last_x, y, last_y, self.owner.to_field()] } - // Cannot use the automatic deserialization for the aforementioned reasons - fn unpack_content(serialized_note: [Field; ECDSA_PUBLIC_KEY_NOTE_LEN]) -> EcdsaPublicKeyNote { + // Cannot use the automatic unpacking for the aforementioned reasons + fn unpack_content(packed_content: [Field; ECDSA_PUBLIC_KEY_NOTE_LEN]) -> EcdsaPublicKeyNote { let mut x: [u8; 32] = [0; 32]; let mut y: [u8; 32] = [0; 32]; - let part_x:[u8; 32] = serialized_note[0].to_be_bytes(); + let part_x:[u8; 32] = packed_content[0].to_be_bytes(); for i in 0..31 { x[i] = part_x[i + 1]; } - x[31] = serialized_note[1].to_be_bytes::<32>()[31]; + x[31] = packed_content[1].to_be_bytes::<32>()[31]; - let part_y:[u8; 32] = serialized_note[2].to_be_bytes(); + let part_y:[u8; 32] = packed_content[2].to_be_bytes(); for i in 0..31 { y[i] = part_y[i + 1]; } - y[31] = serialized_note[3].to_be_bytes::<32>()[31]; + y[31] = packed_content[3].to_be_bytes::<32>()[31]; - EcdsaPublicKeyNote { x, y, owner: AztecAddress::from_field(serialized_note[4]), header: NoteHeader::empty() } + EcdsaPublicKeyNote { x, y, owner: AztecAddress::from_field(packed_content[4]), header: NoteHeader::empty() } } fn get_note_type_id() -> Field { @@ -80,15 +80,15 @@ impl NoteInterface for EcdsaPublicKeyNote { } fn compute_note_hash(self) -> Field { - let serialized = self.pack_content(); + let packed_content = self.pack_content(); std::embedded_curve_ops::multi_scalar_mul( [Gx_1, Gx_2, Gy_1, Gy_2, G_owner, G_slot], [ - from_field_unsafe(serialized[0]), - from_field_unsafe(serialized[1]), - from_field_unsafe(serialized[2]), - from_field_unsafe(serialized[3]), - from_field_unsafe(serialized[4]), + from_field_unsafe(packed_content[0]), + from_field_unsafe(packed_content[1]), + from_field_unsafe(packed_content[2]), + from_field_unsafe(packed_content[3]), + from_field_unsafe(packed_content[4]), from_field_unsafe(self.get_header().storage_slot) ] ).x diff --git a/yarn-project/pxe/src/database/note_dao.ts b/yarn-project/pxe/src/database/note_dao.ts index 77b5ed85e806..242968609db6 100644 --- a/yarn-project/pxe/src/database/note_dao.ts +++ b/yarn-project/pxe/src/database/note_dao.ts @@ -6,14 +6,14 @@ import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { type NoteData } from '@aztec/simulator/client'; /** - * A Note Data Access Object, representing a note that was comitted to the note hash tree, holding all of the + * A Note Data Access Object, representing a note that was committed to the note hash tree, holding all of the * information required to use it during execution and manage its state. */ export class NoteDao implements NoteData { constructor( // Note information - /** The serialized content of the note, as will be returned in the getNotes oracle. */ + /** The packed content of the note, as will be returned in the getNotes oracle. */ public note: Note, /** The address of the contract that created the note (i.e. the address used by the kernel during siloing). */ public contractAddress: AztecAddress, diff --git a/yarn-project/simulator/src/client/pick_notes.ts b/yarn-project/simulator/src/client/pick_notes.ts index 26e65e64616b..1e27fefa3320 100644 --- a/yarn-project/simulator/src/client/pick_notes.ts +++ b/yarn-project/simulator/src/client/pick_notes.ts @@ -84,7 +84,7 @@ interface ContainsNote { note: Note; } -const selectPropertyFromSerializedNote = (noteData: Fr[], selector: PropertySelector): Fr => { +const selectPropertyFromPackedNoteContent = (noteData: Fr[], selector: PropertySelector): Fr => { const noteValueBuffer = noteData[selector.index].toBuffer(); const noteValue = noteValueBuffer.subarray(selector.offset, selector.offset + selector.length); return Fr.fromBuffer(noteValue); @@ -93,7 +93,7 @@ const selectPropertyFromSerializedNote = (noteData: Fr[], selector: PropertySele const selectNotes = (noteDatas: T[], selects: Select[]): T[] => noteDatas.filter(noteData => selects.every(({ selector, value, comparator }) => { - const noteValueFr = selectPropertyFromSerializedNote(noteData.note.items, selector); + const noteValueFr = selectPropertyFromPackedNoteContent(noteData.note.items, selector); const comparatorSelector = { [Comparator.EQ]: () => noteValueFr.equals(value), [Comparator.NEQ]: () => !noteValueFr.equals(value), @@ -117,8 +117,8 @@ const sortNotes = (a: Fr[], b: Fr[], sorts: Sort[], level = 0): number => { return 0; } - const aValue = selectPropertyFromSerializedNote(a, selector); - const bValue = selectPropertyFromSerializedNote(b, selector); + const aValue = selectPropertyFromPackedNoteContent(a, selector); + const bValue = selectPropertyFromPackedNoteContent(b, selector); const dir = order === 1 ? [-1, 1] : [1, -1]; return aValue.toBigInt() === bValue.toBigInt() From 59d24b09e7a6247577a0f0f7c654624aefff762f Mon Sep 17 00:00:00 2001 From: benesjan Date: Fri, 24 Jan 2025 16:07:11 +0000 Subject: [PATCH 03/12] WIP --- .../aztec-nr/aztec/src/macros/events/mod.nr | 2 +- .../aztec/src/macros/functions/mod.nr | 4 +- .../aztec-nr/aztec/src/macros/notes/mod.nr | 12 ++-- .../crates/types/src/meta/mod.nr | 71 +++++++++++++++---- 4 files changed, 69 insertions(+), 20 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/events/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/events/mod.nr index cb1f1aa6a70b..ced8b82c4018 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/events/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/events/mod.nr @@ -5,7 +5,7 @@ comptime fn generate_event_interface(s: StructDefinition) -> Quoted { let name = s.name(); let typ = s.as_type(); let (serialization_fields, _) = - generate_serialize_to_fields(quote { self }, typ, &[quote {self.header}]); + generate_serialize_to_fields(quote { self }, typ, &[quote {self.header}], false); let content_len = serialization_fields.len(); let event_type_id = compute_event_selector(s); diff --git a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr index 45f01b7b9e73..78aca4f53a55 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr @@ -250,7 +250,9 @@ comptime fn transform_public(f: FunctionDefinition) -> Quoted { // Public functions undergo a lot of transformations from their Aztec.nr form. let original_params = f.parameters(); let args_len = original_params - .map(|(name, typ): (Quoted, Type)| generate_serialize_to_fields(name, typ, &[]).0.len()) + .map(|(name, typ): (Quoted, Type)| { + generate_serialize_to_fields(name, typ, &[], false).0.len() + }) .fold(0, |acc: u32, val: u32| acc + val); // Unlike in the private case, in public the `context` does not need to receive the hash of the original params. diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index 488a43b6aac6..b09ae9a7584b 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -74,7 +74,7 @@ comptime fn generate_note_interface( // First we compute note content serialization. We do that by passing the whole note struct // to the `generate_serialize_to_fields(...)` and omitting the header. let (content_fields_list, content_aux_vars_list) = - generate_serialize_to_fields(quote { self }, typ, &[quote {self.header}]); + generate_serialize_to_fields(quote { self }, typ, &[quote {self.header}], false); // If there are `aux_vars` we need to join them with `;` and add a trailing `;` to the joined string. let content_aux_vars = if content_aux_vars_list.len() > 0 { @@ -293,7 +293,8 @@ comptime fn generate_multi_scalar_mul( for i in 0..indexed_fields.len() { let (field_name, typ, index) = indexed_fields[i]; let start_generator_index = index + 1; - let (serialization_fields, aux_vars) = generate_serialize_to_fields(field_name, typ, &[]); + let (serialization_fields, aux_vars) = + generate_serialize_to_fields(field_name, typ, &[], false); for j in 0..serialization_fields.len() { let serialization_field = serialization_fields[j]; let generator_index = start_generator_index + j; @@ -487,7 +488,8 @@ comptime fn get_setup_log_plaintext_body( let to_omit = indexed_nullable_fields.map(|(name, _, _): (Quoted, Type, u32)| name).push_back( quote { header }, ); - let (fields_list, aux_vars) = generate_serialize_to_fields(quote { }, s.as_type(), to_omit); + let (fields_list, aux_vars) = + generate_serialize_to_fields(quote { }, s.as_type(), to_omit, false); // If there are `aux_vars` we need to join them with `;` and add a trailing `;` to the joined string. let aux_vars_for_serialization = if aux_vars.len() > 0 { @@ -609,7 +611,7 @@ comptime fn generate_finalization_payload( quote { header }, ); let (nullable_fields_list, aux_vars) = - generate_serialize_to_fields(quote { }, s.as_type(), to_omit); + generate_serialize_to_fields(quote { }, s.as_type(), to_omit, false); // If there are `aux_vars` we need to join them with `;` and add a trailing `;` to the joined string. let aux_vars_for_serialization = if aux_vars.len() > 0 { @@ -834,7 +836,7 @@ comptime fn index_note_fields( indexed_nullable_fields = indexed_nullable_fields.push_back((name, typ, counter)); } } - let (serialization_fields, _) = generate_serialize_to_fields(name, typ, &[]); + let (serialization_fields, _) = generate_serialize_to_fields(name, typ, &[], false); // Each struct member can occupy multiple fields so we need to increment the counter accordingly counter += serialization_fields.len(); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr index 301be09198fb..569fd380ad63 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr @@ -1,4 +1,4 @@ -use super::traits::{Deserialize, Serialize}; +use super::traits::{Deserialize, Packable, Serialize}; /// Generates code that deserializes a struct, primitive type, array or string from a field array. /// @@ -185,12 +185,14 @@ pub comptime fn generate_deserialize_from_fields( } /// Generates code that serializes a type into an array of fields. Also generates auxiliary variables if necessary -/// for serialization. +/// for serialization. If `should_pack` is true, we check if the type implements the `Packable` trait and pack it +/// if it does. /// /// # Parameters /// - `name`: The base identifier (e.g., `self`, `some_var`). /// - `typ`: The type being serialized (e.g., a custom struct, array, or primitive type). /// - `omit`: A list of field names (as `Quoted`) to be excluded from the serialized output. +/// - `should_pack`: A boolean indicating whether the type should be packed. /// /// # Returns /// A tuple containing: @@ -210,7 +212,7 @@ pub comptime fn generate_deserialize_from_fields( /// /// Serializing the struct: /// ```rust -/// generate_serialize_to_fields(quote { my_u128 }, U128, &[]) +/// generate_serialize_to_fields(quote { my_u128 }, U128, &[], false) /// // Returns: /// // ([`my_u128.lo`, `my_u128.hi`], []) /// ``` @@ -227,7 +229,7 @@ pub comptime fn generate_deserialize_from_fields( /// /// Serializing while omitting `header`: /// ```rust -/// generate_serialize_to_fields(quote { self }, UintNote, &[quote { self.header }]) +/// generate_serialize_to_fields(quote { self }, UintNote, &[quote { self.header }], false) /// // Returns: /// // ([`self.value.lo`, `self.value.hi`, `self.randomness`], []) /// ``` @@ -235,7 +237,7 @@ pub comptime fn generate_deserialize_from_fields( /// ## Array /// For an array type: /// ```rust -/// generate_serialize_to_fields(quote { my_array }, [Field; 3], &[]) +/// generate_serialize_to_fields(quote { my_array }, [Field; 3], &[], false) /// // Returns: /// // ([`my_array[0]`, `my_array[1]`, `my_array[2]`], []) /// ``` @@ -243,12 +245,31 @@ pub comptime fn generate_deserialize_from_fields( /// ## String /// For a string field, where each character is serialized as a `Field`: /// ```rust -/// generate_serialize_to_fields(quote { my_string }, StringType, &[]) +/// generate_serialize_to_fields(quote { my_string }, StringType, &[], false) /// // Returns: /// // ([`my_string_as_bytes[0] as Field`, `my_string_as_bytes[1] as Field`, ...], /// // [`let my_string_as_bytes = my_string.as_bytes()`]) /// ``` /// +/// ## Nested Struct with Omitted Field and packing enabled +/// - U128 has a `Packable` implementation hence it will be packed. +/// +/// For a more complex struct: +/// ```rust +/// struct UintNote { +/// value: U128, +/// randomness: Field, +/// header: NoteHeader, +/// } +/// ``` +/// +/// Serializing while omitting `header`: +/// ```rust +/// generate_serialize_to_fields(quote { self }, UintNote, &[quote { self.header }], true) +/// // Returns: +/// // ([`value_packed[0]`, `self.randomness`], [`let value_packed = self.value.pack()`]) +/// ``` +/// /// # Panics /// - If the type is unsupported for serialization. /// - If the provided `typ` contains invalid constants or incompatible structures. @@ -256,13 +277,28 @@ pub comptime fn generate_serialize_to_fields( name: Quoted, typ: Type, omit: [Quoted], + should_pack: bool, ) -> ([Quoted], [Quoted]) { let mut fields = &[]; let mut aux_vars = &[]; // Proceed if none of the omit rules omits this name if !omit.any(|to_omit| to_omit == name) { - if typ.is_field() { + // If the type implements `Packable`, its length will be assigned to the `maybe_packed_len_typ` variable. + let maybe_packed_len_typ = std::meta::typ::fresh_type_variable(); + let packable_constraint = quote { Packable<$maybe_packed_len_typ> }.as_trait_constraint(); + + if (should_pack & typ.implements(packable_constraint)) { + // Packing is enabled and the given type implements the `Packable` trait so we call the `pack()` + // method, add the resulting field array to `aux_vars` and each field to `fields`. + let packed_len = maybe_packed_len_typ.as_constant().unwrap(); + let packed_struct_name = f"{name}_packed".quoted_contents(); + let packed_struct = quote { let $packed_struct_name = $name.pack() }; + for i in 0..packed_len { + fields = fields.push_back(quote { $packed_struct[$i] as Field }); + } + aux_vars = aux_vars.push_back(packed_struct); + } else if typ.is_field() { // For field we just add the value to fields fields = fields.push_back(name); } else if typ.as_integer().is_some() | typ.is_bool() { @@ -282,7 +318,12 @@ pub comptime fn generate_serialize_to_fields( // can typically be `self` when implementing a method on a struct. quote { $name.$param_name } }; - generate_serialize_to_fields(quote {$maybe_prefixed_name}, param_type, omit) + generate_serialize_to_fields( + quote {$maybe_prefixed_name}, + param_type, + omit, + should_pack, + ) }); let struct_flattened_fields = struct_flattened.fold( &[], @@ -295,12 +336,16 @@ pub comptime fn generate_serialize_to_fields( fields = fields.append(struct_flattened_fields); aux_vars = aux_vars.append(struct_flattened_aux_vars); } else if typ.as_array().is_some() { - // For array we recursively call generate_serialize_to_fields for each element + // For array we recursively call `generate_serialize_to_fields(...)` for each element let (element_type, array_len) = typ.as_array().unwrap(); let array_len = array_len.as_constant().unwrap(); for i in 0..array_len { - let (element_fields, element_aux_vars) = - generate_serialize_to_fields(quote { $name[$i] }, element_type, omit); + let (element_fields, element_aux_vars) = generate_serialize_to_fields( + quote { $name[$i] }, + element_type, + omit, + should_pack, + ); fields = fields.append(element_fields); aux_vars = aux_vars.append(element_aux_vars); } @@ -332,7 +377,7 @@ pub comptime fn generate_serialize_to_fields( pub(crate) comptime fn derive_serialize(s: StructDefinition) -> Quoted { let typ = s.as_type(); - let (fields, aux_vars) = generate_serialize_to_fields(quote { self }, typ, &[]); + let (fields, aux_vars) = generate_serialize_to_fields(quote { self }, typ, &[], false); let aux_vars_for_serialization = if aux_vars.len() > 0 { let joint = aux_vars.join(quote {;}); quote { $joint; } @@ -354,7 +399,7 @@ pub(crate) comptime fn derive_serialize(s: StructDefinition) -> Quoted { pub(crate) comptime fn derive_deserialize(s: StructDefinition) -> Quoted { let typ = s.as_type(); - let (fields, _) = generate_serialize_to_fields(quote { self }, typ, &[]); + let (fields, _) = generate_serialize_to_fields(quote { self }, typ, &[], false); let serialized_len = fields.len(); let (deserialized, _) = generate_deserialize_from_fields( quote { self }, From ba8439408abb72f7174340f7059f65edfff68bf1 Mon Sep 17 00:00:00 2001 From: benesjan Date: Fri, 24 Jan 2025 18:36:10 +0000 Subject: [PATCH 04/12] WIP --- .../aztec-nr/aztec/src/macros/notes/mod.nr | 1 + .../crates/types/src/meta/mod.nr | 41 ++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index b09ae9a7584b..a21ac4ad32fc 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -93,6 +93,7 @@ comptime fn generate_note_interface( 0, quote {header}, quote { aztec::note::note_header::NoteHeader::empty() }, + false, ); // Second we compute quotes for MSM diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr index 569fd380ad63..ed8ea6f37e7f 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr @@ -50,6 +50,18 @@ use super::traits::{Deserialize, Packable, Serialize}; /// header: NoteHeader::empty() // Default/empty header /// } /// ``` +/// # Nested Struct Example with Unpacking +/// - given the same setup as above and `U128` implements `Packable` and skipping `header` the result would be: +/// ``` +/// UintNote { +/// value: Packable::unpack([fields[0]]), +/// owner: AztecAddress { +/// inner: fields[1], +/// }, +/// randomness: fields[2], +/// header: NoteHeader::empty() +/// } +/// ``` /// /// # Panics /// - If the deserialization logic encounters a type it does not support. @@ -61,6 +73,7 @@ pub comptime fn generate_deserialize_from_fields( num_already_consumed: u32, to_replace: Quoted, ro_replace_with: Quoted, + should_unpack: bool, ) -> (Quoted, u32) { let mut result = quote {}; // Counter for the number of fields consumed @@ -71,7 +84,29 @@ pub comptime fn generate_deserialize_from_fields( // The currently processed field should be replaced so we do so result = ro_replace_with; } else { - if typ.is_field() | typ.as_integer().is_some() | typ.is_bool() { + // If the type implements `Packable`, its length will be assigned to the `maybe_packed_len_typ` variable. + let maybe_packed_len_typ = std::meta::typ::fresh_type_variable(); + let packable_constraint = quote { Packable<$maybe_packed_len_typ> }.as_trait_constraint(); + + if (should_unpack & typ.implements(packable_constraint)) { + // Unpacking is enabled and the given type implements the `Packable` trait so we call the `unpack()` + // method, add the resulting field array to `aux_vars` and each field to `fields`. + let packed_len = maybe_packed_len_typ.as_constant().unwrap(); + + // We copy the packed fields into a new array and pass that to the unpack function in a quote + let mut packed_fields_quotes = &[]; + for i in 0..packed_len { + packed_fields_quotes = packed_fields_quotes.push_back( + quote { $field_array_name[$i + $num_already_consumed] }, + ); + } + let packed_fields = packed_fields_quotes.join(quote {,}); + + // No we call unpack on the type + result = quote { Packable::unpack([ $packed_fields ]) }; + + consumed_counter = packed_len; + } else if typ.is_field() | typ.as_integer().is_some() | typ.is_bool() { // The field is a primitive so we just reference it in the field array result = quote { $field_array_name[$num_already_consumed] as $typ }; consumed_counter = 1; @@ -93,6 +128,7 @@ pub comptime fn generate_deserialize_from_fields( consumed_counter + num_already_consumed, to_replace, ro_replace_with, + should_unpack, ); // We increment the consumed counter by the number of fields consumed in the recursion consumed_counter += num_consumed_in_recursion; @@ -126,6 +162,7 @@ pub comptime fn generate_deserialize_from_fields( consumed_counter + num_already_consumed, to_replace, ro_replace_with, + should_unpack, ); // We increment the consumed counter by the number of fields consumed in the recursion consumed_counter += num_consumed_in_recursion; @@ -154,6 +191,7 @@ pub comptime fn generate_deserialize_from_fields( consumed_counter + num_already_consumed, to_replace, ro_replace_with, + should_unpack, ); // We should consume just one field in the recursion so we sanity check that @@ -408,6 +446,7 @@ pub(crate) comptime fn derive_deserialize(s: StructDefinition) -> Quoted { 0, quote {}, quote {}, + false, ); quote { impl Deserialize<$serialized_len> for $typ { From 4a3c4f167975feb77634c4782858c8030b3fdbf8 Mon Sep 17 00:00:00 2001 From: benesjan Date: Fri, 24 Jan 2025 18:57:41 +0000 Subject: [PATCH 05/12] fix --- .../crates/types/src/meta/mod.nr | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr index ed8ea6f37e7f..8234d5b6bb27 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr @@ -51,14 +51,13 @@ use super::traits::{Deserialize, Packable, Serialize}; /// } /// ``` /// # Nested Struct Example with Unpacking -/// - given the same setup as above and `U128` implements `Packable` and skipping `header` the result would be: +/// - given the same setup as above and given that U128, AztecAddress and Field implement the `Packable` trait +/// when skipping `header` the result we get is: /// ``` /// UintNote { -/// value: Packable::unpack([fields[0]]), -/// owner: AztecAddress { -/// inner: fields[1], -/// }, -/// randomness: fields[2], +/// value: aztec::protocol_types::traits::Packable::unpack([fields[0]]), +/// owner: aztec::protocol_types::traits::Packable::unpack([fields[1]]), +/// randomness: aztec::protocol_types::traits::Packable::unpack([fields[2]]), /// header: NoteHeader::empty() /// } /// ``` @@ -96,14 +95,15 @@ pub comptime fn generate_deserialize_from_fields( // We copy the packed fields into a new array and pass that to the unpack function in a quote let mut packed_fields_quotes = &[]; for i in 0..packed_len { + let index_in_field_array = i + num_already_consumed; packed_fields_quotes = packed_fields_quotes.push_back( - quote { $field_array_name[$i + $num_already_consumed] }, + quote { $field_array_name[$index_in_field_array] }, ); } let packed_fields = packed_fields_quotes.join(quote {,}); // No we call unpack on the type - result = quote { Packable::unpack([ $packed_fields ]) }; + result = quote { aztec::protocol_types::traits::Packable::unpack([ $packed_fields ]) }; consumed_counter = packed_len; } else if typ.is_field() | typ.as_integer().is_some() | typ.is_bool() { From 5d13c2dff1b78b021288644ef964531fea032281 Mon Sep 17 00:00:00 2001 From: benesjan Date: Fri, 24 Jan 2025 21:16:47 +0000 Subject: [PATCH 06/12] WIP --- .../crates/types/src/meta/mod.nr | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr index 8234d5b6bb27..5d18db735cbd 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr @@ -330,11 +330,18 @@ pub comptime fn generate_serialize_to_fields( // Packing is enabled and the given type implements the `Packable` trait so we call the `pack()` // method, add the resulting field array to `aux_vars` and each field to `fields`. let packed_len = maybe_packed_len_typ.as_constant().unwrap(); - let packed_struct_name = f"{name}_packed".quoted_contents(); + + // We collapse the name to a one that gets tokenized as a single token (e.g. "self.value" -> "self_value"). + let name_at_one_token = collapse_to_one_token(name); + let packed_struct_name = f"{name_at_one_token}_aux_var".quoted_contents(); + + // We add the individual fields to the fields array let packed_struct = quote { let $packed_struct_name = $name.pack() }; for i in 0..packed_len { - fields = fields.push_back(quote { $packed_struct[$i] as Field }); + fields = fields.push_back(quote { $packed_struct_name[$i] }); } + + // We add the new auxiliary variable to the aux_vars array aux_vars = aux_vars.push_back(packed_struct); } else if typ.is_field() { // For field we just add the value to fields @@ -413,6 +420,19 @@ pub comptime fn generate_serialize_to_fields( (fields, aux_vars) } +/// From a quote that gets tokenized to a multiple tokens we collapse it to a single token by replacing all `.` with `_`. +/// E.g. "self.value" -> "self_value" +comptime fn collapse_to_one_token(q: Quoted) -> Quoted { + let tokens = q.tokens(); + + let mut single_token = quote {}; + for token in tokens { + let new_token = if token == quote {.} { quote {_} } else { token }; + single_token = f"{single_token}{new_token}".quoted_contents(); + } + single_token +} + pub(crate) comptime fn derive_serialize(s: StructDefinition) -> Quoted { let typ = s.as_type(); let (fields, aux_vars) = generate_serialize_to_fields(quote { self }, typ, &[], false); From 11bc4b7fe12631206e726bb7971be24a9a2d29a5 Mon Sep 17 00:00:00 2001 From: benesjan Date: Mon, 27 Jan 2025 01:23:58 +0000 Subject: [PATCH 07/12] fixes --- .../aztec-nr/aztec/src/macros/notes/mod.nr | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index a21ac4ad32fc..0fb75750808e 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -71,10 +71,13 @@ comptime fn generate_note_interface( let name = s.name(); let typ = s.as_type(); + // In notes we care about DA costs so we enable packing + let packing_enabled = true; + // First we compute note content serialization. We do that by passing the whole note struct // to the `generate_serialize_to_fields(...)` and omitting the header. let (content_fields_list, content_aux_vars_list) = - generate_serialize_to_fields(quote { self }, typ, &[quote {self.header}], false); + generate_serialize_to_fields(quote { self }, typ, &[quote {self.header}], packing_enabled); // If there are `aux_vars` we need to join them with `;` and add a trailing `;` to the joined string. let content_aux_vars = if content_aux_vars_list.len() > 0 { @@ -93,7 +96,7 @@ comptime fn generate_note_interface( 0, quote {header}, quote { aztec::note::note_header::NoteHeader::empty() }, - false, + packing_enabled, ); // Second we compute quotes for MSM @@ -295,7 +298,7 @@ comptime fn generate_multi_scalar_mul( let (field_name, typ, index) = indexed_fields[i]; let start_generator_index = index + 1; let (serialization_fields, aux_vars) = - generate_serialize_to_fields(field_name, typ, &[], false); + generate_serialize_to_fields(field_name, typ, &[], true); for j in 0..serialization_fields.len() { let serialization_field = serialization_fields[j]; let generator_index = start_generator_index + j; @@ -490,7 +493,7 @@ comptime fn get_setup_log_plaintext_body( quote { header }, ); let (fields_list, aux_vars) = - generate_serialize_to_fields(quote { }, s.as_type(), to_omit, false); + generate_serialize_to_fields(quote { }, s.as_type(), to_omit, true); // If there are `aux_vars` we need to join them with `;` and add a trailing `;` to the joined string. let aux_vars_for_serialization = if aux_vars.len() > 0 { @@ -612,7 +615,7 @@ comptime fn generate_finalization_payload( quote { header }, ); let (nullable_fields_list, aux_vars) = - generate_serialize_to_fields(quote { }, s.as_type(), to_omit, false); + generate_serialize_to_fields(quote { }, s.as_type(), to_omit, true); // If there are `aux_vars` we need to join them with `;` and add a trailing `;` to the joined string. let aux_vars_for_serialization = if aux_vars.len() > 0 { @@ -627,8 +630,11 @@ comptime fn generate_finalization_payload( let nullable_fields = nullable_fields_list.join(quote {,}); // Now we compute quotes relevant to the multi-scalar multiplication. - let (generators_list, _, args_list, msm_aux_vars) = - generate_multi_scalar_mul(indexed_nullable_fields); + // Note 1: We ignore the `scalars_list` and `aux_vars` return values because it's not used by the `emit_note_hash` + // function. Instead, we use `public_values` (defined on the finalization payload struct) and the scalar list + // is computed in the for-loop below. + // Note 2: The `args_list` is not used for note hash MSM but instead for the `new` function. + let (generators_list, _, args_list, _) = generate_multi_scalar_mul(indexed_nullable_fields); // We generate scalars_list manually as we need it to refer self.public_values let mut scalars_list: [Quoted] = &[]; @@ -691,7 +697,6 @@ comptime fn generate_finalization_payload( let hiding_point: aztec::prelude::Point = self.context.storage_read(self.hiding_point_slot); assert(!aztec::protocol_types::traits::is_empty(hiding_point), "transfer not prepared"); - $msm_aux_vars let finalization_hiding_point = std::embedded_curve_ops::multi_scalar_mul( [$generators], [$scalars] @@ -837,7 +842,7 @@ comptime fn index_note_fields( indexed_nullable_fields = indexed_nullable_fields.push_back((name, typ, counter)); } } - let (serialization_fields, _) = generate_serialize_to_fields(name, typ, &[], false); + let (serialization_fields, _) = generate_serialize_to_fields(name, typ, &[], true); // Each struct member can occupy multiple fields so we need to increment the counter accordingly counter += serialization_fields.len(); } @@ -854,7 +859,7 @@ comptime fn inject_note_header(s: StructDefinition) { } } -/// Injects `NoteHeader` to the note struct if not present and generates the following: +/// Injects `NoteHeader` to the note struct `s` if not present and generates the following: /// - NoteTypeProperties /// - SetupPayload /// - FinalizationPayload @@ -864,10 +869,13 @@ comptime fn inject_note_header(s: StructDefinition) { /// - Registers the note in the global `NOTES` map. /// /// For more details on the generated code, see the individual functions. +/// +/// `nullable_fields` are a list of quotes passed in as varargs which are used to identify which fields/struct members +/// in the partial note are nullable. #[varargs] pub comptime fn partial_note(s: StructDefinition, nullable_fields: [Quoted]) -> Quoted { // We separate struct members into fixed ones and nullable ones and we store info about the start index of each - // member in the serialized note array. + // member in the packed note array. let (indexed_fixed_fields, indexed_nullable_fields) = index_note_fields(s, nullable_fields); // We inject NoteHeader if it's not present in the note struct. From 4915b726840716f8e57ba4581b1564e2dc37271c Mon Sep 17 00:00:00 2001 From: benesjan Date: Mon, 27 Jan 2025 01:39:54 +0000 Subject: [PATCH 08/12] WIP --- .../smart_contracts/functions/attributes.md | 10 +++++----- .../functions/function_transforms.md | 14 +++++++------- docs/docs/migration_notes.md | 19 +++++++++++++++++++ .../aztec-nr/aztec/src/macros/notes/mod.nr | 2 +- 4 files changed, 32 insertions(+), 13 deletions(-) diff --git a/docs/docs/aztec/smart_contracts/functions/attributes.md b/docs/docs/aztec/smart_contracts/functions/attributes.md index 707241b79469..46ff05a666b1 100644 --- a/docs/docs/aztec/smart_contracts/functions/attributes.md +++ b/docs/docs/aztec/smart_contracts/functions/attributes.md @@ -186,7 +186,7 @@ When a struct is annotated with `#[note]`, the Aztec macro applies a series of t 1. **NoteInterface Implementation**: The macro automatically implements most methods of the `NoteInterface` trait for the annotated struct. This includes: - - `serialize_content` and `deserialize_content` + - `pack_content` and `unpack_content` - `get_header` and `set_header` - `get_note_type_id` - `compute_note_hiding_point` @@ -219,14 +219,14 @@ struct CustomNote { ```rust impl CustomNote { - fn serialize_content(self: CustomNote) -> [Field; NOTE_SERIALIZED_LEN] { + fn pack_content(self: CustomNote) -> [Field; PACKED_NOTE_CONTENT_LEN] { [self.data, self.owner.to_field()] } - fn deserialize_content(serialized_note: [Field; NOTE_SERIALIZED_LEN]) -> Self { + fn unpack_content(packed_content: [Field; PACKED_NOTE_CONTENT_LEN]) -> Self { CustomNote { - data: serialized_note[0] as Field, - owner: Address::from_field(serialized_note[1]), + data: packed_content[0] as Field, + owner: Address::from_field(packed_content[1]), header: NoteHeader::empty() } } diff --git a/docs/docs/aztec/smart_contracts/functions/function_transforms.md b/docs/docs/aztec/smart_contracts/functions/function_transforms.md index 2254bb44a315..c87aeda95c14 100644 --- a/docs/docs/aztec/smart_contracts/functions/function_transforms.md +++ b/docs/docs/aztec/smart_contracts/functions/function_transforms.md @@ -30,7 +30,7 @@ For private functions, the context creation involves hashing all input parameter ```rust let mut args_hasher = ArgsHasher::new(); -// Hash each parameter +// Hash each parameter args_hasher.add(param1); args_hasher.add(param2); // add all parameters @@ -71,8 +71,8 @@ The context provides methods to call other contracts: ```rust let token_contract = TokenContract::at(token); ``` - -Under the hood, this creates a new instance of the contract interface with the specified address. + +Under the hood, this creates a new instance of the contract interface with the specified address. ## Private and public input injection @@ -102,7 +102,7 @@ This makes these inputs available to be consumed within private annotated functi ## Return value handling -Return values in Aztec contracts are processed differently from traditional smart contracts when using private functions. +Return values in Aztec contracts are processed differently from traditional smart contracts when using private functions. ### Private functions @@ -156,10 +156,10 @@ The function is automatically generated based on the note types defined in the c ```rust if (note_type_id == NoteType::get_note_type_id()) { aztec::note::utils::compute_note_hash_and_optionally_a_nullifier( - NoteType::deserialize_content, + NoteType::unpack_content, note_header, compute_nullifier, - serialized_note + packed_note_content ) } ``` @@ -206,7 +206,7 @@ The computed function signatures are integrated into the contract interface like - The function's parameters are extracted - The signature hash is computed using `compute_fn_signature_hash` - The placeholder in the contract interface is replaced with the computed hash - + This process ensures that each function in the contract has a unique, deterministic signature based on its name and parameter types. They are inspired by Solidity's function selector mechanism. ## Contract artifacts diff --git a/docs/docs/migration_notes.md b/docs/docs/migration_notes.md index d14f634ccc4c..f1a1b0b245ea 100644 --- a/docs/docs/migration_notes.md +++ b/docs/docs/migration_notes.md @@ -47,6 +47,25 @@ The way in which logs are assembled in this "default_aes128" strategy is has als You can remove this method from any custom notes or events that you've implemented. +### [Aztec.nr] Packing notes resulting in changes in `NoteInterface` +Note interface implementation generated by our macros now packs note content instead of serializing it +With this change notes are being less costly DA-wise to emit when some of the note struct members implements the `Packable` trait (this is typically the `UintNote` which represents `value` as `U128` that gets serialized as 2 fields but packed as 1). +This results in the following changes in the `NoteInterface`: + +```diff +pub trait NoteInterface { +- fn serialize_content(self) -> [Field; N]; ++ fn pack_content(self) -> [Field; N]; + +- fn deserialize_content(fields: [Field; N]) -> Self; ++ fn unpack_content(fields: [Field; N]) -> Self; + + fn get_header(self) -> NoteHeader; + fn set_header(&mut self, header: NoteHeader) -> (); + fn get_note_type_id() -> Field; + fn compute_note_hash(self) -> Field; +} +``` ## 0.72.0 ### Some functions in `aztec.js` and `@aztec/accounts` are now async diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index 0fb75750808e..64f77347721b 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -92,7 +92,7 @@ comptime fn generate_note_interface( let (unpacked_content, _) = generate_deserialize_from_fields( quote {}, typ, - quote { packed_content }, // "packed_content" is argument of NoteInterface::deserialize_content + quote { packed_content }, // "packed_content" is argument of NoteInterface::unpack_content 0, quote {header}, quote { aztec::note::note_header::NoteHeader::empty() }, From 67d025142e55b60eee3d89076b8da7331a4b8d77 Mon Sep 17 00:00:00 2001 From: benesjan Date: Mon, 27 Jan 2025 02:10:51 +0000 Subject: [PATCH 09/12] last touches --- noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr | 6 +++--- .../contracts/ecdsa_public_key_note/src/lib.nr | 2 +- .../noir-protocol-circuits/crates/types/src/meta/mod.nr | 2 ++ 3 files changed, 6 insertions(+), 4 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 75481c9d036a..560969ca1986 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 @@ -20,9 +20,9 @@ fn extract_property_value_from_selector( packed_note_content: [Field; N], selector: PropertySelector, ) -> Field { - // 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. + // Selectors use PropertySelectors in order to locate note properties inside the packed note. + // This allows easier packing and custom (un)packing schemas. A note property is located + // inside the packed note using the index inside the array, a byte offset and a length. let value: [u8; 32] = packed_note_content[selector.index].to_be_bytes(); let offset = selector.offset; let length = selector.length; diff --git a/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr b/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr index d86b4a76161d..d3d5589c3005 100644 --- a/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr +++ b/noir-projects/noir-contracts/contracts/ecdsa_public_key_note/src/lib.nr @@ -21,7 +21,7 @@ pub struct EcdsaPublicKeyNote { } impl NoteInterface for EcdsaPublicKeyNote { - // Cannot use the automatic packing since x and y don't fit. Serialize the note as 5 fields where: + // Cannot use the automatic packing since x and y don't fit. Pack the note as 5 fields where: // [0] = x[0..31] (upper bound excluded) // [1] = x[31] // [2] = y[0..31] diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr index 5d18db735cbd..5ce00c03f859 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr @@ -9,6 +9,8 @@ use super::traits::{Deserialize, Packable, Serialize}; /// - `num_already_consumed`: The number of fields already processed in previous recursion calls. /// - `to_replace`: The name of a specific field that should be replaced during deserialization. /// - `ro_replace_with`: The value to replace the `to_replace` field with (e.g., `NoteHeader::empty()`). +/// - `should_unpack`: A boolean indicating whether the type should be unpacked (see description of `Packable` +/// and `Serialize` trait for more information about the difference between packing and serialization). /// /// # Returns /// A tuple containing: From e60770a3c49098445e8d7e692cc2954077f647eb Mon Sep 17 00:00:00 2001 From: benesjan Date: Tue, 28 Jan 2025 17:20:19 +0000 Subject: [PATCH 10/12] fixes after rebase --- .../aztec-nr/aztec/src/macros/notes/mod.nr | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index 64f77347721b..2f480ebf68c1 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -34,7 +34,7 @@ comptime fn get_next_note_type_id() -> Field { /// the length of the packed note. /// /// impl NoteInterface for NoteStruct { -/// fn to_be_bytes(self, storage_slot: Field) -> [u8; N * 32 + 64] { +/// fn pack_content(self) -> [Field; N] { /// ... /// } /// @@ -42,10 +42,6 @@ comptime fn get_next_note_type_id() -> Field { /// ... /// } /// -/// fn pack_content(self) -> [Field; N] { -/// ... -/// } -/// /// fn get_note_type_id() -> Field { /// ... /// } @@ -118,15 +114,15 @@ comptime fn generate_note_interface( ( quote { impl aztec::note::note_interface::NoteInterface<$content_len> for $name { - fn unpack_content(packed_content: [Field; $content_len]) -> Self { - $unpacked_content - } - fn pack_content(self) -> [Field; $content_len] { $content_aux_vars [$content_fields] } + fn unpack_content(packed_content: [Field; $content_len]) -> Self { + $unpacked_content + } + fn get_note_type_id() -> Field { $note_type_id } From ed5e73edf271349d218ebce429d75ec944b628d4 Mon Sep 17 00:00:00 2001 From: benesjan Date: Tue, 28 Jan 2025 18:24:04 +0000 Subject: [PATCH 11/12] fixes --- .../log_assembly_strategies/default_aes128/note.nr | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/encrypted_logs/log_assembly_strategies/default_aes128/note.nr b/noir-projects/aztec-nr/aztec/src/encrypted_logs/log_assembly_strategies/default_aes128/note.nr index eb368074aed1..e80f82f07f71 100644 --- a/noir-projects/aztec-nr/aztec/src/encrypted_logs/log_assembly_strategies/default_aes128/note.nr +++ b/noir-projects/aztec-nr/aztec/src/encrypted_logs/log_assembly_strategies/default_aes128/note.nr @@ -221,7 +221,7 @@ fn compute_note_plaintext_for_this_strategy(note: Note) -> [u8 where Note: NoteInterface, { - let serialized_note = note.serialize_content(); + let packed_note = note.pack_content(); let note_header = note.get_header(); let storage_slot = note_header.storage_slot; @@ -237,8 +237,8 @@ where plaintext_bytes[32 + i] = note_type_id_bytes[i]; } - for i in 0..serialized_note.len() { - let bytes: [u8; 32] = serialized_note[i].to_be_bytes(); + for i in 0..packed_note.len() { + let bytes: [u8; 32] = packed_note[i].to_be_bytes(); for j in 0..32 { plaintext_bytes[64 + i * 32 + j] = bytes[j]; } From 3cad55fd0b38d7735a0cef1b34be87d0d75ceadb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bene=C5=A1?= Date: Wed, 29 Jan 2025 06:54:13 -0600 Subject: [PATCH 12/12] Update noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr Co-authored-by: esau <152162806+sklppy88@users.noreply.github.com> --- .../noir-protocol-circuits/crates/types/src/meta/mod.nr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr index 5ce00c03f859..d08d8416f066 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr @@ -104,7 +104,7 @@ pub comptime fn generate_deserialize_from_fields( } let packed_fields = packed_fields_quotes.join(quote {,}); - // No we call unpack on the type + // Now we call unpack on the type result = quote { aztec::protocol_types::traits::Packable::unpack([ $packed_fields ]) }; consumed_counter = packed_len;