diff --git a/noir-projects/aztec-nr/aztec/src/messages/discovery/partial_notes.nr b/noir-projects/aztec-nr/aztec/src/messages/discovery/partial_notes.nr index 0298748136f1..f8075f269661 100644 --- a/noir-projects/aztec-nr/aztec/src/messages/discovery/partial_notes.nr +++ b/noir-projects/aztec-nr/aztec/src/messages/discovery/partial_notes.nr @@ -10,10 +10,9 @@ use crate::{ use dep::protocol_types::{ address::AztecAddress, - constants::PUBLIC_LOG_SIZE_IN_FIELDS, debug_log::debug_log_format, hash::sha256_to_field, - traits::{Deserialize, Serialize, ToField}, + traits::{Deserialize, Serialize}, }; global PARTIAL_NOTE_PRIVATE_MSG_CONTENT_NON_NOTE_FIELDS_LEN: u32 = 2; @@ -28,17 +27,6 @@ pub global DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_CAPSULES_SLOT: Field = sh "AZTEC_NR::DELIVERED_PENDING_PARTIAL_NOTE_ARRAY_LENGTH_CAPSULES_SLOT".as_bytes(), ); -/// Public logs contain an extra field at the beginning with the address of the contract that emitted them, and partial -/// notes emit their completion tag in the log, resulting in the first two fields in the public log not being part of -/// the packed public content. -// TODO(#10273): improve how contract log siloing is handled -pub global NON_PACKED_CONTENT_FIELDS_IN_PUBLIC_LOG: u32 = 2; - -/// The maximum length of the packed representation of public fields in a partial note. This is limited by public log -/// size and extra fields in the log (e.g. the tag). -pub global MAX_PUBLIC_PARTIAL_NOTE_PACKED_CONTENT_LENGTH: u32 = - PUBLIC_LOG_SIZE_IN_FIELDS - NON_PACKED_CONTENT_FIELDS_IN_PUBLIC_LOG; - /// A partial note that was delivered but is still pending completion. Contains the information necessary to find the /// log that will complete it and lead to a note being discovered and delivered. #[derive(Serialize, Deserialize)] @@ -113,23 +101,12 @@ pub unconstrained fn fetch_and_process_public_partial_note_completion_logs( ); let log = maybe_log.unwrap(); - // Public logs have an extra field at the beginning with the contract address, which we use to verify - // that we're getting the logs from the expected contract. - // TODO(#10273): improve how contract log siloing is handled - assert_eq( - log.log_content.get(0), - contract_address.to_field(), - "Got a public log emitted by a different contract", - ); - // Public fields are assumed to all be placed at the end of the packed representation, so we combine the - // private and public packed fields (i.e. the contents of the private message and public log sans the extra - // fields) to get the complete packed content. - let packed_public_note_content: BoundedVec<_, MAX_PUBLIC_PARTIAL_NOTE_PACKED_CONTENT_LENGTH> = - array::subbvec(log.log_content, NON_PACKED_CONTENT_FIELDS_IN_PUBLIC_LOG); + // private and public packed fields (i.e. the contents of the private message and public log plaintext to get + // the complete packed content. let complete_packed_note = array::append( pending_partial_note.packed_private_note_content, - packed_public_note_content, + log.log_plaintext, ); let discovered_notes = attempt_note_nonce_discovery( diff --git a/noir-projects/aztec-nr/aztec/src/messages/encryption/aes128.nr b/noir-projects/aztec-nr/aztec/src/messages/encryption/aes128.nr index 862deb65b8d5..82b3c2d46089 100644 --- a/noir-projects/aztec-nr/aztec/src/messages/encryption/aes128.nr +++ b/noir-projects/aztec-nr/aztec/src/messages/encryption/aes128.nr @@ -1,5 +1,8 @@ use dep::protocol_types::{ - constants::{GENERATOR_INDEX__SYMMETRIC_KEY, GENERATOR_INDEX__SYMMETRIC_KEY_2}, + constants::{ + GENERATOR_INDEX__SYMMETRIC_KEY, GENERATOR_INDEX__SYMMETRIC_KEY_2, + PRIVATE_LOG_CIPHERTEXT_LEN, + }, hash::poseidon2_hash_with_separator, point::Point, }; @@ -12,8 +15,7 @@ use crate::{ messages::{ encryption::log_encryption::{ EPH_PK_SIGN_BYTE_SIZE_IN_BYTES, EPH_PK_X_SIZE_IN_FIELDS, - HEADER_CIPHERTEXT_SIZE_IN_BYTES, LogEncryption, PRIVATE_LOG_CIPHERTEXT_LEN, - PRIVATE_LOG_PLAINTEXT_SIZE_IN_FIELDS, + HEADER_CIPHERTEXT_SIZE_IN_BYTES, LogEncryption, PRIVATE_LOG_PLAINTEXT_SIZE_IN_FIELDS, }, logs::arithmetic_generics_utils::{ get_arr_of_size__log_bytes__from_PT, get_arr_of_size__log_bytes_padding__from_PT, diff --git a/noir-projects/aztec-nr/aztec/src/messages/encryption/log_encryption.nr b/noir-projects/aztec-nr/aztec/src/messages/encryption/log_encryption.nr index d328dcbf323a..23c425fa1fb8 100644 --- a/noir-projects/aztec-nr/aztec/src/messages/encryption/log_encryption.nr +++ b/noir-projects/aztec-nr/aztec/src/messages/encryption/log_encryption.nr @@ -1,7 +1,5 @@ use crate::prelude::AztecAddress; -use protocol_types::constants::PRIVATE_LOG_SIZE_IN_FIELDS; - -pub global PRIVATE_LOG_CIPHERTEXT_LEN: u32 = PRIVATE_LOG_SIZE_IN_FIELDS - 1; // 1 field for the tag +use protocol_types::constants::PRIVATE_LOG_CIPHERTEXT_LEN; // TODO(#12750): The global variables below should not be here as they are AES128 specific. // ciphertext_length (2) + 14 bytes pkcs#7 AES padding. diff --git a/noir-projects/aztec-nr/aztec/src/oracle/message_discovery.nr b/noir-projects/aztec-nr/aztec/src/oracle/message_discovery.nr index 5a4ae812df2e..59fc4c309ef1 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/message_discovery.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/message_discovery.nr @@ -1,7 +1,7 @@ use crate::messages::discovery::private_notes::MAX_NOTE_PACKED_LEN; use dep::protocol_types::{ address::AztecAddress, - constants::{MAX_NOTE_HASHES_PER_TX, PUBLIC_LOG_SIZE_IN_FIELDS}, + constants::{MAX_NOTE_HASHES_PER_TX, PUBLIC_LOG_PLAINTEXT_LEN}, }; /// Finds new private logs that may have been sent to all registered accounts in PXE in the current contract and makes @@ -48,11 +48,11 @@ pub unconstrained fn deliver_note( ) } -/// The contents of a public log, plus contextual information about the transaction in which the log was emitted. This -/// is the data required in order to discover notes that are being delivered in a log. +/// The plaintext of a public log (i.e. the content minus the tag), plus contextual information about the transaction +// in which the log was emitted. This is the data required in order to discover notes that are being delivered in a +// log. pub struct PublicLogWithTxData { - // The log fields length is PUBLIC_LOG_SIZE_IN_FIELDS. + 1 because the contract address is prepended to the content. - pub log_content: BoundedVec, + pub log_plaintext: BoundedVec, pub tx_hash: Field, /// The array of new note hashes created by `tx_hash` pub unique_note_hashes_in_tx: BoundedVec, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index be878904e1df..1c2b80b4796a 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -250,11 +250,20 @@ pub global PRIVATE_LOG_LENGTH: u32 = PRIVATE_LOG_SIZE_IN_FIELDS + 1 /* length */ pub global PRIVATE_LOG_DATA_LENGTH: u32 = PRIVATE_LOG_LENGTH + 1 /* note_hash_counter */ + 1 /* counter */; +/// A private log's ciphertext is all fields except the first one, which is called 'tag'. We call this 'ciphertext' +/// because, unlike public logs, it is expected that private logs are encrypted (though this is not +/// mandatory). +pub global PRIVATE_LOG_CIPHERTEXT_LEN: u32 = PRIVATE_LOG_SIZE_IN_FIELDS - 1; // -1 for the tag pub global SCOPED_PRIVATE_LOG_DATA_LENGTH: u32 = PRIVATE_LOG_DATA_LENGTH + 1 /* contract_address */; pub global PUBLIC_LOG_SIZE_IN_FIELDS: u32 = 13; pub global PUBLIC_LOG_LENGTH: u32 = PUBLIC_LOG_SIZE_IN_FIELDS + 1 /* length */ + 1 /* contract_address */; +/// A public log's plaintext is all fields except the first one, which is called 'tag'. We call this 'plaintext' because, +/// unlike public logs, it is expected that public logs are not encrypted (since the encryption would be public, +/// revealing the plaintext). +pub global PUBLIC_LOG_PLAINTEXT_LEN: u32 = PUBLIC_LOG_SIZE_IN_FIELDS - 1; // -1 for the tag + // TODO(MW): add new constant for this - the below is just the largest combination atm pub global CONTRACT_CLASS_LOG_SIZE_IN_FIELDS: u32 = MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS + REGISTERER_PRIVATE_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS; diff --git a/yarn-project/constants/src/constants.gen.ts b/yarn-project/constants/src/constants.gen.ts index c4f138959a84..a9340b3e055f 100644 --- a/yarn-project/constants/src/constants.gen.ts +++ b/yarn-project/constants/src/constants.gen.ts @@ -143,9 +143,11 @@ export const TREE_LEAF_READ_REQUEST_LENGTH = 2; export const PRIVATE_LOG_SIZE_IN_FIELDS = 18; export const PRIVATE_LOG_LENGTH = 19; export const PRIVATE_LOG_DATA_LENGTH = 21; +export const PRIVATE_LOG_CIPHERTEXT_LEN = 17; export const SCOPED_PRIVATE_LOG_DATA_LENGTH = 22; export const PUBLIC_LOG_SIZE_IN_FIELDS = 13; export const PUBLIC_LOG_LENGTH = 15; +export const PUBLIC_LOG_PLAINTEXT_LEN = 12; export const CONTRACT_CLASS_LOG_SIZE_IN_FIELDS = 3019; export const CONTRACT_CLASS_LOG_LENGTH = 3021; export const LOG_HASH_LENGTH = 2; diff --git a/yarn-project/pxe/src/pxe_oracle_interface/pxe_oracle_interface.test.ts b/yarn-project/pxe/src/pxe_oracle_interface/pxe_oracle_interface.test.ts index 9effc3f239ab..415ebc32244c 100644 --- a/yarn-project/pxe/src/pxe_oracle_interface/pxe_oracle_interface.test.ts +++ b/yarn-project/pxe/src/pxe_oracle_interface/pxe_oracle_interface.test.ts @@ -639,7 +639,7 @@ describe('PXEOracleInterface', () => { const result = (await pxeOracleInterface.getPublicLogByTag(tag, logContractAddress))!; - expect(result.logContent).toEqual([logContractAddress.toField()].concat(scopedLog.log.getEmittedFields())); + expect(result.logPlaintext).toEqual(scopedLog.log.getEmittedFieldsWithoutTag()); expect(result.uniqueNoteHashesInTx).toEqual(indexedTxEffect.data.noteHashes); expect(result.txHash).toEqual(scopedLog.txHash); expect(result.firstNullifierInTx).toEqual(indexedTxEffect.data.nullifiers[0]); @@ -668,8 +668,9 @@ describe('PXEOracleInterface', () => { }); it('returns log fields that are actually emitted', async () => { - const logContent = [Fr.random(), Fr.random()]; const logContractAddress = await AztecAddress.random(); + const logPlaintext = [Fr.random()]; + const logContent = [tag, ...logPlaintext]; const log = PublicLog.from({ contractAddress: logContractAddress, @@ -689,7 +690,7 @@ describe('PXEOracleInterface', () => { const result = await pxeOracleInterface.getPublicLogByTag(tag, logContractAddress); - expect(result?.logContent).toEqual([log.contractAddress.toField(), ...logContent]); + expect(result?.logPlaintext).toEqual(logPlaintext); }); }); diff --git a/yarn-project/pxe/src/pxe_oracle_interface/pxe_oracle_interface.ts b/yarn-project/pxe/src/pxe_oracle_interface/pxe_oracle_interface.ts index 48ff18828437..39b34d7da00c 100644 --- a/yarn-project/pxe/src/pxe_oracle_interface/pxe_oracle_interface.ts +++ b/yarn-project/pxe/src/pxe_oracle_interface/pxe_oracle_interface.ts @@ -719,11 +719,12 @@ export class PXEOracleInterface implements ExecutionDataProvider { throw new Error(`Unexpected: failed to retrieve tx effects for tx ${scopedLog.txHash} which is known to exist`); } - const logContent = (scopedLog.isFromPublic ? [(scopedLog.log as PublicLog).contractAddress.toField()] : []).concat( - scopedLog.log.getEmittedFields(), + return new PublicLogWithTxData( + scopedLog.log.getEmittedFieldsWithoutTag(), + scopedLog.txHash, + txEffect.data.noteHashes, + txEffect.data.nullifiers[0], ); - - return new PublicLogWithTxData(logContent, scopedLog.txHash, txEffect.data.noteHashes, txEffect.data.nullifiers[0]); } public async removeNullifiedNotes(contractAddress: AztecAddress) { diff --git a/yarn-project/stdlib/src/logs/log_with_tx_data.ts b/yarn-project/stdlib/src/logs/log_with_tx_data.ts index b5fa2e15f948..3168eb70c363 100644 --- a/yarn-project/stdlib/src/logs/log_with_tx_data.ts +++ b/yarn-project/stdlib/src/logs/log_with_tx_data.ts @@ -1,4 +1,4 @@ -import { MAX_NOTE_HASHES_PER_TX, PUBLIC_LOG_SIZE_IN_FIELDS } from '@aztec/constants'; +import { MAX_NOTE_HASHES_PER_TX, PUBLIC_LOG_PLAINTEXT_LEN } from '@aztec/constants'; import { Fr } from '@aztec/foundation/fields'; import { TxHash } from '@aztec/stdlib/tx'; @@ -7,8 +7,7 @@ import { TxHash } from '@aztec/stdlib/tx'; export class PublicLogWithTxData { constructor( // The emitted fields of a log. - // For public logs, the contract address is prepended to the content. - public logContent: Fr[], + public logPlaintext: Fr[], public txHash: TxHash, public uniqueNoteHashesInTx: Fr[], public firstNullifierInTx: Fr, @@ -16,9 +15,7 @@ export class PublicLogWithTxData { toNoirSerialization(): (Fr | Fr[])[] { return [ - // The log fields length is PUBLIC_LOG_SIZE_IN_FIELDS. + 1 because the contract address is prepended to the content. - // This is only used for public logs currently, so the maxLength is PUBLIC_LOG_SIZE_IN_FIELDS + 1. - ...toBoundedVecSerialization(this.logContent, PUBLIC_LOG_SIZE_IN_FIELDS + 1), + ...toBoundedVecSerialization(this.logPlaintext, PUBLIC_LOG_PLAINTEXT_LEN), this.txHash.hash, ...toBoundedVecSerialization(this.uniqueNoteHashesInTx, MAX_NOTE_HASHES_PER_TX), this.firstNullifierInTx, diff --git a/yarn-project/stdlib/src/logs/private_log.ts b/yarn-project/stdlib/src/logs/private_log.ts index 49a40e3be1dc..848f20d5d00b 100644 --- a/yarn-project/stdlib/src/logs/private_log.ts +++ b/yarn-project/stdlib/src/logs/private_log.ts @@ -44,6 +44,10 @@ export class PrivateLog { return this.fields.slice(0, this.emittedLength); } + getEmittedFieldsWithoutTag() { + return this.fields.slice(1, this.emittedLength); + } + toBlobFields(): Fr[] { return [new Fr(this.emittedLength)].concat(this.getEmittedFields()); } diff --git a/yarn-project/stdlib/src/logs/public_log.ts b/yarn-project/stdlib/src/logs/public_log.ts index a52e7085dd54..43727682ba55 100644 --- a/yarn-project/stdlib/src/logs/public_log.ts +++ b/yarn-project/stdlib/src/logs/public_log.ts @@ -50,6 +50,10 @@ export class PublicLog { return this.fields.slice(0, this.emittedLength); } + getEmittedFieldsWithoutTag() { + return this.fields.slice(1, this.emittedLength); + } + toBlobFields(): Fr[] { return [new Fr(this.emittedLength), this.contractAddress.toField()].concat(this.getEmittedFields()); }