Skip to content

Commit

Permalink
refactor!: Use NoteSerialize and NoteDeserialize traits for note spec…
Browse files Browse the repository at this point in the history
…ific serialization (AztecProtocol#4383)

This PR introduces updates the `NoteInterface` to include serialization and deserialization specific to notes.
  • Loading branch information
LHerskind committed Feb 5, 2024
1 parent e63bbae commit 14dd0b8
Show file tree
Hide file tree
Showing 43 changed files with 184 additions and 265 deletions.
4 changes: 2 additions & 2 deletions boxes/token/src/contracts/src/main.nr
Original file line number Diff line number Diff line change
Expand Up @@ -328,9 +328,9 @@ contract Token {
) -> pub [Field; 4] {
let note_header = NoteHeader::new(contract_address, nonce, storage_slot);
if (storage_slot == storage.pending_shields.get_storage_slot()) {
note_utils::compute_note_hash_and_nullifier(TransparentNote::deserialize, note_header, serialized_note)
note_utils::compute_note_hash_and_nullifier(TransparentNote::deserialize_content, note_header, serialized_note)
} else {
note_utils::compute_note_hash_and_nullifier(TokenNote::deserialize, note_header, serialized_note)
note_utils::compute_note_hash_and_nullifier(TokenNote::deserialize_content, note_header, serialized_note)
}
}
// docs:end:compute_note_hash_and_nullifier
Expand Down
11 changes: 5 additions & 6 deletions boxes/token/src/contracts/src/types/balances_map.nr
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use dep::aztec::{
protocol_types::{
address::AztecAddress,
constants::MAX_READ_REQUESTS_PER_CALL,
traits::{Serialize, Deserialize}
},
state_vars::{
set::Set,
Expand Down Expand Up @@ -37,11 +36,11 @@ impl<T> BalancesMap<T> {
}
}

unconstrained pub fn balance_of<T_SERIALIZED_LEN>(self: Self, owner: AztecAddress) -> SafeU120 where T: Deserialize<T_SERIALIZED_LEN> + Serialize<T_SERIALIZED_LEN> + NoteInterface + OwnedNote {
unconstrained pub fn balance_of<T_SERIALIZED_LEN>(self: Self, owner: AztecAddress) -> SafeU120 where T: NoteInterface<T_SERIALIZED_LEN> + OwnedNote {
self.balance_of_with_offset(owner, 0)
}

unconstrained pub fn balance_of_with_offset<T_SERIALIZED_LEN>(self: Self, owner: AztecAddress, offset: u32) -> SafeU120 where T: Deserialize<T_SERIALIZED_LEN> + Serialize<T_SERIALIZED_LEN> + NoteInterface + OwnedNote {
unconstrained pub fn balance_of_with_offset<T_SERIALIZED_LEN>(self: Self, owner: AztecAddress, offset: u32) -> SafeU120 where T: NoteInterface<T_SERIALIZED_LEN> + OwnedNote {
// Same as SafeU120::new(0), but fewer constraints because no check.
let mut balance = SafeU120::min();
// docs:start:view_notes
Expand All @@ -61,15 +60,15 @@ impl<T> BalancesMap<T> {
balance
}

pub fn add<T_SERIALIZED_LEN>(self: Self, owner: AztecAddress, addend: SafeU120) where T: Deserialize<T_SERIALIZED_LEN> + Serialize<T_SERIALIZED_LEN> + NoteInterface + OwnedNote {
pub fn add<T_SERIALIZED_LEN>(self: Self, owner: AztecAddress, addend: SafeU120) where T: NoteInterface<T_SERIALIZED_LEN> + OwnedNote {
let mut addend_note = T::new(addend, owner);

// docs:start:insert
self.map.at(owner).insert(&mut addend_note, true);
// docs:end:insert
}

pub fn sub<T_SERIALIZED_LEN>(self: Self, owner: AztecAddress, subtrahend: SafeU120) where T: Deserialize<T_SERIALIZED_LEN> + Serialize<T_SERIALIZED_LEN> + NoteInterface + OwnedNote{
pub fn sub<T_SERIALIZED_LEN>(self: Self, owner: AztecAddress, subtrahend: SafeU120) where T: NoteInterface<T_SERIALIZED_LEN> + OwnedNote{
// docs:start:get_notes
let options = NoteGetterOptions::with_filter(filter_notes_min_sum, subtrahend);
let maybe_notes = self.map.at(owner).get_notes(options);
Expand Down Expand Up @@ -105,7 +104,7 @@ impl<T> BalancesMap<T> {
pub fn filter_notes_min_sum<T, T_SERIALIZED_LEN>(
notes: [Option<T>; MAX_READ_REQUESTS_PER_CALL],
min_sum: SafeU120
) -> [Option<T>; MAX_READ_REQUESTS_PER_CALL] where T: Deserialize<T_SERIALIZED_LEN> + Serialize<T_SERIALIZED_LEN> + NoteInterface + OwnedNote {
) -> [Option<T>; MAX_READ_REQUESTS_PER_CALL] where T: NoteInterface<T_SERIALIZED_LEN> + OwnedNote {
let mut selected = [Option::none(); MAX_READ_REQUESTS_PER_CALL];
let mut sum = SafeU120::min();
for i in 0..notes.len() {
Expand Down
32 changes: 11 additions & 21 deletions boxes/token/src/contracts/src/types/token_note.nr
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
use dep::aztec::protocol_types::{
address::AztecAddress,
constants::{
MAX_READ_REQUESTS_PER_CALL
},
};
use dep::aztec::{
protocol_types::{
address::AztecAddress,
constants::MAX_READ_REQUESTS_PER_CALL
},
note::{
note_header::NoteHeader,
note_interface::NoteInterface,
Expand All @@ -14,10 +12,6 @@ use dep::aztec::{
state_vars::set::Set,
log::emit_encrypted_log,
hash::pedersen_hash,
protocol_types::traits::{
Serialize,
Deserialize
},
};
use dep::aztec::oracle::{
rand::rand,
Expand Down Expand Up @@ -49,27 +43,23 @@ struct TokenNote {
header: NoteHeader,
}

impl Serialize<TOKEN_NOTE_LEN> for TokenNote {
fn serialize(self) -> [Field; TOKEN_NOTE_LEN] {
impl NoteInterface<TOKEN_NOTE_LEN> for TokenNote {
fn serialize_content(self) -> [Field; TOKEN_NOTE_LEN] {
[self.amount.value as Field, self.owner.to_field(), self.randomness]
}
}

impl Deserialize<TOKEN_NOTE_LEN> for TokenNote {
fn deserialize(serialized_note: [Field; TOKEN_NOTE_LEN]) -> Self {
fn deserialize_content(serialized_note: [Field; TOKEN_NOTE_LEN]) -> Self {
Self {
amount: SafeU120::new(serialized_note[0]),
owner: AztecAddress::from_field(serialized_note[1]),
randomness: serialized_note[2],
header: NoteHeader::empty(),
}
}
}

impl NoteInterface for TokenNote {
fn compute_note_content_hash(self) -> Field {
// TODO(#1205) Should use a non-zero generator index.
pedersen_hash(self.serialize(), 0)
pedersen_hash(self.serialize_content(), 0)
}

// docs:start:nullifier
Expand Down Expand Up @@ -100,8 +90,8 @@ impl NoteInterface for TokenNote {
self.header = header;
}

fn get_header(note: TokenNote) -> NoteHeader {
note.header
fn get_header(self) -> NoteHeader {
self.header
}

// Broadcasts the note as an encrypted log on L1.
Expand All @@ -114,7 +104,7 @@ impl NoteInterface for TokenNote {
(*context).this_address(),
slot,
encryption_pub_key,
self.serialize(),
self.serialize_content(),
);
}
}
Expand Down
26 changes: 7 additions & 19 deletions boxes/token/src/contracts/src/types/transparent_note.nr
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use dep::aztec::{
},
hash::{compute_secret_hash, pedersen_hash},
context::PrivateContext,
protocol_types::traits::{Serialize, Deserialize, Empty}
};

global TRANSPARENT_NOTE_LEN: Field = 2;
Expand All @@ -23,34 +22,23 @@ struct TransparentNote {
header: NoteHeader,
}

impl Serialize<TRANSPARENT_NOTE_LEN> for TransparentNote {
fn serialize(self) -> [Field; TRANSPARENT_NOTE_LEN] {
impl NoteInterface<TRANSPARENT_NOTE_LEN> for TransparentNote {
fn serialize_content(self) -> [Field; TRANSPARENT_NOTE_LEN] {
[self.amount, self.secret_hash]
}
}

impl Deserialize<TRANSPARENT_NOTE_LEN> for TransparentNote {
fn deserialize(serialized_note: [Field; TRANSPARENT_NOTE_LEN]) -> Self {
fn deserialize_content(serialized_note: [Field; TRANSPARENT_NOTE_LEN]) -> Self {
TransparentNote {
amount: serialized_note[0],
secret_hash: serialized_note[1],
secret: 0,
header: NoteHeader::empty(),
}
}
}

impl Empty for TransparentNote {
fn empty() -> Self {
TransparentNote::new(0, 0)
}
}

impl NoteInterface for TransparentNote {

fn compute_note_content_hash(self) -> Field {
// TODO(#1205) Should use a non-zero generator index.
pedersen_hash(self.serialize(), 0)
pedersen_hash(self.serialize_content(), 0)
}

fn compute_nullifier(self, _context: &mut PrivateContext) -> Field {
Expand All @@ -63,13 +51,12 @@ impl NoteInterface for TransparentNote {
pedersen_hash([self.secret, siloed_note_hash],0)
}


fn set_header(&mut self, header: NoteHeader) {
self.header = header;
}

fn get_header(note: TransparentNote) -> NoteHeader {
note.header
fn get_header(self) -> NoteHeader {
self.header
}

fn broadcast(self, context: &mut PrivateContext, slot: Field) {
Expand All @@ -89,6 +76,7 @@ impl TransparentNote {
header: NoteHeader::empty(),
}
}

// new oracle call primitive
// get me the secret corresponding to this hash
pub fn new_from_secret(amount: Field, secret: Field) -> Self {
Expand Down
16 changes: 6 additions & 10 deletions yarn-project/aztec-nr/address-note/src/address_note.nr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use dep::aztec::log::emit_encrypted_log;
use dep::aztec::{
protocol_types::{
address::AztecAddress,
traits::{Serialize, Deserialize, Empty}
traits::Empty
},
note::{
note_header::NoteHeader,
Expand All @@ -31,27 +31,23 @@ struct AddressNote {
header: NoteHeader,
}

impl Serialize<ADDRESS_NOTE_LEN> for AddressNote {
fn serialize(self) -> [Field; ADDRESS_NOTE_LEN]{
impl NoteInterface<ADDRESS_NOTE_LEN> for AddressNote {
fn serialize_content(self) -> [Field; ADDRESS_NOTE_LEN]{
[self.address.to_field(), self.owner.to_field(), self.randomness]
}
}

impl Deserialize<ADDRESS_NOTE_LEN> for AddressNote {
fn deserialize(serialized_note: [Field; ADDRESS_NOTE_LEN]) -> Self {
fn deserialize_content(serialized_note: [Field; ADDRESS_NOTE_LEN]) -> Self {
AddressNote {
address: AztecAddress::from_field(serialized_note[0]),
owner: AztecAddress::from_field(serialized_note[1]),
randomness: serialized_note[2],
header: NoteHeader::empty(),
}
}
}

impl NoteInterface for AddressNote {
fn compute_note_content_hash(self) -> Field {
// TODO(#1205) Should use a non-zero generator index.
pedersen_hash(self.serialize(), 0)
pedersen_hash(self.serialize_content(), 0)
}

fn compute_nullifier(self, context: &mut PrivateContext) -> Field {
Expand Down Expand Up @@ -93,7 +89,7 @@ impl NoteInterface for AddressNote {
(*context).this_address(),
slot,
encryption_pub_key,
self.serialize(),
self.serialize_content(),
);
// docs:end:encrypted
}
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/aztec-nr/aztec/src/history/note_inclusion.nr
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub fn prove_note_inclusion<Note, N>(
note_with_header: Note,
block_number: u32, // The block at which we'll prove that the note exists
context: PrivateContext
) where Note: NoteInterface {
) where Note: NoteInterface<N> {
let note_commitment = compute_note_hash_for_consumption(note_with_header);

prove_note_commitment_inclusion(note_commitment, block_number, context);
Expand Down
2 changes: 1 addition & 1 deletion yarn-project/aztec-nr/aztec/src/history/note_validity.nr
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub fn prove_note_validity<Note, N>(
note_with_header: Note,
block_number: u32, // The block at which we'll prove that the note exists
context: &mut PrivateContext
) where Note: NoteInterface {
) where Note: NoteInterface<N> {
prove_note_inclusion(note_with_header, block_number, *context);
prove_note_not_nullified(note_with_header, block_number, context);
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ pub fn prove_note_not_nullified<Note, N>(
note_with_header: Note,
block_number: u32, // The block at which we'll prove that the note was not nullified
context: &mut PrivateContext
) where Note: NoteInterface {
) where Note: NoteInterface<N> {
let nullifier = compute_siloed_nullifier(note_with_header, context);

prove_nullifier_non_inclusion(nullifier, block_number, *context);
Expand Down
13 changes: 8 additions & 5 deletions yarn-project/aztec-nr/aztec/src/note/lifecycle.nr
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@ use crate::note::{
utils::{compute_note_hash_for_insertion, compute_note_hash_for_consumption},
};
use crate::oracle::notes::{notify_created_note, notify_nullified_note};
use dep::protocol_types::traits::{Serialize, Deserialize};

pub fn create_note<Note, N>(
context: &mut PrivateContext,
storage_slot: Field,
note: &mut Note,
broadcast: bool
) where Note: NoteInterface + Serialize<N> + Deserialize<N> {
) where Note: NoteInterface<N> {
let contract_address = (*context).this_address();

let header = NoteHeader { contract_address, storage_slot, nonce: 0, is_transient: true };
Expand All @@ -26,7 +25,7 @@ pub fn create_note<Note, N>(
let inner_note_hash = compute_note_hash_for_insertion(*note);

// TODO: Strong typing required because of https://github.com/noir-lang/noir/issues/4088
let serialized_note: [Field; N] = Note::serialize(*note);
let serialized_note: [Field; N] = Note::serialize_content(*note);
assert(notify_created_note(storage_slot, serialized_note, inner_note_hash) == 0);

context.push_new_note_hash(inner_note_hash);
Expand All @@ -36,7 +35,11 @@ pub fn create_note<Note, N>(
}
}

pub fn create_note_hash_from_public<Note>(context: &mut PublicContext, storage_slot: Field, note: &mut Note) where Note: NoteInterface {
pub fn create_note_hash_from_public<Note, N>(
context: &mut PublicContext,
storage_slot: Field,
note: &mut Note
) where Note: NoteInterface<N> {
let contract_address = (*context).this_address();

let header = NoteHeader { contract_address, storage_slot, nonce: 0, is_transient: true };
Expand All @@ -47,7 +50,7 @@ pub fn create_note_hash_from_public<Note>(context: &mut PublicContext, storage_s
context.push_new_note_hash(inner_note_hash);
}

pub fn destroy_note<Note>(context: &mut PrivateContext, note: Note) where Note: NoteInterface {
pub fn destroy_note<Note, N>(context: &mut PrivateContext, note: Note) where Note: NoteInterface<N> {
let mut nullifier = 0;
let mut consumed_note_hash: Field = 0;
nullifier = note.compute_nullifier(context);
Expand Down
Loading

0 comments on commit 14dd0b8

Please sign in to comment.