diff --git a/noir-projects/aztec-nr/aztec/src/discovery/mod.nr b/noir-projects/aztec-nr/aztec/src/discovery/mod.nr index d473c3d19eaf..08355b18c22c 100644 --- a/noir-projects/aztec-nr/aztec/src/discovery/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/discovery/mod.nr @@ -3,6 +3,7 @@ use crate::encrypted_logs::log_assembly_strategies::default_aes128::note::encryp use dep::protocol_types::{address::AztecAddress, debug_log::debug_log}; pub mod private_logs; +pub mod private_notes; pub mod partial_notes; pub mod nonce_discovery; diff --git a/noir-projects/aztec-nr/aztec/src/discovery/partial_notes.nr b/noir-projects/aztec-nr/aztec/src/discovery/partial_notes.nr index 7b517c34ae4f..d231a067df24 100644 --- a/noir-projects/aztec-nr/aztec/src/discovery/partial_notes.nr +++ b/noir-projects/aztec-nr/aztec/src/discovery/partial_notes.nr @@ -2,8 +2,8 @@ use crate::{ capsules::CapsuleArray, discovery::{ ComputeNoteHashAndNullifier, + MAX_NOTE_PACKED_LEN, nonce_discovery::{attempt_note_nonce_discovery, DiscoveredNoteInfo}, - private_logs::MAX_PARTIAL_NOTE_PRIVATE_PACKED_LEN, }, oracle::message_discovery::{deliver_note, get_log_by_tag}, utils::array, @@ -16,6 +16,12 @@ use dep::protocol_types::{ traits::{Deserialize, Serialize, ToField}, }; +pub global PARTIAL_NOTE_COMPLETION_LOG_TAG_LEN: u32 = 1; +/// Partial notes have a maximum packed length of their private fields bound by extra content in their private log (i.e. +/// the note completion log tag). +pub global MAX_PARTIAL_NOTE_PRIVATE_PACKED_LEN: u32 = + MAX_NOTE_PACKED_LEN - PARTIAL_NOTE_COMPLETION_LOG_TAG_LEN; + /// The slot in the PXE capsules where we store a `CapsuleArray` of `DeliveredPendingPartialNote`. // TODO(#11630): come up with some sort of slot allocation scheme. pub global DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_CAPSULES_SLOT: Field = 77; @@ -42,6 +48,35 @@ pub(crate) struct DeliveredPendingPartialNote { pub(crate) recipient: AztecAddress, } +pub unconstrained fn process_partial_note_private_log( + contract_address: AztecAddress, + storage_slot: Field, + note_type_id: Field, + log_payload: BoundedVec, + recipient: AztecAddress, +) { + // We store the information of the partial note we found so that we can later search for the public log that will + // complete it. The tag is the first value in the payload, with the packed note content taking up the rest of it. + std::static_assert( + PARTIAL_NOTE_COMPLETION_LOG_TAG_LEN == 1, + "unexpected value for PARTIAL_NOTE_COMPLETION_LOG_TAG_LEN", + ); + + let pending = DeliveredPendingPartialNote { + note_completion_log_tag: log_payload.get(0), + storage_slot, + note_type_id, + packed_private_note_content: array::subbvec(log_payload, 1), + recipient, + }; + + CapsuleArray::at( + contract_address, + DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_CAPSULES_SLOT, + ) + .push(pending); +} + /// Searches for public logs that would result in the completion of pending partial notes, ultimately resulting in the /// notes being delivered to PXE if completed. pub unconstrained fn fetch_and_process_public_partial_note_completion_logs( diff --git a/noir-projects/aztec-nr/aztec/src/discovery/private_logs.nr b/noir-projects/aztec-nr/aztec/src/discovery/private_logs.nr index d5591d8a6ee0..e9543650f43a 100644 --- a/noir-projects/aztec-nr/aztec/src/discovery/private_logs.nr +++ b/noir-projects/aztec-nr/aztec/src/discovery/private_logs.nr @@ -1,10 +1,6 @@ use std::static_assert; -use crate::{ - capsules::CapsuleArray, - oracle::message_discovery::{deliver_note, sync_notes}, - utils::array, -}; +use crate::{oracle::message_discovery::sync_notes, utils::array}; use dep::protocol_types::{ address::AztecAddress, @@ -13,24 +9,13 @@ use dep::protocol_types::{ }; use crate::discovery::{ - ComputeNoteHashAndNullifier, - MAX_NOTE_PACKED_LEN, - nonce_discovery::{attempt_note_nonce_discovery, DiscoveredNoteInfo}, - NOTE_PRIVATE_LOG_RESERVED_FIELDS, - partial_notes::{ - DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_CAPSULES_SLOT, DeliveredPendingPartialNote, - }, + ComputeNoteHashAndNullifier, MAX_NOTE_PACKED_LEN, NOTE_PRIVATE_LOG_RESERVED_FIELDS, + partial_notes::process_partial_note_private_log, private_notes::process_private_note_log, }; use crate::encrypted_logs::log_assembly_strategies::default_aes128::note::encryption::decrypt_log; // TODO(#12750): don't make this value assume we're using AES. use crate::encrypted_logs::log_assembly_strategies::default_aes128::note::encryption::PRIVATE_LOG_PLAINTEXT_SIZE_IN_FIELDS; -pub global PARTIAL_NOTE_COMPLETION_LOG_TAG_LEN: u32 = 1; -/// Partial notes have a maximum packed length of their private fields bound by extra content in their private log (i.e. -/// the note completion log tag). -pub global MAX_PARTIAL_NOTE_PRIVATE_PACKED_LEN: u32 = - MAX_NOTE_PACKED_LEN - PARTIAL_NOTE_COMPLETION_LOG_TAG_LEN; - /// Searches for private logs that signal new private notes that are then delivered to PXE, or new partial notes that /// are stored in the PXE capsules so that `fetch_and_process_public_partial_note_completion_logs` can later search for /// public logs that will complete them. @@ -45,10 +30,15 @@ pub unconstrained fn fetch_and_process_private_tagged_logs( sync_notes(); } -/// Processes a log's ciphertext by decrypting it and then searching the plaintext for private notes or partial notes. Private -/// notes result in nonce discovery being performed prior to delivery, which requires knowledge of the transaction hash in -/// which the notes would've been created (typically the same transaction in which the log was emitted), along with the -/// list of unique note hashes in said transaction and the `compute_note_hash_and_nullifier` function. +/// Processes a log's ciphertext by decrypting it and then searching the plaintext for private notes or partial notes. +/// +/// Private notes result in nonce discovery being performed prior to delivery, which requires knowledge of the +/// transaction hash in which the notes would've been created (typically the same transaction in which the log was +/// emitted), along with the list of unique note hashes in said transaction and the `compute_note_hash_and_nullifier` +/// function. +/// +/// Partial notes result in a pending partial note entry being stored in a PXE capsule, which will later be retrieved to +/// search for the note's completion public log. pub unconstrained fn do_process_log( contract_address: AztecAddress, log: BoundedVec, @@ -70,7 +60,7 @@ pub unconstrained fn do_process_log( if log_type_id == 0 { debug_log("Processing private note log"); - attempt_note_discovery( + process_private_note_log( contract_address, tx_hash, unique_note_hashes_in_tx, @@ -127,82 +117,3 @@ unconstrained fn destructure_log_plaintext( (storage_slot, note_type_id, log_type_id, log_payload) } - -/// Attempts discovery of a note given information about its contents and the transaction in which it is -/// suspected the note was created. -pub unconstrained fn attempt_note_discovery( - contract_address: AztecAddress, - tx_hash: Field, - unique_note_hashes_in_tx: BoundedVec, - first_nullifier_in_tx: Field, - recipient: AztecAddress, - compute_note_hash_and_nullifier: ComputeNoteHashAndNullifier, - storage_slot: Field, - note_type_id: Field, - packed_note_content: BoundedVec, -) { - let discovered_notes = attempt_note_nonce_discovery( - unique_note_hashes_in_tx, - first_nullifier_in_tx, - compute_note_hash_and_nullifier, - contract_address, - storage_slot, - note_type_id, - packed_note_content, - ); - - debug_log_format( - "Discovered {0} notes from a private log", - [discovered_notes.len() as Field], - ); - - array::for_each_in_bounded_vec( - discovered_notes, - |discovered_note: DiscoveredNoteInfo, _| { - // TODO:(#10728): handle notes that fail delivery. This could be due to e.g. a temporary node connectivity - // issue, and we should perhaps not have marked the tag index as taken. - assert( - deliver_note( - contract_address, - storage_slot, - discovered_note.nonce, - packed_note_content, - discovered_note.note_hash, - discovered_note.inner_nullifier, - tx_hash, - recipient, - ), - "Failed to deliver note", - ); - }, - ); -} - -unconstrained fn process_partial_note_private_log( - contract_address: AztecAddress, - storage_slot: Field, - note_type_id: Field, - log_payload: BoundedVec, - recipient: AztecAddress, -) { - // We store the information of the partial note we found so that we can later search for the public log that will - // complete it. The tag is the first value in the payload, with the packed note content taking up the rest of it. - static_assert( - PARTIAL_NOTE_COMPLETION_LOG_TAG_LEN == 1, - "unexpected value for PARTIAL_NOTE_COMPLETION_LOG_TAG_LEN", - ); - - let pending = DeliveredPendingPartialNote { - note_completion_log_tag: log_payload.get(0), - storage_slot, - note_type_id, - packed_private_note_content: array::subbvec(log_payload, 1), - recipient, - }; - - CapsuleArray::at( - contract_address, - DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_CAPSULES_SLOT, - ) - .push(pending); -} diff --git a/noir-projects/aztec-nr/aztec/src/discovery/private_notes.nr b/noir-projects/aztec-nr/aztec/src/discovery/private_notes.nr new file mode 100644 index 000000000000..6ab67303b951 --- /dev/null +++ b/noir-projects/aztec-nr/aztec/src/discovery/private_notes.nr @@ -0,0 +1,90 @@ +use crate::{ + discovery::{ + ComputeNoteHashAndNullifier, + MAX_NOTE_PACKED_LEN, + nonce_discovery::{attempt_note_nonce_discovery, DiscoveredNoteInfo}, + }, + oracle, + utils::array, +}; +use protocol_types::{ + address::AztecAddress, constants::MAX_NOTE_HASHES_PER_TX, debug_log::debug_log_format, +}; + +pub unconstrained fn process_private_note_log( + contract_address: AztecAddress, + tx_hash: Field, + unique_note_hashes_in_tx: BoundedVec, + first_nullifier_in_tx: Field, + recipient: AztecAddress, + compute_note_hash_and_nullifier: ComputeNoteHashAndNullifier, + storage_slot: Field, + note_type_id: Field, + packed_note_content: BoundedVec, +) { + // Currently a placeholder, since we want to both have a 'process log kind' fn and keep 'attempt_note_discovery'. + // This is where we'll soon extract note type id, storage slot and packed note content from the log metadata and log + // content. + + attempt_note_discovery( + contract_address, + tx_hash, + unique_note_hashes_in_tx, + first_nullifier_in_tx, + recipient, + compute_note_hash_and_nullifier, + storage_slot, + note_type_id, + packed_note_content, + ); +} + +/// Attempts discovery of a note given information about its contents and the transaction in which it is +/// suspected the note was created. +pub unconstrained fn attempt_note_discovery( + contract_address: AztecAddress, + tx_hash: Field, + unique_note_hashes_in_tx: BoundedVec, + first_nullifier_in_tx: Field, + recipient: AztecAddress, + compute_note_hash_and_nullifier: ComputeNoteHashAndNullifier, + storage_slot: Field, + note_type_id: Field, + packed_note_content: BoundedVec, +) { + let discovered_notes = attempt_note_nonce_discovery( + unique_note_hashes_in_tx, + first_nullifier_in_tx, + compute_note_hash_and_nullifier, + contract_address, + storage_slot, + note_type_id, + packed_note_content, + ); + + debug_log_format( + "Discovered {0} notes from a private log", + [discovered_notes.len() as Field], + ); + + array::for_each_in_bounded_vec( + discovered_notes, + |discovered_note: DiscoveredNoteInfo, _| { + // TODO:(#10728): handle notes that fail delivery. This could be due to e.g. a temporary node connectivity + // issue, and we should perhaps not have marked the tag index as taken. + assert( + oracle::message_discovery::deliver_note( + contract_address, + storage_slot, + discovered_note.nonce, + packed_note_content, + discovered_note.note_hash, + discovered_note.inner_nullifier, + tx_hash, + recipient, + ), + "Failed to deliver note", + ); + }, + ); +} diff --git a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr index ad2cb0f4015f..0e3ada6c7830 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -32,7 +32,7 @@ pub contract Test { use dep::aztec::{ deploy::deploy_contract as aztec_deploy_contract, - discovery::private_logs::attempt_note_discovery, + discovery::private_notes::attempt_note_discovery, event::event_interface::EventInterface, hash::{ArgsHasher, pedersen_hash}, history::note_inclusion::ProveNoteInclusion, diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr index f19053725d7a..f8e4331e74e7 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr @@ -18,7 +18,7 @@ use dep::aztec::macros::aztec; pub contract TokenBlacklist { // Libs use dep::aztec::{ - discovery::private_logs::attempt_note_discovery, + discovery::private_notes::attempt_note_discovery, encrypted_logs::log_assembly_strategies::default_aes128::note::{ encode_and_encrypt_note, encode_and_encrypt_note_unconstrained, },