diff --git a/noir-projects/aztec-nr/address-note/src/address_note.nr b/noir-projects/aztec-nr/address-note/src/address_note.nr index bdaf172a402..f1aa4f334a8 100644 --- a/noir-projects/aztec-nr/address-note/src/address_note.nr +++ b/noir-projects/aztec-nr/address-note/src/address_note.nr @@ -8,8 +8,10 @@ use dep::aztec::{ }, oracle::random::random, protocol_types::{ - address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER, - hash::poseidon2_hash_with_separator, traits::Serialize, + address::AztecAddress, + constants::GENERATOR_INDEX__NOTE_NULLIFIER, + hash::poseidon2_hash_with_separator, + traits::{Packable, Serialize}, }, }; diff --git a/noir-projects/aztec-nr/compressed-string/src/field_compressed_string.nr b/noir-projects/aztec-nr/compressed-string/src/field_compressed_string.nr index 0356b2501af..54d21c79a30 100644 --- a/noir-projects/aztec-nr/compressed-string/src/field_compressed_string.nr +++ b/noir-projects/aztec-nr/compressed-string/src/field_compressed_string.nr @@ -6,23 +6,11 @@ use std::meta::derive; // A Fixedsize Compressed String. // Essentially a special version of Compressed String for practical use. -#[derive(Serialize, Deserialize)] +#[derive(Deserialize, Packable, Serialize)] pub struct FieldCompressedString { value: Field, } -/// We implement the Packable trait for FieldCompressedString because it can be stored in contract's storage -/// (and there the implementation of Packable is required). -impl Packable<1> for FieldCompressedString { - fn pack(self) -> [Field; 1] { - self.serialize() - } - - fn unpack(input: [Field; 1]) -> Self { - Self::deserialize(input) - } -} - impl FieldCompressedString { pub fn is_eq(self, other: FieldCompressedString) -> bool { self.value == other.value diff --git a/noir-projects/aztec-nr/uint-note/src/uint_note.nr b/noir-projects/aztec-nr/uint-note/src/uint_note.nr index 4da883eb0e2..f8ada18c0ad 100644 --- a/noir-projects/aztec-nr/uint-note/src/uint_note.nr +++ b/noir-projects/aztec-nr/uint-note/src/uint_note.nr @@ -5,8 +5,10 @@ use dep::aztec::{ oracle::random::random, prelude::{NoteHeader, NullifiableNote, PrivateContext}, protocol_types::{ - address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER, - hash::poseidon2_hash_with_separator, traits::Serialize, + address::AztecAddress, + constants::GENERATOR_INDEX__NOTE_NULLIFIER, + hash::poseidon2_hash_with_separator, + traits::{Packable, Serialize}, }, }; diff --git a/noir-projects/aztec-nr/value-note/src/value_note.nr b/noir-projects/aztec-nr/value-note/src/value_note.nr index f786a91e9ff..e28706f783e 100644 --- a/noir-projects/aztec-nr/value-note/src/value_note.nr +++ b/noir-projects/aztec-nr/value-note/src/value_note.nr @@ -8,8 +8,10 @@ use dep::aztec::{ }, oracle::random::random, protocol_types::{ - address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER, - hash::poseidon2_hash_with_separator, traits::Serialize, + address::AztecAddress, + constants::GENERATOR_INDEX__NOTE_NULLIFIER, + hash::poseidon2_hash_with_separator, + traits::{Packable, Serialize}, }, }; diff --git a/noir-projects/noir-contracts/contracts/amm_contract/src/config.nr b/noir-projects/noir-contracts/contracts/amm_contract/src/config.nr index e56f3160aa1..c18136f4412 100644 --- a/noir-projects/noir-contracts/contracts/amm_contract/src/config.nr +++ b/noir-projects/noir-contracts/contracts/amm_contract/src/config.nr @@ -1,26 +1,12 @@ use dep::aztec::protocol_types::{address::AztecAddress, traits::{Deserialize, Packable, Serialize}}; use std::meta::derive; -global CONFIG_LENGTH: u32 = 3; - /// We store the tokens of the pool in a struct such that to load it from SharedImmutable asserts only a single /// merkle proof. /// (Once we actually do the optimization. WIP in https://github.com/AztecProtocol/aztec-packages/pull/8022). -#[derive(Serialize, Deserialize)] +#[derive(Deserialize, Packable, Serialize)] pub struct Config { pub token0: AztecAddress, pub token1: AztecAddress, pub liquidity_token: AztecAddress, } - -/// We implement the Packable trait for Config because it can be stored in contract's storage (and there -/// the implementation of Packable is required). -impl Packable for Config { - fn pack(self: Self) -> [Field; CONFIG_LENGTH] { - self.serialize() - } - - fn unpack(fields: [Field; CONFIG_LENGTH]) -> Self { - Self::deserialize(fields) - } -} diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr index 4bcd36d90f3..50b75a2e0d9 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr @@ -5,7 +5,9 @@ use dep::aztec::{ note::utils::compute_note_hash_for_nullify, oracle::random::random, prelude::{NoteHeader, NullifiableNote, PrivateContext}, - protocol_types::{address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER}, + protocol_types::{ + address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER, traits::Packable, + }, }; #[note] diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index 91f12b94552..1c8f5c9c756 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -1,38 +1,9 @@ -use dep::aztec::{macros::aztec, protocol_types::traits::{Deserialize, Packable, Serialize}}; - -// I tried using #[derive(Serialize, Deserialize)] macro here but for whatever reason it fails to compile. -pub struct Note { - a: Field, - b: Field, -} - -impl Serialize<2> for Note { - fn serialize(self) -> [Field; 2] { - [self.a, self.b] - } -} - -impl Deserialize<2> for Note { - fn deserialize(wire: [Field; 2]) -> Note { - Note { a: wire[0], b: wire[1] } - } -} - -/// We implement the Packable trait for Note because it can be stored in contract's storage (and there -/// the implementation of Packable is required). -impl Packable<2> for Note { - fn pack(self) -> [Field; 2] { - self.serialize() - } - - fn unpack(fields: [Field; 2]) -> Self { - Self::deserialize(fields) - } -} +mod note; +use dep::aztec::macros::aztec; #[aztec] contract AvmTest { - use crate::Note; + use crate::note::Note; global big_field_128_bits: Field = 0x001234567890abcdef1234567890abcdef; global big_field_136_bits: Field = 0x991234567890abcdef1234567890abcdef; diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/note.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/note.nr new file mode 100644 index 00000000000..223c0ffa714 --- /dev/null +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/note.nr @@ -0,0 +1,8 @@ +use dep::aztec::protocol_types::traits::{Deserialize, Packable, Serialize}; +use std::meta::derive; + +#[derive(Deserialize, Packable, Serialize)] +pub struct Note { + a: Field, + b: Field, +} diff --git a/noir-projects/noir-contracts/contracts/card_game_contract/src/game.nr b/noir-projects/noir-contracts/contracts/card_game_contract/src/game.nr index 9113b14ec8f..1020bfdc8d9 100644 --- a/noir-projects/noir-contracts/contracts/card_game_contract/src/game.nr +++ b/noir-projects/noir-contracts/contracts/card_game_contract/src/game.nr @@ -1,9 +1,11 @@ use crate::cards::Card; use dep::aztec::protocol_types::{address::AztecAddress, traits::{Deserialize, Packable}}; +use std::meta::derive; global NUMBER_OF_PLAYERS: u32 = 2; global NUMBER_OF_CARDS_DECK: u32 = 2; +#[derive(Deserialize, Eq)] pub struct PlayerEntry { address: AztecAddress, deck_strength: u32, @@ -16,28 +18,9 @@ impl PlayerEntry { } } -global PLAYER_SERIALIZED_LEN: u32 = 3; - -impl Deserialize for PlayerEntry { - fn deserialize(fields: [Field; PLAYER_SERIALIZED_LEN]) -> PlayerEntry { - let address = AztecAddress::from_field(fields[0]); - let deck_strength = fields[1] as u32; - let points = fields[2] as u64; - - PlayerEntry { address, deck_strength, points } - } -} - -impl Eq for PlayerEntry { - fn eq(self, other: PlayerEntry) -> bool { - self.address.eq(other.address) - & self.deck_strength.eq(other.deck_strength) - & self.points.eq(other.points) - } -} - global PLAYABLE_CARDS: u32 = 4; +#[derive(Packable)] pub struct Game { players: [PlayerEntry; NUMBER_OF_PLAYERS], rounds_cards: [Card; PLAYABLE_CARDS], @@ -48,52 +31,6 @@ pub struct Game { current_round: u32, } -global GAME_SERIALIZED_LEN: u32 = 15; - -impl Packable for Game { - fn pack(game: Game) -> [Field; GAME_SERIALIZED_LEN] { - [ - game.players[0].address.to_field(), - game.players[0].deck_strength as Field, - game.players[0].points as Field, - game.players[1].address.to_field(), - game.players[1].deck_strength as Field, - game.players[1].points as Field, - game.rounds_cards[0].to_field(), - game.rounds_cards[1].to_field(), - game.rounds_cards[2].to_field(), - game.rounds_cards[3].to_field(), - game.started as Field, - game.finished as Field, - game.claimed as Field, - game.current_player as Field, - game.current_round as Field, - ] - } - - fn unpack(fields: [Field; GAME_SERIALIZED_LEN]) -> Game { - let player1 = PlayerEntry::deserialize([fields[0], fields[1], fields[2]]); - let player2 = PlayerEntry::deserialize([fields[3], fields[4], fields[5]]); - - let players = [player1, player2]; - let rounds_cards = [ - Card::from_field(fields[6]), - Card::from_field(fields[7]), - Card::from_field(fields[8]), - Card::from_field(fields[9]), - ]; - Game { - players, - rounds_cards, - started: fields[10] as bool, - finished: fields[11] as bool, - claimed: fields[12] as bool, - current_player: fields[13] as u32, - current_round: fields[14] as u32, - } - } -} - impl Game { pub fn add_player(&mut self, player_entry: PlayerEntry) -> bool { let mut added = false; diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr index 17ed22a689a..3bd3c7a3baa 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr @@ -3,8 +3,10 @@ use dep::aztec::{ macros::notes::note, note::utils::compute_note_hash_for_nullify, protocol_types::{ - address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER, - hash::poseidon2_hash_with_separator, traits::Serialize, + address::AztecAddress, + constants::GENERATOR_INDEX__NOTE_NULLIFIER, + hash::poseidon2_hash_with_separator, + traits::{Packable, Serialize}, }, }; use dep::aztec::prelude::{NoteHeader, NullifiableNote, PrivateContext}; diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/leader.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/leader.nr index 0c356228d1f..b2b352b1986 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/leader.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/leader.nr @@ -1,31 +1,9 @@ use dep::aztec::protocol_types::{address::AztecAddress, traits::{Deserialize, Packable, Serialize}}; +use std::meta::derive; // Shows how to create a custom struct in Public +#[derive(Deserialize, Packable, Serialize)] pub struct Leader { account: AztecAddress, points: u8, } - -global LEADER_SERIALIZED_LEN: u32 = 2; - -impl Deserialize for Leader { - fn deserialize(fields: [Field; LEADER_SERIALIZED_LEN]) -> Self { - Leader { account: AztecAddress::from_field(fields[0]), points: fields[1] as u8 } - } -} - -impl Serialize for Leader { - fn serialize(self) -> [Field; LEADER_SERIALIZED_LEN] { - [self.account.to_field(), self.points as Field] - } -} - -impl Packable for Leader { - fn pack(self) -> [Field; LEADER_SERIALIZED_LEN] { - self.serialize() - } - - fn unpack(fields: [Field; LEADER_SERIALIZED_LEN]) -> Self { - Self::deserialize(fields) - } -} diff --git a/noir-projects/noir-contracts/contracts/fpc_contract/src/config.nr b/noir-projects/noir-contracts/contracts/fpc_contract/src/config.nr index 9b91358594d..cb07cc225f5 100644 --- a/noir-projects/noir-contracts/contracts/fpc_contract/src/config.nr +++ b/noir-projects/noir-contracts/contracts/fpc_contract/src/config.nr @@ -1,33 +1,8 @@ use dep::aztec::protocol_types::{address::AztecAddress, traits::{Deserialize, Packable, Serialize}}; +use std::meta::derive; -global CONFIG_LENGTH: u32 = 2; - +#[derive(Deserialize, Packable, Serialize)] pub struct Config { pub accepted_asset: AztecAddress, // Asset the FPC accepts (denoted as AA below) pub admin: AztecAddress, // Address to which AA is sent during the private fee payment flow } - -impl Serialize for Config { - fn serialize(self: Self) -> [Field; CONFIG_LENGTH] { - [self.accepted_asset.to_field(), self.admin.to_field()] - } -} - -impl Deserialize for Config { - fn deserialize(fields: [Field; CONFIG_LENGTH]) -> Self { - Config { - accepted_asset: AztecAddress::from_field(fields[0]), - admin: AztecAddress::from_field(fields[1]), - } - } -} - -impl Packable for Config { - fn pack(self) -> [Field; CONFIG_LENGTH] { - self.serialize() - } - - fn unpack(fields: [Field; CONFIG_LENGTH]) -> Self { - Self::deserialize(fields) - } -} diff --git a/noir-projects/noir-contracts/contracts/lending_contract/src/asset.nr b/noir-projects/noir-contracts/contracts/lending_contract/src/asset.nr index 2b0f7d57ef3..67a98b0fd2d 100644 --- a/noir-projects/noir-contracts/contracts/lending_contract/src/asset.nr +++ b/noir-projects/noir-contracts/contracts/lending_contract/src/asset.nr @@ -1,52 +1,18 @@ -use dep::aztec::prelude::AztecAddress; -use dep::aztec::protocol_types::traits::{Deserialize, Packable, Serialize}; +use dep::aztec::{prelude::AztecAddress, protocol_types::traits::{Deserialize, Packable, Serialize}}; +use std::meta::derive; -// Struct to be used to represent "totals". Generally, there should be one per Asset. -// It stores the global values that are shared among all users, such as an accumulator -// and last time it was updated. -// In practice, it should also point to an oracle and have more fields related to -// loan to value ratios and other things, but we did not have enough reads/writes for this. +/// Struct to be used to represent "totals". Generally, there should be one per Asset. +/// It stores the global values that are shared among all users, such as an accumulator +/// and last time it was updated. +/// In practice, it should also point to an oracle and have more fields related to +/// loan to value ratios and other things, but we did not have enough reads/writes for this. +/// +/// Note: Right now we are wasting so many writes. If changing last_updated_ts we will end +/// up rewriting all the values. +#[derive(Deserialize, Packable, Serialize)] pub struct Asset { interest_accumulator: U128, last_updated_ts: u64, loan_to_value: U128, oracle: AztecAddress, } - -global SERIALIZED_LEN: u32 = 6; - -impl Serialize for Asset { - fn serialize(Asset: Asset) -> [Field; SERIALIZED_LEN] { - [ - Asset.interest_accumulator.lo, - Asset.interest_accumulator.hi, - Asset.last_updated_ts as Field, - Asset.loan_to_value.lo, - Asset.loan_to_value.hi, - Asset.oracle.to_field(), - ] - } -} - -impl Deserialize for Asset { - // Right now we are wasting so many writes. If changing last_updated_ts - // we will end up rewriting all of them, wasting writes. - fn deserialize(fields: [Field; SERIALIZED_LEN]) -> Asset { - let interest_accumulator = U128 { lo: fields[0], hi: fields[1] }; - let last_updated_ts = fields[2] as u64; - let loan_to_value = U128 { lo: fields[3], hi: fields[4] }; - let oracle = AztecAddress::from_field(fields[5]); - - Asset { interest_accumulator, last_updated_ts, loan_to_value, oracle } - } -} - -impl Packable for Asset { - fn pack(self) -> [Field; SERIALIZED_LEN] { - self.serialize() - } - - fn unpack(fields: [Field; SERIALIZED_LEN]) -> Self { - Self::deserialize(fields) - } -} diff --git a/noir-projects/noir-contracts/contracts/nft_contract/src/types/nft_note.nr b/noir-projects/noir-contracts/contracts/nft_contract/src/types/nft_note.nr index fef53c69a0f..94ad26e5161 100644 --- a/noir-projects/noir-contracts/contracts/nft_contract/src/types/nft_note.nr +++ b/noir-projects/noir-contracts/contracts/nft_contract/src/types/nft_note.nr @@ -6,7 +6,7 @@ use dep::aztec::{ prelude::{NoteHeader, NullifiableNote, PrivateContext}, protocol_types::{ address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER, - hash::poseidon2_hash_with_separator, + hash::poseidon2_hash_with_separator, traits::Packable, }, }; diff --git a/noir-projects/noir-contracts/contracts/price_feed_contract/src/asset.nr b/noir-projects/noir-contracts/contracts/price_feed_contract/src/asset.nr index 60c3c14c563..8a16ce4abfb 100644 --- a/noir-projects/noir-contracts/contracts/price_feed_contract/src/asset.nr +++ b/noir-projects/noir-contracts/contracts/price_feed_contract/src/asset.nr @@ -1,32 +1,7 @@ use dep::aztec::protocol_types::traits::{Deserialize, Packable, Serialize}; +use std::meta::derive; +#[derive(Deserialize, Packable, Serialize)] pub struct Asset { price: U128, } - -global ASSET_SERIALIZED_LEN: u32 = 2; - -impl Serialize for Asset { - fn serialize(asset: Asset) -> [Field; ASSET_SERIALIZED_LEN] { - [asset.price.lo, asset.price.hi] - } -} - -impl Deserialize for Asset { - fn deserialize(fields: [Field; ASSET_SERIALIZED_LEN]) -> Asset { - let price = U128 { lo: fields[0], hi: fields[1] }; - Asset { price } - } -} - -global ASSET_PACKED_LEN: u32 = 1; - -impl Packable for Asset { - fn pack(self) -> [Field; ASSET_PACKED_LEN] { - self.price.pack() - } - - fn unpack(fields: [Field; ASSET_PACKED_LEN]) -> Self { - Self { price: U128::unpack(fields) } - } -} diff --git a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr index 27cfb18abf3..cb3f763fc54 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr @@ -4,7 +4,7 @@ use dep::aztec::{ note::utils::compute_note_hash_for_nullify, protocol_types::{ address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER, - hash::poseidon2_hash_with_separator, + hash::poseidon2_hash_with_separator, traits::Packable, }, }; use dep::aztec::prelude::{NoteHeader, NullifiableNote, PrivateContext}; diff --git a/noir-projects/noir-contracts/contracts/spam_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/spam_contract/src/types/token_note.nr index b4a97534fd6..c7c28b8ed5f 100644 --- a/noir-projects/noir-contracts/contracts/spam_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/spam_contract/src/types/token_note.nr @@ -6,7 +6,7 @@ use dep::aztec::{ prelude::{NoteHeader, NullifiableNote, PrivateContext}, protocol_types::{ address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER, - hash::poseidon2_hash_with_separator, + hash::poseidon2_hash_with_separator, traits::Packable, }, }; diff --git a/noir-projects/noir-contracts/contracts/test_contract/src/test_note.nr b/noir-projects/noir-contracts/contracts/test_contract/src/test_note.nr index 6425daaffb8..ebc901dad87 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/test_note.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/test_note.nr @@ -38,12 +38,17 @@ impl TestNote { } } +// Note: We are not deriving Eq here because generally we don't want to include the header in the comparison. +// This is bad note design and a tech debt. Ideally derive it once the note design is fixed. impl Eq for TestNote { fn eq(self, other: Self) -> bool { self.value == other.value } } +// Note: We are not deriving Packable here because that would pack the whole struct including the note header +// (so the resulting field array size would be 5). +// This is bad note design and a tech debt. Ideally derive it once the note design is fixed. impl Packable<1> for TestNote { fn pack(self) -> [Field; 1] { [self.value] diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr index b1c644f50bf..8ecddfb090f 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr @@ -6,7 +6,7 @@ use dep::aztec::{ prelude::{NoteHeader, NullifiableNote, PrivateContext}, protocol_types::{ address::AztecAddress, constants::GENERATOR_INDEX__NOTE_NULLIFIER, - hash::poseidon2_hash_with_separator, + hash::poseidon2_hash_with_separator, traits::Packable, }, }; diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr index f830f8265c8..6008cc616a5 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr @@ -1,10 +1,11 @@ // docs:start:token_types_all use dep::aztec::{ macros::notes::note, - note::{note_getter_options::PropertySelector, utils::compute_note_hash_for_nullify}, + note::utils::compute_note_hash_for_nullify, prelude::{NoteHeader, NullifiableNote, PrivateContext}, protocol_types::{ constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash_with_separator, + traits::Packable, }, }; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr index d08d8416f06..5146f86d315 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/meta/mod.nr @@ -105,7 +105,7 @@ pub comptime fn generate_deserialize_from_fields( let packed_fields = packed_fields_quotes.join(quote {,}); // Now we call unpack on the type - result = quote { aztec::protocol_types::traits::Packable::unpack([ $packed_fields ]) }; + result = quote { Packable::unpack([ $packed_fields ]) }; consumed_counter = packed_len; } else if typ.is_field() | typ.as_integer().is_some() | typ.is_bool() { @@ -423,13 +423,17 @@ pub comptime fn generate_serialize_to_fields( } /// From a quote that gets tokenized to a multiple tokens we collapse it to a single token by replacing all `.` with `_`. -/// E.g. "self.value" -> "self_value" +/// E.g. "self.values[0]" -> "self_values_0_" comptime fn collapse_to_one_token(q: Quoted) -> Quoted { let tokens = q.tokens(); let mut single_token = quote {}; for token in tokens { - let new_token = if token == quote {.} { quote {_} } else { token }; + let new_token = if ((token == quote {.}) | (token == quote {[}) | (token == quote {]})) { + quote {_} + } else { + token + }; single_token = f"{single_token}{new_token}".quoted_contents(); } single_token @@ -479,7 +483,46 @@ pub(crate) comptime fn derive_deserialize(s: StructDefinition) -> Quoted { } } -#[derive(Serialize, Deserialize, Eq)] +pub(crate) comptime fn derive_packable(s: StructDefinition) -> Quoted { + let packing_enabled = true; + + let typ = s.as_type(); + let (fields, aux_vars) = + generate_serialize_to_fields(quote { self }, typ, &[], packing_enabled); + let aux_vars_for_packing = if aux_vars.len() > 0 { + let joint = aux_vars.join(quote {;}); + quote { $joint; } + } else { + quote {} + }; + + let (unpacked, _) = generate_deserialize_from_fields( + quote { self }, + typ, + quote { packed }, + 0, + quote {}, + quote {}, + packing_enabled, + ); + + let field_packings = fields.join(quote {,}); + let packed_len = fields.len(); + quote { + impl Packable<$packed_len> for $typ { + fn pack(self) -> [Field; $packed_len] { + $aux_vars_for_packing + [ $field_packings ] + } + + fn unpack(packed: [Field; $packed_len]) -> Self { + $unpacked + } + } + } +} + +#[derive(Packable, Serialize, Deserialize, Eq)] pub struct Smol { a: Field, b: Field, @@ -499,6 +542,12 @@ pub struct Fancier { d: str<16>, } +#[derive(Eq, Packable)] +pub struct ContainsU128 { + a: U128, + b: Field, +} + fn main() { assert(false); } @@ -510,6 +559,10 @@ fn smol_test() { assert(serialized == [1, 2], serialized); let deserialized = Smol::deserialize(serialized); assert(deserialized == smol); + + // None of the struct members implements the `Packable` trait so the packed and serialized data should be the same + let packed = smol.pack(); + assert_eq(packed, serialized, "Packed does not match serialized"); } #[test] @@ -537,3 +590,13 @@ fn fancier_test() { let deserialized = Fancier::deserialize(serialized); assert(deserialized == fancier); } + +#[test] +fn contains_u128_test() { + let contains_u128 = ContainsU128 { a: U128::from_integer(5), b: 3 }; + let packed = contains_u128.pack(); + assert_eq(packed, [5, 3], "Packed does not match the expected"); + + let unpacked = ContainsU128::unpack(packed); + assert_eq(unpacked, contains_u128, "Unpacked does not match the original"); +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/traits.nr b/noir-projects/noir-protocol-circuits/crates/types/src/traits.nr index 2c7f7882e9a..2ecb40dd98a 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/traits.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/traits.nr @@ -1,4 +1,4 @@ -use crate::meta::{derive_deserialize, derive_serialize}; +use crate::meta::{derive_deserialize, derive_packable, derive_serialize}; use crate::utils::field::field_from_bytes; // Trait: is_empty @@ -241,6 +241,7 @@ impl Deserialize for str { /// /// # Type Parameters /// * `N` - The length of the Field array, known at compile time. +#[derive_via(derive_packable)] pub trait Packable { /// Packs the current value into a compact array of `Field` elements. fn pack(self) -> [Field; N]; diff --git a/yarn-project/end-to-end/src/composed/e2e_aztec_js_browser.test.ts b/yarn-project/end-to-end/src/composed/e2e_aztec_js_browser.test.ts index c364baba203..33f7dce9ae0 100644 --- a/yarn-project/end-to-end/src/composed/e2e_aztec_js_browser.test.ts +++ b/yarn-project/end-to-end/src/composed/e2e_aztec_js_browser.test.ts @@ -20,7 +20,7 @@ const pageLogger = createLogger('e2e:aztec_browser.js:web:page'); /** * This test is a bit of a special case as it's on a web browser and not only on anvil and node.js. - * To run the test, do the following: + * To run the test on mainframe, do the following: * 1) Build the whole repository, * 2) If playwright is not installed, install it with `sudo npx playwright install`, * 3) start anvil: `anvil`, @@ -32,10 +32,10 @@ const pageLogger = createLogger('e2e:aztec_browser.js:web:page'); * * Note 1: if you get browser executable not found error check the path from step 6 and fix it if necessary (browser version might have changed), * Note 2: If you get dependency error run `apt install libnss3 libatk1.0-0t64 libatk-bridge2.0-0t64 libcups2t64 libxdamage1 libxkbcommon0 libpango-1.0-0 libcairo2 libasound2t64`. - * NOTE 3: If you see the logs spammed with unexpected logs there is probably a chrome process with a webpage + * Note 3: If you see the logs spammed with unexpected logs there is probably a chrome process with a webpage * unexpectedly running in the background. Kill it with `killall chrome` - * NOTE 4: Don't forget to run `yarn build:web` once you make changes! - * NOTE 5: The test serializes token contract artifact to and from buffer. If you introduce a new type in the artifact + * Note 4: Don't forget to run `yarn build:web` once you make changes! + * Note 5: The test serializes token contract artifact to and from buffer. If you introduce a new type in the artifact * you have to register it on `TypeRegistry` class, implement fromJSON method just like TypeRegistry requires * and add a case in `contractArtifactFromBuffer(...)` function. */