Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
245 changes: 119 additions & 126 deletions noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,20 @@ comptime fn generate_note_interface(
) -> (Quoted, u32) {
let name = s.name();
let typ = s.as_type();
let (fields, aux_vars) = flatten_to_fields(quote { self }, typ, &[quote {self.header}]);
let aux_vars_for_serialization = if aux_vars.len() > 0 {
let joint = aux_vars.join(quote {;});

// First we compute note content serialization. We do that by passing the whole note struct
// to the `flatten_to_fields(...)` and omitting the header.
let (content_fields_list, content_aux_vars_list) = flatten_to_fields(quote { self }, typ, &[quote {self.header}]);

// 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 {
let joint = content_aux_vars_list.join(quote {;});
quote { $joint; }
} else {
quote {}
};
let serialized_fields = fields.join(quote {,});
let content_len = fields.len();
let content_fields = content_fields_list.join(quote {,});
let content_len = content_fields_list.len();

let (deserialized_content, _) = pack_from_fields(
quote { self },
Expand All @@ -52,11 +57,12 @@ comptime fn generate_note_interface(
&[(quote {header}, quote { aztec::note::note_header::NoteHeader::empty() })]
);

// `compute_note_hash()` is computed over all the fields so we need to merge fixed and nullable fields.
// Second we compute quotes for MSM
// `compute_note_hash()` is computed over all the fields so we need to merge fixed and nullable.
let merged_fields = indexed_fixed_fields.append(indexed_nullable_fields);
// Now we prefix each of the merged fields with `self.` since they refer to the struct members here.
let merged_fields = merged_fields.map(| (name, typ, index): (Quoted, Type, u32) | (quote { self.$name }, typ, index));
let (new_generators_list, new_scalars_list, _, new_aux_vars) = generate_multi_scalar_mul(merged_fields);
let prefixed_merged_fields = merged_fields.map(| (name, typ, index): (Quoted, Type, u32) | (quote { self.$name }, typ, index));
let (new_generators_list, new_scalars_list, _, new_aux_vars) = generate_multi_scalar_mul(prefixed_merged_fields);

let new_generators = new_generators_list.push_back(quote { aztec::generators::G_slot }).join(quote {,});
let new_scalars = new_scalars_list.push_back(quote { std::hash::from_field_unsafe(self.header.storage_slot) }).join(quote {,});
Expand Down Expand Up @@ -90,8 +96,8 @@ comptime fn generate_note_interface(
}

fn serialize_content(self) -> [Field; $content_len] {
$aux_vars_for_serialization
[$serialized_fields]
$content_aux_vars
[$content_fields]
}

fn get_note_type_id() -> Field {
Expand Down Expand Up @@ -224,117 +230,76 @@ comptime fn generate_multi_scalar_mul(indexed_fields: [(Quoted, Type, u32)]) ->
(generators_list, scalars_list, args_list, aux_vars)
}

comptime fn generate_note_hiding_point(
comptime fn generate_setup_payload(
s: StructDefinition,
indexed_fixed_fields: [(Quoted, Type, u32)],
indexed_nullable_fields: [(Quoted, Type, u32)]
) -> (Quoted, Quoted) {
let name = s.name();
let hiding_point_name = f"{name}HidingPoint".quoted_contents();
let setup_payload_name = f"{name}SetupPayload".quoted_contents();

let (finalize_generators_list, finalize_scalars_list, finalize_args_list, finalize_aux_vars) = generate_multi_scalar_mul(indexed_nullable_fields);

let finalize_args = if finalize_args_list.len() > 0 {
&[quote {self}].append(finalize_args_list).join(quote {,})
} else {
quote {self}
};
// First we get the MSM related quotes
let (new_generators_list, new_scalars_list, new_args_list, new_aux_vars) = generate_multi_scalar_mul(indexed_fixed_fields);
let new_args = &[quote {mut self}].append(new_args_list).push_back(quote { storage_slot: Field }).join(quote {,});
let new_generators = new_generators_list.push_back(quote { aztec::generators::G_slot }).join(quote {,});
let new_scalars = new_scalars_list.push_back(quote { std::hash::from_field_unsafe(storage_slot) }).join(quote {,});

let finalize_body = if indexed_nullable_fields.len() > 0 {
let finalize_generators = finalize_generators_list.join(quote {,});
let finalize_scalars = finalize_scalars_list.join(quote {,});
quote {
$finalize_aux_vars
let point = std::embedded_curve_ops::multi_scalar_mul(
[$finalize_generators],
[$finalize_scalars]
) + self.inner;
point.x
}
} else {
quote { self.inner.x }
};
// Then the log plaintext ones
let log_plaintext_length = indexed_fixed_fields.len() * 32 + 64;
let setup_log_plaintext = get_setup_log_plaintext_body(s, log_plaintext_length, indexed_nullable_fields);

(quote {
struct $hiding_point_name {
inner: aztec::protocol_types::point::Point
}

impl $hiding_point_name {
fn from_point(mut self, point: aztec::protocol_types::point::Point) -> $hiding_point_name {
self.inner = point;
self
}


fn finalize($finalize_args) -> Field {
$finalize_body
}

fn to_point(self) -> aztec::protocol_types::point::Point {
self.inner
}
struct $setup_payload_name {
log_plaintext: [u8; $log_plaintext_length],
hiding_point: aztec::protocol_types::point::Point
}

impl aztec::protocol_types::traits::Serialize<aztec::protocol_types::point::POINT_LENGTH> for $hiding_point_name {
fn serialize(self) -> [Field; aztec::protocol_types::point::POINT_LENGTH] {
self.inner.serialize()
}
}
impl $setup_payload_name {
fn new($new_args) -> $setup_payload_name {
$new_aux_vars
let hiding_point = std::embedded_curve_ops::multi_scalar_mul(
[$new_generators],
[$new_scalars]
);
$setup_log_plaintext

impl aztec::protocol_types::traits::Deserialize<aztec::protocol_types::point::POINT_LENGTH> for $hiding_point_name {
fn deserialize(serialized: [Field; aztec::protocol_types::point::POINT_LENGTH]) -> $hiding_point_name {
$hiding_point_name { inner: aztec::protocol_types::point::Point::deserialize(serialized) }
$setup_payload_name {
log_plaintext,
hiding_point
}
}
}

impl aztec::protocol_types::traits::Empty for $hiding_point_name {
impl aztec::protocol_types::traits::Empty for $setup_payload_name {
fn empty() -> Self {
Self { inner: aztec::protocol_types::point::Point::empty() }
}
}

impl Eq for $hiding_point_name {
fn eq(self, other: Self) -> bool {
self.inner == other.inner
Self { log_plaintext: [0; $log_plaintext_length], hiding_point: aztec::protocol_types::point::Point::empty() }
}
}

}, hiding_point_name)
}, setup_payload_name)
}

comptime fn generate_partial_payload(
comptime fn get_setup_log_plaintext_body(
s: StructDefinition,
hiding_point_name: Quoted,
indexed_fixed_fields: [(Quoted, Type, u32)],
log_plaintext_length: u32,
indexed_nullable_fields: [(Quoted, Type, u32)]
) -> (Quoted, Quoted) {
) -> Quoted {
let name = s.name();
let partial_payload_name = f"{name}PartialPayload".quoted_contents();

let (new_generators_list, new_scalars_list, new_args_list, new_aux_vars) = generate_multi_scalar_mul(indexed_fixed_fields);

let new_args = &[quote {mut self}].append(new_args_list).push_back(quote { storage_slot: Field }).join(quote {,});
let new_generators = new_generators_list.push_back(quote { aztec::generators::G_slot }).join(quote {,});
let new_scalars = new_scalars_list.push_back(quote { std::hash::from_field_unsafe(storage_slot) }).join(quote {,});

let log_plaintext_length = indexed_fixed_fields.len() * 32 + 64;

// Now we compute serialization of the fixed fields. We do that by passing the whole note struct
// to the flatten_to_fields function but we omit the NoteHeader and the nullable fields.
let typ = s.as_type();
let mut to_omit = indexed_nullable_fields.map(| (name, _, _): (Quoted, Type, u32) | name);
to_omit = to_omit.push_back(quote { header });
let (fields, aux_vars) = flatten_to_fields(quote { }, typ, to_omit);
let to_omit = indexed_nullable_fields.map(| (name, _, _): (Quoted, Type, u32) | name).push_back(quote { header });
let (fields_list, aux_vars) = flatten_to_fields(quote { }, s.as_type(), to_omit);

// 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 {
let joint = aux_vars.join(quote {;});
quote { $joint; }
} else {
quote {}
};
let serialized_fields = fields.join(quote {,});
let fields = fields_list.join(quote {,});

// indexed_fixed_fields has preserved order so we can used to serialize the note to log
let partial_note_log_plaintext = quote {
quote {
let mut log_plaintext: [u8; $log_plaintext_length] = [0; $log_plaintext_length];

let storage_slot_bytes: [u8; 32] = storage_slot.to_be_bytes();
Expand All @@ -346,61 +311,94 @@ comptime fn generate_partial_payload(
}

$aux_vars_for_serialization
let serialized_note = [$serialized_fields];
let serialized_note = [$fields];

for i in 0..serialized_note.len() {
let bytes: [u8; 32] = serialized_note[i].to_be_bytes();
for j in 0..32 {
log_plaintext[64 + i * 32 + j] = bytes[j];
}
}
}
}

comptime fn generate_finalization_payload(
s: StructDefinition,
indexed_fixed_fields: [(Quoted, Type, u32)],
indexed_nullable_fields: [(Quoted, Type, u32)]
) -> (Quoted, Quoted) {
let name = s.name();
let finalization_payload_name = f"{name}FinalizationPayload".quoted_contents();

// We compute serialization of the nullable fields which are to be emitted as an unencrypted log. We do that by
// passing the whole note struct to the `flatten_to_fields(...)` function but we omit the `NoteHeader` and
// the fixed fields.
let to_omit = indexed_fixed_fields.map(| (name, _, _): (Quoted, Type, u32) | name).push_back(quote { header });
let (fields_list, aux_vars) = flatten_to_fields(quote { }, s.as_type(), to_omit);

// 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 {
let joint = aux_vars.join(quote {;});
quote { $joint; }
} else {
quote {}
};

// We compute the log length and we concatenate the fields into a single quote.
let log_length = fields_list.len();
let fields = fields_list.join(quote {,});

// Now we compute quotes relevant to the multi-scalar multiplication.
let (generators_list, scalars_list, args_list, msm_aux_vars) = generate_multi_scalar_mul(indexed_nullable_fields);

let generators = generators_list.join(quote {,});
let scalars = scalars_list.join(quote {,});
let args = args_list.join(quote {,});

(quote {
struct $partial_payload_name {
log_plaintext: [u8; $log_plaintext_length],
hiding_point: $hiding_point_name
struct $finalization_payload_name {
log: [Field; $log_length],
note_hash: Field,
}

impl $partial_payload_name {
fn new($new_args) -> $partial_payload_name {
$new_aux_vars
let point = std::embedded_curve_ops::multi_scalar_mul(
[$new_generators],
[$new_scalars]
);
let hiding_point = $hiding_point_name::empty().from_point(point);
$partial_note_log_plaintext
impl $finalization_payload_name {
fn new(mut self, hiding_point: aztec::protocol_types::point::Point, $args) -> $finalization_payload_name {
$aux_vars_for_serialization
self.log = [$fields];

$partial_payload_name {
log_plaintext,
hiding_point
}
$msm_aux_vars
let finalization_hiding_point = std::embedded_curve_ops::multi_scalar_mul(
[$generators],
[$scalars]
) + hiding_point;

self.note_hash = finalization_hiding_point.x;
self
}
}

impl aztec::protocol_types::traits::Empty for $partial_payload_name {
impl aztec::protocol_types::traits::Empty for $finalization_payload_name {
fn empty() -> Self {
Self { log_plaintext: [0; $log_plaintext_length], hiding_point: $hiding_point_name::empty() }
Self { log: [0; $log_length], note_hash: 0 }
}
}
}, partial_payload_name)
}, finalization_payload_name)
}

comptime fn generate_partial_note_impl(
s: StructDefinition,
hiding_point_name: Quoted,
partial_payload_name: Quoted
setup_payload_name: Quoted,
finalization_payload_name: Quoted
) -> Quoted {
let name = s.name();
quote {
impl aztec::note::note_interface::PartialNote<$hiding_point_name, $partial_payload_name> for $name {
fn hiding_point() -> $hiding_point_name {
$hiding_point_name::empty()
impl aztec::note::note_interface::PartialNote<$setup_payload_name, $finalization_payload_name> for $name {
fn setup_payload() -> $setup_payload_name {
$setup_payload_name::empty()
}

fn partial_payload() -> $partial_payload_name {
$partial_payload_name::empty()
fn finalization_payload() -> $finalization_payload_name {
$finalization_payload_name::empty()
}
}
}
Expand Down Expand Up @@ -477,15 +475,10 @@ pub comptime fn partial_note(s: StructDefinition, nullable_fields: [Quoted]) ->
let (indexed_fixed_fields, indexed_nullable_fields) = index_note_fields(s, nullable_fields);

let (common, note_type_id) = common_note_annotation(s);
let (note_hiding_point, hiding_point_name) = generate_note_hiding_point(s, indexed_nullable_fields);
let (partial_payload_impl, partial_payload_name) = generate_partial_payload(
s,
hiding_point_name,
indexed_fixed_fields,
indexed_nullable_fields
);
let (setup_payload_impl, setup_payload_name) = 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(s, note_type_id, indexed_fixed_fields, indexed_nullable_fields);
let partial_note_impl = generate_partial_note_impl(s, hiding_point_name, partial_payload_name);
let partial_note_impl = generate_partial_note_impl(s, setup_payload_name, finalization_payload_name);
register_note(
s,
note_serialized_len,
Expand All @@ -496,8 +489,8 @@ pub comptime fn partial_note(s: StructDefinition, nullable_fields: [Quoted]) ->

quote {
$common
$note_hiding_point
$partial_payload_impl
$setup_payload_impl
$finalization_payload_impl
$note_interface_impl
$partial_note_impl
}
Expand Down
6 changes: 3 additions & 3 deletions noir-projects/aztec-nr/aztec/src/note/note_interface.nr
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ pub trait NoteProperties<T> {
fn properties() -> T;
}

pub trait PartialNote<T, P> {
fn hiding_point() -> T;
pub trait PartialNote<S, F> {
fn setup_payload() -> S;

fn partial_payload() -> P;
fn finalization_payload() -> F;
}

pub trait NullifiableNote {
Expand Down
Loading