diff --git a/cspell.json b/cspell.json index 3ed9bc44cf44..0002201c734c 100644 --- a/cspell.json +++ b/cspell.json @@ -175,6 +175,7 @@ "noirc", "noirup", "nullifer", + "Nullifiable", "offchain", "onchain", "opentelemetry", diff --git a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr index 5d8aa114b09c..cef593b8849f 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/notes/mod.nr @@ -19,26 +19,26 @@ comptime global NOTE_HEADER_TYPE: Type = type_of(NoteHeader::empty()); pub comptime mut global NOTES: UHashMap> = UHashMap::default(); -/// Computes a note type id by hashing a note name (e.g. `TokenNote`), getting the first 4 bytes of the hash -/// and returning it as a `Field`. -comptime fn compute_note_type_id(name: Quoted) -> Field { - let (name_as_str_quote, _) = name.as_str_quote(); +pub comptime mut global NOTE_TYPE_ID_COUNTER: u32 = 0; + +/// The note type id is set by enumerating the note types. +comptime fn get_next_note_type_id() -> Field { + // We assert that the note type id fits within 7 bits + assert( + NOTE_TYPE_ID_COUNTER < 128 as u32, + "A contract can contain at most 128 different note types", + ); - unquote!( - quote { - let bytes = $name_as_str_quote.as_bytes(); - let hash = protocol_types::hash::poseidon2_hash_bytes(bytes); - let hash_bytes = hash.to_be_bytes::<4>(); - protocol_types::utils::field::field_from_bytes(hash_bytes, true) - }, - ) + let note_type_id = NOTE_TYPE_ID_COUNTER as Field; + NOTE_TYPE_ID_COUNTER += 1; + note_type_id } /// Generates default `NoteInterface` implementation for a given note struct `s` and returns it as quote along with /// the length of the serialized note. /// /// impl NoteInterface for NoteStruct { -/// fn to_be_bytes(self, storage_slot: Field) -> [u8; N * 32 + 64] { +/// fn to_be_bytes(self, storage_slot: Field) -> [u8; N * 32 + 34] { /// ... /// } /// @@ -117,23 +117,27 @@ comptime fn generate_note_interface( ( quote { impl aztec::note::note_interface::NoteInterface<$content_len> for $name { - fn to_be_bytes(self, storage_slot: Field) -> [u8; $content_len * 32 + 64] { - let serialized_note = self.serialize_content(); - - let mut buffer: [u8; $content_len * 32 + 64] = [0; $content_len * 32 + 64]; + fn to_be_bytes(self, storage_slot: Field) -> [u8; $content_len * 32 + 34] { + let mut buffer: [u8; $content_len * 32 + 34] = [0; $content_len * 32 + 34]; let storage_slot_bytes: [u8; 32] = storage_slot.to_be_bytes(); - let note_type_id_bytes: [u8; 32] = $name::get_note_type_id().to_be_bytes(); + // TODO(#10724): Since `note_type_id` is 7 bits long in the 2 bytes there is a space for a 1 bit + // partial note flag. + let note_type_id_bytes: [u8; 2] = $name::get_note_type_id().to_be_bytes(); + let serialized_note = self.serialize_content(); for i in 0..32 { buffer[i] = storage_slot_bytes[i]; + } + + for i in 0..2 { buffer[32 + i] = note_type_id_bytes[i]; } for i in 0..serialized_note.len() { let bytes: [u8; 32] = serialized_note[i].to_be_bytes(); for j in 0..32 { - buffer[64 + i * 32 + j] = bytes[j]; + buffer[34 + i * 32 + j] = bytes[j]; } } buffer @@ -370,18 +374,21 @@ comptime fn generate_multi_scalar_mul( /// /// let let storage_slot_bytes = storage_slot.to_be_bytes(); /// let let note_type_id_bytes = TokenNote::get_note_type_id().to_be_bytes(); +/// let serialized_note = [npk_m_hash as Field, randomness as Field]; /// /// for i in 0..32 { /// log_plaintext[i] = storage_slot_bytes[i]; +/// } +/// +/// for i in 0..2 { /// log_plaintext[32 + i] = note_type_id_bytes[i]; /// } /// -/// let serialized_note = [npk_m_hash as Field, randomness as Field]; /// /// for i in 0..serialized_note.len() { /// let bytes: [u8; 32] = serialized_note[i].to_be_bytes(); /// for j in 0..32 { -/// log_plaintext[64 + i * 32 + j] = bytes[j]; +/// log_plaintext[34 + i * 32 + j] = bytes[j]; /// } /// } /// @@ -430,7 +437,7 @@ comptime fn generate_setup_payload( .join(quote {,}); // Then the log plaintext ones - let log_plaintext_length = indexed_fixed_fields.len() * 32 + 64; + let log_plaintext_length = indexed_fixed_fields.len() * 32 + 34; let setup_log_plaintext = get_setup_log_plaintext_body(s, log_plaintext_length, indexed_nullable_fields); @@ -441,7 +448,7 @@ comptime fn generate_setup_payload( + 2 /* log_plaintext_length */ + 14 /* AES padding */; // Each field contains 31 bytes so the length in fields is computed as ceil(encrypted_log_byte_length / 31) - // --> we achieve rouding by adding 30 and then dividing without remainder + // --> we achieve rounding by adding 30 and then dividing without remainder let encrypted_log_field_length = (encrypted_log_byte_length + 30) / 31; ( @@ -519,10 +526,15 @@ comptime fn get_setup_log_plaintext_body( let mut log_plaintext: [u8; $log_plaintext_length] = [0; $log_plaintext_length]; let storage_slot_bytes: [u8; 32] = storage_slot.to_be_bytes(); - let note_type_id_bytes: [u8; 32] = $name::get_note_type_id().to_be_bytes(); + // TODO(#10724): Since `note_type_id` is 7 bits long in the 2 bytes there is a space for a 1 bit partial note + // flag. + let note_type_id_bytes: [u8; 2] = $name::get_note_type_id().to_be_bytes(); for i in 0..32 { log_plaintext[i] = storage_slot_bytes[i]; + } + + for i in 0..2 { log_plaintext[32 + i] = note_type_id_bytes[i]; } @@ -532,7 +544,7 @@ comptime fn get_setup_log_plaintext_body( for i in 0..serialized_note.len() { let bytes: [u8; 32] = serialized_note[i].to_be_bytes(); for j in 0..32 { - log_plaintext[64 + i * 32 + j] = bytes[j]; + log_plaintext[34 + i * 32 + j] = bytes[j]; } } } @@ -654,14 +666,14 @@ comptime fn generate_finalization_payload( let args = args_list.join(quote {,}); // Then we compute values for `encrypt_log(...)` function - let setup_log_plaintext_length = indexed_fixed_fields.len() * 32 + 64; + let setup_log_plaintext_length = indexed_fixed_fields.len() * 32 + 34; let setup_log_byte_length = 32 /* tag */ + OVERHEAD_SIZE + setup_log_plaintext_length + 2 /* log_plaintext_length */ + 14 /* AES padding */; // Each field contains 31 bytes so the length in fields is computed as ceil(setup_log_byte_length / 31) - // --> we achieve rouding by adding 30 and then dividing without remainder + // --> we achieve rounding by adding 30 and then dividing without remainder let setup_log_field_length = (setup_log_byte_length + 30) / 31; let public_values_field_length = public_values_length * 32; let finalization_log_byte_length = @@ -871,7 +883,7 @@ pub comptime fn partial_note(s: StructDefinition, nullable_fields: [Quoted]) -> inject_note_header(s); let note_properties = generate_note_properties(s); - let note_type_id = compute_note_type_id(s.name()); + let note_type_id = get_next_note_type_id(); let (setup_payload_impl, setup_payload_name) = generate_setup_payload(s, indexed_fixed_fields, indexed_nullable_fields); let (finalization_payload_impl, finalization_payload_name) = @@ -893,6 +905,7 @@ pub comptime fn partial_note(s: StructDefinition, nullable_fields: [Quoted]) -> ); quote { + l $note_properties $setup_payload_impl $finalization_payload_impl @@ -914,7 +927,7 @@ pub comptime fn note(s: StructDefinition) -> Quoted { inject_note_header(s); let note_properties = generate_note_properties(s); - let note_type_id = compute_note_type_id(s.name()); + let note_type_id = get_next_note_type_id(); let (note_interface_impl, note_serialized_len) = generate_note_interface( s, note_type_id, @@ -944,7 +957,7 @@ pub comptime fn note_custom_interface(s: StructDefinition) -> Quoted { inject_note_header(s); let note_properties = generate_note_properties(s); - let note_type_id = compute_note_type_id(s.name()); + let note_type_id = get_next_note_type_id(); let serialized_len_type = fresh_type_variable(); let note_interface_impl = s.as_type().get_trait_impl( quote { crate::note::note_interface::NoteInterface<$serialized_len_type> } diff --git a/noir-projects/aztec-nr/aztec/src/note/note_type_id.nr b/noir-projects/aztec-nr/aztec/src/note/note_type_id.nr deleted file mode 100644 index 8b137891791f..000000000000 --- a/noir-projects/aztec-nr/aztec/src/note/note_type_id.nr +++ /dev/null @@ -1 +0,0 @@ - diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr index f1ec6266f7e1..925fa7a6bf6b 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr @@ -668,7 +668,7 @@ contract Token { fn _store_payload_in_transient_storage_unsafe( slot: Field, point: Point, - setup_log: [Field; 9], + setup_log: [Field; 8], ) { context.storage_write(slot, point); context.storage_write(slot + aztec::protocol_types::point::POINT_LENGTH as Field, setup_log); diff --git a/noir-projects/noir-protocol-circuits/.yarn/install-state.gz b/noir-projects/noir-protocol-circuits/.yarn/install-state.gz index 5c46fdd2fed8..a46c5f7e9d80 100644 Binary files a/noir-projects/noir-protocol-circuits/.yarn/install-state.gz and b/noir-projects/noir-protocol-circuits/.yarn/install-state.gz differ diff --git a/noir-projects/noir-protocol-circuits/package.json b/noir-projects/noir-protocol-circuits/package.json index 2f5efb48850c..0fe327c2d053 100644 --- a/noir-projects/noir-protocol-circuits/package.json +++ b/noir-projects/noir-protocol-circuits/package.json @@ -4,5 +4,6 @@ "main": "index.js", "dependencies": { "@iarna/toml": "^2.2.5" - } + }, + "packageManager": "yarn@4.5.2+sha512.570504f67349ef26d2d86a768dc5ec976ead977aa086b0bb4237e97d5db7ae5c620f9f0e0edf3ea5047205063faff102bf2a2d778664a94eaaa1085ad483fe2e" } diff --git a/yarn-project/circuit-types/src/interfaces/pxe.ts b/yarn-project/circuit-types/src/interfaces/pxe.ts index d70216ef15c0..13fd3dbe8b1a 100644 --- a/yarn-project/circuit-types/src/interfaces/pxe.ts +++ b/yarn-project/circuit-types/src/interfaces/pxe.ts @@ -388,7 +388,7 @@ export interface PXE { isContractInitialized(address: AztecAddress): Promise; /** - * Returns the enctypred events given search parameters. + * Returns the encrypted events given search parameters. * @param eventMetadata - Metadata of the event. This should be the class generated from the contract. e.g. Contract.events.Event * @param from - The block number to search from. * @param limit - The amount of blocks to search. diff --git a/yarn-project/circuit-types/src/logs/l1_payload/l1_note_payload.ts b/yarn-project/circuit-types/src/logs/l1_payload/l1_note_payload.ts index 70b8628ecfdd..cfb70dc71bde 100644 --- a/yarn-project/circuit-types/src/logs/l1_payload/l1_note_payload.ts +++ b/yarn-project/circuit-types/src/logs/l1_payload/l1_note_payload.ts @@ -46,12 +46,13 @@ export class L1NotePayload { ): L1NotePayload | undefined { try { const reader = BufferReader.asReader(plaintext); - const fields = reader.readArray(plaintext.length / Fr.SIZE_IN_BYTES, Fr); - const storageSlot = fields[0]; - const noteTypeId = NoteSelector.fromField(fields[1]); + const storageSlot = reader.readObject(Fr); + // TODO(#10724): Since `note_type_id` is 7 bits long in the 2 bytes there is a space for a 1 bit partial note + // flag. + const noteTypeId = new NoteSelector(reader.readUInt16()); - const privateNoteValues = fields.slice(2); + const privateNoteValues = reader.readArray(reader.remainingBytes() / Fr.SIZE_IN_BYTES, Fr); return new L1NotePayload(contractAddress, storageSlot, noteTypeId, privateNoteValues, publicNoteValues); } catch (e) {