diff --git a/address-note/src/address_note.nr b/address-note/src/address_note.nr index 199cbd7..3dc9457 100644 --- a/address-note/src/address_note.nr +++ b/address-note/src/address_note.nr @@ -2,7 +2,10 @@ use dep::aztec::log::emit_encrypted_log; // docs:end:encrypted_import use dep::aztec::{ - protocol_types::address::AztecAddress, + protocol_types::{ + address::AztecAddress, + traits::{Serialize, Deserialize, Empty} + }, note::{ note_header::NoteHeader, note_interface::NoteInterface, @@ -14,7 +17,7 @@ use dep::aztec::{ get_public_key::get_public_key, }, hash::pedersen_hash, - context::PrivateContext, + context::PrivateContext }; global ADDRESS_NOTE_LEN: Field = 3; @@ -28,24 +31,14 @@ struct AddressNote { header: NoteHeader, } -impl AddressNote { - pub fn new(address: AztecAddress, owner: AztecAddress) -> Self { - let randomness = rand(); - AddressNote { - address, - owner, - randomness, - header: NoteHeader::empty(), - } - } -// docs:end:address_note_def - - - pub fn serialize(self) -> [Field; ADDRESS_NOTE_LEN]{ +impl Serialize for AddressNote { + fn serialize(self) -> [Field; ADDRESS_NOTE_LEN]{ [self.address.to_field(), self.owner.to_field(), self.randomness] } +} - pub fn deserialize(serialized_note: [Field; ADDRESS_NOTE_LEN]) -> Self { +impl Deserialize for AddressNote { + fn deserialize(serialized_note: [Field; ADDRESS_NOTE_LEN]) -> Self { AddressNote { address: AztecAddress::from_field(serialized_note[0]), owner: AztecAddress::from_field(serialized_note[1]), @@ -53,14 +46,16 @@ impl AddressNote { header: NoteHeader::empty(), } } +} - pub fn compute_note_hash(self) -> Field { +impl NoteInterface for AddressNote { + fn compute_note_hash(self) -> Field { // TODO(#1205) Should use a non-zero generator index. pedersen_hash(self.serialize(), 0) } - pub fn compute_nullifier(self, context: &mut PrivateContext) -> Field { - let note_hash_for_nullify = compute_note_hash_for_read_or_nullify(AddressNoteMethods, self); + fn compute_nullifier(self, context: &mut PrivateContext) -> Field { + let note_hash_for_nullify = compute_note_hash_for_read_or_nullify(self); let secret = context.request_nullifier_secret_key(self.owner); // TODO(#1205) Should use a non-zero generator index. pedersen_hash([ @@ -70,8 +65,8 @@ impl AddressNote { ],0) } - pub fn compute_nullifier_without_context(self) -> Field { - let note_hash_for_nullify = compute_note_hash_for_read_or_nullify(AddressNoteMethods, self); + fn compute_nullifier_without_context(self) -> Field { + let note_hash_for_nullify = compute_note_hash_for_read_or_nullify(self); let secret = get_nullifier_secret_key(self.owner); // TODO(#1205) Should use a non-zero generator index. pedersen_hash([ @@ -81,12 +76,16 @@ impl AddressNote { ],0) } - pub fn set_header(&mut self, header: NoteHeader) { + fn set_header(&mut self, header: NoteHeader) { self.header = header; } + fn get_header(note: Self) -> NoteHeader { + note.header + } + // Broadcasts the note as an encrypted log on L1. - pub fn broadcast(self, context: &mut PrivateContext, slot: Field) { + fn broadcast(self, context: &mut PrivateContext, slot: Field) { let encryption_pub_key = get_public_key(self.owner); // docs:start:encrypted emit_encrypted_log( @@ -100,46 +99,15 @@ impl AddressNote { } } -fn deserialize(serialized_note: [Field; ADDRESS_NOTE_LEN]) -> AddressNote { - AddressNote::deserialize(serialized_note) -} - -fn serialize(note: AddressNote) -> [Field; ADDRESS_NOTE_LEN] { - note.serialize() -} - -fn compute_note_hash(note: AddressNote) -> Field { - note.compute_note_hash() -} - -fn compute_nullifier(note: AddressNote, context: &mut PrivateContext) -> Field { - note.compute_nullifier(context) -} - -fn compute_nullifier_without_context(note: AddressNote) -> Field { - note.compute_nullifier_without_context() -} - -fn get_header(note: AddressNote) -> NoteHeader { - note.header -} - -fn set_header(note: &mut AddressNote, header: NoteHeader) { - note.set_header(header); -} - -// Broadcasts the note as an encrypted log on L1. -fn broadcast(context: &mut PrivateContext, slot: Field, note: AddressNote) { - note.broadcast(context, slot); +impl AddressNote { + pub fn new(address: AztecAddress, owner: AztecAddress) -> Self { + let randomness = rand(); + AddressNote { + address, + owner, + randomness, + header: NoteHeader::empty(), + } + } +// docs:end:address_note_def } - -global AddressNoteMethods = NoteInterface { - deserialize, - serialize, - compute_note_hash, - compute_nullifier, - compute_nullifier_without_context, - get_header, - set_header, - broadcast, -}; diff --git a/authwit/src/account.nr b/authwit/src/account.nr index 21c13e3..790aee2 100644 --- a/authwit/src/account.nr +++ b/authwit/src/account.nr @@ -1,6 +1,5 @@ use dep::aztec::context::{PrivateContext, PublicContext, Context}; use dep::aztec::state_vars::{map::Map, public_state::PublicState}; -use dep::aztec::types::type_serialization::bool_serialization::{BoolSerializationMethods,BOOL_SERIALIZED_LEN}; use crate::entrypoint::EntrypointPayload; use crate::auth::IS_VALID_SELECTOR; @@ -8,7 +7,7 @@ use crate::auth::IS_VALID_SELECTOR; struct AccountActions { context: Context, is_valid_impl: fn(&mut PrivateContext, Field) -> bool, - approved_action: Map>, + approved_action: Map>, } impl AccountActions { @@ -20,7 +19,7 @@ impl AccountActions { context, approved_action_storage_slot, |context, slot| { - PublicState::new(context, slot, BoolSerializationMethods) + PublicState::new(context, slot) }, ), } diff --git a/authwit/src/entrypoint.nr b/authwit/src/entrypoint.nr index 82c3f5f..05ca662 100644 --- a/authwit/src/entrypoint.nr +++ b/authwit/src/entrypoint.nr @@ -12,6 +12,7 @@ use dep::aztec::protocol_types::{ address::AztecAddress, constants::GENERATOR_INDEX__SIGNATURE_PAYLOAD, hash::pedersen_hash, + traits::{Hash, Serialize} }; global ACCOUNT_MAX_CALLS: Field = 4; @@ -27,11 +28,13 @@ struct FunctionCall { is_public: bool, } -impl FunctionCall { +impl Serialize for FunctionCall { fn serialize(self) -> [Field; FUNCTION_CALL_SIZE] { [self.args_hash, self.function_selector.to_field(), self.target_address.to_field(), self.is_public as Field] } +} +impl FunctionCall { fn to_be_bytes(self) -> [u8; FUNCTION_CALL_SIZE_IN_BYTES] { let mut bytes: [u8; FUNCTION_CALL_SIZE_IN_BYTES] = [0; FUNCTION_CALL_SIZE_IN_BYTES]; let args_hash_bytes = self.args_hash.to_be_bytes(32); @@ -58,14 +61,7 @@ struct EntrypointPayload { } // docs:end:entrypoint-struct -impl EntrypointPayload { - fn hash(self) -> Field { - pedersen_hash( - self.serialize(), - GENERATOR_INDEX__SIGNATURE_PAYLOAD - ) - } - +impl Serialize for EntrypointPayload { // Serializes the entrypoint struct fn serialize(self) -> [Field; ENTRYPOINT_PAYLOAD_SIZE] { let mut fields: BoundedVec = BoundedVec::new(0); @@ -75,7 +71,18 @@ impl EntrypointPayload { fields.push(self.nonce); fields.storage } +} + +impl Hash for EntrypointPayload { + fn hash(self) -> Field { + pedersen_hash( + self.serialize(), + GENERATOR_INDEX__SIGNATURE_PAYLOAD + ) + } +} +impl EntrypointPayload { // Serializes the payload as an array of bytes. Useful for hashing with sha256. fn to_be_bytes(self) -> [u8; ENTRYPOINT_PAYLOAD_SIZE_IN_BYTES] { let mut bytes: [u8; ENTRYPOINT_PAYLOAD_SIZE_IN_BYTES] = [0; ENTRYPOINT_PAYLOAD_SIZE_IN_BYTES]; diff --git a/aztec/src/abi.nr b/aztec/src/abi.nr index 74ba77d..6e19458 100644 --- a/aztec/src/abi.nr +++ b/aztec/src/abi.nr @@ -6,6 +6,7 @@ use dep::protocol_types::{ }, contrakt::deployment_data::ContractDeploymentData, hash::hash_args, + traits::{Hash, Serialize}, header::Header, }; @@ -16,7 +17,7 @@ struct PrivateGlobalVariables { } // docs:end:private-global-variables -impl PrivateGlobalVariables { +impl Serialize<2> for PrivateGlobalVariables { fn serialize(self) -> [Field; 2] { [self.chain_id, self.version] } @@ -31,7 +32,7 @@ struct PublicGlobalVariables { } // docs:end:public-global-variables -impl PublicGlobalVariables { +impl Serialize<4> for PublicGlobalVariables { fn serialize(self) -> [Field; 4] { [self.chain_id, self.version, self.block_number, self.timestamp] } @@ -61,6 +62,12 @@ struct Hasher { fields: [Field], } +impl Hash for Hasher { + fn hash(self) -> Field { + hash_args(self.fields) + } +} + impl Hasher { pub fn new()-> Self { Self { fields: [] } @@ -75,8 +82,4 @@ impl Hasher { self.fields = self.fields.push_back(fields[i]); } } - - pub fn hash(self) -> Field { - hash_args(self.fields) - } } diff --git a/aztec/src/context.nr b/aztec/src/context.nr index 777c6ec..9a838bc 100644 --- a/aztec/src/context.nr +++ b/aztec/src/context.nr @@ -330,10 +330,10 @@ impl PrivateContext { }, args_hash: reader.read(), return_values: reader.read_array([0; RETURN_VALUES_LENGTH]), // +1 - read_requests: reader.read_struct_array(SideEffect::deserialise, [SideEffect::empty(); MAX_READ_REQUESTS_PER_CALL]), - nullifier_key_validation_requests: reader.read_struct_array(NullifierKeyValidationRequest::deserialise, [NullifierKeyValidationRequest::empty(); MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL]), - new_commitments: reader.read_struct_array(SideEffect::deserialise, [SideEffect::empty(); MAX_NEW_COMMITMENTS_PER_CALL]), - new_nullifiers: reader.read_struct_array(SideEffectLinkedToNoteHash::deserialise, [SideEffectLinkedToNoteHash::empty(); MAX_NEW_NULLIFIERS_PER_CALL]), + read_requests: reader.read_struct_array(SideEffect::deserialize, [SideEffect::empty(); MAX_READ_REQUESTS_PER_CALL]), + nullifier_key_validation_requests: reader.read_struct_array(NullifierKeyValidationRequest::deserialize, [NullifierKeyValidationRequest::empty(); MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL]), + new_commitments: reader.read_struct_array(SideEffect::deserialize, [SideEffect::empty(); MAX_NEW_COMMITMENTS_PER_CALL]), + new_nullifiers: reader.read_struct_array(SideEffectLinkedToNoteHash::deserialize, [SideEffectLinkedToNoteHash::empty(); MAX_NEW_NULLIFIERS_PER_CALL]), private_call_stack_hashes: reader.read_array([0; MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL]), public_call_stack_hashes: reader.read_array([0; MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL]), new_l2_to_l1_msgs: reader.read_array([0; MAX_NEW_L2_TO_L1_MSGS_PER_CALL]), diff --git a/aztec/src/history/note_inclusion.nr b/aztec/src/history/note_inclusion.nr index 1949395..15a2acc 100644 --- a/aztec/src/history/note_inclusion.nr +++ b/aztec/src/history/note_inclusion.nr @@ -30,12 +30,11 @@ pub fn prove_note_commitment_inclusion( } pub fn prove_note_inclusion( - note_interface: NoteInterface, note_with_header: Note, block_number: u32, // The block at which we'll prove that the note exists context: PrivateContext -) { - let note_commitment = compute_note_hash_for_read_or_nullify(note_interface, note_with_header); +) where Note: NoteInterface { + let note_commitment = compute_note_hash_for_read_or_nullify(note_with_header); prove_note_commitment_inclusion(note_commitment, block_number, context); } diff --git a/aztec/src/history/note_validity.nr b/aztec/src/history/note_validity.nr index 30abac5..6742771 100644 --- a/aztec/src/history/note_validity.nr +++ b/aztec/src/history/note_validity.nr @@ -9,11 +9,10 @@ use crate::{ // A helper function that proves that a note is valid at the given block number pub fn prove_note_validity( - note_interface: NoteInterface, note_with_header: Note, block_number: u32, // The block at which we'll prove that the note exists context: &mut PrivateContext -) { - prove_note_inclusion(note_interface, note_with_header, block_number, *context); - prove_note_not_nullified(note_interface, note_with_header, block_number, context); +) where Note: NoteInterface { + prove_note_inclusion(note_with_header, block_number, *context); + prove_note_not_nullified(note_with_header, block_number, context); } diff --git a/aztec/src/history/nullifier_non_inclusion.nr b/aztec/src/history/nullifier_non_inclusion.nr index 812165a..0c40d4d 100644 --- a/aztec/src/history/nullifier_non_inclusion.nr +++ b/aztec/src/history/nullifier_non_inclusion.nr @@ -50,12 +50,11 @@ pub fn prove_nullifier_non_inclusion( } pub fn prove_note_not_nullified( - note_interface: NoteInterface, note_with_header: Note, block_number: u32, // The block at which we'll prove that the note was not nullified context: &mut PrivateContext -) { - let nullifier = compute_siloed_nullifier(note_interface, note_with_header, context); +) where Note: NoteInterface { + let nullifier = compute_siloed_nullifier(note_with_header, context); prove_nullifier_non_inclusion(nullifier, block_number, *context); } diff --git a/aztec/src/note/lifecycle.nr b/aztec/src/note/lifecycle.nr index d91154e..75d7bfc 100644 --- a/aztec/src/note/lifecycle.nr +++ b/aztec/src/note/lifecycle.nr @@ -9,63 +9,51 @@ use crate::note::{ utils::compute_note_hash_for_read_or_nullify, }; use crate::oracle::notes::{notify_created_note, notify_nullified_note}; +use dep::protocol_types::traits::{Serialize, Deserialize}; pub fn create_note( context: &mut PrivateContext, storage_slot: Field, note: &mut Note, - note_interface: NoteInterface, broadcast: bool -) { +) where Note: NoteInterface + Serialize + Deserialize { let contract_address = (*context).this_address(); let header = NoteHeader { contract_address, storage_slot, nonce: 0, is_transient: true }; - let set_header = note_interface.set_header; - set_header(note, header); + // TODO: change this to note.setHeader(header) once https://github.com/noir-lang/noir/issues/4095 is fixed + Note::set_header(note, header); // As `is_transient` is true, this will compute the inner note hsah - let inner_note_hash = compute_note_hash_for_read_or_nullify(note_interface, *note); + let inner_note_hash = compute_note_hash_for_read_or_nullify(*note); - let serialize = note_interface.serialize; - let serialized_note = serialize(*note); + // TODO: Strong typing required because of https://github.com/noir-lang/noir/issues/4088 + let serialized_note: [Field; N] = Note::serialize(*note); assert(notify_created_note(storage_slot, serialized_note, inner_note_hash) == 0); context.push_new_note_hash(inner_note_hash); if broadcast { - let broadcast = note_interface.broadcast; - broadcast(context, storage_slot, *note); + Note::broadcast(*note, context, storage_slot); } } -pub fn create_note_hash_from_public( - context: &mut PublicContext, - storage_slot: Field, - note: &mut Note, - note_interface: NoteInterface -) { +pub fn create_note_hash_from_public(context: &mut PublicContext, storage_slot: Field, note: &mut Note) where Note: NoteInterface { let contract_address = (*context).this_address(); let header = NoteHeader { contract_address, storage_slot, nonce: 0, is_transient: true }; - let set_header = note_interface.set_header; - set_header(note, header); - let inner_note_hash = compute_note_hash_for_read_or_nullify(note_interface, *note); + // TODO: change this to note.setHeader(header) once https://github.com/noir-lang/noir/issues/4095 is fixed + Note::set_header(note, header); + let inner_note_hash = compute_note_hash_for_read_or_nullify(*note); context.push_new_note_hash(inner_note_hash); } -pub fn destroy_note( - context: &mut PrivateContext, - note: Note, - note_interface: NoteInterface -) { +pub fn destroy_note(context: &mut PrivateContext, note: Note) where Note: NoteInterface { let mut nullifier = 0; let mut nullified_commitment: Field = 0; - let compute_nullifier = note_interface.compute_nullifier; - nullifier = compute_nullifier(note, context); + nullifier = note.compute_nullifier(context); // We also need the note commitment corresponding to the "nullifier" - let get_header = note_interface.get_header; - let header = get_header(note); + let header = note.get_header(); // `nullified_commitment` is used to inform the kernel which pending commitment // the nullifier corresponds to so they can be matched and both squashed/deleted. // nonzero nonce implies "persistable" nullifier (nullifies a persistent/in-tree @@ -73,7 +61,7 @@ pub fn destroy_note( // just siloes and forwards the nullifier to its output. if (header.is_transient) { // TODO(1718): Can we reuse the note commitment computed in `compute_nullifier`? - nullified_commitment = compute_note_hash_for_read_or_nullify(note_interface, note); + nullified_commitment = compute_note_hash_for_read_or_nullify(note); } assert(notify_nullified_note(nullifier, nullified_commitment) == 0); diff --git a/aztec/src/note/note_getter.nr b/aztec/src/note/note_getter.nr index 441f77f..a442aad 100644 --- a/aztec/src/note/note_getter.nr +++ b/aztec/src/note/note_getter.nr @@ -1,10 +1,13 @@ use dep::std::option::Option; -use dep::protocol_types::constants::{ - MAX_READ_REQUESTS_PER_CALL, - GET_NOTE_ORACLE_RETURN_LENGTH, - GET_NOTES_ORACLE_RETURN_LENGTH, - MAX_NOTES_PER_PAGE, - VIEW_NOTE_ORACLE_RETURN_LENGTH, +use dep::protocol_types::{ + constants::{ + MAX_READ_REQUESTS_PER_CALL, + GET_NOTE_ORACLE_RETURN_LENGTH, + GET_NOTES_ORACLE_RETURN_LENGTH, + MAX_NOTES_PER_PAGE, + VIEW_NOTE_ORACLE_RETURN_LENGTH, + }, + traits::{Deserialize, Serialize} }; use crate::context::PrivateContext; use crate::note::{ @@ -19,11 +22,9 @@ use crate::types::vec::BoundedVec; fn check_note_header( context: PrivateContext, storage_slot: Field, - note_interface: NoteInterface, note: Note -) { - let get_header = note_interface.get_header; - let header = get_header(note); +) where Note: NoteInterface { + let header = note.get_header(); let contract_address = context.this_address(); assert(header.contract_address.eq(contract_address)); assert(header.storage_slot == storage_slot); @@ -72,14 +73,13 @@ fn check_notes_order( pub fn get_note( context: &mut PrivateContext, - storage_slot: Field, - note_interface: NoteInterface -) -> Note { - let note = get_note_internal(storage_slot, note_interface); + storage_slot: Field +) -> Note where Note: NoteInterface + Deserialize { + let note = get_note_internal(storage_slot); - check_note_header(*context, storage_slot, note_interface, note); + check_note_header(*context, storage_slot, note); - let note_hash_for_read_request = compute_note_hash_for_read_or_nullify(note_interface, note); + let note_hash_for_read_request = compute_note_hash_for_read_or_nullify(note); context.push_read_request(note_hash_for_read_request); note @@ -88,26 +88,24 @@ pub fn get_note( pub fn get_notes( context: &mut PrivateContext, storage_slot: Field, - note_interface: NoteInterface, options: NoteGetterOptions -) -> [Option; MAX_READ_REQUESTS_PER_CALL] { - let opt_notes = get_notes_internal(storage_slot, note_interface, options); +) -> [Option; MAX_READ_REQUESTS_PER_CALL] where Note: NoteInterface + Deserialize + Serialize { + let opt_notes = get_notes_internal(storage_slot, options); let mut num_notes = 0; let mut prev_fields = [0; N]; for i in 0..opt_notes.len() { let opt_note = opt_notes[i]; if opt_note.is_some() { let note = opt_note.unwrap_unchecked(); - let serialize = note_interface.serialize; - let fields = serialize(note); - check_note_header(*context, storage_slot, note_interface, note); + let fields = note.serialize(); + check_note_header(*context, storage_slot, note); check_note_fields(fields, options.selects); if i != 0 { check_notes_order(prev_fields, fields, options.sorts); } prev_fields = fields; - let note_hash_for_read_request = compute_note_hash_for_read_or_nullify(note_interface, note); + let note_hash_for_read_request = compute_note_hash_for_read_or_nullify(note); // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1410): test to ensure // failure if malicious oracle injects 0 nonce here for a "pre-existing" note. context.push_read_request(note_hash_for_read_request); @@ -121,12 +119,12 @@ pub fn get_notes( opt_notes } -unconstrained fn get_note_internal(storage_slot: Field, note_interface: NoteInterface) -> Note { +unconstrained fn get_note_internal(storage_slot: Field) -> Note where Note: NoteInterface + Deserialize { let placeholder_note = [Option::none()]; let placeholder_fields = [0; GET_NOTE_ORACLE_RETURN_LENGTH]; + let placeholder_note_length = [0; N]; oracle::notes::get_notes( storage_slot, - note_interface, 0, [], [], @@ -137,21 +135,21 @@ unconstrained fn get_note_internal(storage_slot: Field, note_interface: 0, // offset NoteStatus.ACTIVE, placeholder_note, - placeholder_fields + placeholder_fields, + placeholder_note_length )[0].unwrap() // Notice: we don't allow dummies to be returned from get_note (singular). } unconstrained fn get_notes_internal( storage_slot: Field, - note_interface: NoteInterface, options: NoteGetterOptions -) -> [Option; MAX_READ_REQUESTS_PER_CALL] { +) -> [Option; MAX_READ_REQUESTS_PER_CALL] where Note: NoteInterface + Deserialize { let (num_selects, select_by, select_values, select_comparators, sort_by, sort_order) = flatten_options(options.selects, options.sorts); let placeholder_opt_notes = [Option::none(); MAX_READ_REQUESTS_PER_CALL]; let placeholder_fields = [0; GET_NOTES_ORACLE_RETURN_LENGTH]; + let placeholder_note_length = [0; N]; let opt_notes = oracle::notes::get_notes( storage_slot, - note_interface, num_selects, select_by, select_values, @@ -162,7 +160,8 @@ unconstrained fn get_notes_internal( options.offset, options.status, placeholder_opt_notes, - placeholder_fields + placeholder_fields, + placeholder_note_length ); let filter = options.filter; @@ -172,15 +171,14 @@ unconstrained fn get_notes_internal( unconstrained pub fn view_notes( storage_slot: Field, - note_interface: NoteInterface, options: NoteViewerOptions -) -> [Option; MAX_NOTES_PER_PAGE] { +) -> [Option; MAX_NOTES_PER_PAGE] where Note: NoteInterface + Deserialize { let (num_selects, select_by, select_values, select_comparators, sort_by, sort_order) = flatten_options(options.selects, options.sorts); let placeholder_opt_notes = [Option::none(); MAX_NOTES_PER_PAGE]; let placeholder_fields = [0; VIEW_NOTE_ORACLE_RETURN_LENGTH]; + let placeholder_note_length = [0; N]; oracle::notes::get_notes( storage_slot, - note_interface, num_selects, select_by, select_values, @@ -191,7 +189,8 @@ unconstrained pub fn view_notes( options.offset, options.status, placeholder_opt_notes, - placeholder_fields + placeholder_fields, + placeholder_note_length ) } diff --git a/aztec/src/note/note_getter_options.nr b/aztec/src/note/note_getter_options.nr index 3010135..611ac23 100644 --- a/aztec/src/note/note_getter_options.nr +++ b/aztec/src/note/note_getter_options.nr @@ -1,6 +1,10 @@ use dep::std::option::Option; use crate::types::vec::BoundedVec; -use dep::protocol_types::constants::MAX_READ_REQUESTS_PER_CALL; +use dep::protocol_types::{ + constants::MAX_READ_REQUESTS_PER_CALL, + traits::Deserialize, +}; +use crate::note::note_interface::NoteInterface; struct ComparatorEnum { EQ: u3, @@ -89,7 +93,7 @@ struct NoteGetterOptions { // And finally, a custom filter to refine the outcome further. impl NoteGetterOptions { // This function initializes a NoteGetterOptions that simply returns the maximum number of notes allowed in a call. - pub fn new() -> NoteGetterOptions { + pub fn new() -> NoteGetterOptions where Note: NoteInterface + Deserialize { NoteGetterOptions { selects: BoundedVec::new(Option::none()), sorts: BoundedVec::new(Option::none()), @@ -106,7 +110,7 @@ impl NoteGetterOptions { pub fn with_filter( filter: fn ([Option; MAX_READ_REQUESTS_PER_CALL], FILTER_ARGS) -> [Option; MAX_READ_REQUESTS_PER_CALL], filter_args: FILTER_ARGS, - ) -> Self { + ) -> Self where Note: NoteInterface + Deserialize { NoteGetterOptions { selects: BoundedVec::new(Option::none()), sorts: BoundedVec::new(Option::none()), diff --git a/aztec/src/note/note_interface.nr b/aztec/src/note/note_interface.nr index 614c20d..48bd234 100644 --- a/aztec/src/note/note_interface.nr +++ b/aztec/src/note/note_interface.nr @@ -1,22 +1,19 @@ use crate::context::PrivateContext; use crate::note::note_header::NoteHeader; -// docs:start:NoteInterface -struct NoteInterface { - deserialize: fn ([Field; N]) -> Note, +// docs:start:note_interface +trait NoteInterface { + fn compute_note_hash(self) -> Field; - serialize: fn (Note) -> [Field; N], + fn get_header(self) -> NoteHeader; - compute_note_hash: fn (Note) -> Field, + fn set_header(&mut self, header: NoteHeader) -> (); - compute_nullifier: fn (Note, &mut PrivateContext) -> Field, + fn compute_nullifier(self, context: &mut PrivateContext) -> Field; - compute_nullifier_without_context: fn (Note) -> Field, + fn compute_nullifier_without_context(self) -> Field; - get_header: fn (Note) -> NoteHeader, - - set_header: fn (&mut Note, NoteHeader) -> (), - - broadcast: fn (&mut PrivateContext, Field, Note) -> (), + fn broadcast(self, context: &mut PrivateContext, slot: Field) -> (); } -// docs:end:NoteInterface \ No newline at end of file +// docs:end:note_interface + diff --git a/aztec/src/note/note_viewer_options.nr b/aztec/src/note/note_viewer_options.nr index 4b1c894..5677b33 100644 --- a/aztec/src/note/note_viewer_options.nr +++ b/aztec/src/note/note_viewer_options.nr @@ -1,7 +1,11 @@ use dep::std::option::Option; -use dep::protocol_types::constants::MAX_NOTES_PER_PAGE; use crate::note::note_getter_options::{Select, Sort, Comparator, NoteStatus}; use crate::types::vec::BoundedVec; +use dep::protocol_types::{ + constants::MAX_NOTES_PER_PAGE, + traits::Deserialize, +}; +use crate::note::note_interface::NoteInterface; // docs:start:NoteViewerOptions struct NoteViewerOptions { @@ -14,7 +18,7 @@ struct NoteViewerOptions { // docs:end:NoteViewerOptions impl NoteViewerOptions { - pub fn new() -> NoteViewerOptions { + pub fn new() -> NoteViewerOptions where Note: NoteInterface + Deserialize { NoteViewerOptions { selects: BoundedVec::new(Option::none()), sorts: BoundedVec::new(Option::none()), diff --git a/aztec/src/note/utils.nr b/aztec/src/note/utils.nr index e38a141..1486577 100644 --- a/aztec/src/note/utils.nr +++ b/aztec/src/note/utils.nr @@ -15,6 +15,7 @@ use dep::protocol_types::{ GENERATOR_INDEX__SILOED_COMMITMENT, }, hash::pedersen_hash, + traits::{Deserialize, Serialize}, }; fn compute_inner_hash(storage_slot: Field, note_hash: Field) -> Field { @@ -32,89 +33,76 @@ fn compute_unique_hash(nonce: Field, siloed_note_hash: Field) -> Field { pedersen_hash(inputs, GENERATOR_INDEX__UNIQUE_COMMITMENT) } -fn compute_inner_note_hash(note_interface: NoteInterface, note: Note) -> Field { - let get_header = note_interface.get_header; - let header = get_header(note); - - let compute_note_hash = note_interface.compute_note_hash; - let note_hash = compute_note_hash(note); +fn compute_inner_note_hash(note: Note) -> Field where Note: NoteInterface { + let header = note.get_header(); + let note_hash = note.compute_note_hash(); compute_inner_hash(header.storage_slot, note_hash) } -fn compute_siloed_note_hash(note_interface: NoteInterface, note_with_header: Note) -> Field { - let get_header = note_interface.get_header; - let header = get_header(note_with_header); +fn compute_siloed_note_hash(note_with_header: Note) -> Field where Note: NoteInterface { + let header = note_with_header.get_header(); - let inner_note_hash = compute_inner_note_hash(note_interface, note_with_header); + let inner_note_hash = compute_inner_note_hash(note_with_header); compute_siloed_hash(header.contract_address, inner_note_hash) } -fn compute_unique_siloed_note_hash(note_interface: NoteInterface, note_with_header: Note) -> Field { - let get_header = note_interface.get_header; - let header = get_header(note_with_header); +fn compute_unique_siloed_note_hash(note_with_header: Note) -> Field where Note: NoteInterface { + let header = note_with_header.get_header(); - let siloed_note_hash = compute_siloed_note_hash(note_interface, note_with_header); + let siloed_note_hash = compute_siloed_note_hash(note_with_header); compute_unique_hash(header.nonce, siloed_note_hash) } -pub fn compute_siloed_nullifier( - note_interface: NoteInterface, +pub fn compute_siloed_nullifier( note_with_header: Note, context: &mut PrivateContext -) -> Field { - let get_header = note_interface.get_header; - let header = get_header(note_with_header); - - let compute_nullifier = note_interface.compute_nullifier; - let inner_nullifier = compute_nullifier(note_with_header, context); +) -> Field where Note: NoteInterface { + let header = note_with_header.get_header(); + let inner_nullifier = note_with_header.compute_nullifier(context); let input = [header.contract_address.to_field(), inner_nullifier]; pedersen_hash(input, GENERATOR_INDEX__OUTER_NULLIFIER) } -pub fn compute_note_hash_for_read_or_nullify(note_interface: NoteInterface, note_with_header: Note) -> Field { - let get_header = note_interface.get_header; - let header = get_header(note_with_header); +pub fn compute_note_hash_for_read_or_nullify(note: Note) -> Field where Note: NoteInterface { + let header = note.get_header(); // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1386) if (header.is_transient) { // If a note is transient, we just read the inner_note_hash (kernel will silo by contract address). - compute_inner_note_hash(note_interface, note_with_header) + compute_inner_note_hash(note) } else if (header.nonce == 0) { // If not transient and nonce is zero, that means we are reading a public note. - compute_siloed_note_hash(note_interface, note_with_header) + compute_siloed_note_hash(note) } else { // When nonce is nonzero, that means we are reading a settled note (from tree) created in a // previous TX. So we need the unique_siloed_note_hash which has already been hashed with // contract address and then nonce. This hash will match the existing leaf in the private // data tree, so the kernel can just perform a membership check directly on this hash/leaf. - compute_unique_siloed_note_hash(note_interface, note_with_header) + compute_unique_siloed_note_hash(note) } } -pub fn compute_note_hash_and_nullifier( - note_interface: NoteInterface, +pub fn compute_note_hash_and_nullifier( + deserialize: fn([Field; N]) -> T, note_header: NoteHeader, serialized_note: [Field; S] -) -> [Field; 4] { - let deserialize = note_interface.deserialize; - let set_header = note_interface.set_header; +) -> [Field; 4] where T: NoteInterface { let mut note = deserialize(arr_copy_slice(serialized_note, [0; N], 0)); - set_header(&mut note, note_header); + // TODO: change this to note.setHeader(header) once https://github.com/noir-lang/noir/issues/4095 is fixed + T::set_header((&mut note), note_header); - let compute_note_hash = note_interface.compute_note_hash; - let note_hash = compute_note_hash(note); + let note_hash = note.compute_note_hash(); let inner_note_hash = compute_inner_hash(note_header.storage_slot, note_hash); let siloed_note_hash = compute_siloed_hash(note_header.contract_address, inner_note_hash); let unique_siloed_note_hash = compute_unique_hash(note_header.nonce, siloed_note_hash); - let compute_nullifier_without_context = note_interface.compute_nullifier_without_context; - let inner_nullifier = compute_nullifier_without_context(note); + let inner_nullifier = note.compute_nullifier_without_context(); [inner_note_hash, siloed_note_hash, unique_siloed_note_hash, inner_nullifier] } diff --git a/aztec/src/oracle/get_public_data_witness.nr b/aztec/src/oracle/get_public_data_witness.nr index 555a807..f0c4ce2 100644 --- a/aztec/src/oracle/get_public_data_witness.nr +++ b/aztec/src/oracle/get_public_data_witness.nr @@ -1,5 +1,8 @@ -use dep::protocol_types::constants::PUBLIC_DATA_TREE_HEIGHT; -use dep::protocol_types::hash::pedersen_hash; +use dep::protocol_types::{ + constants::PUBLIC_DATA_TREE_HEIGHT, + hash::pedersen_hash, + traits::{Hash, Serialize} +}; use crate::utils::arr_copy_slice; global LEAF_PREIMAGE_LENGTH: Field = 4; @@ -14,11 +17,13 @@ struct PublicDataTreeLeafPreimage { next_slot :Field, } -impl PublicDataTreeLeafPreimage { +impl Serialize for PublicDataTreeLeafPreimage { fn serialize(self) -> [Field; LEAF_PREIMAGE_LENGTH] { [self.slot, self.value, self.next_index as Field, self.next_slot] } +} +impl Hash for PublicDataTreeLeafPreimage { fn hash(self) -> Field { // Performs the same hashing as StandardIndexedTree::encodeLeaf(...) pedersen_hash(self.serialize(), 0) @@ -34,10 +39,7 @@ struct PublicDataWitness { #[oracle(getPublicDataTreeWitness)] fn get_public_data_witness_oracle(_block_number: u32, _leaf_slot: Field) -> [Field; PUBLIC_DATA_WITNESS] {} -unconstrained pub fn get_public_data_witness( - block_number: u32, - leaf_slot: Field -) -> PublicDataWitness { +unconstrained pub fn get_public_data_witness(block_number: u32, leaf_slot: Field) -> PublicDataWitness { let fields = get_public_data_witness_oracle(block_number, leaf_slot); PublicDataWitness { index: fields[0], diff --git a/aztec/src/oracle/notes.nr b/aztec/src/oracle/notes.nr index c4f2940..3c7c7eb 100644 --- a/aztec/src/oracle/notes.nr +++ b/aztec/src/oracle/notes.nr @@ -5,7 +5,10 @@ use crate::note::{ }; use crate::utils::arr_copy_slice; -use dep::protocol_types::address::AztecAddress; +use dep::protocol_types::{ + address::AztecAddress, + traits::Deserialize +}; #[oracle(notifyCreatedNote)] fn notify_created_note_oracle(_storage_slot: Field, _serialized_note: [Field; N], _inner_note_hash: Field) -> Field {} @@ -69,7 +72,6 @@ unconstrained fn get_notes_oracle_wrapper( unconstrained pub fn get_notes( storage_slot: Field, - note_interface: NoteInterface, num_selects: u8, select_by: [u8; M], select_values: [Field; M], @@ -80,8 +82,9 @@ unconstrained pub fn get_notes( offset: u32, status: u2, mut placeholder_opt_notes: [Option; S], // TODO: Remove it and use `limit` to initialize the note array. - placeholder_fields: [Field; NS] // TODO: Remove it and use `limit` to initialize the note array. -) -> [Option; S] { + placeholder_fields: [Field; NS], // TODO: Remove it and use `limit` to initialize the note array. + _placeholder_note_length: [Field; N] // Turbofish hack? Compiler breaks calculating read_offset unless we add this parameter +) -> [Option; S] where Note: NoteInterface + Deserialize { let fields = get_notes_oracle_wrapper( storage_slot, num_selects, @@ -97,8 +100,6 @@ unconstrained pub fn get_notes( ); let num_notes = fields[0] as u32; let contract_address = AztecAddress::from_field(fields[1]); - let deserialize = note_interface.deserialize; - let set_header = note_interface.set_header; for i in 0..placeholder_opt_notes.len() { if i as u32 < num_notes { // lengths named as per typescript. @@ -109,8 +110,9 @@ unconstrained pub fn get_notes( let is_transient = fields[read_offset + 1] as bool; let header = NoteHeader { contract_address, nonce, storage_slot, is_transient }; let serialized_note = arr_copy_slice(fields, [0; N], read_offset + 2); - let mut note = deserialize(serialized_note); - set_header(&mut note, header); + let mut note = Note::deserialize(serialized_note); + // TODO: change this to note.setHeader(header) once https://github.com/noir-lang/noir/issues/4095 is fixed + Note::set_header(&mut note, header); placeholder_opt_notes[i] = Option::some(note); }; } diff --git a/aztec/src/oracle/storage.nr b/aztec/src/oracle/storage.nr index abb7766..72bec83 100644 --- a/aztec/src/oracle/storage.nr +++ b/aztec/src/oracle/storage.nr @@ -1,3 +1,5 @@ +use dep::protocol_types::traits::{Deserialize, Serialize}; + #[oracle(storageRead)] fn storage_read_oracle(_storage_slot: Field, _number_of_elements: Field) -> [Field; N] {} @@ -5,15 +7,13 @@ unconstrained fn storage_read_oracle_wrapper(_storage_slot: Field) -> [Field; storage_read_oracle(_storage_slot, N) } -pub fn storage_read(storage_slot: Field, deserialize: fn([Field; N]) -> T) -> T { - let fields = storage_read_oracle_wrapper(storage_slot); - deserialize(fields) +pub fn storage_read(storage_slot: Field) -> [Field; N] { + storage_read_oracle_wrapper(storage_slot) } #[oracle(storageWrite)] fn storage_write_oracle(_storage_slot: Field, _values: [Field; N]) -> [Field; N] {} -// TODO: Remove return value. unconstrained pub fn storage_write(storage_slot: Field, fields: [Field; N]) { let _hash = storage_write_oracle(storage_slot, fields); } diff --git a/aztec/src/state_vars/immutable_singleton.nr b/aztec/src/state_vars/immutable_singleton.nr index 5bdc4d0..187feca 100644 --- a/aztec/src/state_vars/immutable_singleton.nr +++ b/aztec/src/state_vars/immutable_singleton.nr @@ -1,7 +1,8 @@ use dep::std::option::Option; use dep::protocol_types::{ address::AztecAddress, - constants::{ + traits::{Serialize, Deserialize}, + constants::{ GENERATOR_INDEX__INITIALIZATION_NULLIFIER, }, hash::pedersen_hash, @@ -17,25 +18,22 @@ use crate::note::{ use crate::oracle::notes::check_nullifier_exists; // docs:start:struct -struct ImmutableSingleton { +struct ImmutableSingleton { context: Option<&mut PrivateContext>, storage_slot: Field, - note_interface: NoteInterface, } // docs:end:struct -impl ImmutableSingleton { +impl ImmutableSingleton { // docs:start:new pub fn new( context: Context, storage_slot: Field, - note_interface: NoteInterface, ) -> Self { assert(storage_slot != 0, "Storage slot 0 not allowed. Storage slots must start from 1."); Self { context: context.private, storage_slot, - note_interface, } } // docs:end:new @@ -58,11 +56,11 @@ impl ImmutableSingleton { // docs:end:is_initialized // docs:start:initialize - pub fn initialize( + pub fn initialize( self, note: &mut Note, broadcast: bool, - ) { + ) where Note: NoteInterface + Serialize + Deserialize { let context = self.context.unwrap(); // Nullify the storage slot. @@ -73,24 +71,23 @@ impl ImmutableSingleton { context, self.storage_slot, note, - self.note_interface, broadcast, ); } // docs:end:initialize // docs:start:get_note - pub fn get_note(self) -> Note { + pub fn get_note(self) -> Note where Note: NoteInterface + Deserialize { let context = self.context.unwrap(); let storage_slot = self.storage_slot; - get_note(context, storage_slot, self.note_interface) + get_note(context, storage_slot) } // docs:end:get_note // docs:start:view_note - unconstrained pub fn view_note(self) -> Note { + unconstrained pub fn view_note(self) -> Note where Note: NoteInterface + Deserialize { let options = NoteViewerOptions::new().set_limit(1); - view_notes(self.storage_slot, self.note_interface, options)[0].unwrap() + view_notes(self.storage_slot, options)[0].unwrap() } // docs:end:view_note } diff --git a/aztec/src/state_vars/public_state.nr b/aztec/src/state_vars/public_state.nr index 10970a9..9309f3d 100644 --- a/aztec/src/state_vars/public_state.nr +++ b/aztec/src/state_vars/public_state.nr @@ -1,46 +1,43 @@ use crate::context::{Context}; use crate::oracle::storage::storage_read; use crate::oracle::storage::storage_write; -use crate::types::type_serialization::TypeSerializationInterface; use dep::std::option::Option; +use dep::protocol_types::traits::{Deserialize, Serialize}; // docs:start:public_state_struct -struct PublicState { +struct PublicState { context: Context, storage_slot: Field, - serialization_methods: TypeSerializationInterface, } // docs:end:public_state_struct -impl PublicState { +impl PublicState { // docs:start:public_state_struct_new pub fn new( // Note: Passing the contexts to new(...) just to have an interface compatible with a Map. context: Context, storage_slot: Field, - serialization_methods: TypeSerializationInterface, ) -> Self { assert(storage_slot != 0, "Storage slot 0 not allowed. Storage slots must start from 1."); PublicState { context, storage_slot, - serialization_methods, } } // docs:end:public_state_struct_new // docs:start:public_state_struct_read - pub fn read(self) -> T { - assert(self.context.private.is_none(), "Public state reads only supported in public functions"); - storage_read(self.storage_slot, self.serialization_methods.deserialize) + pub fn read(self) -> T where T: Deserialize { + assert(self.context.private.is_none(), "Public state writes only supported in public functions"); + let fields = storage_read(self.storage_slot); + T::deserialize(fields) } // docs:end:public_state_struct_read // docs:start:public_state_struct_write - pub fn write(self, value: T) { + pub fn write(self, value: T) where T: Serialize { assert(self.context.private.is_none(), "Public state writes only supported in public functions"); - let serialize = self.serialization_methods.serialize; - let fields = serialize(value); + let fields = T::serialize(value); storage_write(self.storage_slot, fields); } // docs:end:public_state_struct_write diff --git a/aztec/src/state_vars/set.nr b/aztec/src/state_vars/set.nr index 1d873e1..489ccfa 100644 --- a/aztec/src/state_vars/set.nr +++ b/aztec/src/state_vars/set.nr @@ -3,6 +3,7 @@ use crate::abi::PublicContextInputs; use dep::protocol_types::{ constants::{MAX_NOTES_PER_PAGE, MAX_READ_REQUESTS_PER_CALL}, abis::side_effect::{SideEffect, SideEffectLinkedToNoteHash}, + traits::{Deserialize, Serialize}, }; use crate::context::{PrivateContext, PublicContext, Context}; use crate::note::{ @@ -16,51 +17,46 @@ use crate::note::{ }; // docs:start:struct -struct Set { +struct Set { context: Context, storage_slot: Field, - note_interface: NoteInterface, } // docs:end:struct -impl Set { +impl Set { // docs:start:new pub fn new( context: Context, storage_slot: Field, - note_interface: NoteInterface, ) -> Self { assert(storage_slot != 0, "Storage slot 0 not allowed. Storage slots must start from 1."); Set { context, storage_slot, - note_interface, } } // docs:end:new // docs:start:insert - pub fn insert(self, + pub fn insert(self, note: &mut Note, broadcast: bool, - ) { + ) where Note: NoteInterface + Deserialize + Serialize { create_note( self.context.private.unwrap(), self.storage_slot, note, - self.note_interface, broadcast, ); } // docs:end:insert // docs:start:insert_from_public - pub fn insert_from_public(self, note: &mut Note) { + pub fn insert_from_public(self, note: &mut Note) where Note: NoteInterface { create_note_hash_from_public( self.context.public.unwrap(), self.storage_slot, note, - self.note_interface, ); } // docs:end:insert_from_public @@ -76,30 +72,28 @@ impl Set { } // docs:start:remove - pub fn remove(self, note: Note) { + pub fn remove(self, note: Note) where Note: NoteInterface { let context = self.context.private.unwrap(); - let note_hash = compute_note_hash_for_read_or_nullify(self.note_interface, note); + let note_hash = compute_note_hash_for_read_or_nullify(note); let has_been_read = context.read_requests.any(|r: SideEffect| r.value == note_hash); assert(has_been_read, "Can only remove a note that has been read from the set."); destroy_note( context, note, - self.note_interface, ); } // docs:end:remove // docs:start:get_notes - pub fn get_notes( + pub fn get_notes( self, options: NoteGetterOptions, - ) -> [Option; MAX_READ_REQUESTS_PER_CALL] { + ) -> [Option; MAX_READ_REQUESTS_PER_CALL] where Note: NoteInterface + Serialize + Deserialize { let storage_slot = self.storage_slot; let opt_notes = get_notes( self.context.private.unwrap(), storage_slot, - self.note_interface, options, ); opt_notes @@ -107,11 +101,11 @@ impl Set { // docs:end:get_notes // docs:start:view_notes - unconstrained pub fn view_notes( + unconstrained pub fn view_notes( self, options: NoteViewerOptions, - ) -> [Option; MAX_NOTES_PER_PAGE] { - view_notes(self.storage_slot, self.note_interface, options) + ) -> [Option; MAX_NOTES_PER_PAGE] where Note: NoteInterface + Deserialize { + view_notes(self.storage_slot, options) } // docs:end:view_notes } diff --git a/aztec/src/state_vars/singleton.nr b/aztec/src/state_vars/singleton.nr index b5a2d3f..19b4e91 100644 --- a/aztec/src/state_vars/singleton.nr +++ b/aztec/src/state_vars/singleton.nr @@ -6,6 +6,7 @@ use dep::protocol_types::{ GENERATOR_INDEX__INITIALIZATION_NULLIFIER, }, hash::pedersen_hash, + traits::{Serialize, Deserialize}, }; use crate::context::{PrivateContext, PublicContext, Context}; @@ -21,25 +22,22 @@ use crate::oracle::{ }; // docs:start:struct -struct Singleton { +struct Singleton { context: Option<&mut PrivateContext>, - storage_slot: Field, - note_interface: NoteInterface, + storage_slot: Field } // docs:end:struct -impl Singleton { +impl Singleton { // docs:start:new pub fn new( context: Context, storage_slot: Field, - note_interface: NoteInterface, ) -> Self { assert(storage_slot != 0, "Storage slot 0 not allowed. Storage slots must start from 1."); Self { context: context.private, storage_slot, - note_interface, } } // docs:end:new @@ -64,58 +62,58 @@ impl Singleton { // docs:end:is_initialized // docs:start:initialize - pub fn initialize( + pub fn initialize( self, note: &mut Note, broadcast: bool, - ) { + ) where Note: NoteInterface + Serialize + Deserialize { let context = self.context.unwrap(); // Nullify the storage slot. let nullifier = self.compute_initialization_nullifier(); context.push_new_nullifier(nullifier, 0); - create_note(context, self.storage_slot, note, self.note_interface, broadcast); + create_note(context, self.storage_slot, note, broadcast); } // docs:end:initialize // docs:start:replace - pub fn replace( + pub fn replace( self, new_note: &mut Note, broadcast: bool, - ) { + ) where Note: NoteInterface + Serialize + Deserialize { let context = self.context.unwrap(); - let prev_note = get_note(context, self.storage_slot, self.note_interface); + let prev_note = get_note(context, self.storage_slot); // Nullify previous note. - destroy_note(context, prev_note, self.note_interface); + destroy_note(context, prev_note); // Add replacement note. - create_note(context, self.storage_slot, new_note, self.note_interface, broadcast); + create_note(context, self.storage_slot, new_note, broadcast); } // docs:end:replace // docs:start:get_note - pub fn get_note(self, broadcast: bool) -> Note { + pub fn get_note(self, broadcast: bool) -> Note where Note: NoteInterface + Serialize + Deserialize { let context = self.context.unwrap(); - let mut note = get_note(context, self.storage_slot, self.note_interface); + let mut note = get_note(context, self.storage_slot); // Nullify current note to make sure it's reading the latest note. - destroy_note(context, note, self.note_interface); + destroy_note(context, note); // Add the same note again. // Because a nonce is added to every note in the kernel, its nullifier will be different. - create_note(context, self.storage_slot, &mut note, self.note_interface, broadcast); + create_note(context, self.storage_slot, &mut note, broadcast); note } // docs:end:get_note // docs:start:view_note - unconstrained pub fn view_note(self) -> Note { + unconstrained pub fn view_note(self) -> Note where Note: NoteInterface + Deserialize { let options = NoteViewerOptions::new().set_limit(1); - view_notes(self.storage_slot, self.note_interface, options)[0].unwrap() + view_notes(self.storage_slot, options)[0].unwrap() } // docs:end:view_note } diff --git a/aztec/src/types.nr b/aztec/src/types.nr index 18f6888..ae46c9e 100644 --- a/aztec/src/types.nr +++ b/aztec/src/types.nr @@ -1,2 +1 @@ mod vec; // This can/should be moved out into an official noir library -mod type_serialization; diff --git a/aztec/src/types/type_serialization.nr b/aztec/src/types/type_serialization.nr deleted file mode 100644 index 016548a..0000000 --- a/aztec/src/types/type_serialization.nr +++ /dev/null @@ -1,15 +0,0 @@ -mod bool_serialization; -mod field_serialization; -mod u8_serialization; -mod u32_serialization; -mod address_serialization; - -/** - * Before Noir supports traits, a way of specifying the serialization and deserialization methods for a type. - */ -// docs:start:TypeSerializationInterface -struct TypeSerializationInterface { - deserialize: fn ([Field; N]) -> T, - serialize: fn (T) -> [Field; N], -} -// docs:end:TypeSerializationInterface \ No newline at end of file diff --git a/aztec/src/types/type_serialization/address_serialization.nr b/aztec/src/types/type_serialization/address_serialization.nr deleted file mode 100644 index 4994bdc..0000000 --- a/aztec/src/types/type_serialization/address_serialization.nr +++ /dev/null @@ -1,22 +0,0 @@ -use crate::types::type_serialization::TypeSerializationInterface; -use dep::protocol_types::{ - address::{ - AztecAddress, - EthAddress - }, -}; - -global AZTEC_ADDRESS_SERIALIZED_LEN: Field = 1; - -fn deserialize(fields: [Field; AZTEC_ADDRESS_SERIALIZED_LEN]) -> AztecAddress { - AztecAddress::from_field(fields[0]) -} - -fn serialize(value: AztecAddress) -> [Field; AZTEC_ADDRESS_SERIALIZED_LEN] { - [value.to_field()] -} - -global AddressSerializationMethods = TypeSerializationInterface { - deserialize, - serialize, -}; diff --git a/aztec/src/types/type_serialization/bool_serialization.nr b/aztec/src/types/type_serialization/bool_serialization.nr deleted file mode 100644 index 255f519..0000000 --- a/aztec/src/types/type_serialization/bool_serialization.nr +++ /dev/null @@ -1,16 +0,0 @@ -use crate::types::type_serialization::TypeSerializationInterface; - -global BOOL_SERIALIZED_LEN: Field = 1; - -fn deserializeBool(fields: [Field; BOOL_SERIALIZED_LEN]) -> bool { - fields[0] as bool -} - -fn serializeBool(value: bool) -> [Field; BOOL_SERIALIZED_LEN] { - [value as Field] -} - -global BoolSerializationMethods = TypeSerializationInterface { - deserialize: deserializeBool, - serialize: serializeBool, -}; diff --git a/aztec/src/types/type_serialization/field_serialization.nr b/aztec/src/types/type_serialization/field_serialization.nr deleted file mode 100644 index 3c13de1..0000000 --- a/aztec/src/types/type_serialization/field_serialization.nr +++ /dev/null @@ -1,18 +0,0 @@ -use crate::types::type_serialization::TypeSerializationInterface; - -// docs:start:field_serialization -global FIELD_SERIALIZED_LEN: Field = 1; - -fn deserializeField(fields: [Field; FIELD_SERIALIZED_LEN]) -> Field { - fields[0] -} - -fn serializeField(value: Field) -> [Field; FIELD_SERIALIZED_LEN] { - [value] -} - -global FieldSerializationMethods = TypeSerializationInterface { - deserialize: deserializeField, - serialize: serializeField, -}; -// docs:end:field_serialization \ No newline at end of file diff --git a/aztec/src/types/type_serialization/u32_serialization.nr b/aztec/src/types/type_serialization/u32_serialization.nr deleted file mode 100644 index 2517532..0000000 --- a/aztec/src/types/type_serialization/u32_serialization.nr +++ /dev/null @@ -1,16 +0,0 @@ -use crate::types::type_serialization::TypeSerializationInterface; - -global U32_SERIALIZED_LEN: Field = 1; - -fn deserializeU32(fields: [Field; U32_SERIALIZED_LEN]) -> u32 { - fields[0] as u32 -} - -fn serializeU32(value: u32) -> [Field; U32_SERIALIZED_LEN] { - [value as Field] -} - -global U32SerializationMethods = TypeSerializationInterface { - deserialize: deserializeU32, - serialize: serializeU32, -}; diff --git a/aztec/src/types/type_serialization/u8_serialization.nr b/aztec/src/types/type_serialization/u8_serialization.nr deleted file mode 100644 index 8011d02..0000000 --- a/aztec/src/types/type_serialization/u8_serialization.nr +++ /dev/null @@ -1,16 +0,0 @@ -use crate::types::type_serialization::TypeSerializationInterface; - -global U8_SERIALIZED_LEN: Field = 1; - -fn deserializeU8(fields: [Field; U8_SERIALIZED_LEN]) -> u8 { - fields[0] as u8 -} - -fn serializeU8(value: u8) -> [Field; U8_SERIALIZED_LEN] { - [value as Field] -} - -global U8SerializationMethods = TypeSerializationInterface { - deserialize: deserializeU8, - serialize: serializeU8, -}; diff --git a/compressed-string/src/compressed_string.nr b/compressed-string/src/compressed_string.nr index 0cf51b8..7f7945d 100644 --- a/compressed-string/src/compressed_string.nr +++ b/compressed-string/src/compressed_string.nr @@ -1,5 +1,7 @@ -use dep::aztec::types::type_serialization::TypeSerializationInterface; -use dep::aztec::protocol_types::utils::field::field_from_bytes; +use dep::aztec::protocol_types::{ + utils::field::field_from_bytes, + traits::{Serialize, Deserialize} +}; use dep::std; // A Fixedsize Compressed String. @@ -8,6 +10,18 @@ struct FieldCompressedString{ value: Field } +impl Serialize<1> for FieldCompressedString { + fn serialize(self) -> [Field; 1] { + [self.value] + } +} + +impl Deserialize<1> for FieldCompressedString { + fn deserialize(input: [Field; 1]) -> Self { + Self { value: input[0] } + } +} + impl FieldCompressedString{ pub fn is_eq(self, other: FieldCompressedString) -> bool { self.value == other.value @@ -29,28 +43,8 @@ impl FieldCompressedString{ } result } - - pub fn serialize(self) -> [Field; 1] { - [self.value] - } - - pub fn deserialize(input: [Field; 1]) -> Self { - Self { value: input[0] } - } } -fn deserialize(fields: [Field; 1]) -> FieldCompressedString { - FieldCompressedString { value: fields[0] } -} - -fn serialize(value: FieldCompressedString) -> [Field; 1] { - value.serialize() -} -global FieldCompressedStringSerializationMethods = TypeSerializationInterface { - deserialize, - serialize, -}; - // The general Compressed String. // Compresses M bytes into N fields. // Can be used for longer strings that don't fit in a single field. diff --git a/compressed-string/src/lib.nr b/compressed-string/src/lib.nr index aef2a57..b441f62 100644 --- a/compressed-string/src/lib.nr +++ b/compressed-string/src/lib.nr @@ -1,4 +1,4 @@ mod compressed_string; use crate::compressed_string::{CompressedString}; -use crate::compressed_string::{FieldCompressedString, FieldCompressedStringSerializationMethods}; +use crate::compressed_string::FieldCompressedString; diff --git a/easy-private-state/src/easy_private_state.nr b/easy-private-state/src/easy_private_state.nr index 29feeeb..d6b6fbf 100644 --- a/easy-private-state/src/easy_private_state.nr +++ b/easy-private-state/src/easy_private_state.nr @@ -6,12 +6,12 @@ use dep::aztec::{ }; use dep::value_note::{ filter::filter_notes_min_sum, - value_note::{ValueNote, ValueNoteMethods, VALUE_NOTE_LEN}, + value_note::ValueNote, }; struct EasyPrivateUint { context: Context, - set: Set, + set: Set, storage_slot: Field, } @@ -23,8 +23,7 @@ impl EasyPrivateUint { assert(storage_slot != 0, "Storage slot 0 not allowed. Storage slots must start from 1."); let set = Set { context, - storage_slot, - note_interface: ValueNoteMethods, + storage_slot }; EasyPrivateUint { context, diff --git a/field-note/src/field_note.nr b/field-note/src/field_note.nr index 8aa8fbe..45b2ba6 100644 --- a/field-note/src/field_note.nr +++ b/field-note/src/field_note.nr @@ -5,6 +5,7 @@ use dep::aztec::{ }, hash::pedersen_hash, context::PrivateContext, + protocol_types::traits::{Serialize, Deserialize}, }; global FIELD_NOTE_LEN: Field = 1; @@ -17,86 +18,58 @@ struct FieldNote { header: NoteHeader, } -impl FieldNote { - pub fn new(value: Field) -> Self { - FieldNote { - value, - header: NoteHeader::empty(), - } - } - - pub fn serialize(self) -> [Field; FIELD_NOTE_LEN]{ +impl Serialize for FieldNote { + fn serialize(self) -> [Field; FIELD_NOTE_LEN]{ [self.value] } +} - pub fn deserialize(serialized_note: [Field; FIELD_NOTE_LEN]) -> Self { +impl Deserialize for FieldNote { + fn deserialize(serialized_note: [Field; FIELD_NOTE_LEN]) -> Self { FieldNote { value: serialized_note[0], header: NoteHeader::empty(), } } +} - pub fn compute_note_hash(self) -> Field { +impl NoteInterface for FieldNote { + fn compute_note_hash(self) -> Field { // TODO(#1205) Should use a non-zero generator index. pedersen_hash(self.serialize(), 0) } - pub fn compute_nullifier(_self: Self, _context: &mut PrivateContext) -> Field { + fn compute_nullifier(self, _context: &mut PrivateContext) -> Field { // This note is expected to be shared between users and for this reason can't be nullified using a secret. 0 } - pub fn compute_nullifier_without_context(_self: Self) -> Field { + fn compute_nullifier_without_context(self) -> Field { // This note is expected to be shared between users and for this reason can't be nullified using a secret. 0 } - pub fn set_header(&mut self, header: NoteHeader) { + fn set_header(&mut self, header: NoteHeader) { self.header = header; } -} - -fn deserialize(serialized_note: [Field; FIELD_NOTE_LEN]) -> FieldNote { - FieldNote::deserialize(serialized_note) -} - -fn serialize(note: FieldNote) -> [Field; FIELD_NOTE_LEN] { - note.serialize() -} - -fn compute_note_hash(note: FieldNote) -> Field { - note.compute_note_hash() -} - -fn compute_nullifier(note: FieldNote, context: &mut PrivateContext) -> Field { - note.compute_nullifier(context) -} - -fn compute_nullifier_without_context(note: FieldNote) -> Field { - note.compute_nullifier_without_context() -} -fn get_header(note: FieldNote) -> NoteHeader { - note.header -} + fn get_header(self) -> NoteHeader { + self.header + } -fn set_header(note: &mut FieldNote, header: NoteHeader) { - note.set_header(header); + fn broadcast(self, context: &mut PrivateContext, slot: Field) { + assert( + false, "FieldNote does not support broadcast. Add it to PXE directly using the `.addNote` function." + ); + } } -fn broadcast(context: &mut PrivateContext, slot: Field, note: FieldNote) { - assert( - false, "FieldNote does not support broadcast. Add it to PXE directly using the `.addNote` function." - ); +impl FieldNote { + pub fn new(value: Field) -> Self { + FieldNote { + value, + header: NoteHeader::empty(), + } + } } -global FieldNoteMethods = NoteInterface { - deserialize, - serialize, - compute_note_hash, - compute_nullifier, - compute_nullifier_without_context, - get_header, - set_header, - broadcast, -}; diff --git a/safe-math/Nargo.toml b/safe-math/Nargo.toml index 6625680..aaa75e6 100644 --- a/safe-math/Nargo.toml +++ b/safe-math/Nargo.toml @@ -4,4 +4,5 @@ authors = [""] compiler_version = ">=0.18.0" type = "lib" -[dependencies] \ No newline at end of file +[dependencies] +aztec = { path = "../aztec" } \ No newline at end of file diff --git a/safe-math/src/lib.nr b/safe-math/src/lib.nr index 7e29a39..79dd63e 100644 --- a/safe-math/src/lib.nr +++ b/safe-math/src/lib.nr @@ -1,3 +1,3 @@ mod safe_u120; -use crate::safe_u120::SafeU120; +use crate::safe_u120::{SafeU120, SAFE_U120_SERIALIZED_LEN}; diff --git a/safe-math/src/safe_u120.nr b/safe-math/src/safe_u120.nr index d1ce40a..4ef341b 100644 --- a/safe-math/src/safe_u120.nr +++ b/safe-math/src/safe_u120.nr @@ -1,4 +1,5 @@ use dep::std::cmp::Eq; +use dep::aztec::protocol_types::traits::{Deserialize, Serialize}; struct SafeU120 { value: u120, @@ -13,6 +14,21 @@ impl Eq for SafeU120 { } } +global SAFE_U120_SERIALIZED_LEN: Field = 1; + +impl Serialize for SafeU120 { + fn serialize(value: SafeU120) -> [Field; SAFE_U120_SERIALIZED_LEN] { + [value.value as Field] + } +} + +impl Deserialize for SafeU120 { + // This is safe when reading from storage IF only correct safeu120 was written to storage + fn deserialize(fields: [Field; SAFE_U120_SERIALIZED_LEN]) -> SafeU120 { + SafeU120 { value: fields[0] as u120 } + } +} + impl SafeU120 { pub fn min() -> Self { Self { diff --git a/slow-updates-tree/src/slow_map.nr b/slow-updates-tree/src/slow_map.nr index d2dc5c6..065ab00 100644 --- a/slow-updates-tree/src/slow_map.nr +++ b/slow-updates-tree/src/slow_map.nr @@ -1,7 +1,6 @@ use dep::aztec::context::{PrivateContext, PublicContext, Context}; -use dep::aztec::types::type_serialization::TypeSerializationInterface; use dep::aztec::oracle::storage::{storage_read, storage_write}; - +use dep::aztec::protocol_types::traits::{Serialize, Deserialize}; use dep::std::hash::pedersen_hash; use dep::std::merkle::compute_merkle_root; use dep::std::option::Option; @@ -20,20 +19,15 @@ struct Leaf { after: Field, } -fn serialize_leaf(leaf: Leaf) -> [Field; 3] { - [leaf.next_change, leaf.before, leaf.after] -} - -fn deserialize_leaf(serialized: [Field; 3]) -> Leaf { - Leaf { next_change: serialized[0], before: serialized[1], after: serialized[2] } +impl Serialize<3> for Leaf { + fn serialize(leaf: Leaf) -> [Field; 3] { + [leaf.next_change, leaf.before, leaf.after] + } } -impl Leaf { - fn serialize(self: Self) -> [Field; 3] { - serialize_leaf(self) - } - fn deserialize(serialized: [Field; 3]) -> Self { - deserialize_leaf(serialized) +impl Deserialize<3> for Leaf { + fn deserialize(serialized: [Field; 3]) -> Leaf { + Leaf { next_change: serialized[0], before: serialized[1], after: serialized[2] } } } @@ -117,7 +111,8 @@ impl SlowMap { } pub fn read_root(self: Self) -> Leaf { - storage_read(self.storage_slot, deserialize_leaf) + let fields = storage_read(self.storage_slot); + Leaf::deserialize(fields) } // Beware that the initial root could include much state that is not shown by the public storage! @@ -147,7 +142,8 @@ impl SlowMap { // docs:start:read_leaf_at pub fn read_leaf_at(self: Self, key: Field) -> Leaf { let derived_storage_slot = pedersen_hash([self.storage_slot, key]); - storage_read(derived_storage_slot, deserialize_leaf) + let fields = storage_read(derived_storage_slot); + Leaf::deserialize(fields) } // docs:end:read_leaf_at diff --git a/value-note/src/balance_utils.nr b/value-note/src/balance_utils.nr index cd577b9..74c6c79 100644 --- a/value-note/src/balance_utils.nr +++ b/value-note/src/balance_utils.nr @@ -5,11 +5,11 @@ use dep::aztec::note::{ use dep::aztec::state_vars::set::Set; use crate::value_note::{VALUE_NOTE_LEN, ValueNote}; -unconstrained pub fn get_balance(set: Set) -> Field { +unconstrained pub fn get_balance(set: Set) -> Field { get_balance_with_offset(set, 0) } -unconstrained pub fn get_balance_with_offset(set: Set, offset: u32) -> Field { +unconstrained pub fn get_balance_with_offset(set: Set, offset: u32) -> Field { let mut balance = 0; // docs:start:view_notes let options = NoteViewerOptions::new().set_offset(offset); diff --git a/value-note/src/utils.nr b/value-note/src/utils.nr index 277e0b1..d7ef7c9 100644 --- a/value-note/src/utils.nr +++ b/value-note/src/utils.nr @@ -17,7 +17,7 @@ pub fn create_note_getter_options_for_decreasing_balance(amount: Field) -> NoteG // Creates a new note for the recipient. // Inserts it to the recipient's set of notes. -pub fn increment(balance: Set, amount: Field, recipient: AztecAddress) { +pub fn increment(balance: Set, amount: Field, recipient: AztecAddress) { let mut note = ValueNote::new(amount, recipient); // Insert the new note to the owner's set of notes and emit the log if value is non-zero. balance.insert(&mut note, amount != 0); @@ -27,7 +27,7 @@ pub fn increment(balance: Set, amount: Field, recipie // Remove those notes. // If the value of the removed notes exceeds the requested `amount`, create a new note containing the excess value, so that exactly `amount` is removed. // Fail if the sum of the selected notes is less than the amount. -pub fn decrement(balance: Set, amount: Field, owner: AztecAddress) { +pub fn decrement(balance: Set, amount: Field, owner: AztecAddress) { let sum = decrement_by_at_most(balance, amount, owner); assert(sum == amount, "Balance too low"); } @@ -40,11 +40,7 @@ pub fn decrement(balance: Set, amount: Field, owner: // equal `amount`. // // It returns the decremented amount, which should be less than or equal to max_amount. -pub fn decrement_by_at_most( - balance: Set, - max_amount: Field, - owner: AztecAddress -) -> Field { +pub fn decrement_by_at_most(balance: Set, max_amount: Field, owner: AztecAddress) -> Field { let options = create_note_getter_options_for_decreasing_balance(max_amount); let opt_notes = balance.get_notes(options); @@ -68,11 +64,7 @@ pub fn decrement_by_at_most( // Removes the note from the owner's set of notes. // Returns the value of the destroyed note. -pub fn destroy_note( - balance: Set, - owner: AztecAddress, - note: ValueNote -) -> Field { +pub fn destroy_note(balance: Set, owner: AztecAddress, note: ValueNote) -> Field { // Ensure the note is actually owned by the owner (to prevent user from generating a valid proof while // spending someone else's notes). assert(note.owner.eq(owner)); diff --git a/value-note/src/value_note.nr b/value-note/src/value_note.nr index 4cffea0..db0516f 100644 --- a/value-note/src/value_note.nr +++ b/value-note/src/value_note.nr @@ -1,5 +1,8 @@ use dep::aztec::{ - protocol_types::address::AztecAddress, + protocol_types::{ + address::AztecAddress, + traits::{Deserialize, Serialize} + }, note::{ note_header::NoteHeader, note_interface::NoteInterface, @@ -26,23 +29,14 @@ struct ValueNote { } // docs:end:value-note-def -impl ValueNote { - pub fn new(value: Field, owner: AztecAddress) -> Self { - let randomness = rand(); - let header = NoteHeader::empty(); - ValueNote { - value, - owner, - randomness, - header, - } - } - - pub fn serialize(self) -> [Field; VALUE_NOTE_LEN] { +impl Serialize for ValueNote { + fn serialize(self) -> [Field; VALUE_NOTE_LEN] { [self.value, self.owner.to_field(), self.randomness] } +} - pub fn deserialize(serialized_note: [Field; VALUE_NOTE_LEN]) -> Self { +impl Deserialize for ValueNote { + fn deserialize(serialized_note: [Field; VALUE_NOTE_LEN]) -> Self { ValueNote { value: serialized_note[0], owner: AztecAddress::from_field(serialized_note[1]), @@ -50,16 +44,19 @@ impl ValueNote { header: NoteHeader::empty(), } } +} - pub fn compute_note_hash(self) -> Field { +impl NoteInterface for ValueNote { + + fn compute_note_hash(self) -> Field { // TODO(#1205) Should use a non-zero generator index. pedersen_hash(self.serialize(),0) } // docs:start:nullifier - pub fn compute_nullifier(self, context: &mut PrivateContext) -> Field { - let note_hash_for_nullify = compute_note_hash_for_read_or_nullify(ValueNoteMethods, self); + fn compute_nullifier(self, context: &mut PrivateContext) -> Field { + let note_hash_for_nullify = compute_note_hash_for_read_or_nullify(self); let secret = context.request_nullifier_secret_key(self.owner); // TODO(#1205) Should use a non-zero generator index. pedersen_hash([ @@ -71,8 +68,8 @@ impl ValueNote { // docs:end:nullifier - pub fn compute_nullifier_without_context(self) -> Field { - let note_hash_for_nullify = compute_note_hash_for_read_or_nullify(ValueNoteMethods, self); + fn compute_nullifier_without_context(self) -> Field { + let note_hash_for_nullify = compute_note_hash_for_read_or_nullify(self); let secret = get_nullifier_secret_key(self.owner); // TODO(#1205) Should use a non-zero generator index. pedersen_hash([ @@ -82,12 +79,16 @@ impl ValueNote { ],0) } - pub fn set_header(&mut self, header: NoteHeader) { + fn set_header(&mut self, header: NoteHeader) { self.header = header; } + fn get_header(self) -> NoteHeader { + self.header + } + // Broadcasts the note as an encrypted log on L1. - pub fn broadcast(self, context: &mut PrivateContext, slot: Field) { + fn broadcast(self, context: &mut PrivateContext, slot: Field) { let encryption_pub_key = get_public_key(self.owner); emit_encrypted_log( context, @@ -99,46 +100,15 @@ impl ValueNote { } } -fn deserialize(serialized_note: [Field; VALUE_NOTE_LEN]) -> ValueNote { - ValueNote::deserialize(serialized_note) -} - -fn serialize(note: ValueNote) -> [Field; VALUE_NOTE_LEN] { - note.serialize() -} - -fn compute_note_hash(note: ValueNote) -> Field { - note.compute_note_hash() -} - -fn compute_nullifier(note: ValueNote, context: &mut PrivateContext) -> Field { - note.compute_nullifier(context) -} - -fn compute_nullifier_without_context(note: ValueNote) -> Field { - note.compute_nullifier_without_context() -} - -fn get_header(note: ValueNote) -> NoteHeader { - note.header -} - -fn set_header(note: &mut ValueNote, header: NoteHeader) { - note.set_header(header) -} - -// Broadcasts the note as an encrypted log on L1. -fn broadcast(context: &mut PrivateContext, slot: Field, note: ValueNote) { - note.broadcast(context, slot); +impl ValueNote { + pub fn new(value: Field, owner: AztecAddress) -> Self { + let randomness = rand(); + let header = NoteHeader::empty(); + ValueNote { + value, + owner, + randomness, + header, + } + } } - -global ValueNoteMethods = NoteInterface { - deserialize, - serialize, - compute_note_hash, - compute_nullifier, - compute_nullifier_without_context, - get_header, - set_header, - broadcast, -};