Skip to content

Commit

Permalink
feat: packing note content
Browse files Browse the repository at this point in the history
  • Loading branch information
benesjan committed Jan 21, 2025
1 parent 64cbb33 commit 2efa082
Show file tree
Hide file tree
Showing 12 changed files with 60 additions and 64 deletions.
18 changes: 9 additions & 9 deletions noir-projects/aztec-nr/aztec/src/macros/mod.nr
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
},
);
Expand Down Expand Up @@ -184,14 +184,14 @@ comptime fn generate_process_log() -> Quoted {

// A typical implementation of the lambda looks something like this:
// ```
// |serialized_note_content: BoundedVec<Field, MAX_NOTE_SERIALIZED_LEN>, note_header: NoteHeader, note_type_id: Field| {
// |packed_note_content: BoundedVec<Field, MAX_NOTE_SERIALIZED_LEN>, 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}")
Expand Down Expand Up @@ -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())
}
},
);
Expand All @@ -256,7 +256,7 @@ comptime fn generate_process_log() -> Quoted {
unique_note_hashes_in_tx,
first_nullifier_in_tx,
recipient,
|serialized_note_content: BoundedVec<Field, _>, note_header, note_type_id| {
|packed_note_content: BoundedVec<Field, _>, note_header, note_type_id| {
let hashes = $if_note_type_id_match_statements
else {
panic(f"Unknown note type id {note_type_id}")
Expand Down
50 changes: 25 additions & 25 deletions noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,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.
Expand Down Expand Up @@ -42,11 +42,11 @@ comptime fn get_next_note_type_id() -> Field {
/// ...
/// }
///
/// fn deserialize_content(value: [Field; N]) -> Self {
/// fn unpack_content(value: [Field; N]) -> Self {
/// ...
/// }
///
/// fn serialize_content(self) -> [Field; N] {
/// fn pack_content(self) -> [Field; N] {
/// ...
/// }
///
Expand Down Expand Up @@ -90,7 +90,7 @@ comptime fn generate_note_interface(
let content_fields = content_fields_list.join(quote {,});
let content_len = content_fields_list.len();

let (deserialized_content, _) = pack_from_fields(
let (unpacked_content, _) = pack_from_fields(
quote { self },
typ,
quote { value },
Expand Down Expand Up @@ -118,7 +118,7 @@ comptime fn generate_note_interface(
quote {
impl aztec::note::note_interface::NoteInterface<$content_len> for $name {
fn to_be_bytes(self, storage_slot: Field) -> [u8; $content_len * 32 + 64] {
let serialized_note = self.serialize_content();
let packed_note_content = self.pack_content();

let mut buffer: [u8; $content_len * 32 + 64] = [0; $content_len * 32 + 64];

Expand All @@ -131,20 +131,20 @@ comptime fn generate_note_interface(
buffer[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_content.len() {
let bytes: [u8; 32] = packed_note_content[i].to_be_bytes();
for j in 0..32 {
buffer[64 + i * 32 + j] = bytes[j];
}
}
buffer
}

fn deserialize_content(value: [Field; $content_len]) -> Self {
$deserialized_content
fn unpack_content(value: [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]
}
Expand Down Expand Up @@ -378,10 +378,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];
/// }
Expand Down Expand Up @@ -526,10 +526,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];
}
Expand Down Expand Up @@ -801,11 +801,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)],
Expand All @@ -820,7 +820,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
Expand Down Expand Up @@ -884,7 +884,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,
Expand All @@ -894,7 +894,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,
Expand Down Expand Up @@ -923,15 +923,15 @@ 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,
indexed_nullable_fields,
);
register_note(
s,
note_serialized_len,
note_packed_len,
note_type_id,
indexed_fixed_fields,
indexed_nullable_fields,
Expand Down Expand Up @@ -960,7 +960,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()
Expand All @@ -969,7 +969,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,
Expand Down
24 changes: 10 additions & 14 deletions noir-projects/aztec-nr/aztec/src/note/discovery/mod.nr
Original file line number Diff line number Diff line change
Expand Up @@ -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}")
Expand All @@ -59,7 +59,7 @@ pub unconstrained fn do_process_log<Env>(
recipient: AztecAddress,
compute_note_hash_and_nullifier: fn[Env](BoundedVec<Field, MAX_NOTE_SERIALIZED_LEN>, NoteHeader, Field) -> Option<NoteHashesAndNullifier>,
) {
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
Expand All @@ -71,12 +71,8 @@ pub unconstrained fn do_process_log<Env>(
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
Expand All @@ -86,7 +82,7 @@ pub unconstrained fn do_process_log<Env>(
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,
Expand Down Expand Up @@ -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<T, let MaxLen: u32, Env>(
Expand Down
2 changes: 1 addition & 1 deletion noir-projects/aztec-nr/aztec/src/note/lifecycle.nr
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
2 changes: 1 addition & 1 deletion noir-projects/aztec-nr/aztec/src/note/note_getter/mod.nr
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions noir-projects/aztec-nr/aztec/src/note/note_interface.nr
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ pub trait NullifiableNote {
// docs:start:note_interface
// Autogenerated by the #[note] macro
pub trait NoteInterface<let N: u32> {
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;

Expand Down
4 changes: 2 additions & 2 deletions noir-projects/aztec-nr/aztec/src/note/utils.nr
Original file line number Diff line number Diff line change
Expand Up @@ -117,15 +117,15 @@ where
}

pub unconstrained fn compute_note_hash_and_optionally_a_nullifier<T, let N: u32, let S: u32>(
deserialize_content: fn([Field; N]) -> T,
unpack_content: fn([Field; N]) -> T,
note_header: NoteHeader,
compute_nullifier: bool,
serialized_note: [Field; S],
) -> [Field; 4]
where
T: NoteInterface<N> + 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();
Expand Down
2 changes: 1 addition & 1 deletion noir-projects/aztec-nr/aztec/src/oracle/notes.nr
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
6 changes: 3 additions & 3 deletions noir-projects/aztec-nr/aztec/src/test/mocks/mock_note.nr
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ impl NullifiableNote for MockNote {
}

impl NoteInterface<MOCK_NOTE_LENGTH> 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() }
}

Expand All @@ -69,7 +69,7 @@ impl NoteInterface<MOCK_NOTE_LENGTH> for MockNote {
}

fn to_be_bytes(self, storage_slot: Field) -> [u8; MOCK_NOTE_LENGTH * 32 + 64] {
let serialized_note = self.serialize_content();
let serialized_note = self.pack_content();

let mut buffer: [u8; MOCK_NOTE_LENGTH * 32 + 64] = [0; MOCK_NOTE_LENGTH * 32 + 64];

Expand Down
Loading

0 comments on commit 2efa082

Please sign in to comment.