Skip to content

Commit

Permalink
chore!: Serialize, Deserialize and NoteInterface as Traits (#4135)
Browse files Browse the repository at this point in the history
Closes: AztecProtocol/aztec-packages#3756,
AztecProtocol/aztec-packages#2838


Taking advantage of @jfecher's fantastic work in
noir-lang/noir#4000, implemented `Serialize<N>`
and `Deserialize<N>`. Together with `NoteInterface`, they make possible
getting rid of all the serialization interfaces, which greatly simplify
how the storage is handled and opens the door to further improvements.
~~Still some clutter to go, the lengths are still needed in some
places.~~


![Brace yourself](https://i.imgflip.com/8crkve.jpg)

I'm so sorry.

---------

Co-authored-by: sirasistant <sirasistant@gmail.com>
  • Loading branch information
2 people authored and AztecBot committed Jan 31, 2024
1 parent b524154 commit 8aa2962
Show file tree
Hide file tree
Showing 39 changed files with 361 additions and 580 deletions.
100 changes: 34 additions & 66 deletions address-note/src/address_note.nr
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
Expand All @@ -28,39 +31,31 @@ 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<ADDRESS_NOTE_LEN> 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<ADDRESS_NOTE_LEN> 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]),
randomness: serialized_note[2],
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([
Expand All @@ -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([
Expand All @@ -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(
Expand All @@ -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,
};
5 changes: 2 additions & 3 deletions authwit/src/account.nr
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
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;

struct AccountActions {
context: Context,
is_valid_impl: fn(&mut PrivateContext, Field) -> bool,
approved_action: Map<Field, PublicState<bool, BOOL_SERIALIZED_LEN>>,
approved_action: Map<Field, PublicState<bool>>,
}

impl AccountActions {
Expand All @@ -20,7 +19,7 @@ impl AccountActions {
context,
approved_action_storage_slot,
|context, slot| {
PublicState::new(context, slot, BoolSerializationMethods)
PublicState::new(context, slot)
},
),
}
Expand Down
25 changes: 16 additions & 9 deletions authwit/src/entrypoint.nr
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -27,11 +28,13 @@ struct FunctionCall {
is_public: bool,
}

impl FunctionCall {
impl Serialize<FUNCTION_CALL_SIZE> 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);
Expand All @@ -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<ENTRYPOINT_PAYLOAD_SIZE> for EntrypointPayload {
// Serializes the entrypoint struct
fn serialize(self) -> [Field; ENTRYPOINT_PAYLOAD_SIZE] {
let mut fields: BoundedVec<Field, ENTRYPOINT_PAYLOAD_SIZE> = BoundedVec::new(0);
Expand All @@ -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];
Expand Down
15 changes: 9 additions & 6 deletions aztec/src/abi.nr
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use dep::protocol_types::{
},
contrakt::deployment_data::ContractDeploymentData,
hash::hash_args,
traits::{Hash, Serialize},
header::Header,
};

Expand All @@ -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]
}
Expand All @@ -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]
}
Expand Down Expand Up @@ -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: [] }
Expand All @@ -75,8 +82,4 @@ impl Hasher {
self.fields = self.fields.push_back(fields[i]);
}
}

pub fn hash(self) -> Field {
hash_args(self.fields)
}
}
8 changes: 4 additions & 4 deletions aztec/src/context.nr
Original file line number Diff line number Diff line change
Expand Up @@ -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]),
Expand Down
5 changes: 2 additions & 3 deletions aztec/src/history/note_inclusion.nr
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,11 @@ pub fn prove_note_commitment_inclusion(
}

pub fn prove_note_inclusion<Note, N>(
note_interface: NoteInterface<Note, N>,
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);
}
7 changes: 3 additions & 4 deletions aztec/src/history/note_validity.nr
Original file line number Diff line number Diff line change
Expand Up @@ -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, N>(
note_interface: NoteInterface<Note, N>,
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);
}
5 changes: 2 additions & 3 deletions aztec/src/history/nullifier_non_inclusion.nr
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,11 @@ pub fn prove_nullifier_non_inclusion(
}

pub fn prove_note_not_nullified<Note, N>(
note_interface: NoteInterface<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
) {
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);
}

0 comments on commit 8aa2962

Please sign in to comment.