diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index 29a43807bb1..a026721c12f 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -115,15 +115,18 @@ library Constants { uint256 internal constant GLOBAL_VARIABLES_LENGTH = 6 + GAS_FEES_LENGTH; uint256 internal constant APPEND_ONLY_TREE_SNAPSHOT_LENGTH = 2; uint256 internal constant L1_TO_L2_MESSAGE_LENGTH = 6; - uint256 internal constant L2_TO_L1_MESSAGE_LENGTH = 2; + uint256 internal constant L2_TO_L1_MESSAGE_LENGTH = 3; + uint256 internal constant SCOPED_L2_TO_L1_MESSAGE_LENGTH = L2_TO_L1_MESSAGE_LENGTH + 1; uint256 internal constant MAX_BLOCK_NUMBER_LENGTH = 2; uint256 internal constant NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH = 3; - uint256 internal constant NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_LENGTH = 4; + uint256 internal constant SCOPED_NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH = + NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH + 1; uint256 internal constant PARTIAL_STATE_REFERENCE_LENGTH = 6; uint256 internal constant READ_REQUEST_LENGTH = 2; uint256 internal constant NOTE_HASH_LENGTH = 2; - uint256 internal constant NOTE_HASH_CONTEXT_LENGTH = 3; + uint256 internal constant SCOPED_NOTE_HASH_LENGTH = NOTE_HASH_LENGTH + 2; uint256 internal constant NULLIFIER_LENGTH = 3; + uint256 internal constant SCOPED_NULLIFIER_LENGTH = NULLIFIER_LENGTH + 1; uint256 internal constant SIDE_EFFECT_LENGTH = 2; uint256 internal constant STATE_REFERENCE_LENGTH = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH; diff --git a/noir-projects/aztec-nr/aztec/src/context/private_context.nr b/noir-projects/aztec-nr/aztec/src/context/private_context.nr index 0411ba566a0..9d7010e3107 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -96,13 +96,11 @@ impl ContextInterface for PrivateContext { } fn push_new_note_hash(&mut self, note_hash: Field) { - self.new_note_hashes.push(NoteHash { value: note_hash, counter: self.side_effect_counter }); - self.side_effect_counter = self.side_effect_counter + 1; + self.new_note_hashes.push(NoteHash { value: note_hash, counter: self.next_counter() }); } fn push_new_nullifier(&mut self, nullifier: Field, nullified_note_hash: Field) { - self.new_nullifiers.push(Nullifier { value: nullifier, note_hash: nullified_note_hash, counter: self.side_effect_counter }); - self.side_effect_counter = self.side_effect_counter + 1; + self.new_nullifiers.push(Nullifier { value: nullifier, note_hash: nullified_note_hash, counter: self.next_counter() }); } } @@ -193,15 +191,13 @@ impl PrivateContext { } pub fn push_note_hash_read_request(&mut self, note_hash: Field) { - let side_effect = ReadRequest { value: note_hash, counter: self.side_effect_counter }; + let side_effect = ReadRequest { value: note_hash, counter: self.next_counter() }; self.note_hash_read_requests.push(side_effect); - self.side_effect_counter = self.side_effect_counter + 1; } pub fn push_nullifier_read_request(&mut self, nullifier: Field) { - let request = ReadRequest { value: nullifier, counter: self.side_effect_counter }; + let request = ReadRequest { value: nullifier, counter: self.next_counter() }; self.nullifier_read_requests.push(request); - self.side_effect_counter = self.side_effect_counter + 1; } pub fn request_app_nullifier_secret_key(&mut self, account: AztecAddress) -> Field { @@ -227,7 +223,7 @@ impl PrivateContext { // docs:start:context_message_portal pub fn message_portal(&mut self, recipient: EthAddress, content: Field) { // docs:end:context_message_portal - let message = L2ToL1Message { recipient, content }; + let message = L2ToL1Message { recipient, content, counter: self.next_counter() }; self.new_l2_to_l1_msgs.push(message); } @@ -259,9 +255,8 @@ impl PrivateContext { let contract_address = self.this_address(); let log_slice = log.to_be_bytes_arr(); let log_hash = compute_unencrypted_log_hash(contract_address, event_selector, log); - let side_effect = SideEffect { value: log_hash, counter: self.side_effect_counter }; + let side_effect = SideEffect { value: log_hash, counter: self.next_counter() }; self.unencrypted_logs_hashes.push(side_effect); - self.side_effect_counter = self.side_effect_counter + 1; // 44 = addr (32) + selector (4) + raw log len (4) + processed log len (4) self.unencrypted_log_preimages_length += 44 + log_slice.len().to_field(); // call oracle @@ -278,10 +273,10 @@ impl PrivateContext { pub fn emit_contract_class_unencrypted_log(&mut self, log: [Field; N]) { let event_selector = 5; // TODO: compute actual event selector. let contract_address = self.this_address(); - let log_hash = emit_contract_class_unencrypted_log_private_internal(contract_address, event_selector, log, self.side_effect_counter); - let side_effect = SideEffect { value: log_hash, counter: self.side_effect_counter }; + let counter = self.next_counter(); + let log_hash = emit_contract_class_unencrypted_log_private_internal(contract_address, event_selector, log, counter); + let side_effect = SideEffect { value: log_hash, counter }; self.unencrypted_logs_hashes.push(side_effect); - self.side_effect_counter = self.side_effect_counter + 1; // 44 = addr (32) + selector (4) + raw log len (4) + processed log len (4) self.unencrypted_log_preimages_length += 44 + N*32; } @@ -296,18 +291,18 @@ impl PrivateContext { ) where [Field; N]: LensForEncryptedLog { // TODO(1139): perform encryption in the circuit // The oracle call should come last, but we require the encrypted value for now + let counter = self.next_counter(); let encrypted_log: [Field; M] = emit_encrypted_log( contract_address, storage_slot, note_type_id, encryption_pub_key, preimage, - self.side_effect_counter + counter ); let log_hash = compute_encrypted_log_hash(encrypted_log); - let side_effect = SideEffect { value: log_hash, counter: self.side_effect_counter }; + let side_effect = SideEffect { value: log_hash, counter }; self.encrypted_logs_hashes.push(side_effect); - self.side_effect_counter = self.side_effect_counter + 1; let encrypted_log_byte_len = 112 + 32 * (N + 3); // + processed log len (4) self.encrypted_log_preimages_length += encrypted_log_byte_len + 4; @@ -600,6 +595,12 @@ impl PrivateContext { ); } } + + fn next_counter(&mut self) -> u32 { + let counter = self.side_effect_counter; + self.side_effect_counter += 1; + counter + } } impl Empty for PrivateContext { diff --git a/noir-projects/aztec-nr/aztec/src/context/public_context.nr b/noir-projects/aztec-nr/aztec/src/context/public_context.nr index a410a4accb1..ef0fff635bd 100644 --- a/noir-projects/aztec-nr/aztec/src/context/public_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/public_context.nr @@ -131,16 +131,14 @@ impl PublicContext { // Keep private or ask the AVM team if you want to change it. fn push_nullifier_read_request(&mut self, nullifier: Field) { - let request = ReadRequest { value: nullifier, counter: self.side_effect_counter }; + let request = ReadRequest { value: nullifier, counter: self.next_counter() }; self.nullifier_read_requests.push(request); - self.side_effect_counter = self.side_effect_counter + 1; } // Keep private or ask the AVM team if you want to change it. fn push_nullifier_non_existent_read_request(&mut self, nullifier: Field) { - let request = ReadRequest { value: nullifier, counter: self.side_effect_counter }; + let request = ReadRequest { value: nullifier, counter: self.next_counter() }; self.nullifier_non_existent_read_requests.push(request); - self.side_effect_counter = self.side_effect_counter + 1; } pub fn finish(self) -> PublicCircuitPublicInputs { @@ -171,6 +169,12 @@ impl PublicContext { }; pub_circuit_pub_inputs } + + fn next_counter(&mut self) -> u32 { + let counter = self.side_effect_counter; + self.side_effect_counter += 1; + counter + } } impl ContextInterface for PublicContext { @@ -199,17 +203,15 @@ impl ContextInterface for PublicContext { } fn push_new_note_hash(&mut self, note_hash: Field) { - self.new_note_hashes.push(NoteHash { value: note_hash, counter: self.side_effect_counter }); - self.side_effect_counter = self.side_effect_counter + 1; + self.new_note_hashes.push(NoteHash { value: note_hash, counter: self.next_counter() }); } fn push_new_nullifier(&mut self, nullifier: Field, _nullified_note_hash: Field) { self.new_nullifiers.push(Nullifier { value: nullifier, note_hash: 0, // cannot nullify pending notes in public context - counter: self.side_effect_counter + counter: self.next_counter() }); - self.side_effect_counter = self.side_effect_counter + 1; } } @@ -249,7 +251,7 @@ impl PublicContextInterface for PublicContext { } fn message_portal(&mut self, recipient: EthAddress, content: Field) { - let message = L2ToL1Message { recipient, content }; + let message = L2ToL1Message { recipient, content, counter: self.next_counter() }; self.new_l2_to_l1_msgs.push(message); } @@ -281,9 +283,8 @@ impl PublicContextInterface for PublicContext { event_selector, log ); - let side_effect = SideEffect { value: log_hash, counter: self.side_effect_counter }; + let side_effect = SideEffect { value: log_hash, counter: self.next_counter() }; self.unencrypted_logs_hashes.push(side_effect); - self.side_effect_counter = self.side_effect_counter + 1; // 44 = addr (32) + selector (4) + raw log len (4) + processed log len (4) self.unencrypted_log_preimages_length = self.unencrypted_log_preimages_length + 44 + log_slice.len().to_field(); // Call oracle to broadcast log diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/common.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/common.nr index 618741fd50b..940e0230db2 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/common.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/common.nr @@ -142,7 +142,9 @@ fn contract_logic(private_call: PrivateCallData) { } pub fn validate_previous_kernel_values(end: PrivateAccumulatedData) { - assert(end.new_nullifiers[0].value != 0, "The 0th nullifier in the accumulated nullifier array is zero"); + assert( + end.new_nullifiers[0].value() != 0, "The 0th nullifier in the accumulated nullifier array is zero" + ); } pub fn validate_call_against_request(private_call: PrivateCallData, request: CallRequest) { diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/kernel_circuit_public_inputs_composer.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/kernel_circuit_public_inputs_composer.nr index fee2d1293ac..5abc9c8f4f4 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/kernel_circuit_public_inputs_composer.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/kernel_circuit_public_inputs_composer.nr @@ -3,13 +3,16 @@ use dep::types::{ abis::{ kernel_data::PrivateKernelData, kernel_circuit_public_inputs::{KernelCircuitPublicInputs, PrivateKernelCircuitPublicInputsBuilder, PublicKernelCircuitPublicInputs}, - note_hash::NoteHashContext, nullifier::Nullifier, side_effect::{SideEffect, Ordered}, gas::Gas + note_hash::ScopedNoteHash, nullifier::ScopedNullifier, side_effect::{SideEffect, Ordered}, gas::Gas }, constants::{ MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_ENCRYPTED_LOGS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX }, - hash::{compute_note_hash_nonce, compute_unique_siloed_note_hash}, + hash::{ + compute_l2_to_l1_hash, compute_note_hash_nonce, compute_unique_siloed_note_hash, silo_note_hash, + silo_nullifier +}, utils::arrays::{array_length, array_to_bounded_vec, assert_sorted_array} }; @@ -24,14 +27,14 @@ struct KernelCircuitPublicInputsComposer { public_inputs: PrivateKernelCircuitPublicInputsBuilder, previous_kernel: PrivateKernelData, // Final data - note_hashes: [NoteHashContext; MAX_NEW_NOTE_HASHES_PER_TX], - nullifiers: [Nullifier; MAX_NEW_NULLIFIERS_PER_TX], + note_hashes: [ScopedNoteHash; MAX_NEW_NOTE_HASHES_PER_TX], + nullifiers: [ScopedNullifier; MAX_NEW_NULLIFIERS_PER_TX], // Hints transient_nullifier_indexes_for_note_hashes: [u64; MAX_NEW_NOTE_HASHES_PER_TX], transient_note_hash_indexes_for_nullifiers: [u64; MAX_NEW_NULLIFIERS_PER_TX], - sorted_note_hashes: [NoteHashContext; MAX_NEW_NOTE_HASHES_PER_TX], + sorted_note_hashes: [ScopedNoteHash; MAX_NEW_NOTE_HASHES_PER_TX], sorted_note_hashes_indexes: [u64; MAX_NEW_NOTE_HASHES_PER_TX], - sorted_nullifiers: [Nullifier; MAX_NEW_NULLIFIERS_PER_TX], + sorted_nullifiers: [ScopedNullifier; MAX_NEW_NULLIFIERS_PER_TX], sorted_nullifiers_indexes: [u64; MAX_NEW_NULLIFIERS_PER_TX], sorted_encrypted_log_hashes: [SideEffect; MAX_ENCRYPTED_LOGS_PER_TX], sorted_encrypted_log_hashes_indexes: [u64; MAX_ENCRYPTED_LOGS_PER_TX], @@ -42,13 +45,13 @@ struct KernelCircuitPublicInputsComposer { impl KernelCircuitPublicInputsComposer { pub fn new( previous_kernel: PrivateKernelData, - note_hashes: [NoteHashContext; MAX_NEW_NOTE_HASHES_PER_TX], - nullifiers: [Nullifier; MAX_NEW_NULLIFIERS_PER_TX], + note_hashes: [ScopedNoteHash; MAX_NEW_NOTE_HASHES_PER_TX], + nullifiers: [ScopedNullifier; MAX_NEW_NULLIFIERS_PER_TX], transient_nullifier_indexes_for_note_hashes: [u64; MAX_NEW_NOTE_HASHES_PER_TX], transient_note_hash_indexes_for_nullifiers: [u64; MAX_NEW_NULLIFIERS_PER_TX], - sorted_note_hashes: [NoteHashContext; MAX_NEW_NOTE_HASHES_PER_TX], + sorted_note_hashes: [ScopedNoteHash; MAX_NEW_NOTE_HASHES_PER_TX], sorted_note_hashes_indexes: [u64; MAX_NEW_NOTE_HASHES_PER_TX], - sorted_nullifiers: [Nullifier; MAX_NEW_NULLIFIERS_PER_TX], + sorted_nullifiers: [ScopedNullifier; MAX_NEW_NULLIFIERS_PER_TX], sorted_nullifiers_indexes: [u64; MAX_NEW_NULLIFIERS_PER_TX], sorted_encrypted_log_hashes: [SideEffect; MAX_ENCRYPTED_LOGS_PER_TX], sorted_encrypted_log_hashes_indexes: [u64; MAX_ENCRYPTED_LOGS_PER_TX], @@ -122,20 +125,50 @@ impl KernelCircuitPublicInputsComposer { fn silo_values(&mut self) { self.silo_note_hashes(); - // TODO: Move siloing from init/inner circuits to here. + self.silo_nullifiers(); + self.silo_l2_to_l1_messages(); } fn silo_note_hashes(&mut self) { - let first_nullifier = self.public_inputs.end.new_nullifiers.get_unchecked(0); - assert(first_nullifier.value != 0, "The 0th nullifier in the accumulated nullifier array is zero"); + let first_nullifier = self.public_inputs.end.new_nullifiers.get_unchecked(0).value(); + assert(first_nullifier != 0, "The 0th nullifier in the accumulated nullifier array is zero"); let note_hashes = self.public_inputs.end.new_note_hashes.storage; for i in 0..MAX_NEW_NOTE_HASHES_PER_TX { let note_hash = note_hashes[i]; - if note_hash.value != 0 { - let nonce = compute_note_hash_nonce(first_nullifier.value, i); - let unique_note_hash = compute_unique_siloed_note_hash(nonce, note_hash.value); - self.public_inputs.end.new_note_hashes.storage[i].value = unique_note_hash; + if note_hash.value() != 0 { + let siloed = silo_note_hash(note_hash.contract_address, note_hash.value()); + let nonce = compute_note_hash_nonce(first_nullifier, i); + let unique_note_hash = compute_unique_siloed_note_hash(nonce, siloed); + self.public_inputs.end.new_note_hashes.storage[i].note_hash.value = unique_note_hash; + } + } + } + + fn silo_nullifiers(&mut self) { + let nullifiers = self.public_inputs.end.new_nullifiers.storage; + for i in 1..MAX_NEW_NOTE_HASHES_PER_TX { // i starts from 1 to skip the first nullifier. + let nullifier = nullifiers[i]; + if nullifier.value() != 0 { + let siloed = silo_nullifier(nullifier.contract_address, nullifier.value()); + self.public_inputs.end.new_nullifiers.storage[i].nullifier.value = siloed; + } + } + } + + fn silo_l2_to_l1_messages(&mut self) { + let l2_to_l1_msgs = self.public_inputs.end.new_l2_to_l1_msgs.storage; + let tx_context = self.previous_kernel.public_inputs.constants.tx_context; + for i in 0..l2_to_l1_msgs.len() { + let msg = l2_to_l1_msgs[i]; + if !msg.contract_address.is_zero() { + let siloed = compute_l2_to_l1_hash( + msg.contract_address, + tx_context.version, + tx_context.chain_id, + msg.message + ); + self.public_inputs.end.new_l2_to_l1_msgs.storage[i].message.content = siloed; } } } @@ -209,7 +242,7 @@ impl KernelCircuitPublicInputsComposer { assert(self.note_hashes[i].nullifier_counter == 0, "Unresolved transient note hash"); } for i in 0..self.nullifiers.len() { - assert(self.nullifiers[i].note_hash == 0, "Unresolved transient nullifier"); + assert(self.nullifiers[i].nullified_note_hash() == 0, "Unresolved transient nullifier"); } self.public_inputs.end.new_note_hashes = array_to_bounded_vec(self.note_hashes); diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_circuit_public_inputs_composer.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_circuit_public_inputs_composer.nr index f50048579aa..dda3224b07d 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_circuit_public_inputs_composer.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_circuit_public_inputs_composer.nr @@ -10,8 +10,7 @@ use dep::types::{ MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL }, - hash::{compute_l2_to_l1_hash, silo_note_hash, silo_nullifier}, traits::is_empty, - transaction::tx_request::TxRequest, utils::arrays::array_to_bounded_vec + traits::is_empty, transaction::tx_request::TxRequest, utils::arrays::array_to_bounded_vec }; struct DataSource { @@ -38,7 +37,7 @@ impl PrivateKernelCircuitPublicInputsComposer { public_inputs.min_revertible_side_effect_counter = private_call_public_inputs.min_revertible_side_effect_counter; // Since it's the first iteration, we need to push the the tx hash nullifier into the `new_nullifiers` array - public_inputs.end.new_nullifiers.push(Nullifier { value: tx_request.hash(), note_hash: 0, counter: 0 }); + public_inputs.end.new_nullifiers.push(Nullifier { value: tx_request.hash(), note_hash: 0, counter: 0 }.scope(AztecAddress::zero())); // Note that we do not need to nullify the transaction request nonce anymore. // Should an account want to additionally use nonces for replay protection or handling cancellations, // they will be able to do so in the account contract logic: @@ -118,7 +117,7 @@ impl PrivateKernelCircuitPublicInputsComposer { for i in 0..read_requests.len() { let request = read_requests[i]; if !is_empty(request) { - self.public_inputs.validation_requests.note_hash_read_requests.push(request.to_context(source.storage_contract_address)); + self.public_inputs.validation_requests.note_hash_read_requests.push(request.scope(source.storage_contract_address)); } } } @@ -128,7 +127,7 @@ impl PrivateKernelCircuitPublicInputsComposer { for i in 0..nullifier_read_requests.len() { let request = nullifier_read_requests[i]; if !is_empty(request) { - self.public_inputs.validation_requests.nullifier_read_requests.push(request.to_context(source.storage_contract_address)); + self.public_inputs.validation_requests.nullifier_read_requests.push(request.scope(source.storage_contract_address)); } } } @@ -138,7 +137,7 @@ impl PrivateKernelCircuitPublicInputsComposer { for i in 0..nullifier_key_validation_requests.len() { let request = nullifier_key_validation_requests[i]; if !is_empty(request) { - self.public_inputs.validation_requests.nullifier_key_validation_requests.push(request.to_context(source.storage_contract_address)); + self.public_inputs.validation_requests.nullifier_key_validation_requests.push(request.scope(source.storage_contract_address)); } } } @@ -150,12 +149,9 @@ impl PrivateKernelCircuitPublicInputsComposer { if note_hash.value != 0 { let nullifier_counter = source.note_hash_nullifier_counters[i]; assert( - (nullifier_counter == 0) | (nullifier_counter > note_hash.counter), "invalid nullifier counter" + (nullifier_counter == 0) | (nullifier_counter > note_hash.counter), "Invalid nullifier counter" ); - - // TODO: Silo values in the tail circuit. - note_hash.value = silo_note_hash(source.storage_contract_address, note_hash.value); - self.public_inputs.end.new_note_hashes.push(note_hash.to_context(nullifier_counter)); + self.public_inputs.end.new_note_hashes.push(note_hash.scope(nullifier_counter, source.storage_contract_address)); } } } @@ -165,18 +161,7 @@ impl PrivateKernelCircuitPublicInputsComposer { for i in 0..nullifiers.len() { let nullifier = nullifiers[i]; if nullifier.value != 0 { - let siloed_note_hash = if nullifier.note_hash == 0 { - 0 - } else { - silo_note_hash(source.storage_contract_address, nullifier.note_hash) - }; - self.public_inputs.end.new_nullifiers.push( - Nullifier { - value: silo_nullifier(source.storage_contract_address, nullifier.value), - counter: nullifier.counter, - note_hash: siloed_note_hash - } - ); + self.public_inputs.end.new_nullifiers.push(nullifier.scope(source.storage_contract_address)); } } } @@ -186,13 +171,7 @@ impl PrivateKernelCircuitPublicInputsComposer { for i in 0..l2_to_l1_msgs.len() { let msg = l2_to_l1_msgs[i]; if !is_empty(msg) { - let hash = compute_l2_to_l1_hash( - source.storage_contract_address, - source.private_call_public_inputs.tx_context.version, - source.private_call_public_inputs.tx_context.chain_id, - msg - ); - self.public_inputs.end.new_l2_to_l1_msgs.push(hash); + self.public_inputs.end.new_l2_to_l1_msgs.push(msg.scope(source.storage_contract_address)); } } } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr index 769e5021dff..64a08cdc7b1 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr @@ -150,7 +150,7 @@ mod tests { // Check the first nullifier is hash of the signed tx request let tx_hash = builder.tx_request.hash(); - assert_eq(public_inputs.end.new_nullifiers[0].value, tx_hash); + assert_eq(public_inputs.end.new_nullifiers[0].value(), tx_hash); // Log preimages length should increase by `(un)encrypted_log_preimages_length` from private input assert_eq( @@ -232,7 +232,7 @@ mod tests { builder.private_call.public_inputs.new_l2_to_l1_msgs.extend_from_array( [ L2ToL1Message::empty(), - L2ToL1Message { recipient: EthAddress::from_field(6), content: 9123 } + L2ToL1Message { recipient: EthAddress::from_field(6), content: 9123, counter: 0 } ] ); @@ -368,15 +368,13 @@ mod tests { let end_note_hash_read_requests = public_inputs.validation_requests.note_hash_read_requests; assert_eq(array_length(end_note_hash_read_requests), 2); - let request_context = end_note_hash_read_requests[0]; - assert_eq(request_context.value, request_0.value); - assert_eq(request_context.counter, request_0.counter); - assert_eq(request_context.contract_address, storage_contract_address); + let request = end_note_hash_read_requests[0]; + assert_eq(request.read_request, request_0); + assert_eq(request.contract_address, storage_contract_address); - let request_context = end_note_hash_read_requests[1]; - assert_eq(request_context.value, request_1.value); - assert_eq(request_context.counter, request_1.counter); - assert_eq(request_context.contract_address, storage_contract_address); + let request = end_note_hash_read_requests[1]; + assert_eq(request.read_request, request_1); + assert_eq(request.contract_address, storage_contract_address); } #[test] @@ -394,33 +392,30 @@ mod tests { let end_nullifier_read_requests = public_inputs.validation_requests.nullifier_read_requests; assert_eq(array_length(end_nullifier_read_requests), 2); - let request_context = end_nullifier_read_requests[0]; - assert_eq(request_context.value, request_0.value); - assert_eq(request_context.counter, request_0.counter); - assert_eq(request_context.contract_address, storage_contract_address); + let request = end_nullifier_read_requests[0]; + assert_eq(request.read_request, request_0); + assert_eq(request.contract_address, storage_contract_address); - let request_context = end_nullifier_read_requests[1]; - assert_eq(request_context.value, request_1.value); - assert_eq(request_context.counter, request_1.counter); - assert_eq(request_context.contract_address, storage_contract_address); + let request = end_nullifier_read_requests[1]; + assert_eq(request.read_request, request_1); + assert_eq(request.contract_address, storage_contract_address); } #[test] fn propagate_nullifier_key_validation_requests() { let mut builder = PrivateKernelInitInputsBuilder::new(); - let request = NullifierKeyValidationRequest { master_nullifier_public_key: GrumpkinPoint { x: 1, y: 2 }, app_nullifier_secret_key: 3 }; - builder.private_call.public_inputs.nullifier_key_validation_requests.push(request); + let request_0 = NullifierKeyValidationRequest { master_nullifier_public_key: GrumpkinPoint { x: 1, y: 2 }, app_nullifier_secret_key: 3 }; + builder.private_call.public_inputs.nullifier_key_validation_requests.push(request_0); let public_inputs = builder.execute(); assert_eq(array_length(public_inputs.validation_requests.nullifier_key_validation_requests), 1); - let request_context = public_inputs.validation_requests.nullifier_key_validation_requests[0]; - assert_eq(request_context.master_nullifier_public_key, request.master_nullifier_public_key); - assert_eq(request_context.app_nullifier_secret_key, request.app_nullifier_secret_key); + let request = public_inputs.validation_requests.nullifier_key_validation_requests[0]; + assert_eq(request.request, request_0); assert_eq( - request_context.contract_address, builder.private_call.public_inputs.call_context.storage_contract_address + request.contract_address, builder.private_call.public_inputs.call_context.storage_contract_address ); } } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr index e7671e53d0b..6a291bafbfa 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr @@ -451,7 +451,7 @@ mod tests { builder.private_call.public_inputs.new_l2_to_l1_msgs.extend_from_array( [ L2ToL1Message::empty(), - L2ToL1Message { recipient: EthAddress::from_field(6), content: 888 } + L2ToL1Message { recipient: EthAddress::from_field(6), content: 888, counter: 0 } ] ); @@ -504,7 +504,7 @@ mod tests { assert_eq(public_inputs.end.new_note_hashes[2].nullifier_counter, 20); } - #[test(should_fail_with="invalid nullifier counter")] + #[test(should_fail_with="Invalid nullifier counter")] fn propagate_note_hashes_with_incorrect_nullifier_counters_fails() { let mut builder = PrivateKernelInnerInputsBuilder::new(); builder.private_call.public_inputs.new_note_hashes.push(NoteHash { value: 12, counter: 3 }); @@ -571,15 +571,13 @@ mod tests { assert_eq(end_note_hash_read_requests[0], prev_requests.storage[0]); assert_eq(end_note_hash_read_requests[1], prev_requests.storage[1]); - let request_context = end_note_hash_read_requests[2]; - assert_eq(request_context.value, cur_requests[0].value); - assert_eq(request_context.counter, cur_requests[0].counter); - assert_eq(request_context.contract_address, cur_storage_contract_address); + let request = end_note_hash_read_requests[2]; + assert_eq(request.read_request, cur_requests[0]); + assert_eq(request.contract_address, cur_storage_contract_address); - let request_context = end_note_hash_read_requests[3]; - assert_eq(request_context.value, cur_requests[1].value); - assert_eq(request_context.counter, cur_requests[1].counter); - assert_eq(request_context.contract_address, cur_storage_contract_address); + let request = end_note_hash_read_requests[3]; + assert_eq(request.read_request, cur_requests[1]); + assert_eq(request.contract_address, cur_storage_contract_address); } #[test] diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr index f38d494395b..2471caad0be 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr @@ -3,7 +3,7 @@ use dep::reset_kernel_lib::{NoteHashReadRequestHints, NullifierReadRequestHints, use dep::types::{ abis::{ kernel_data::PrivateKernelData, kernel_circuit_public_inputs::KernelCircuitPublicInputs, - note_hash::NoteHashContext, nullifier::Nullifier, side_effect::SideEffect + note_hash::ScopedNoteHash, nullifier::ScopedNullifier, side_effect::SideEffect }, constants::{ MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, @@ -14,8 +14,8 @@ use dep::types::{ // Can just be KernelCircuitPublicInputs. struct PrivateKernelTailOutputs { - note_hashes: [NoteHashContext; MAX_NEW_NOTE_HASHES_PER_TX], - nullifiers: [Nullifier; MAX_NEW_NULLIFIERS_PER_TX], + note_hashes: [ScopedNoteHash; MAX_NEW_NOTE_HASHES_PER_TX], + nullifiers: [ScopedNullifier; MAX_NEW_NULLIFIERS_PER_TX], } struct PrivateKernelTailHints { @@ -24,9 +24,9 @@ struct PrivateKernelTailHints { note_hash_read_request_hints: NoteHashReadRequestHints, nullifier_read_request_hints: NullifierReadRequestHints, master_nullifier_secret_keys: [GrumpkinPrivateKey; MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX], - sorted_new_note_hashes: [NoteHashContext; MAX_NEW_NOTE_HASHES_PER_TX], + sorted_new_note_hashes: [ScopedNoteHash; MAX_NEW_NOTE_HASHES_PER_TX], sorted_new_note_hashes_indexes: [u64; MAX_NEW_NOTE_HASHES_PER_TX], - sorted_new_nullifiers: [Nullifier; MAX_NEW_NULLIFIERS_PER_TX], + sorted_new_nullifiers: [ScopedNullifier; MAX_NEW_NULLIFIERS_PER_TX], sorted_new_nullifiers_indexes: [u64; MAX_NEW_NULLIFIERS_PER_TX], sorted_encrypted_log_hashes: [SideEffect; MAX_ENCRYPTED_LOGS_PER_TX], sorted_encrypted_log_hashes_indexes: [u64; MAX_ENCRYPTED_LOGS_PER_TX], @@ -49,7 +49,7 @@ impl PrivateKernelTailCircuitPrivateInputs { let note_hash_tree_root = previous_public_inputs.constants.historical_header.state.partial.note_hash_tree.root; let nullifier_tree_root = previous_public_inputs.constants.historical_header.state.partial.nullifier_tree.root; - let request_processor = PrivateValidationRequestProcessor { + PrivateValidationRequestProcessor { validation_requests: previous_public_inputs.validation_requests, note_hash_read_request_hints: self.hints.note_hash_read_request_hints, pending_note_hashes: previous_public_inputs.end.new_note_hashes, @@ -58,10 +58,9 @@ impl PrivateKernelTailCircuitPrivateInputs { pending_nullifiers: previous_public_inputs.end.new_nullifiers, nullifier_tree_root, master_nullifier_secret_keys: self.hints.master_nullifier_secret_keys - }; - request_processor.validate(); + }.validate(); - let mut composer = KernelCircuitPublicInputsComposer::new( + KernelCircuitPublicInputsComposer::new( self.previous_kernel, self.outputs.note_hashes, self.outputs.nullifiers, @@ -75,8 +74,7 @@ impl PrivateKernelTailCircuitPrivateInputs { self.hints.sorted_encrypted_log_hashes_indexes, self.hints.sorted_unencrypted_log_hashes, self.hints.sorted_unencrypted_log_hashes_indexes - ); - composer.compose().finish() + ).compose().finish() } } @@ -99,10 +97,10 @@ mod tests { use dep::types::{ abis::{ kernel_circuit_public_inputs::KernelCircuitPublicInputs, max_block_number::MaxBlockNumber, - note_hash::NoteHashContext, nullifier::Nullifier, side_effect::{SideEffect, Ordered}, gas::Gas + note_hash::{NoteHash, ScopedNoteHash}, nullifier::{Nullifier, ScopedNullifier}, side_effect::SideEffect, gas::Gas }, grumpkin_private_key::GrumpkinPrivateKey, - hash::{compute_note_hash_nonce, compute_unique_siloed_note_hash, sha256_to_field}, + hash::{compute_note_hash_nonce, compute_unique_siloed_note_hash, sha256_to_field, silo_note_hash, silo_nullifier}, tests::{fixture_builder::FixtureBuilder, sort::sort_get_sorted_hints}, utils::{arrays::{array_eq, array_length}}, traits::{Empty, is_empty, is_empty_array} }; @@ -134,21 +132,32 @@ mod tests { // A helper function that uses the first nullifer in the previous kernel to compute the unique siloed // note_hashes for the given note_hashes. - pub fn compute_unique_siloed_note_hashes( + pub fn compute_output_note_hashes( self, - note_hashes: [NoteHashContext; N] + note_hashes: [ScopedNoteHash; N] ) -> [Field; N] { let first_nullifier = self.previous_kernel.new_nullifiers.get_unchecked(0); let mut unique_siloed_note_hashes = [0; N]; for i in 0..N { - if note_hashes[i].value != 0 { - let nonce = compute_note_hash_nonce(first_nullifier.value, i); - unique_siloed_note_hashes[i] = compute_unique_siloed_note_hash(nonce, note_hashes[i].value); + let note_hash = note_hashes[i]; + if note_hash.value() != 0 { + let siloed = silo_note_hash(note_hash.contract_address, note_hash.value()); + let nonce = compute_note_hash_nonce(first_nullifier.value(), i); + unique_siloed_note_hashes[i] = compute_unique_siloed_note_hash(nonce, siloed); } } unique_siloed_note_hashes } + pub fn compute_output_nullifiers(_self: Self, nullifiers: [ScopedNullifier; N]) -> [Field; N] { + let mut output = [0; N]; + output[0] = nullifiers[0].value(); + for i in 1..N { + output[i] = silo_nullifier(nullifiers[i].contract_address, nullifiers[i].value()); + } + output + } + pub fn add_pending_note_hash_read_request(&mut self, note_hash_index: u64) { let read_request_index = self.previous_kernel.add_read_request_for_pending_note_hash(note_hash_index); let hint_index = self.note_hash_read_request_hints_builder.pending_read_hints.len(); @@ -167,8 +176,8 @@ mod tests { } pub fn nullify_pending_note_hash(&mut self, nullifier_index: u64, note_hash_index: u64) { - self.previous_kernel.new_note_hashes.storage[note_hash_index].nullifier_counter = self.previous_kernel.new_nullifiers.get(nullifier_index).counter; - self.previous_kernel.new_nullifiers.storage[nullifier_index].note_hash = self.previous_kernel.new_note_hashes.get(note_hash_index).value; + self.previous_kernel.new_note_hashes.storage[note_hash_index].nullifier_counter = self.previous_kernel.new_nullifiers.get(nullifier_index).counter(); + self.previous_kernel.new_nullifiers.storage[nullifier_index].nullifier.note_hash = self.previous_kernel.new_note_hashes.get(note_hash_index).note_hash.value; self.transient_nullifier_indexes_for_note_hashes[note_hash_index] = nullifier_index; self.transient_note_hash_indexes_for_nullifiers[nullifier_index] = note_hash_index; } @@ -176,14 +185,14 @@ mod tests { pub fn execute(&mut self) -> KernelCircuitPublicInputs { let sorted = sort_get_sorted_hints( self.previous_kernel.new_note_hashes.storage, - |a: NoteHashContext, b: NoteHashContext| a.counter < b.counter + |a: ScopedNoteHash, b: ScopedNoteHash| a.counter() < b.counter() ); let sorted_new_note_hashes = sorted.sorted_array; let sorted_new_note_hashes_indexes = sorted.sorted_index_hints; let sorted = sort_get_sorted_hints( self.previous_kernel.new_nullifiers.storage, - |a: Nullifier, b: Nullifier| a.counter < b.counter + |a: ScopedNullifier, b: ScopedNullifier| a.counter() < b.counter() ); let sorted_new_nullifiers = sorted.sorted_array; let sorted_new_nullifiers_indexes = sorted.sorted_index_hints; @@ -379,7 +388,7 @@ mod tests { builder.add_pending_nullifier_read_request(1); let nullifier_being_read = builder.previous_kernel.new_nullifiers.storage[2]; let mut read_request = builder.previous_kernel.nullifier_read_requests.pop(); - read_request.counter = nullifier_being_read.counter - 1; + read_request.read_request.counter = nullifier_being_read.counter() - 1; builder.previous_kernel.nullifier_read_requests.push(read_request); builder.failed(); @@ -394,15 +403,12 @@ mod tests { builder.nullify_pending_note_hash(1, 0); let new_nullifiers = builder.previous_kernel.new_nullifiers.storage; let public_inputs = builder.execute(); + assert(is_empty_array(public_inputs.end.new_note_hashes)); // The nullifier at index 1 is chopped. - assert( - array_eq( - public_inputs.end.new_nullifiers, - [new_nullifiers[0].value, new_nullifiers[2].value] - ) - ); + let expected_nullifiers = builder.compute_output_nullifiers([new_nullifiers[0], new_nullifiers[2]]); + assert(array_eq(public_inputs.end.new_nullifiers, expected_nullifiers)); } #[test] @@ -413,23 +419,16 @@ mod tests { // The nullifier at index 1 is nullifying the hash at index 0; builder.nullify_pending_note_hash(1, 0); let new_note_hashes = builder.previous_kernel.new_note_hashes.storage; - // The 0th hash will be chopped. - let unique_siloed_note_hashes = builder.compute_unique_siloed_note_hashes([new_note_hashes[1]]); let new_nullifiers = builder.previous_kernel.new_nullifiers.storage; let public_inputs = builder.execute(); - assert( - array_eq( - public_inputs.end.new_note_hashes, - [unique_siloed_note_hashes[0]] - ) - ); + + // The 0th hash is chopped. + let expected_note_hashes = builder.compute_output_note_hashes([new_note_hashes[1]]); + assert(array_eq(public_inputs.end.new_note_hashes, expected_note_hashes)); + // The nullifier at index 1 is chopped. - assert( - array_eq( - public_inputs.end.new_nullifiers, - [new_nullifiers[0].value, new_nullifiers[2].value] - ) - ); + let expected_nullifiers = builder.compute_output_nullifiers([new_nullifiers[0], new_nullifiers[2]]); + assert(array_eq(public_inputs.end.new_nullifiers, expected_nullifiers)); } #[test] @@ -444,9 +443,11 @@ mod tests { let new_nullifiers = builder.previous_kernel.new_nullifiers.storage; let public_inputs = builder.execute(); - // Only the first nullifier is left after squashing. assert(is_empty_array(public_inputs.end.new_note_hashes)); - assert(array_eq(public_inputs.end.new_nullifiers, [new_nullifiers[0].value])); + + // Only the first nullifier is left after squashing. + let expected_nullifiers = builder.compute_output_nullifiers([new_nullifiers[0]]); + assert(array_eq(public_inputs.end.new_nullifiers, expected_nullifiers)); } #[test] @@ -477,9 +478,11 @@ mod tests { let new_nullifiers = builder.previous_kernel.new_nullifiers.storage; let public_inputs = builder.execute(); - // Only the first nullifier is left after squashing. assert(is_empty_array(public_inputs.end.new_note_hashes)); - assert(array_eq(public_inputs.end.new_nullifiers, [new_nullifiers[0].value])); + + // Only the first nullifier is left after squashing. + let expected_nullifiers = builder.compute_output_nullifiers([new_nullifiers[0]]); + assert(array_eq(public_inputs.end.new_nullifiers, expected_nullifiers)); } #[test] @@ -492,8 +495,8 @@ mod tests { let sorted_note_hashes = builder.previous_kernel.new_note_hashes.storage; let sorted_nullifiers = builder.previous_kernel.new_nullifiers.storage; - let mut reversed_note_hashes = [NoteHashContext::empty(); 10]; - let mut reversed_nullifiers = [Nullifier::empty(); 10]; + let mut reversed_note_hashes = [ScopedNoteHash::empty(); 10]; + let mut reversed_nullifiers = [ScopedNullifier::empty(); 10]; for i in 0..10 { reversed_note_hashes[9 - i] = builder.previous_kernel.new_note_hashes.pop(); @@ -503,13 +506,13 @@ mod tests { builder.previous_kernel.new_note_hashes.extend_from_array(reversed_note_hashes); builder.previous_kernel.new_nullifiers.extend_from_array(reversed_nullifiers); - let sorted_unique_note_hashes = builder.compute_unique_siloed_note_hashes(sorted_note_hashes); - let public_inputs = builder.execute(); + let expected_note_hashes = builder.compute_output_note_hashes(sorted_note_hashes); + let expected_nullifiers = builder.compute_output_nullifiers(sorted_nullifiers); for i in 0..10 { - assert(public_inputs.end.new_note_hashes[i].eq(sorted_unique_note_hashes[i])); - assert(public_inputs.end.new_nullifiers[i].eq(sorted_nullifiers[i].value)); + assert(public_inputs.end.new_note_hashes[i].eq(expected_note_hashes[i])); + assert(public_inputs.end.new_nullifiers[i].eq(expected_nullifiers[i])); } } @@ -525,7 +528,7 @@ mod tests { assert_eq(public_inputs.end.gas_used, expected_gas); } - #[test(should_fail_with="Hinted note hash does not match")] + #[test(should_fail_with="Value of the hinted transient note hash does not match")] unconstrained fn wrong_transient_nullifier_index_for_note_hash_fails() { let mut builder = PrivateKernelTailInputsBuilder::new(); builder.previous_kernel.append_new_note_hashes(1); diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr index aa1726db148..a16c3ea41ba 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr @@ -3,7 +3,7 @@ use dep::reset_kernel_lib::{NoteHashReadRequestHints, NullifierReadRequestHints, use dep::types::{ abis::{ kernel_data::PrivateKernelData, kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, - note_hash::NoteHashContext, nullifier::Nullifier, side_effect::SideEffect + note_hash::ScopedNoteHash, nullifier::ScopedNullifier, side_effect::SideEffect }, constants::{ MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, @@ -14,8 +14,8 @@ use dep::types::{ // Can just be PublicKernelCircuitPublicInputs. struct PrivateKernelTailToPublicOutputs { - note_hashes: [NoteHashContext; MAX_NEW_NOTE_HASHES_PER_TX], - nullifiers: [Nullifier; MAX_NEW_NULLIFIERS_PER_TX], + note_hashes: [ScopedNoteHash; MAX_NEW_NOTE_HASHES_PER_TX], + nullifiers: [ScopedNullifier; MAX_NEW_NULLIFIERS_PER_TX], } struct PrivateKernelTailToPublicHints { @@ -24,9 +24,9 @@ struct PrivateKernelTailToPublicHints { note_hash_read_request_hints: NoteHashReadRequestHints, nullifier_read_request_hints: NullifierReadRequestHints, master_nullifier_secret_keys: [GrumpkinPrivateKey; MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX], - sorted_new_note_hashes: [NoteHashContext; MAX_NEW_NOTE_HASHES_PER_TX], + sorted_new_note_hashes: [ScopedNoteHash; MAX_NEW_NOTE_HASHES_PER_TX], sorted_new_note_hashes_indexes: [u64; MAX_NEW_NOTE_HASHES_PER_TX], - sorted_new_nullifiers: [Nullifier; MAX_NEW_NULLIFIERS_PER_TX], + sorted_new_nullifiers: [ScopedNullifier; MAX_NEW_NULLIFIERS_PER_TX], sorted_new_nullifiers_indexes: [u64; MAX_NEW_NULLIFIERS_PER_TX], sorted_encrypted_log_hashes: [SideEffect; MAX_ENCRYPTED_LOGS_PER_TX], sorted_encrypted_log_hashes_indexes: [u64; MAX_ENCRYPTED_LOGS_PER_TX], @@ -49,7 +49,7 @@ impl PrivateKernelTailToPublicCircuitPrivateInputs { let note_hash_tree_root = previous_public_inputs.constants.historical_header.state.partial.note_hash_tree.root; let nullifier_tree_root = previous_public_inputs.constants.historical_header.state.partial.nullifier_tree.root; - let request_processor = PrivateValidationRequestProcessor { + PrivateValidationRequestProcessor { validation_requests: previous_public_inputs.validation_requests, note_hash_read_request_hints: self.hints.note_hash_read_request_hints, pending_note_hashes: previous_public_inputs.end.new_note_hashes, @@ -58,10 +58,9 @@ impl PrivateKernelTailToPublicCircuitPrivateInputs { pending_nullifiers: previous_public_inputs.end.new_nullifiers, nullifier_tree_root, master_nullifier_secret_keys: self.hints.master_nullifier_secret_keys - }; - request_processor.validate(); + }.validate(); - let mut composer = KernelCircuitPublicInputsComposer::new( + KernelCircuitPublicInputsComposer::new( self.previous_kernel, self.outputs.note_hashes, self.outputs.nullifiers, @@ -75,8 +74,7 @@ impl PrivateKernelTailToPublicCircuitPrivateInputs { self.hints.sorted_encrypted_log_hashes_indexes, self.hints.sorted_unencrypted_log_hashes, self.hints.sorted_unencrypted_log_hashes_indexes - ); - composer.compose_public().finish_to_public() + ).compose_public().finish_to_public() } } @@ -101,10 +99,11 @@ mod tests { use dep::types::{ abis::{ kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, gas::Gas, - note_hash::{NoteHash, NoteHashContext}, nullifier::Nullifier, side_effect::{SideEffect, Ordered} + note_hash::{NoteHash, ScopedNoteHash}, nullifier::{Nullifier, ScopedNullifier}, + side_effect::SideEffect }, grumpkin_private_key::GrumpkinPrivateKey, - hash::{compute_note_hash_nonce, compute_unique_siloed_note_hash}, + hash::{compute_note_hash_nonce, compute_unique_siloed_note_hash, silo_note_hash, silo_nullifier}, tests::{fixture_builder::FixtureBuilder, sort::sort_get_sorted_hints}, utils::{arrays::{array_eq, array_length}}, traits::is_empty_array }; @@ -136,17 +135,16 @@ mod tests { // A helper function that uses the first nullifer in the previous kernel to compute the unique siloed // note_hashes for the given note_hashes. - pub fn compute_unique_siloed_note_hashes( - self, - note_hashes: [NoteHashContext; N] - ) -> [NoteHash; N] { - let first_nullifier = self.previous_kernel.new_nullifiers.get_unchecked(0); + pub fn compute_output_note_hashes(self, note_hashes: [ScopedNoteHash; N]) -> [NoteHash; N] { + let first_nullifier = self.previous_kernel.new_nullifiers.get_unchecked(0).value(); let mut unique_siloed_note_hashes = [NoteHash::empty(); N]; for i in 0..N { - if note_hashes[i].value != 0 { - let nonce = compute_note_hash_nonce(first_nullifier.value, i); + let note_hash = note_hashes[i]; + if note_hash.value() != 0 { + let siloed = silo_note_hash(note_hash.contract_address, note_hash.value()); + let nonce = compute_note_hash_nonce(first_nullifier, i); unique_siloed_note_hashes[i] = NoteHash { - value: compute_unique_siloed_note_hash(nonce, note_hashes[i].value), + value: compute_unique_siloed_note_hash(nonce, siloed), counter: 0, // Counter is cleared so it's not exposed to the public. }; } @@ -154,6 +152,18 @@ mod tests { unique_siloed_note_hashes } + pub fn compute_output_nullifiers( + _self: Self, + nullifiers: [ScopedNullifier; N] + ) -> [Nullifier; N] { + let mut output = [Nullifier::empty(); N]; + output[0].value = nullifiers[0].value(); + for i in 1..N { + output[i] = Nullifier { value: silo_nullifier(nullifiers[i].contract_address, nullifiers[i].value()), counter: 0, note_hash: 0 }; + } + output + } + pub fn add_pending_note_hash_read_request(&mut self, note_hash_index: u64) { let read_request_index = self.previous_kernel.add_read_request_for_pending_note_hash(note_hash_index); let hint_index = self.note_hash_read_request_hints_builder.pending_read_hints.len(); @@ -172,8 +182,8 @@ mod tests { } pub fn nullify_pending_note_hash(&mut self, nullifier_index: u64, note_hash_index: u64) { - self.previous_kernel.new_note_hashes.storage[note_hash_index].nullifier_counter = self.previous_kernel.new_nullifiers.get(nullifier_index).counter; - self.previous_kernel.new_nullifiers.storage[nullifier_index].note_hash = self.previous_kernel.new_note_hashes.get(note_hash_index).value; + self.previous_kernel.new_note_hashes.storage[note_hash_index].nullifier_counter = self.previous_kernel.new_nullifiers.get(nullifier_index).counter(); + self.previous_kernel.new_nullifiers.storage[nullifier_index].nullifier.note_hash = self.previous_kernel.new_note_hashes.get(note_hash_index).value(); self.transient_nullifier_indexes_for_note_hashes[note_hash_index] = nullifier_index; self.transient_note_hash_indexes_for_nullifiers[nullifier_index] = note_hash_index; } @@ -181,14 +191,14 @@ mod tests { pub fn execute(&mut self) -> PublicKernelCircuitPublicInputs { let sorted = sort_get_sorted_hints( self.previous_kernel.new_note_hashes.storage, - |a: NoteHashContext, b: NoteHashContext| a.counter < b.counter + |a: ScopedNoteHash, b: ScopedNoteHash| a.counter() < b.counter() ); let sorted_new_note_hashes = sorted.sorted_array; let sorted_new_note_hashes_indexes = sorted.sorted_index_hints; let sorted = sort_get_sorted_hints( self.previous_kernel.new_nullifiers.storage, - |a: Nullifier, b: Nullifier| a.counter < b.counter + |a: ScopedNullifier, b: ScopedNullifier| a.counter() < b.counter() ); let sorted_new_nullifiers = sorted.sorted_array; let sorted_new_nullifiers_indexes = sorted.sorted_index_hints; @@ -326,7 +336,7 @@ mod tests { builder.add_pending_nullifier_read_request(1); let nullifier_being_read = builder.previous_kernel.new_nullifiers.storage[2]; let mut read_request = builder.previous_kernel.nullifier_read_requests.pop(); - read_request.counter = nullifier_being_read.counter - 1; + read_request.read_request.counter = nullifier_being_read.counter() - 1; builder.previous_kernel.nullifier_read_requests.push(read_request); builder.failed(); @@ -341,15 +351,12 @@ mod tests { builder.nullify_pending_note_hash(1, 0); let new_nullifiers = builder.previous_kernel.new_nullifiers.storage; let public_inputs = builder.execute(); + assert(is_empty_array(public_inputs.end.new_note_hashes)); // The nullifier at index 1 is chopped. - assert( - array_eq( - public_inputs.end.new_nullifiers, - [new_nullifiers[0], new_nullifiers[2]] - ) - ); + let expected_nullifiers = builder.compute_output_nullifiers([new_nullifiers[0], new_nullifiers[2]]); + assert(array_eq(public_inputs.end.new_nullifiers, expected_nullifiers)); } #[test] @@ -360,23 +367,16 @@ mod tests { // The nullifier at index 1 is nullifying the hash at index 0; builder.nullify_pending_note_hash(1, 0); let new_note_hashes = builder.previous_kernel.new_note_hashes.storage; - // The 0th hash will be chopped. - let unique_siloed_note_hashes = builder.compute_unique_siloed_note_hashes([new_note_hashes[1]]); let new_nullifiers = builder.previous_kernel.new_nullifiers.storage; let public_inputs = builder.execute(); - assert( - array_eq( - public_inputs.end.new_note_hashes, - [unique_siloed_note_hashes[0]] - ) - ); + + // The 0th hash will be chopped. + let expected_note_hashes = builder.compute_output_note_hashes([new_note_hashes[1]]); + assert(array_eq(public_inputs.end.new_note_hashes, expected_note_hashes)); + // The nullifier at index 1 is chopped. - assert( - array_eq( - public_inputs.end.new_nullifiers, - [new_nullifiers[0], new_nullifiers[2]] - ) - ); + let expected_nullifiers = builder.compute_output_nullifiers([new_nullifiers[0], new_nullifiers[2]]); + assert(array_eq(public_inputs.end.new_nullifiers, expected_nullifiers)); } #[test] @@ -393,7 +393,8 @@ mod tests { // Only the first nullifier is left after squashing. assert(is_empty_array(public_inputs.end.new_note_hashes)); - assert(array_eq(public_inputs.end.new_nullifiers, [new_nullifiers[0]])); + let expected_nullifiers = builder.compute_output_nullifiers([new_nullifiers[0]]); + assert(array_eq(public_inputs.end.new_nullifiers, expected_nullifiers)); } #[test] @@ -406,8 +407,8 @@ mod tests { let sorted_note_hashes = builder.previous_kernel.new_note_hashes.storage; let sorted_nullifiers = builder.previous_kernel.new_nullifiers.storage; - let mut reversed_note_hashes = [NoteHashContext::empty(); 10]; - let mut reversed_nullifiers = [Nullifier::empty(); 10]; + let mut reversed_note_hashes = [ScopedNoteHash::empty(); 10]; + let mut reversed_nullifiers = [ScopedNullifier::empty(); 10]; for i in 0..10 { reversed_note_hashes[9 - i] = builder.previous_kernel.new_note_hashes.pop(); @@ -417,17 +418,17 @@ mod tests { builder.previous_kernel.new_note_hashes.extend_from_array(reversed_note_hashes); builder.previous_kernel.new_nullifiers.extend_from_array(reversed_nullifiers); - let sorted_unique_note_hashes = builder.compute_unique_siloed_note_hashes(sorted_note_hashes); - let public_inputs = builder.execute(); + let output_note_hashes = builder.compute_output_note_hashes(sorted_note_hashes); + let output_nullifiers = builder.compute_output_nullifiers(sorted_nullifiers); for i in 0..10 { - assert(public_inputs.end.new_note_hashes[i].eq(sorted_unique_note_hashes[i])); - assert(public_inputs.end.new_nullifiers[i].eq(sorted_nullifiers[i])); + assert(public_inputs.end.new_note_hashes[i].eq(output_note_hashes[i])); + assert(public_inputs.end.new_nullifiers[i].eq(output_nullifiers[i])); } } - #[test(should_fail_with="Hinted note hash does not match")] + #[test(should_fail_with="Value of the hinted transient note hash does not match")] unconstrained fn wrong_transient_nullifier_index_for_note_hash_fails() { let mut builder = PrivateKernelTailToPublicInputsBuilder::new(); builder.previous_kernel.append_new_note_hashes(1); @@ -487,17 +488,19 @@ mod tests { let new_nullifiers = builder.previous_kernel.new_nullifiers.storage; let public_inputs = builder.execute(); + let output_nullifiers = builder.compute_output_nullifiers(new_nullifiers); + assert( array_eq( public_inputs.end_non_revertible.new_nullifiers, - [new_nullifiers[0], new_nullifiers[1], new_nullifiers[2]] + [output_nullifiers[0], output_nullifiers[1], output_nullifiers[2]] ) ); assert( array_eq( public_inputs.end.new_nullifiers, - [new_nullifiers[3], new_nullifiers[4]] + [output_nullifiers[3], output_nullifiers[4]] ) ); @@ -521,7 +524,7 @@ mod tests { let new_note_hashes = builder.previous_kernel.new_note_hashes.storage; let public_inputs = builder.execute(); - let siloed_note_hashes = builder.compute_unique_siloed_note_hashes(new_note_hashes); + let siloed_note_hashes = builder.compute_output_note_hashes(new_note_hashes); assert( array_eq( diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr index adf8f2a1952..83d5770a806 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr @@ -4,7 +4,7 @@ use dep::types::{ kernel_circuit_public_inputs::PublicKernelCircuitPublicInputsBuilder, kernel_data::PublicKernelData, note_hash::NoteHash, nullifier::Nullifier, public_call_data::PublicCallData, public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, - read_request::ReadRequestContext, side_effect::SideEffect, global_variables::GlobalVariables, + side_effect::SideEffect, global_variables::GlobalVariables, combined_constant_data::CombinedConstantData }, address::AztecAddress, @@ -324,7 +324,7 @@ fn propagate_nullifier_read_requests( for i in 0..MAX_NULLIFIER_READ_REQUESTS_PER_CALL { let request = nullifier_read_requests[i]; if !is_empty(request) { - circuit_outputs.validation_requests.nullifier_read_requests.push(request.to_context(storage_contract_address)); + circuit_outputs.validation_requests.nullifier_read_requests.push(request.scope(storage_contract_address)); } } } @@ -340,7 +340,7 @@ fn propagate_nullifier_non_existent_read_requests( for i in 0..MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL { let request = nullifier_non_existent_read_requests[i]; if !is_empty(request) { - circuit_outputs.validation_requests.nullifier_non_existent_read_requests.push(request.to_context(storage_contract_address)); + circuit_outputs.validation_requests.nullifier_non_existent_read_requests.push(request.scope(storage_contract_address)); } } } diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_app_logic.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_app_logic.nr index ddfd090a546..6fd4e359211 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_app_logic.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_app_logic.nr @@ -78,8 +78,9 @@ mod tests { use dep::types::{ abis::{ gas::Gas, kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, - note_hash::{NoteHash, NoteHashContext}, nullifier::Nullifier, public_data_read::PublicDataRead, - public_data_update_request::PublicDataUpdateRequest, read_request::ReadRequest + note_hash::{NoteHash, ScopedNoteHash}, nullifier::{Nullifier, ScopedNullifier}, + public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, + read_request::ReadRequest }, address::{AztecAddress, EthAddress}, contract_class_id::ContractClassId, hash::{compute_l2_to_l1_hash, silo_note_hash, silo_nullifier}, @@ -186,7 +187,7 @@ mod tests { let contract_address = builder.public_call.contract_address; // Setup 2 new note hashes on the previous kernel. builder.previous_kernel.append_new_note_hashes(2); - let previous = builder.previous_kernel.new_note_hashes.storage.map(|n: NoteHashContext| n.to_note_hash()); + let previous = builder.previous_kernel.new_note_hashes.storage.map(|n: ScopedNoteHash| n.note_hash); // Setup 2 new note hashes on the current public inputs. let current = [ NoteHash { value: previous[1].value + 1, counter: 3 }, @@ -247,19 +248,19 @@ mod tests { // Setup 2 new nullifiers on the previous kernel. builder.previous_kernel.append_new_nullifiers(2); - let previous = builder.previous_kernel.new_nullifiers.storage; + let previous = builder.previous_kernel.new_nullifiers.storage.map(|n: ScopedNullifier| n.nullifier); // Setup 2 new note hashes on the current public inputs. let current = [ Nullifier { value: previous[1].value + 1, note_hash: 0, counter: 4 }, Nullifier { value: previous[1].value + 2, note_hash: 0, counter: 5 } ]; + builder.public_call.public_inputs.new_nullifiers.extend_from_array(current); let siloed = current.map( |current: Nullifier| Nullifier { value: silo_nullifier(contract_address, current.value), note_hash: current.note_hash, counter: current.counter } ); - builder.public_call.public_inputs.new_nullifiers.extend_from_array(current); // There are 2 revertible nullifiers in the previous kernel. // The tx nullifier is part of the non-revertible nullifiers. let new_nullifiers = [previous[0], previous[1], siloed[0], siloed[1]]; @@ -278,9 +279,9 @@ mod tests { // Setup 1 new l2 to l1 message on the previous kernel. let previous = [12345]; - builder.previous_kernel.new_l2_to_l1_msgs.extend_from_array(previous); + builder.previous_kernel.add_l2_to_l1_message(previous[0], portal_contract_address); // Setup 1 new l2 to l1 message on the current public inputs. - let current = [L2ToL1Message { recipient: portal_contract_address, content: 67890 }]; + let current = [L2ToL1Message { recipient: portal_contract_address, content: 67890, counter: 0 }]; builder.public_call.public_inputs.new_l2_to_l1_msgs.extend_from_array(current); let tx_context = builder.previous_kernel.tx_context; let version = tx_context.version; @@ -438,15 +439,13 @@ mod tests { let end_requests = public_inputs.validation_requests.nullifier_non_existent_read_requests; assert_eq(array_length(end_requests), 2); - let request_context = end_requests[0]; - assert_eq(request_context.value, request_0.value); - assert_eq(request_context.counter, request_0.counter); - assert_eq(request_context.contract_address, storage_contract_address); + let request = end_requests[0]; + assert_eq(request.read_request, request_0); + assert_eq(request.contract_address, storage_contract_address); - let request_context = end_requests[1]; - assert_eq(request_context.value, request_1.value); - assert_eq(request_context.counter, request_1.counter); - assert_eq(request_context.contract_address, storage_contract_address); + let request = end_requests[1]; + assert_eq(request.read_request, request_1); + assert_eq(request.contract_address, storage_contract_address); } #[test] diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_setup.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_setup.nr index 57baeb5d851..248c89c0b7a 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_setup.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_setup.nr @@ -483,15 +483,13 @@ mod tests { let end_requests = public_inputs.validation_requests.nullifier_non_existent_read_requests; assert_eq(array_length(end_requests), 2); - let request_context = end_requests[0]; - assert_eq(request_context.value, request_0.value); - assert_eq(request_context.counter, request_0.counter); - assert_eq(request_context.contract_address, storage_contract_address); - - let request_context = end_requests[1]; - assert_eq(request_context.value, request_1.value); - assert_eq(request_context.counter, request_1.counter); - assert_eq(request_context.contract_address, storage_contract_address); + let request = end_requests[0]; + assert_eq(request.read_request, request_0); + assert_eq(request.contract_address, storage_contract_address); + + let request = end_requests[1]; + assert_eq(request.read_request, request_1); + assert_eq(request.contract_address, storage_contract_address); } #[test(should_fail_with="Public call cannot be reverted")] diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr index bbc11756c56..f8bc620c100 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr @@ -115,7 +115,7 @@ mod tests { use dep::types::{ abis::{ kernel_circuit_public_inputs::KernelCircuitPublicInputs, kernel_data::PublicKernelData, - nullifier_leaf_preimage::NullifierLeafPreimage + nullifier::ScopedNullifier, nullifier_leaf_preimage::NullifierLeafPreimage }, constants::{ MAX_NEW_NULLIFIERS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_PUBLIC_DATA_HINTS, @@ -209,19 +209,19 @@ mod tests { } pub fn add_nullifier(&mut self, unsiloed_nullifier: Field) { - self.previous_kernel.add_nullifier(unsiloed_nullifier); + self.previous_kernel.add_siloed_nullifier(unsiloed_nullifier); self.sync_counters(); self.set_nullifiers_for_non_existent_read_request_hints(); } pub fn append_nullifiers_revertible(&mut self, num_nullifiers: u64) { - self.previous_revertible.append_new_nullifiers(num_nullifiers); + self.previous_revertible.append_siloed_nullifiers(num_nullifiers); self.sync_counters(); self.set_nullifiers_for_non_existent_read_request_hints(); } pub fn append_nullifiers_non_revertible(&mut self, num_nullifiers: u64) { - self.previous_kernel.append_new_nullifiers(num_nullifiers); + self.previous_kernel.append_siloed_nullifiers(num_nullifiers); self.sync_counters(); self.set_nullifiers_for_non_existent_read_request_hints(); } @@ -230,7 +230,7 @@ mod tests { let nullifiers = array_merge( self.previous_kernel.new_nullifiers.storage, self.previous_revertible.new_nullifiers.storage - ); + ).map(|n: ScopedNullifier| n.nullifier); self.nullifier_non_existent_read_request_hints_builder.set_nullifiers(nullifiers); } @@ -420,7 +420,7 @@ mod tests { builder.add_pending_revertible_nullifier_read_request(1); let nullifier_being_read = builder.previous_revertible.new_nullifiers.get(1); let mut read_request = builder.previous_kernel.nullifier_read_requests.pop(); - read_request.counter = nullifier_being_read.counter - 1; + read_request.read_request.counter = nullifier_being_read.counter() - 1; builder.previous_kernel.nullifier_read_requests.push(read_request); builder.failed(); diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/note_hash_read_request_reset.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/note_hash_read_request_reset.nr index 8bb008c5421..a7f53d46d62 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/note_hash_read_request_reset.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/note_hash_read_request_reset.nr @@ -47,10 +47,7 @@ mod tests { use crate::reset::read_request::{PendingReadHint, ReadRequestState, ReadRequestStatus, reset_read_requests}; use dep::types::{ address::AztecAddress, merkle_tree::MembershipWitness, - abis::{ - note_hash::NoteHashContext, note_hash_leaf_preimage::NoteHashLeafPreimage, - read_request::ReadRequestContext - }, + abis::{note_hash::NoteHash, note_hash_leaf_preimage::NoteHashLeafPreimage, read_request::ReadRequest}, constants::NOTE_HASH_TREE_HEIGHT, hash::silo_note_hash, tests::merkle_tree_utils::NonEmptyMerkleTree }; @@ -64,15 +61,17 @@ mod tests { // Create 5 read requests. 0 and 3 are reading settled note hashes. 1, 2 and 4 are reading pending note hashes. // TODO(#2847): Read request values for settled note hashes shouldn't have been siloed by apps. global read_requests = [ - ReadRequestContext { value: note_hashes[1], counter: 11, contract_address }, // settled - ReadRequestContext { value: inner_note_hashes[3], counter: 13, contract_address }, // pending - ReadRequestContext { value: inner_note_hashes[2], counter: 39, contract_address }, // pending - ReadRequestContext { value: note_hashes[0], counter: 46, contract_address }, // settled - ReadRequestContext { value: inner_note_hashes[3], counter: 78, contract_address }, // pending + ReadRequest { value: note_hashes[1], counter: 11 }.scope(contract_address), // settled + ReadRequest { value: inner_note_hashes[3], counter: 13 }.scope(contract_address), // pending + ReadRequest { value: inner_note_hashes[2], counter: 39 }.scope(contract_address), // pending + ReadRequest { value: note_hashes[0], counter: 46 }.scope(contract_address), // settled + ReadRequest { value: inner_note_hashes[3], counter: 78 }.scope(contract_address), // pending ]; - // TODO(#6122): Pending values shouldn't have been siloed at this point. - global pending_values = [NoteHashContext { value: note_hashes[2], counter: 2, nullifier_counter: 0 }, NoteHashContext { value: note_hashes[3], counter: 8, nullifier_counter: 0 }]; + global pending_values = [ + NoteHash { value: inner_note_hashes[2], counter: 2, }.scope(0, contract_address), + NoteHash { value: inner_note_hashes[3], counter: 8, }.scope(0, contract_address), + ]; global pending_read_hints = [ PendingReadHint { read_request_index: 1, pending_value_index: 1 }, PendingReadHint { read_request_index: 2, pending_value_index: 0 }, @@ -159,7 +158,7 @@ mod tests { fn test_reset_note_hash_read_requests_wrong_hinted_value() { let mut tainted_pending_values = pending_values; // Tweak the value to be something different. - tainted_pending_values[0].value += 1; + tainted_pending_values[0].note_hash.value += 1; let (settled_read_hints, tree_root) = get_settled_read_hints(); let _ = reset_read_requests( @@ -178,7 +177,7 @@ mod tests { let pending_read = read_requests[hint.read_request_index]; let mut tainted_pending_values = pending_values; // Tweak the counter of the value to be greater than the read request. - tainted_pending_values[hint.pending_value_index].counter = pending_read.counter + 1; + tainted_pending_values[hint.pending_value_index].note_hash.counter = pending_read.counter() + 1; let (settled_read_hints, tree_root) = get_settled_read_hints(); let _ = reset_read_requests( @@ -197,7 +196,7 @@ mod tests { let pending_read = read_requests[hint.read_request_index]; let mut tainted_pending_values = pending_values; // Tweak the nullifier counter to be less than the read request. - tainted_pending_values[hint.pending_value_index].nullifier_counter = pending_read.counter - 1; + tainted_pending_values[hint.pending_value_index].nullifier_counter = pending_read.counter() - 1; let (settled_read_hints, tree_root) = get_settled_read_hints(); let _ = reset_read_requests( @@ -217,7 +216,7 @@ mod tests { let mut tained_read_requests = read_requests; let hint = settled_read_hints[0]; // Tweak the value of the first settled read to be something different. - tained_read_requests[hint.read_request_index].value += 1; + tained_read_requests[hint.read_request_index].read_request.value += 1; let _ = reset_read_requests( tained_read_requests, diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/nullifier_read_request_reset.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/nullifier_read_request_reset.nr index ba2c15edc39..e7363f828c4 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/nullifier_read_request_reset.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/nullifier_read_request_reset.nr @@ -47,7 +47,7 @@ mod tests { use crate::reset::read_request::{PendingReadHint, ReadRequestState, ReadRequestStatus, reset_read_requests}; use dep::types::{ address::AztecAddress, - abis::{nullifier::Nullifier, nullifier_leaf_preimage::NullifierLeafPreimage, read_request::ReadRequestContext}, + abis::{nullifier::Nullifier, nullifier_leaf_preimage::NullifierLeafPreimage, read_request::ReadRequest}, constants::NULLIFIER_TREE_HEIGHT, hash::silo_nullifier, merkle_tree::MembershipWitness, tests::merkle_tree_utils::NonEmptyMerkleTree }; @@ -60,14 +60,17 @@ mod tests { // Create 5 read requests. 0 and 3 are reading settled nullifiers. 1, 2 and 4 are reading pending nullifiers. global read_requests = [ - ReadRequestContext { value: inner_nullifiers[1], counter: 11, contract_address }, // settled - ReadRequestContext { value: inner_nullifiers[3], counter: 13, contract_address }, // pending - ReadRequestContext { value: inner_nullifiers[2], counter: 39, contract_address }, // pending - ReadRequestContext { value: inner_nullifiers[0], counter: 46, contract_address }, // settled - ReadRequestContext { value: inner_nullifiers[3], counter: 78, contract_address }, // pending + ReadRequest { value: inner_nullifiers[1], counter: 11 }.scope(contract_address), // settled + ReadRequest { value: inner_nullifiers[3], counter: 13 }.scope(contract_address), // pending + ReadRequest { value: inner_nullifiers[2], counter: 39 }.scope(contract_address), // pending + ReadRequest { value: inner_nullifiers[0], counter: 46 }.scope(contract_address), // settled + ReadRequest { value: inner_nullifiers[3], counter: 78 }.scope(contract_address), // pending ]; - global pending_values = [Nullifier { value: nullifiers[2], counter: 2, note_hash: 0 }, Nullifier { value: nullifiers[3], counter: 8, note_hash: 0 }]; + global pending_values = [ + Nullifier { value: inner_nullifiers[2], counter: 2, note_hash: 0 }.scope(contract_address), + Nullifier { value: inner_nullifiers[3], counter: 8, note_hash: 0 }.scope(contract_address), + ]; global pending_read_hints = [ PendingReadHint { read_request_index: 1, pending_value_index: 1 }, PendingReadHint { read_request_index: 2, pending_value_index: 0 }, @@ -156,7 +159,7 @@ mod tests { fn test_reset_nullifier_read_requests_wrong_hinted_value() { let mut tainted_pending_values = pending_values; // Tweak the value to be something different. - tainted_pending_values[0].value += 1; + tainted_pending_values[0].nullifier.value += 1; let (settled_read_hints, tree_root) = get_settled_read_hints(); let _ = reset_read_requests( @@ -175,7 +178,7 @@ mod tests { let pending_read = read_requests[hint.read_request_index]; let mut tainted_pending_values = pending_values; // Tweak the counter of the value to be greater than the read request. - tainted_pending_values[hint.pending_value_index].counter = pending_read.counter + 1; + tainted_pending_values[hint.pending_value_index].nullifier.counter = pending_read.counter() + 1; let (settled_read_hints, tree_root) = get_settled_read_hints(); let _ = reset_read_requests( @@ -195,7 +198,7 @@ mod tests { let mut tained_read_requests = read_requests; let hint = settled_read_hints[0]; // Tweak the value of the first settled read to be something different. - tained_read_requests[hint.read_request_index].value += 1; + tained_read_requests[hint.read_request_index].read_request.value += 1; let _ = reset_read_requests( tained_read_requests, diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/private_validation_request_processor.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/private_validation_request_processor.nr index 2d5adcd31cd..08d63cb14d8 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/private_validation_request_processor.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/private_validation_request_processor.nr @@ -3,7 +3,7 @@ use crate::{ nullifier_read_request_reset::NullifierReadRequestHints, reset::read_request::reset_read_requests }; use dep::types::{ - abis::{note_hash::NoteHashContext, nullifier::Nullifier, validation_requests::ValidationRequests}, + abis::{note_hash::ScopedNoteHash, nullifier::ScopedNullifier, validation_requests::ValidationRequests}, constants::{ MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, GENERATOR_INDEX__NSK_M @@ -14,10 +14,10 @@ use dep::types::{ struct PrivateValidationRequestProcessor { validation_requests: ValidationRequests, note_hash_read_request_hints: NoteHashReadRequestHints, - pending_note_hashes: [NoteHashContext; MAX_NEW_NOTE_HASHES_PER_TX], + pending_note_hashes: [ScopedNoteHash; MAX_NEW_NOTE_HASHES_PER_TX], note_hash_tree_root: Field, nullifier_read_request_hints: NullifierReadRequestHints, - pending_nullifiers: [Nullifier; MAX_NEW_NULLIFIERS_PER_TX], + pending_nullifiers: [ScopedNullifier; MAX_NEW_NULLIFIERS_PER_TX], nullifier_tree_root: Field, master_nullifier_secret_keys: [GrumpkinPrivateKey; MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX], } @@ -62,8 +62,9 @@ impl PrivateValidationRequestProcessor { fn validate_nullifier_keys(self) { let requests = self.validation_requests.nullifier_key_validation_requests; for i in 0..MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX { - let request = requests[i]; + let request = requests[i].request; if !is_empty(request) { + let contract_address = requests[i].contract_address; let master_nullifier_secret_key = self.master_nullifier_secret_keys[i]; // First we check that derived public key matches master nullifier public key from request let master_nullifier_public_key = master_nullifier_secret_key.derive_public_key(); @@ -75,7 +76,7 @@ impl PrivateValidationRequestProcessor { let app_nullifier_secret_key = poseidon2_hash( [ - master_nullifier_secret_key.high, master_nullifier_secret_key.low, request.contract_address.to_field(), GENERATOR_INDEX__NSK_M + master_nullifier_secret_key.high, master_nullifier_secret_key.low, contract_address.to_field(), GENERATOR_INDEX__NSK_M ] ); assert( diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_validation_request_processor.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_validation_request_processor.nr index a3fd6a84cce..a25b760e1d4 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_validation_request_processor.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/public_validation_request_processor.nr @@ -88,7 +88,7 @@ impl PublicValidationRequestProcessor { for i in 0..read_requests.len() { let read_request = read_requests[i]; if !is_empty(read_request) { - read_requests[i].value = silo_nullifier(read_request.contract_address, read_request.value); + read_requests[i].read_request.value = silo_nullifier(read_request.contract_address, read_request.value()); } } diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/non_existent_read_request.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/non_existent_read_request.nr index afb50e68ce5..ec1c8afde44 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/non_existent_read_request.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/non_existent_read_request.nr @@ -1,5 +1,5 @@ use dep::types::{ - abis::{side_effect::OrderedValue, read_request::ReadRequestContext}, + abis::{side_effect::OrderedValue, read_request::ScopedReadRequest}, merkle_tree::{assert_check_non_membership, IndexedTreeLeafPreimage, MembershipWitness}, traits::{Empty, is_empty} }; @@ -10,28 +10,28 @@ trait NonMembershipHint where LEAF_PREIMAGE: Indexed } fn check_no_matching_pending_value( - read_request: ReadRequestContext, + read_request: ScopedReadRequest, sorted_pending_values: BoundedVec, next_value_index: u64 ) -> bool where T: OrderedValue { if next_value_index == sorted_pending_values.len() { let highest_value = sorted_pending_values.get_unchecked(sorted_pending_values.len() - 1).value(); - highest_value.lt(read_request.value) + highest_value.lt(read_request.value()) } else { let next_value = sorted_pending_values.get_unchecked(next_value_index).value(); - let is_less_than_next = read_request.value.lt(next_value); + let is_less_than_next = read_request.value().lt(next_value); let is_greater_than_prev = if next_value_index == 0 { true } else { let prev_value = sorted_pending_values.get_unchecked(next_value_index - 1).value(); - prev_value.lt(read_request.value) + prev_value.lt(read_request.value()) }; is_less_than_next & is_greater_than_prev } } fn check_is_read_before_pending_value( - read_request: ReadRequestContext, + read_request: ScopedReadRequest, sorted_pending_values: BoundedVec, next_value_index: u64 ) -> bool where T: OrderedValue { @@ -39,8 +39,8 @@ fn check_is_read_before_pending_value( false } else { let pending = sorted_pending_values.get_unchecked(next_value_index); - if pending.value() == read_request.value { - assert(read_request.counter < pending.counter(), "Value exists in pending set"); + if pending.value() == read_request.value() { + assert(read_request.counter() < pending.counter(), "Value exists in pending set"); true } else { false @@ -52,7 +52,7 @@ fn check_is_read_before_pending_value( // Non existent read requests can only be verified at the end, after all pending values are present. // The values in read_requests and in sorted_pending_values should've been siloed before calling this. pub fn reset_non_existent_read_requests( - siloed_read_requests: [ReadRequestContext; N], + siloed_read_requests: [ScopedReadRequest; N], non_membership_hints: [NON_MEMBERSHIP_HINT; N], tree_root: Field, sorted_pending_values: BoundedVec, @@ -67,7 +67,7 @@ pub fn reset_non_existent_read_requests where LEAF_PREIMAGE: LeafPreim // - https://discourse.aztec.network/t/to-read-or-not-to-read/178 // - https://discourse.aztec.network/t/spending-notes-which-havent-yet-been-inserted/180 fn validate_pending_read_requests( - read_requests: [ReadRequestContext; READ_REQUEST_LEN], + read_requests: [ScopedReadRequest; READ_REQUEST_LEN], pending_values: [T; PENDING_VALUE_LEN], hints: [PendingReadHint; NUM_PENDING_READS] ) where T: Readable { @@ -76,7 +76,7 @@ fn validate_pending_read_requests( - read_requests: [ReadRequestContext; READ_REQUEST_LEN], + read_requests: [ScopedReadRequest; READ_REQUEST_LEN], hints: [H; NUM_SETTLED_READS], tree_root: Field ) where @@ -97,11 +97,11 @@ fn validate_settled_read_requests( - read_requests: [ReadRequestContext; READ_REQUEST_LEN], + read_requests: [ScopedReadRequest; READ_REQUEST_LEN], read_request_statuses: [ReadRequestStatus; READ_REQUEST_LEN], pending_read_hints: [T; NUM_PENDING_READS], settled_read_hints: [S; NUM_SETTLED_READS] -) -> BoundedVec where T: ReadValueHint, S: ReadValueHint { +) -> BoundedVec where T: ReadValueHint, S: ReadValueHint { let mut propagated_read_requests = BoundedVec::new(); for i in 0..READ_REQUEST_LEN { let read_request = read_requests[i]; @@ -124,13 +124,13 @@ fn propagate_unverified_read_requests( - read_requests: [ReadRequestContext; READ_REQUEST_LEN], + read_requests: [ScopedReadRequest; READ_REQUEST_LEN], pending_values: [P; PENDING_VALUE_LEN], read_request_statuses: [ReadRequestStatus; READ_REQUEST_LEN], pending_read_hints: [PendingReadHint; NUM_PENDING_READS], settled_read_hints: [H; NUM_SETTLED_READS], tree_root: Field -) -> BoundedVec where +) -> BoundedVec where P: Readable, H: SettledReadHint + ReadValueHint, LEAF_PREIMAGE: LeafPreimage + Readable { @@ -153,7 +153,8 @@ mod tests { validate_settled_read_requests }; use dep::types::{ - address::AztecAddress, abis::{read_request::ReadRequestContext, side_effect::Readable}, + address::AztecAddress, + abis::{read_request::{ReadRequest, ScopedReadRequest}, side_effect::Readable}, merkle_tree::{LeafPreimage, MembershipWitness}, tests::merkle_tree_utils::NonEmptyMerkleTree, traits::Empty }; @@ -168,8 +169,8 @@ mod tests { } impl Readable for TestValue { - fn assert_match_read_request(self, read_request: ReadRequestContext) { - let siloed_value = silo_test_value(read_request.value); + fn assert_match_read_request(self, read_request: ScopedReadRequest) { + let siloed_value = silo_test_value(read_request.value()); assert_eq(self.value, siloed_value, "Hinted test value does not match"); } } @@ -197,8 +198,8 @@ mod tests { } impl Readable for TestLeafPreimage { - fn assert_match_read_request(self, read_request: ReadRequestContext) { - let siloed_value = silo_test_value(read_request.value); + fn assert_match_read_request(self, read_request: ScopedReadRequest) { + let siloed_value = silo_test_value(read_request.value()); assert_eq(siloed_value, self.value, "Provided leaf preimage is not for target value"); } } @@ -241,10 +242,10 @@ mod tests { // Create 4 read requests. 0 and 3 are reading settled values. 1 and 2 are reading pending values. global read_requests = [ - ReadRequestContext { value: values[1], counter: 11, contract_address }, // settled - ReadRequestContext { value: values[3], counter: 13, contract_address }, // pending - ReadRequestContext { value: values[2], counter: 39, contract_address }, // pending - ReadRequestContext { value: values[0], counter: 46, contract_address }, // settled + ReadRequest { value: values[1], counter: 11 }.scope(contract_address), // settled + ReadRequest { value: values[3], counter: 13, }.scope(contract_address), // pending + ReadRequest { value: values[2], counter: 39, }.scope(contract_address), // pending + ReadRequest { value: values[0], counter: 46, }.scope(contract_address), // settled ]; global pending_values = [ diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/transient_data.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/transient_data.nr index 56ef524f2dd..a109bdbeb78 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/transient_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/transient_data.nr @@ -1,10 +1,10 @@ -use dep::types::{abis::{note_hash::NoteHashContext, nullifier::Nullifier}, traits::is_empty}; +use dep::types::{abis::{note_hash::ScopedNoteHash, nullifier::ScopedNullifier}, traits::is_empty}; pub fn verify_squashed_transient_note_hashes_and_nullifiers( - note_hashes: [NoteHashContext; NUM_NOTE_HASHES], - nullifiers: [Nullifier; NUM_NULLIFIERS], - expected_note_hashes: [NoteHashContext; NUM_NOTE_HASHES], - expected_nullifiers: [Nullifier; NUM_NULLIFIERS], + note_hashes: [ScopedNoteHash; NUM_NOTE_HASHES], + nullifiers: [ScopedNullifier; NUM_NULLIFIERS], + expected_note_hashes: [ScopedNoteHash; NUM_NOTE_HASHES], + expected_nullifiers: [ScopedNullifier; NUM_NULLIFIERS], transient_nullifier_indexes_for_note_hashes: [u64; NUM_NOTE_HASHES], transient_note_hash_indexes_for_nullifiers: [u64; NUM_NULLIFIERS] ) { @@ -18,14 +18,19 @@ pub fn verify_squashed_transient_note_hashes_and_nullifiers note_hash.counter); + // assert(nullifier.counter > note_hash.counter()); note_hashes_removed += 1; @@ -62,35 +67,40 @@ pub fn verify_squashed_transient_note_hashes_and_nullifiers { num_note_hashes: u64, num_nullifiers: u64, - note_hashes: [NoteHashContext; NUM_NOTE_HASHES], - nullifiers: [Nullifier; NUM_NULLIFIERS], - expected_note_hashes: [NoteHashContext; NUM_NOTE_HASHES], - expected_nullifiers: [Nullifier; NUM_NULLIFIERS], + note_hashes: [ScopedNoteHash; NUM_NOTE_HASHES], + nullifiers: [ScopedNullifier; NUM_NULLIFIERS], + expected_note_hashes: [ScopedNoteHash; NUM_NOTE_HASHES], + expected_nullifiers: [ScopedNullifier; NUM_NULLIFIERS], transient_nullifier_indexes_for_note_hashes: [u64; NUM_NOTE_HASHES], transient_note_hash_indexes_for_nullifiers: [u64; NUM_NULLIFIERS], } impl TestDataBuilder { pub fn default() -> TestDataBuilder<3, 3> { + let contract_address = AztecAddress::from_field(987654); + let note_hashes = [ - NoteHashContext { value: 11, counter: 100, nullifier_counter: 500 }, - NoteHashContext { value: 22, counter: 200, nullifier_counter: 0 }, - NoteHashContext { value: 33, counter: 300, nullifier_counter: 400 } + NoteHash { value: 11, counter: 100 }.scope(500, contract_address), + NoteHash { value: 22, counter: 200 }.scope(0, contract_address), + NoteHash { value: 33, counter: 300 }.scope(400, contract_address) ]; let nullifiers = [ - Nullifier { value: 44, counter: 400, note_hash: 33 }, - Nullifier { value: 55, counter: 500, note_hash: 11 }, - Nullifier { value: 66, counter: 600, note_hash: 0 } + Nullifier { value: 44, counter: 400, note_hash: 33 }.scope(contract_address), + Nullifier { value: 55, counter: 500, note_hash: 11 }.scope(contract_address), + Nullifier { value: 66, counter: 600, note_hash: 0 }.scope(contract_address) ]; - let expected_note_hashes = [note_hashes[1], NoteHashContext::empty(), NoteHashContext::empty()]; - let expected_nullifiers = [nullifiers[2], Nullifier::empty(), Nullifier::empty()]; + let expected_note_hashes = [note_hashes[1], ScopedNoteHash::empty(), ScopedNoteHash::empty()]; + let expected_nullifiers = [nullifiers[2], ScopedNullifier::empty(), ScopedNullifier::empty()]; let transient_nullifier_indexes_for_note_hashes = [1, 3, 0]; let transient_note_hash_indexes_for_nullifiers = [2, 0, 3]; @@ -108,20 +118,22 @@ mod tests { } pub fn default_all_clear() -> TestDataBuilder<3, 3> { + let contract_address = AztecAddress::from_field(987654); + let note_hashes = [ - NoteHashContext { value: 11, counter: 100, nullifier_counter: 500 }, - NoteHashContext { value: 22, counter: 200, nullifier_counter: 600 }, - NoteHashContext { value: 33, counter: 300, nullifier_counter: 400 } + NoteHash { value: 11, counter: 100 }.scope(500, contract_address), + NoteHash { value: 22, counter: 200 }.scope(600, contract_address), + NoteHash { value: 33, counter: 300 }.scope(400, contract_address) ]; let nullifiers = [ - Nullifier { value: 44, counter: 400, note_hash: 33 }, - Nullifier { value: 55, counter: 500, note_hash: 11 }, - Nullifier { value: 66, counter: 600, note_hash: 22 } + Nullifier { value: 44, counter: 400, note_hash: 33 }.scope(contract_address), + Nullifier { value: 55, counter: 500, note_hash: 11 }.scope(contract_address), + Nullifier { value: 66, counter: 600, note_hash: 22 }.scope(contract_address) ]; - let expected_note_hashes = [NoteHashContext::empty(); 3]; - let expected_nullifiers = [Nullifier::empty(); 3]; + let expected_note_hashes = [ScopedNoteHash::empty(); 3]; + let expected_nullifiers = [ScopedNullifier::empty(); 3]; let transient_nullifier_indexes_for_note_hashes = [1, 2, 0]; let transient_note_hash_indexes_for_nullifiers = [2, 0, 1]; @@ -175,16 +187,25 @@ mod tests { builder.verify(); } - #[test(should_fail_with="Hinted note hash does not match")] + #[test(should_fail_with="Value of the hinted transient note hash does not match")] fn mismatch_note_hash_value() { let mut builder = TestDataBuilder::default_all_clear(); - builder.note_hashes[1].value += 1; + builder.note_hashes[1].note_hash.value += 1; + + builder.verify(); + } + + #[test(should_fail_with="Contract address of the hinted transient note hash does not match")] + fn mismatch_contract_address() { + let mut builder = TestDataBuilder::default_all_clear(); + + builder.note_hashes[1].contract_address.inner += 1; builder.verify(); } - #[test(should_fail_with="Hinted nullifier counter does not match")] + #[test(should_fail_with="Nullifier counter of the hinted transient note hash does not match")] fn mismatch_nullifier_counter() { let mut builder = TestDataBuilder::default_all_clear(); @@ -197,7 +218,7 @@ mod tests { fn unexpected_note_hash_value() { let mut builder = TestDataBuilder::default_all_clear(); - builder.expected_note_hashes[2].value = 11; + builder.expected_note_hashes[2].note_hash.value = 11; builder.verify(); } @@ -206,7 +227,7 @@ mod tests { fn wrong_expected_note_hash_value() { let mut builder = TestDataBuilder::default(); - builder.expected_note_hashes[0].value += 1; + builder.expected_note_hashes[0].note_hash.value += 1; builder.verify(); } @@ -215,7 +236,7 @@ mod tests { fn wrong_expected_note_hash_counter() { let mut builder = TestDataBuilder::default(); - builder.expected_note_hashes[0].counter += 1; + builder.expected_note_hashes[0].note_hash.counter += 1; builder.verify(); } @@ -233,7 +254,7 @@ mod tests { fn unexpected_nullifier_value() { let mut builder = TestDataBuilder::default_all_clear(); - builder.expected_nullifiers[2].value = 11; + builder.expected_nullifiers[2].nullifier.value = 11; builder.verify(); } @@ -242,7 +263,7 @@ mod tests { fn wrong_expected_nullifier_value() { let mut builder = TestDataBuilder::default(); - builder.expected_nullifiers[0].value += 1; + builder.expected_nullifiers[0].nullifier.value += 1; builder.verify(); } @@ -251,7 +272,7 @@ mod tests { fn wrong_expected_nullifier_counter() { let mut builder = TestDataBuilder::default(); - builder.expected_nullifiers[0].counter += 1; + builder.expected_nullifiers[0].nullifier.counter += 1; builder.verify(); } diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/squash_transient_data.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/squash_transient_data.nr index 48446480718..264ff0af167 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/squash_transient_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/squash_transient_data.nr @@ -1,7 +1,7 @@ -use dep::types::abis::{note_hash::NoteHashContext, nullifier::Nullifier}; +use dep::types::abis::{note_hash::ScopedNoteHash, nullifier::ScopedNullifier}; -pub fn squash_transient_note_hashes(note_hashes: [NoteHashContext; N]) -> [NoteHashContext; N] { - let mut final_note_hashes = [NoteHashContext::empty(); N]; +pub fn squash_transient_note_hashes(note_hashes: [ScopedNoteHash; N]) -> [ScopedNoteHash; N] { + let mut final_note_hashes = [ScopedNoteHash::empty(); N]; let mut num_note_hashes = 0; for i in 0..N { @@ -15,13 +15,13 @@ pub fn squash_transient_note_hashes(note_hashes: [NoteHashContext; N]) -> [No final_note_hashes } -pub fn squash_transient_nullifiers(nullifiers: [Nullifier; N]) -> [Nullifier; N] { - let mut final_nullifiers = [Nullifier::empty(); N]; +pub fn squash_transient_nullifiers(nullifiers: [ScopedNullifier; N]) -> [ScopedNullifier; N] { + let mut final_nullifiers = [ScopedNullifier::empty(); N]; let mut num_nullifiers = 0; for i in 0..N { let nullifier = nullifiers[i]; - if nullifier.note_hash == 0 { + if nullifier.nullified_note_hash() == 0 { final_nullifiers[num_nullifiers] = nullifier; num_nullifiers += 1; } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr index e6907de06f4..1a49b8de968 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr @@ -48,7 +48,10 @@ impl CombinedAccumulatedData { CombinedAccumulatedData { new_note_hashes: array_merge(non_revertible.new_note_hashes, revertible.new_note_hashes).map(|n: NoteHash| n.value), new_nullifiers: array_merge(non_revertible.new_nullifiers, revertible.new_nullifiers).map(|n: Nullifier| n.value), - new_l2_to_l1_msgs: revertible.new_l2_to_l1_msgs, + new_l2_to_l1_msgs: array_merge( + non_revertible.new_l2_to_l1_msgs, + revertible.new_l2_to_l1_msgs + ), encrypted_logs_hash, unencrypted_logs_hash, encrypted_log_preimages_length: non_revertible.encrypted_log_preimages_length diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data.nr index 31c73652ee0..12c19d640b1 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data.nr @@ -1,8 +1,9 @@ use crate::{ abis::{ - call_request::CallRequest, gas::Gas, note_hash::NoteHashContext, nullifier::Nullifier, + call_request::CallRequest, gas::Gas, note_hash::ScopedNoteHash, nullifier::ScopedNullifier, side_effect::SideEffect -} +}, + messaging::l2_to_l1_message::ScopedL2ToL1Message }; use crate::constants::{ MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, @@ -11,9 +12,9 @@ use crate::constants::{ }; struct PrivateAccumulatedData { - new_note_hashes: [NoteHashContext; MAX_NEW_NOTE_HASHES_PER_TX], - new_nullifiers: [Nullifier; MAX_NEW_NULLIFIERS_PER_TX], - new_l2_to_l1_msgs: [Field; MAX_NEW_L2_TO_L1_MSGS_PER_TX], + new_note_hashes: [ScopedNoteHash; MAX_NEW_NOTE_HASHES_PER_TX], + new_nullifiers: [ScopedNullifier; MAX_NEW_NULLIFIERS_PER_TX], + new_l2_to_l1_msgs: [ScopedL2ToL1Message; MAX_NEW_L2_TO_L1_MSGS_PER_TX], encrypted_logs_hashes: [SideEffect; MAX_ENCRYPTED_LOGS_PER_TX], unencrypted_logs_hashes: [SideEffect; MAX_UNENCRYPTED_LOGS_PER_TX], diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data_builder.nr index 984a1a292a1..08597103279 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data_builder.nr @@ -7,7 +7,7 @@ use crate::{ private_accumulated_data::PrivateAccumulatedData, public_accumulated_data::PublicAccumulatedData, public_accumulated_data_builder::PublicAccumulatedDataBuilder }, - call_request::CallRequest, note_hash::{NoteHash, NoteHashContext}, nullifier::Nullifier, + call_request::CallRequest, note_hash::{NoteHash, ScopedNoteHash}, nullifier::ScopedNullifier, public_data_update_request::PublicDataUpdateRequest, side_effect::SideEffect }, constants::{ @@ -16,7 +16,7 @@ use crate::{ MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_ENCRYPTED_LOGS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX, DA_BYTES_PER_FIELD, DA_GAS_PER_BYTE }, - traits::{Empty, is_empty} + messaging::l2_to_l1_message::ScopedL2ToL1Message, traits::{Empty, is_empty} }; // Builds via PrivateKernelCircuitPublicInputsBuilder: @@ -24,9 +24,9 @@ use crate::{ // .to_combined: KernelCircuitPublicInputs.end // .split_to_public: PublicKernelCircuitPublicInputs.(end,end_non_revertible) struct PrivateAccumulatedDataBuilder { - new_note_hashes: BoundedVec, - new_nullifiers: BoundedVec, - new_l2_to_l1_msgs: BoundedVec, + new_note_hashes: BoundedVec, + new_nullifiers: BoundedVec, + new_l2_to_l1_msgs: BoundedVec, encrypted_logs_hashes: BoundedVec, unencrypted_logs_hashes: BoundedVec, @@ -63,9 +63,9 @@ impl PrivateAccumulatedDataBuilder { let gas_used = self.to_metered_gas_used() + Gas::tx_overhead() + teardown_gas; CombinedAccumulatedData { - new_note_hashes: self.new_note_hashes.storage.map(|n: NoteHashContext| n.value), - new_nullifiers: self.new_nullifiers.storage.map(|n: Nullifier| n.value), - new_l2_to_l1_msgs: self.new_l2_to_l1_msgs.storage, + new_note_hashes: self.new_note_hashes.storage.map(|n: ScopedNoteHash| n.note_hash.value), + new_nullifiers: self.new_nullifiers.storage.map(|n: ScopedNullifier| n.nullifier.value), + new_l2_to_l1_msgs: self.new_l2_to_l1_msgs.storage.map(|m: ScopedL2ToL1Message| m.message.content), encrypted_logs_hash, unencrypted_logs_hash, encrypted_log_preimages_length: self.encrypted_log_preimages_length, @@ -124,7 +124,7 @@ impl PrivateAccumulatedDataBuilder { for i in 0..MAX_NEW_NOTE_HASHES_PER_TX { let note_hash = self.new_note_hashes.storage[i]; let public_note_hash = note_hash.expose_to_public(); - if note_hash.counter < min_revertible_side_effect_counter { + if note_hash.counter() < min_revertible_side_effect_counter { non_revertible_builder.new_note_hashes.push(public_note_hash); if !is_empty(public_note_hash) { non_revertible_da_gas_used += DA_GAS_PER_FIELD ; @@ -139,19 +139,29 @@ impl PrivateAccumulatedDataBuilder { for i in 0..MAX_NEW_NULLIFIERS_PER_TX { let nullifier = self.new_nullifiers.storage[i]; - if nullifier.counter < min_revertible_side_effect_counter { - non_revertible_builder.new_nullifiers.push(nullifier); - if !is_empty(nullifier) { + let public_nullifier = nullifier.expose_to_public(); + if nullifier.counter() < min_revertible_side_effect_counter { + non_revertible_builder.new_nullifiers.push(public_nullifier); + if !is_empty(public_nullifier) { non_revertible_da_gas_used += DA_GAS_PER_FIELD; } } else { - revertible_builder.new_nullifiers.push(nullifier); - if !is_empty(nullifier) { + revertible_builder.new_nullifiers.push(public_nullifier); + if !is_empty(public_nullifier) { revertible_da_gas_used += DA_GAS_PER_FIELD; } } } + for i in 0..MAX_NEW_L2_TO_L1_MSGS_PER_TX { + let msg = self.new_l2_to_l1_msgs.storage[i]; + if msg.counter() < min_revertible_side_effect_counter { + non_revertible_builder.new_l2_to_l1_msgs.push(msg.message.content); + } else { + revertible_builder.new_l2_to_l1_msgs.push(msg.message.content); + } + } + // TODO(gas): add AVM_STARTUP_L2_GAS here for i in 0..MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX { let call_stack_item = self.public_call_stack.storage[i]; @@ -180,7 +190,6 @@ impl PrivateAccumulatedDataBuilder { } } - revertible_builder.new_l2_to_l1_msgs = self.new_l2_to_l1_msgs; // TODO(1641) & TODO(4712): Once we track logs with more info, including individual lens, split here revertible_builder.encrypted_log_preimages_length = self.encrypted_log_preimages_length; revertible_builder.unencrypted_log_preimages_length = self.unencrypted_log_preimages_length; @@ -197,25 +206,35 @@ mod tests { use crate::{ abis::{ accumulated_data::private_accumulated_data_builder::PrivateAccumulatedDataBuilder, gas::Gas, - call_request::CallRequest, caller_context::CallerContext, - note_hash::{NoteHash, NoteHashContext}, nullifier::Nullifier, - public_data_update_request::PublicDataUpdateRequest, side_effect::SideEffect + call_request::CallRequest, caller_context::CallerContext, note_hash::NoteHash, + nullifier::Nullifier, public_data_update_request::PublicDataUpdateRequest, + side_effect::SideEffect }, - address::AztecAddress, utils::arrays::array_eq, constants::{DA_BYTES_PER_FIELD, DA_GAS_PER_BYTE} + address::{AztecAddress, EthAddress}, messaging::l2_to_l1_message::L2ToL1Message, + utils::arrays::array_eq, constants::{DA_BYTES_PER_FIELD, DA_GAS_PER_BYTE} }; #[test] unconstrained fn splits_revertible_and_non_revertible() { let mut builder = PrivateAccumulatedDataBuilder::empty(); + let contract_address = AztecAddress::from_field(8989); + + let min_revertible_side_effect_counter = 7; + + // Non revertible: counter < 7 let non_revertible_note_hashes = [ - NoteHashContext { value: 1, counter: 1, nullifier_counter: 20 }, - NoteHashContext { value: 2, counter: 3, nullifier_counter: 5 } + NoteHash { value: 1, counter: 1 }.scope(20, contract_address), + NoteHash { value: 2, counter: 3 }.scope(5, contract_address) ]; let non_revertible_nullifiers = [ - Nullifier { value: 10, note_hash: 1, counter: 2 }, - Nullifier { value: 20, note_hash: 2, counter: 4 } + Nullifier { value: 10, note_hash: 1, counter: 2 }.scope(contract_address), + Nullifier { value: 20, note_hash: 2, counter: 4 }.scope(contract_address) + ]; + + let non_revertible_l2_to_l1_messages = [ + L2ToL1Message { recipient: EthAddress::from_field(3030), content: 333333, counter: 5 }.scope(AztecAddress::from_field(9900)) ]; let non_revertible_public_stack = [ @@ -235,14 +254,20 @@ mod tests { } ]; + // Revertible: counter >= 7 + let revertible_note_hashes = [ - NoteHashContext { value: 3, counter: 7, nullifier_counter: 15 }, - NoteHashContext { value: 4, counter: 10, nullifier_counter: 0 } + NoteHash { value: 3, counter: 7 }.scope(15, contract_address), + NoteHash { value: 4, counter: 10 }.scope(0, contract_address) ]; let revertible_nullifiers = [ - Nullifier { value: 30, note_hash: 3, counter: 8 }, - Nullifier { value: 40, note_hash: 4, counter: 11 } + Nullifier { value: 30, note_hash: 3, counter: 8 }.scope(contract_address), + Nullifier { value: 40, note_hash: 4, counter: 11 }.scope(contract_address) + ]; + + let revertible_l2_to_l1_messages = [ + L2ToL1Message { recipient: EthAddress::from_field(3030), content: 444444, counter: 13 }.scope(AztecAddress::from_field(7788)) ]; let revertible_public_call_stack = [ @@ -261,10 +286,13 @@ mod tests { builder.new_nullifiers.extend_from_array(non_revertible_nullifiers); builder.new_nullifiers.extend_from_array(revertible_nullifiers); + builder.new_l2_to_l1_msgs.extend_from_array(non_revertible_l2_to_l1_messages); + builder.new_l2_to_l1_msgs.extend_from_array(revertible_l2_to_l1_messages); + builder.public_call_stack.extend_from_array(non_revertible_public_stack); builder.public_call_stack.extend_from_array(revertible_public_call_stack); - let (non_revertible, revertible) = builder.split_to_public(7, Gas::new(42, 17)); + let (non_revertible, revertible) = builder.split_to_public(min_revertible_side_effect_counter, Gas::new(42, 17)); assert( array_eq( @@ -275,7 +303,16 @@ mod tests { ] ) ); - assert(array_eq(non_revertible.new_nullifiers, non_revertible_nullifiers)); + assert( + array_eq( + non_revertible.new_nullifiers, + [ + Nullifier { value: 10, note_hash: 0, counter: 0 }, + Nullifier { value: 20, note_hash: 0, counter: 0 } + ] + ) + ); + assert(array_eq(non_revertible.new_l2_to_l1_msgs, [333333])); assert(array_eq(non_revertible.public_call_stack, non_revertible_public_stack)); assert( @@ -287,7 +324,16 @@ mod tests { ] ) ); - assert(array_eq(revertible.new_nullifiers, revertible_nullifiers)); + assert( + array_eq( + revertible.new_nullifiers, + [ + Nullifier { value: 30, note_hash: 0, counter: 0 }, + Nullifier { value: 40, note_hash: 0, counter: 0 } + ] + ) + ); + assert(array_eq(revertible.new_l2_to_l1_msgs, [444444])); assert(array_eq(revertible.public_call_stack, revertible_public_call_stack)); assert_eq( diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/note_hash.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/note_hash.nr index 64c95058f83..53a248718c2 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/note_hash.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/note_hash.nr @@ -1,8 +1,8 @@ use crate::{ - abis::read_request::ReadRequestContext, address::AztecAddress, + abis::read_request::ScopedReadRequest, address::AztecAddress, abis::side_effect::{Ordered, OrderedValue, Readable}, - constants::{NOTE_HASH_LENGTH, NOTE_HASH_CONTEXT_LENGTH}, hash::silo_note_hash, - traits::{Empty, Serialize, Deserialize} + constants::{NOTE_HASH_LENGTH, SCOPED_NOTE_HASH_LENGTH}, traits::{Empty, Serialize, Deserialize}, + utils::{arrays::array_concat, reader::Reader} }; use dep::std::cmp::Eq; @@ -11,21 +11,6 @@ struct NoteHash { counter: u32, } -impl Ordered for NoteHash { - fn counter(self) -> u32 { - self.counter - } -} - -impl OrderedValue for NoteHash { - fn value(self) -> Field { - self.value - } - fn counter(self) -> u32 { - self.counter - } -} - impl Eq for NoteHash { fn eq(self, other: NoteHash) -> bool { (self.value == other.value) @@ -58,87 +43,85 @@ impl Deserialize for NoteHash { } impl NoteHash { - pub fn to_context(self, nullifier_counter: u32) -> NoteHashContext { - NoteHashContext { value: self.value, counter: self.counter, nullifier_counter } + pub fn scope(self, nullifier_counter: u32, contract_address: AztecAddress) -> ScopedNoteHash { + ScopedNoteHash { note_hash: self, nullifier_counter, contract_address } } } -struct NoteHashContext { - value: Field, - counter: u32, +struct ScopedNoteHash { + note_hash: NoteHash, nullifier_counter: u32, + contract_address: AztecAddress, } -impl Ordered for NoteHashContext { +impl Ordered for ScopedNoteHash { fn counter(self) -> u32 { - self.counter + self.note_hash.counter } } -impl OrderedValue for NoteHashContext { +impl OrderedValue for ScopedNoteHash { fn value(self) -> Field { - self.value + self.note_hash.value } fn counter(self) -> u32 { - self.counter + self.note_hash.counter } } -impl Eq for NoteHashContext { - fn eq(self, other: NoteHashContext) -> bool { - (self.value == other.value) - & (self.counter == other.counter) +impl Eq for ScopedNoteHash { + fn eq(self, other: ScopedNoteHash) -> bool { + (self.note_hash == other.note_hash) & (self.nullifier_counter == other.nullifier_counter) + & (self.contract_address == other.contract_address) } } -impl Empty for NoteHashContext { +impl Empty for ScopedNoteHash { fn empty() -> Self { - NoteHashContext { - value: 0, - counter: 0, + ScopedNoteHash { + note_hash: NoteHash::empty(), nullifier_counter: 0, + contract_address: AztecAddress::zero(), } } } -impl Serialize for NoteHashContext { - fn serialize(self) -> [Field; NOTE_HASH_CONTEXT_LENGTH] { - [self.value, self.counter as Field, self.nullifier_counter as Field] +impl Serialize for ScopedNoteHash { + fn serialize(self) -> [Field; SCOPED_NOTE_HASH_LENGTH] { + array_concat(self.note_hash.serialize(), [self.nullifier_counter as Field, self.contract_address.to_field()]) } } -impl Deserialize for NoteHashContext { - fn deserialize(values: [Field; NOTE_HASH_CONTEXT_LENGTH]) -> Self { - Self { - value: values[0], - counter: values[1] as u32, - nullifier_counter: values[2] as u32, - } +impl Deserialize for ScopedNoteHash { + fn deserialize(values: [Field; SCOPED_NOTE_HASH_LENGTH]) -> Self { + let mut reader = Reader::new(values); + let res = Self { + note_hash: reader.read_struct(NoteHash::deserialize), + nullifier_counter: reader.read_u32(), + contract_address: reader.read_struct(AztecAddress::deserialize), + }; + reader.finish(); + res } } -impl Readable for NoteHashContext { - fn assert_match_read_request(self, read_request: ReadRequestContext) { - // TODO(#6122) - let siloed_value = silo_note_hash(read_request.contract_address, read_request.value); - assert_eq(self.value, siloed_value, "Value of the note hash does not match read request"); +impl Readable for ScopedNoteHash { + fn assert_match_read_request(self, read_request: ScopedReadRequest) { + assert_eq(self.note_hash.value, read_request.value(), "Value of the note hash does not match read request"); + assert_eq(self.contract_address, read_request.contract_address, "Contract address of the note hash does not match read request"); assert( - read_request.counter > self.counter, "Read request counter must be greater than the counter of the note hash" + read_request.counter() > self.note_hash.counter, "Read request counter must be greater than the counter of the note hash" ); assert( - (self.nullifier_counter == 0) | (read_request.counter < self.nullifier_counter), "Read request counter must be less than the nullifier counter of the note hash" + (self.nullifier_counter == 0) | (read_request.counter() < self.nullifier_counter), "Read request counter must be less than the nullifier counter of the note hash" ); } } -impl NoteHashContext { - pub fn to_note_hash(self) -> NoteHash { - NoteHash { value: self.value, counter: self.counter } - } - +impl ScopedNoteHash { pub fn expose_to_public(self) -> NoteHash { // Hide the actual counter when exposing it to the public kernel. - NoteHash { value: self.value, counter: 0 } + NoteHash { value: self.note_hash.value, counter: 0 } } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/note_hash_leaf_preimage.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/note_hash_leaf_preimage.nr index 5c9cf6ad487..031325e6430 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/note_hash_leaf_preimage.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/note_hash_leaf_preimage.nr @@ -1,7 +1,7 @@ global NOTE_HASH_LEAF_PREIMAGE_LENGTH: u64 = 1; use crate::{ - abis::{read_request::ReadRequestContext, side_effect::Readable}, hash::silo_note_hash, + abis::{read_request::ScopedReadRequest, side_effect::Readable}, hash::silo_note_hash, merkle_tree::leaf_preimage::LeafPreimage, traits::{Empty, Hash} }; @@ -28,11 +28,11 @@ impl LeafPreimage for NoteHashLeafPreimage { } impl Readable for NoteHashLeafPreimage { - fn assert_match_read_request(self, read_request: ReadRequestContext) { + fn assert_match_read_request(self, read_request: ScopedReadRequest) { // TODO(#2847): Read request value shouldn't have been siloed by apps. // let siloed_value = silo_note_hash(read_request.contract_address, read_request.value); // assert_eq(self.value, siloed_value, "Value of the note hash leaf does not match read request"); - assert_eq(self.value, read_request.value, "Value of the note hash leaf does not match read request"); + assert_eq(self.value, read_request.value(), "Value of the note hash leaf does not match read request"); } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/nullifier.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/nullifier.nr index b32a81ee264..da4c140d43d 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/nullifier.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/nullifier.nr @@ -1,7 +1,7 @@ use crate::{ - abis::{side_effect::{Ordered, OrderedValue, Readable}, read_request::ReadRequestContext}, - address::AztecAddress, constants::NULLIFIER_LENGTH, hash::silo_nullifier, - traits::{Empty, Hash, Serialize, Deserialize} + abis::{side_effect::{Ordered, OrderedValue, Readable}, read_request::ScopedReadRequest}, + address::AztecAddress, constants::{NULLIFIER_LENGTH, SCOPED_NULLIFIER_LENGTH}, hash::silo_nullifier, + traits::{Empty, Hash, Serialize, Deserialize}, utils::{arrays::array_concat, reader::Reader} }; struct Nullifier { @@ -10,12 +10,6 @@ struct Nullifier { note_hash: Field, } -impl Ordered for Nullifier { - fn counter(self) -> u32 { - self.counter - } -} - impl OrderedValue for Nullifier { fn value(self) -> Field { self.value @@ -60,11 +54,94 @@ impl Deserialize for Nullifier { } impl Readable for Nullifier { - fn assert_match_read_request(self, read_request: ReadRequestContext) { - let siloed_value = silo_nullifier(read_request.contract_address, read_request.value); - assert_eq(self.value, siloed_value, "Value of the nullifier does not match read request"); + fn assert_match_read_request(self, read_request: ScopedReadRequest) { + // Public kernels output Nullifier instead of ScopedNullifier. + // The nullifier value has been siloed. + let siloed_request_value = silo_nullifier(read_request.contract_address, read_request.value()); + assert_eq(self.value, siloed_request_value, "Value of the nullifier does not match read request"); + assert( + read_request.counter() > self.counter, "Read request counter must be greater than the counter of the nullifier" + ); + } +} + +impl Nullifier { + pub fn scope(self, contract_address: AztecAddress) -> ScopedNullifier { + ScopedNullifier { nullifier: self, contract_address } + } +} + +struct ScopedNullifier { + nullifier: Nullifier, + contract_address: AztecAddress, +} + +impl Ordered for ScopedNullifier { + fn counter(self) -> u32 { + self.nullifier.counter + } +} + +impl OrderedValue for ScopedNullifier { + fn value(self) -> Field { + self.nullifier.value + } + fn counter(self) -> u32 { + self.nullifier.counter + } +} + +impl Eq for ScopedNullifier { + fn eq(self, other: ScopedNullifier) -> bool { + (self.nullifier == other.nullifier) + & (self.contract_address == other.contract_address) + } +} + +impl Empty for ScopedNullifier { + fn empty() -> Self { + ScopedNullifier { + nullifier: Nullifier::empty(), + contract_address: AztecAddress::empty(), + } + } +} + +impl Serialize for ScopedNullifier { + fn serialize(self) -> [Field; SCOPED_NULLIFIER_LENGTH] { + array_concat(self.nullifier.serialize(), [self.contract_address.to_field()]) + } +} + +impl Deserialize for ScopedNullifier { + fn deserialize(values: [Field; SCOPED_NULLIFIER_LENGTH]) -> Self { + let mut reader = Reader::new(values); + let res = Self { + nullifier: reader.read_struct(Nullifier::deserialize), + contract_address: AztecAddress::from_field(values[3]), + }; + reader.finish(); + res + } +} + +impl Readable for ScopedNullifier { + fn assert_match_read_request(self, read_request: ScopedReadRequest) { + assert_eq(self.nullifier.value, read_request.value(), "Value of the nullifier does not match read request"); + assert_eq(self.contract_address, read_request.contract_address, "Contract address of the nullifier does not match read request"); assert( - read_request.counter > self.counter, "Read request counter must be greater than the counter of the nullifier" + read_request.counter() > self.nullifier.counter, "Read request counter must be greater than the counter of the nullifier" ); } } + +impl ScopedNullifier { + pub fn nullified_note_hash(self) -> Field { + self.nullifier.note_hash + } + + pub fn expose_to_public(self) -> Nullifier { + // Hide the actual counter and note hash when exposing it to the public kernel. + Nullifier { value: self.nullifier.value, counter: 0, note_hash: 0 } + } +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/nullifier_key_validation_request.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/nullifier_key_validation_request.nr index bab8b642f09..f0d24b204a4 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/nullifier_key_validation_request.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/nullifier_key_validation_request.nr @@ -1,8 +1,9 @@ use dep::std::cmp::Eq; use crate::{ address::AztecAddress, - constants::{NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_LENGTH, NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH}, + constants::{NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH, SCOPED_NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH}, traits::{Empty, Serialize, Deserialize}, grumpkin_point::GrumpkinPoint, + utils::{arrays::array_concat, reader::Reader} }; struct NullifierKeyValidationRequest { @@ -46,57 +47,47 @@ impl Deserialize for NullifierKeyValida } impl NullifierKeyValidationRequest { - pub fn to_context(self, contract_address: AztecAddress) -> NullifierKeyValidationRequestContext { - NullifierKeyValidationRequestContext { - master_nullifier_public_key: self.master_nullifier_public_key, - app_nullifier_secret_key: self.app_nullifier_secret_key, - contract_address - } + pub fn scope(self, contract_address: AztecAddress) -> ScopedNullifierKeyValidationRequest { + ScopedNullifierKeyValidationRequest { request: self, contract_address } } } -struct NullifierKeyValidationRequestContext { - master_nullifier_public_key: GrumpkinPoint, - app_nullifier_secret_key: Field, +struct ScopedNullifierKeyValidationRequest { + request: NullifierKeyValidationRequest, contract_address: AztecAddress, } -impl Eq for NullifierKeyValidationRequestContext { - fn eq(self, request: NullifierKeyValidationRequestContext) -> bool { - (request.master_nullifier_public_key.eq(self.master_nullifier_public_key)) - & (request.app_nullifier_secret_key.eq(self.app_nullifier_secret_key)) - & (request.contract_address.eq(self.contract_address)) +impl Eq for ScopedNullifierKeyValidationRequest { + fn eq(self, other: ScopedNullifierKeyValidationRequest) -> bool { + (self.request.eq(other.request)) + & (self.contract_address.eq(other.contract_address)) } } -impl Empty for NullifierKeyValidationRequestContext { +impl Empty for ScopedNullifierKeyValidationRequest { fn empty() -> Self { - NullifierKeyValidationRequestContext { - master_nullifier_public_key: GrumpkinPoint::zero(), - app_nullifier_secret_key: 0, + ScopedNullifierKeyValidationRequest { + request: NullifierKeyValidationRequest::empty(), contract_address: AztecAddress::zero(), } } } -impl Serialize for NullifierKeyValidationRequestContext { - fn serialize(self) -> [Field; NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_LENGTH] { - [ - self.master_nullifier_public_key.x, - self.master_nullifier_public_key.y, - self.app_nullifier_secret_key, - self.contract_address.to_field(), - ] +impl Serialize for ScopedNullifierKeyValidationRequest { + fn serialize(self) -> [Field; SCOPED_NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH] { + array_concat(self.request.serialize(), [self.contract_address.to_field()]) } } -impl Deserialize for NullifierKeyValidationRequestContext { - fn deserialize(fields: [Field; NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_LENGTH]) -> Self { - Self { - master_nullifier_public_key: GrumpkinPoint::new(fields[0], fields[1]), - app_nullifier_secret_key: fields[2], +impl Deserialize for ScopedNullifierKeyValidationRequest { + fn deserialize(fields: [Field; SCOPED_NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH]) -> Self { + let mut reader = Reader::new(fields); + let res = Self { + request: reader.read_struct(NullifierKeyValidationRequest::deserialize), contract_address: AztecAddress::from_field(fields[3]), - } + }; + reader.finish(); + res } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/nullifier_leaf_preimage.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/nullifier_leaf_preimage.nr index 0dcba717633..2eaf66edc90 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/nullifier_leaf_preimage.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/nullifier_leaf_preimage.nr @@ -1,7 +1,7 @@ global NULLIFIER_LEAF_PREIMAGE_LENGTH: u64 = 3; use crate::{ - abis::{read_request::ReadRequestContext, side_effect::Readable}, hash::silo_nullifier, + abis::{read_request::ScopedReadRequest, side_effect::Readable}, hash::silo_nullifier, merkle_tree::leaf_preimage::{LeafPreimage, IndexedTreeLeafPreimage}, traits::{Empty, Hash} }; @@ -56,8 +56,8 @@ impl IndexedTreeLeafPreimage for NullifierLeafPreimage { } impl Readable for NullifierLeafPreimage { - fn assert_match_read_request(self, read_request: ReadRequestContext) { - let siloed_value = silo_nullifier(read_request.contract_address, read_request.value); + fn assert_match_read_request(self, read_request: ScopedReadRequest) { + let siloed_value = silo_nullifier(read_request.contract_address, read_request.value()); assert_eq(self.nullifier, siloed_value, "Value of the nullifier leaf does not match read request"); } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr index 652bceb0fe1..a24fd6e9881 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr @@ -85,6 +85,6 @@ fn empty_hash() { let hash = item.hash(); // Value from private_call_stack_item.test.ts "computes empty item hash" test - let test_data_empty_hash = 0x2485b8cfe671417410382ba6dfc803de70d9d45008a1b30c31b34d7c4de92106; + let test_data_empty_hash = 0x2a1bab3d40feb5234df51a7a6665998920119fd60f5c1e4d9ff3f1128a5f8f81; assert_eq(hash, test_data_empty_hash); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr index e48226fa1f4..fe7429aef2a 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr @@ -215,6 +215,6 @@ fn empty_hash() { let inputs = PrivateCircuitPublicInputs::empty(); let hash = inputs.hash(); // Value from private_circuit_public_inputs.test.ts "computes empty item hash" test - let test_data_empty_hash = 0x249d46b5a3e35f6489e793cd604e375634d4bfdac762ec06b5f8f03016bb4257; + let test_data_empty_hash = 0x09cc3ed80b2171f093828087431d66777514912b4e7baddb418ab5f1ddbbfd5a; assert_eq(hash, test_data_empty_hash); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_call_stack_item.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_call_stack_item.nr index bdd3aa1c570..8c24533dd6b 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_call_stack_item.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_call_stack_item.nr @@ -69,7 +69,7 @@ mod tests { let call_stack_item = PublicCallStackItem { contract_address, public_inputs, is_execution_request: true, function_data }; // Value from public_call_stack_item.test.ts "Computes a callstack item request hash" test - let test_data_call_stack_item_request_hash = 0x1595b195f0faa3a492109039dc807b291d0edd81a5e3a380866d5098ffd505dd; + let test_data_call_stack_item_request_hash = 0x1177a69fbc37f0ebdf290025414ff72504497840f174896bd427d0f30ec21c55; assert_eq(call_stack_item.hash(), test_data_call_stack_item_request_hash); } @@ -87,7 +87,7 @@ mod tests { let call_stack_item = PublicCallStackItem { contract_address, public_inputs, is_execution_request: false, function_data }; // Value from public_call_stack_item.test.ts "Computes a callstack item hash" test - let test_data_call_stack_item_hash = 0x1122a7d7e6174b7e5d111c8eb0233564d3a1ffd755afc7ce4b594d738e2770d7; + let test_data_call_stack_item_hash = 0x0f7624c0d5ea65fcec318c4d34cb3fcbf9c67435aebbf1548b3c90ef641424f8; assert_eq(call_stack_item.hash(), test_data_call_stack_item_hash); } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_circuit_public_inputs.nr index 41fadb37de3..aafdd024ec8 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_circuit_public_inputs.nr @@ -195,6 +195,6 @@ fn empty_hash() { let hash = inputs.hash(); // Value from public_circuit_public_inputs.test.ts "computes empty item hash" test - let test_data_empty_hash = 0x1a2da219bb2e3ac24519fd844365c4f656fc3ba8c58f2960706d25bceb4d1769; + let test_data_empty_hash = 0x132559f41b7adc7388e0cd52b91fd6837c296b2f9ec1b6d2ed046f7a56db18f8; assert_eq(hash, test_data_empty_hash); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/read_request.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/read_request.nr index 7bb0e0ffa42..5bea5734d80 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/read_request.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/read_request.nr @@ -1,25 +1,16 @@ use crate::{ - abis::side_effect::OrderedValue, traits::{Empty, Serialize, Deserialize}, address::AztecAddress, - constants::READ_REQUEST_LENGTH + traits::{Empty, Serialize, Deserialize}, address::AztecAddress, constants::READ_REQUEST_LENGTH, + utils::{arrays::array_concat, reader::Reader} }; use dep::std::cmp::Eq; -global READ_REQUEST_CONTEXT_SERIALIZED_LEN = 3; +global SCOPED_READ_REQUEST_SERIALIZED_LEN = READ_REQUEST_LENGTH + 1; struct ReadRequest { value: Field, counter: u32, } -impl OrderedValue for ReadRequest { - fn value(self) -> Field { - self.value - } - fn counter(self) -> u32 { - self.counter - } -} - impl Eq for ReadRequest { fn eq(self, read_request: ReadRequest) -> bool { (self.value == read_request.value) @@ -52,57 +43,55 @@ impl Deserialize for ReadRequest { } impl ReadRequest { - pub fn to_context(self, contract_address: AztecAddress) -> ReadRequestContext { - ReadRequestContext { value: self.value, counter: self.counter, contract_address } + pub fn scope(self, contract_address: AztecAddress) -> ScopedReadRequest { + ScopedReadRequest { read_request: self, contract_address } } } -struct ReadRequestContext { - value: Field, - counter: u32, +struct ScopedReadRequest { + read_request: ReadRequest, contract_address: AztecAddress, } -impl OrderedValue for ReadRequestContext { - fn value(self) -> Field { - self.value - } - fn counter(self) -> u32 { - self.counter - } -} - -impl Eq for ReadRequestContext { - fn eq(self, read_request: ReadRequestContext) -> bool { - (self.value == read_request.value) - & (self.counter == read_request.counter) - & (self.contract_address.eq(read_request.contract_address)) +impl Eq for ScopedReadRequest { + fn eq(self, other: ScopedReadRequest) -> bool { + (self.read_request == other.read_request) + & (self.contract_address.eq(other.contract_address)) } } -impl Empty for ReadRequestContext { +impl Empty for ScopedReadRequest { fn empty() -> Self { - ReadRequestContext { - value: 0, - counter: 0, + ScopedReadRequest { + read_request: ReadRequest::empty(), contract_address: AztecAddress::empty(), } } } -impl Serialize for ReadRequestContext { - fn serialize(self) -> [Field; READ_REQUEST_CONTEXT_SERIALIZED_LEN] { - [self.value, self.counter as Field, self.contract_address.to_field()] +impl Serialize for ScopedReadRequest { + fn serialize(self) -> [Field; SCOPED_READ_REQUEST_SERIALIZED_LEN] { + array_concat(self.read_request.serialize(), [self.contract_address.to_field()]) } } -impl Deserialize for ReadRequestContext { - fn deserialize(values: [Field; READ_REQUEST_CONTEXT_SERIALIZED_LEN]) -> Self { - Self { - value: values[0], - counter: values[1] as u32, +impl Deserialize for ScopedReadRequest { + fn deserialize(values: [Field; SCOPED_READ_REQUEST_SERIALIZED_LEN]) -> Self { + let mut reader = Reader::new(values); + let res = Self { + read_request: reader.read_struct(ReadRequest::deserialize), contract_address: AztecAddress::from_field(values[2]), - } + }; + reader.finish(); + res } } +impl ScopedReadRequest { + pub fn value(self) -> Field { + self.read_request.value + } + pub fn counter(self) -> u32 { + self.read_request.counter + } +} \ No newline at end of file diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/side_effect.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/side_effect.nr index 2f1de297ac4..78b54a59a0b 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/side_effect.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/side_effect.nr @@ -1,5 +1,5 @@ use crate::{ - abis::read_request::ReadRequestContext, address::AztecAddress, + abis::read_request::ScopedReadRequest, address::AztecAddress, constants::{GENERATOR_INDEX__SIDE_EFFECT, SIDE_EFFECT_LENGTH}, traits::{Empty, Hash, Serialize, Deserialize} }; @@ -15,7 +15,7 @@ trait OrderedValue where T: Eq { } trait Readable { - fn assert_match_read_request(self, read_request: ReadRequestContext); + fn assert_match_read_request(self, read_request: ScopedReadRequest); } struct SideEffect { diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests.nr index c49acd2e912..850afddbade 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests.nr @@ -1,8 +1,8 @@ use crate::{ abis::{ max_block_number::MaxBlockNumber, - nullifier_key_validation_request::NullifierKeyValidationRequestContext, - public_data_read::PublicDataRead, read_request::ReadRequestContext, + nullifier_key_validation_request::ScopedNullifierKeyValidationRequest, + public_data_read::PublicDataRead, read_request::ScopedReadRequest, validation_requests::rollup_validation_requests::RollupValidationRequests }, constants::{ @@ -15,9 +15,9 @@ use crate::{ // TODO - Use specific structs for private and public: PrivateValidationRequests vs PublicValidationRequests struct ValidationRequests { for_rollup: RollupValidationRequests, - note_hash_read_requests: [ReadRequestContext; MAX_NOTE_HASH_READ_REQUESTS_PER_TX], - nullifier_read_requests: [ReadRequestContext; MAX_NULLIFIER_READ_REQUESTS_PER_TX], - nullifier_non_existent_read_requests: [ReadRequestContext; MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX], - nullifier_key_validation_requests: [NullifierKeyValidationRequestContext; MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX], + note_hash_read_requests: [ScopedReadRequest; MAX_NOTE_HASH_READ_REQUESTS_PER_TX], + nullifier_read_requests: [ScopedReadRequest; MAX_NULLIFIER_READ_REQUESTS_PER_TX], + nullifier_non_existent_read_requests: [ScopedReadRequest; MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX], + nullifier_key_validation_requests: [ScopedNullifierKeyValidationRequest; MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX], public_data_reads: [PublicDataRead; MAX_PUBLIC_DATA_READS_PER_TX], } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests_builder.nr index 7aa661a9def..6fe9d71310a 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests_builder.nr @@ -1,8 +1,8 @@ use crate::{ abis::{ max_block_number::MaxBlockNumber, - nullifier_key_validation_request::NullifierKeyValidationRequestContext, - public_data_read::PublicDataRead, read_request::ReadRequestContext, + nullifier_key_validation_request::ScopedNullifierKeyValidationRequest, + public_data_read::PublicDataRead, read_request::ScopedReadRequest, validation_requests::validation_requests::ValidationRequests, validation_requests::rollup_validation_requests::RollupValidationRequests }, @@ -16,10 +16,10 @@ use crate::{ struct ValidationRequestsBuilder { max_block_number: MaxBlockNumber, - note_hash_read_requests: BoundedVec, - nullifier_read_requests: BoundedVec, - nullifier_non_existent_read_requests: BoundedVec, - nullifier_key_validation_requests: BoundedVec, + note_hash_read_requests: BoundedVec, + nullifier_read_requests: BoundedVec, + nullifier_non_existent_read_requests: BoundedVec, + nullifier_key_validation_requests: BoundedVec, public_data_reads: 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 254d07a3e0b..5e1631cc24d 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -155,15 +155,17 @@ global FUNCTION_LEAF_PREIMAGE_LENGTH: u64 = 5; global GLOBAL_VARIABLES_LENGTH: u64 = 6 + GAS_FEES_LENGTH; global APPEND_ONLY_TREE_SNAPSHOT_LENGTH = 2; global L1_TO_L2_MESSAGE_LENGTH: u64 = 6; -global L2_TO_L1_MESSAGE_LENGTH: u64 = 2; +global L2_TO_L1_MESSAGE_LENGTH: u64 = 3; +global SCOPED_L2_TO_L1_MESSAGE_LENGTH = L2_TO_L1_MESSAGE_LENGTH + 1; global MAX_BLOCK_NUMBER_LENGTH: u64 = 2; // 1 for the option flag, 1 for the value global NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH = 3; -global NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_LENGTH = 4; +global SCOPED_NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH = NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH + 1; global PARTIAL_STATE_REFERENCE_LENGTH: u64 = 6; global READ_REQUEST_LENGTH = 2; global NOTE_HASH_LENGTH = 2; -global NOTE_HASH_CONTEXT_LENGTH = 3; +global SCOPED_NOTE_HASH_LENGTH = NOTE_HASH_LENGTH + 2; global NULLIFIER_LENGTH = 3; +global SCOPED_NULLIFIER_LENGTH = NULLIFIER_LENGTH + 1; global SIDE_EFFECT_LENGTH = 2; global STATE_REFERENCE_LENGTH: u64 = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH; global TX_CONTEXT_LENGTH: u64 = 2 + GAS_SETTINGS_LENGTH; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr b/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr index 31740a66be7..efb7f6b38c3 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr @@ -202,7 +202,7 @@ fn compute_l2_l1_hash() { assert(hash_result == 0xb393978842a0fa3d3e1470196f098f473f9678e72463cb65ec4ab5581856c2); // Non-zero case - let message = L2ToL1Message { recipient: EthAddress::from_field(3), content: 5 }; + let message = L2ToL1Message { recipient: EthAddress::from_field(3), content: 5, counter: 1234 }; let hash_result = compute_l2_to_l1_hash(AztecAddress::from_field(1), 2, 4, message); assert(hash_result == 0x3f88c1044a05e5340ed20466276500f6d45ca5603913b9091e957161734e16); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/messaging/l2_to_l1_message.nr b/noir-projects/noir-protocol-circuits/crates/types/src/messaging/l2_to_l1_message.nr index 928239bf935..8f21f8e2c77 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/messaging/l2_to_l1_message.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/messaging/l2_to_l1_message.nr @@ -1,9 +1,14 @@ -use crate::{address::EthAddress, constants::L2_TO_L1_MESSAGE_LENGTH, traits::{Deserialize, Empty, Serialize}}; +use crate::{ + address::{AztecAddress, EthAddress}, + constants::{L2_TO_L1_MESSAGE_LENGTH, SCOPED_L2_TO_L1_MESSAGE_LENGTH}, abis::side_effect::Ordered, + traits::{Deserialize, Empty, Serialize}, utils::{arrays::array_concat, reader::Reader} +}; // Note: Not to be confused with L2ToL1Msg in Solidity struct L2ToL1Message { recipient: EthAddress, content: Field, + counter: u32, } impl Empty for L2ToL1Message { @@ -11,19 +16,20 @@ impl Empty for L2ToL1Message { Self { recipient: EthAddress::empty(), content: 0, + counter: 0, } } } impl Eq for L2ToL1Message { fn eq(self, other: Self) -> bool { - (self.recipient == other.recipient) & (self.content == other.content) + (self.recipient == other.recipient) & (self.content == other.content) & (self.counter == other.counter) } } impl Serialize for L2ToL1Message { fn serialize(self) -> [Field; L2_TO_L1_MESSAGE_LENGTH] { - [self.recipient.to_field(), self.content] + [self.recipient.to_field(), self.content, self.counter as Field] } } @@ -32,6 +38,58 @@ impl Deserialize for L2ToL1Message { Self { recipient: EthAddress::from_field(values[0]), content: values[1], + counter: values[2] as u32, } } } + +impl L2ToL1Message { + pub fn scope(self, contract_address: AztecAddress) -> ScopedL2ToL1Message { + ScopedL2ToL1Message { message: self, contract_address } + } +} + +struct ScopedL2ToL1Message { + message: L2ToL1Message, + contract_address: AztecAddress, +} + +impl Ordered for ScopedL2ToL1Message { + fn counter(self) -> u32 { + self.message.counter + } +} + +impl Eq for ScopedL2ToL1Message { + fn eq(self, other: ScopedL2ToL1Message) -> bool { + (self.message == other.message) + & (self.contract_address == other.contract_address) + } +} + +impl Empty for ScopedL2ToL1Message { + fn empty() -> Self { + ScopedL2ToL1Message { + message: L2ToL1Message::empty(), + contract_address: AztecAddress::empty(), + } + } +} + +impl Serialize for ScopedL2ToL1Message { + fn serialize(self) -> [Field; SCOPED_L2_TO_L1_MESSAGE_LENGTH] { + array_concat(self.message.serialize(), [self.contract_address.to_field()]) + } +} + +impl Deserialize for ScopedL2ToL1Message { + fn deserialize(values: [Field; SCOPED_L2_TO_L1_MESSAGE_LENGTH]) -> Self { + let mut reader = Reader::new(values); + let res = Self { + message: reader.read_struct(L2ToL1Message::deserialize), + contract_address: reader.read_struct(AztecAddress::deserialize), + }; + reader.finish(); + res + } +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr index 189e3aeecfe..077007c2b5a 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr @@ -6,13 +6,13 @@ use crate::{ global_variables::GlobalVariables, combined_constant_data::CombinedConstantData, kernel_circuit_public_inputs::{KernelCircuitPublicInputs, PrivateKernelCircuitPublicInputs, PublicKernelCircuitPublicInputs}, kernel_data::{PrivateKernelData, PublicKernelData, KernelData}, max_block_number::MaxBlockNumber, - note_hash::NoteHashContext, nullifier::Nullifier, - nullifier_key_validation_request::NullifierKeyValidationRequestContext, + note_hash::{NoteHash, ScopedNoteHash}, nullifier::{Nullifier, ScopedNullifier}, + nullifier_key_validation_request::ScopedNullifierKeyValidationRequest, public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, - read_request::ReadRequestContext, side_effect::SideEffect, + read_request::{ReadRequest, ScopedReadRequest}, side_effect::SideEffect, validation_requests::{ValidationRequests, ValidationRequestsBuilder} }, - address::AztecAddress, + address::{AztecAddress, EthAddress}, constants::{ MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, MAX_PUBLIC_DATA_READS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, @@ -21,7 +21,8 @@ use crate::{ MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, VK_TREE_HEIGHT, MAX_ENCRYPTED_LOGS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX }, - hash::{silo_note_hash, silo_nullifier}, header::Header, + hash::silo_nullifier, header::Header, + messaging::l2_to_l1_message::{L2ToL1Message, ScopedL2ToL1Message}, mocked::{AggregationObject, Proof, VerificationKey}, partial_state_reference::PartialStateReference, tests::fixtures, transaction::tx_context::TxContext, traits::Empty }; @@ -37,9 +38,9 @@ struct FixtureBuilder { public_teardown_call_request: CallRequest, // Accumulated data. - new_note_hashes: BoundedVec, - new_nullifiers: BoundedVec, - new_l2_to_l1_msgs: BoundedVec, + new_note_hashes: BoundedVec, + new_nullifiers: BoundedVec, + new_l2_to_l1_msgs: BoundedVec, encrypted_logs_hashes: BoundedVec, unencrypted_logs_hashes: BoundedVec, encrypted_logs_hash: Field, @@ -54,10 +55,10 @@ struct FixtureBuilder { // Validation requests. max_block_number: MaxBlockNumber, - note_hash_read_requests: BoundedVec, - nullifier_read_requests: BoundedVec, - nullifier_non_existent_read_requests: BoundedVec, - nullifier_key_validation_requests: BoundedVec, + note_hash_read_requests: BoundedVec, + nullifier_read_requests: BoundedVec, + nullifier_non_existent_read_requests: BoundedVec, + nullifier_key_validation_requests: BoundedVec, public_data_reads: BoundedVec, // Proof. @@ -142,9 +143,9 @@ impl FixtureBuilder { pub fn to_public_accumulated_data(self) -> PublicAccumulatedData { PublicAccumulatedData { - new_note_hashes: self.new_note_hashes.storage.map(|n: NoteHashContext| n.to_note_hash()), - new_nullifiers: self.new_nullifiers.storage, - new_l2_to_l1_msgs: self.new_l2_to_l1_msgs.storage, + new_note_hashes: self.new_note_hashes.storage.map(|n: ScopedNoteHash| n.note_hash), + new_nullifiers: self.new_nullifiers.storage.map(|n: ScopedNullifier| n.nullifier), + new_l2_to_l1_msgs: self.new_l2_to_l1_msgs.storage.map(|m: ScopedL2ToL1Message| m.message.content), encrypted_logs_hashes: self.encrypted_logs_hashes.storage, unencrypted_logs_hashes: self.unencrypted_logs_hashes.storage, encrypted_log_preimages_length: self.encrypted_log_preimages_length, @@ -157,9 +158,9 @@ impl FixtureBuilder { pub fn to_combined_accumulated_data(self) -> CombinedAccumulatedData { CombinedAccumulatedData { - new_note_hashes: self.new_note_hashes.storage.map(|n: NoteHashContext| n.value), - new_nullifiers: self.new_nullifiers.storage.map(|n: Nullifier| n.value), - new_l2_to_l1_msgs: self.new_l2_to_l1_msgs.storage, + new_note_hashes: self.new_note_hashes.storage.map(|n: ScopedNoteHash| n.note_hash.value), + new_nullifiers: self.new_nullifiers.storage.map(|n: ScopedNullifier| n.nullifier.value), + new_l2_to_l1_msgs: self.new_l2_to_l1_msgs.storage.map(|m: ScopedL2ToL1Message| m.message.content), encrypted_logs_hash: self.encrypted_logs_hash, unencrypted_logs_hash: self.unencrypted_logs_hash, encrypted_log_preimages_length: self.encrypted_log_preimages_length, @@ -253,7 +254,7 @@ impl FixtureBuilder { } pub fn add_new_note_hash(&mut self, value: Field) { - self.new_note_hashes.push(NoteHashContext { value, counter: self.next_counter(), nullifier_counter: 0 }); + self.new_note_hashes.push(NoteHash { value, counter: self.next_counter() }.scope(0, self.storage_contract_address)); } pub fn append_new_note_hashes(&mut self, num_new_note_hashes: u64) { @@ -261,15 +262,20 @@ impl FixtureBuilder { for i in 0..MAX_NEW_NOTE_HASHES_PER_TX { if i < num_new_note_hashes { let mocked_value = self.get_mocked_note_hash_value(index_offset + i); - let value = silo_note_hash(self.storage_contract_address, mocked_value); - self.add_new_note_hash(value); + self.add_new_note_hash(mocked_value); } } } - pub fn add_nullifier(&mut self, unsiloed_nullifier: Field) { - let value = silo_nullifier(self.storage_contract_address, unsiloed_nullifier); - self.new_nullifiers.push(Nullifier { value, note_hash: 0, counter: self.next_counter() }); + pub fn add_nullifier(&mut self, value: Field) { + self.new_nullifiers.push( + Nullifier { value, counter: self.next_counter(), note_hash: 0 }.scope(self.storage_contract_address) + ); + } + + pub fn add_siloed_nullifier(&mut self, value: Field) { + let siloed_value = silo_nullifier(self.storage_contract_address, value); + self.add_nullifier(siloed_value); } pub fn append_new_nullifiers(&mut self, num_extra_nullifier: u64) { @@ -282,6 +288,22 @@ impl FixtureBuilder { } } + pub fn append_siloed_nullifiers(&mut self, num_extra_nullifier: u64) { + let index_offset = self.new_nullifiers.len(); + for i in 0..MAX_NEW_NULLIFIERS_PER_TX { + if i < num_extra_nullifier { + let mocked_value = self.get_mocked_nullifier_value(index_offset + i); + self.add_siloed_nullifier(mocked_value); + } + } + } + + pub fn add_l2_to_l1_message(&mut self, content: Field, recipient: EthAddress) { + self.new_l2_to_l1_msgs.push( + L2ToL1Message { recipient, content, counter: self.next_counter() }.scope(self.storage_contract_address) + ); + } + pub fn add_public_data_update_request(&mut self, leaf_slot: Field, value: Field) { let update_request = PublicDataUpdateRequest { leaf_slot, new_value: value }; self.public_data_update_requests.push(update_request); @@ -319,7 +341,7 @@ impl FixtureBuilder { pub fn add_read_request_for_pending_note_hash(&mut self, note_hash_index: u64) -> u64 { let read_request_index = self.note_hash_read_requests.len(); let value = self.get_mocked_note_hash_value(note_hash_index); - let read_request = ReadRequestContext { value, counter: self.next_counter(), contract_address: self.storage_contract_address }; + let read_request = ReadRequest { value, counter: self.next_counter() }.scope(self.storage_contract_address); self.note_hash_read_requests.push(read_request); read_request_index } @@ -328,11 +350,7 @@ impl FixtureBuilder { let value_offset = self.note_hash_read_requests.len(); for i in 0..MAX_NOTE_HASH_READ_REQUESTS_PER_TX { if i < num_reads { - let read_request = ReadRequestContext { - value: (value_offset + i + 789) as Field, - counter: self.next_counter(), - contract_address: self.storage_contract_address - }; + let read_request = ReadRequest { value: (value_offset + i + 789) as Field, counter: self.next_counter() }.scope(self.storage_contract_address); self.note_hash_read_requests.push(read_request); } } @@ -340,22 +358,14 @@ impl FixtureBuilder { pub fn add_read_request_for_pending_nullifier(&mut self, nullifier_index: u64) -> u64 { let read_request_index = self.nullifier_read_requests.len(); - let unsiloed_nullifier = self.get_mocked_nullifier_value(nullifier_index); - let read_request = ReadRequestContext { - value: unsiloed_nullifier, - counter: self.next_counter(), - contract_address: self.storage_contract_address - }; + let nullifier = self.get_mocked_nullifier_value(nullifier_index); + let read_request = ReadRequest { value: nullifier, counter: self.next_counter() }.scope(self.storage_contract_address); self.nullifier_read_requests.push(read_request); read_request_index } - pub fn add_non_existent_read_request_for_nullifier(&mut self, unsiloed_nullifier: Field) { - let read_request = ReadRequestContext { - value: unsiloed_nullifier, - counter: self.next_counter(), - contract_address: self.storage_contract_address - }; + pub fn add_non_existent_read_request_for_nullifier(&mut self, nullifier: Field) { + let read_request = ReadRequest { value: nullifier, counter: self.next_counter() }.scope(self.storage_contract_address); self.nullifier_non_existent_read_requests.push(read_request); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays.nr b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays.nr index 4de0a338525..52c277355c8 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays.nr @@ -75,6 +75,18 @@ pub fn array_cp(array: [T; N]) -> [T; S] where T: Empty { result } +pub fn array_concat(array1: [T; N], array2: [T; M]) -> [T; S] { + assert_eq(N + M, S, "combined array length does not match return array length"); + let mut result = [array1[0]; S]; + for i in 1..N { + result[i] = array1[i]; + } + for i in 0..M { + result[i + N] = array2[i]; + } + result +} + pub fn array_merge(array1: [T; N], array2: [T; N]) -> [T; N] where T: Empty + Eq { let mut result: [T; N] = [T::empty(); N]; let mut i = 0; @@ -195,6 +207,21 @@ fn find_index_not_found() { assert_eq(index, 4); } +#[test] +fn test_array_concat() { + let array0 = [1, 2, 3]; + let array1 = [4, 5]; + let concated = array_concat(array0, array1); + assert_eq(concated, [1, 2, 3, 4, 5]); +} + +#[test(should_fail_with="combined array length does not match return array length")] +fn array_concat_fails_inconsistent_lengths() { + let array0 = [1, 2, 3]; + let array1 = [4, 5]; + let _concated: [Field; 4] = array_concat(array0, array1); +} + #[test] fn check_permutation_basic_test() { let original_array = [1, 2, 3]; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/utils/reader.nr b/noir-projects/noir-protocol-circuits/crates/types/src/utils/reader.nr index dffc118e7d8..4f1b5ab95a1 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/utils/reader.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/utils/reader.nr @@ -14,6 +14,10 @@ impl Reader { result } + pub fn read_u32(&mut self) -> u32 { + self.read() as u32 + } + pub fn read_array(&mut self, mut result: [Field; K]) -> [Field; K] { for i in 0..K { result[i] = self.data[self.offset + i]; diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index 4028ddd3594..1748ff51de3 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -33,8 +33,6 @@ import { type Header, INITIAL_L2_BLOCK_NUM, type L1_TO_L2_MSG_TREE_HEIGHT, - L2_TO_L1_MESSAGE_LENGTH, - MAX_NEW_L2_TO_L1_MSGS_PER_TX, type NOTE_HASH_TREE_HEIGHT, type NULLIFIER_TREE_HEIGHT, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, @@ -45,7 +43,6 @@ import { import { computePublicDataTreeLeafSlot } from '@aztec/circuits.js/hash'; import { type L1ContractAddresses, createEthereumChain } from '@aztec/ethereum'; import { AztecAddress } from '@aztec/foundation/aztec-address'; -import { padArrayEnd } from '@aztec/foundation/collection'; import { createDebugLogger } from '@aztec/foundation/log'; import { type AztecKVStore } from '@aztec/kv-store'; import { AztecLmdbStore } from '@aztec/kv-store/lmdb'; @@ -454,11 +451,7 @@ export class AztecNodeService implements AztecNode { throw new Error('Block is not defined'); } - // We multiply the number of messages per block by the length of each message because each message occupies - // 2 leaves in the tree! - const l2ToL1Messages = block.body.txEffects.flatMap(txEffect => - padArrayEnd(txEffect.l2ToL1Msgs, Fr.ZERO, MAX_NEW_L2_TO_L1_MSGS_PER_TX * L2_TO_L1_MESSAGE_LENGTH), - ); + const l2ToL1Messages = block.body.txEffects.flatMap(txEffect => txEffect.l2ToL1Msgs); const indexOfL2ToL1Message = BigInt( l2ToL1Messages.findIndex(l2ToL1MessageInBlock => l2ToL1MessageInBlock.equals(l2ToL1Message)), @@ -468,7 +461,8 @@ export class AztecNodeService implements AztecNode { throw new Error('The L2ToL1Message you are trying to prove inclusion of does not exist'); } - const treeHeight = Math.ceil(Math.log2(l2ToL1Messages.length)); + // Match how l2ToL1TreeHeight is calculated in Rollup.sol. + const treeHeight = block.header.contentCommitment.txTreeHeight.toNumber() + 1; // The root of this tree is the out_hash calculated in Noir => we truncate to match Noir's SHA const tree = new StandardTree( openTmpStore(true), diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index b7eef53b018..8e143fd70ca 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -98,15 +98,17 @@ export const FUNCTION_LEAF_PREIMAGE_LENGTH = 5; export const GLOBAL_VARIABLES_LENGTH = 6 + GAS_FEES_LENGTH; export const APPEND_ONLY_TREE_SNAPSHOT_LENGTH = 2; export const L1_TO_L2_MESSAGE_LENGTH = 6; -export const L2_TO_L1_MESSAGE_LENGTH = 2; +export const L2_TO_L1_MESSAGE_LENGTH = 3; +export const SCOPED_L2_TO_L1_MESSAGE_LENGTH = L2_TO_L1_MESSAGE_LENGTH + 1; export const MAX_BLOCK_NUMBER_LENGTH = 2; export const NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH = 3; -export const NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_LENGTH = 4; +export const SCOPED_NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH = NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH + 1; export const PARTIAL_STATE_REFERENCE_LENGTH = 6; export const READ_REQUEST_LENGTH = 2; export const NOTE_HASH_LENGTH = 2; -export const NOTE_HASH_CONTEXT_LENGTH = 3; +export const SCOPED_NOTE_HASH_LENGTH = NOTE_HASH_LENGTH + 2; export const NULLIFIER_LENGTH = 3; +export const SCOPED_NULLIFIER_LENGTH = NULLIFIER_LENGTH + 1; export const SIDE_EFFECT_LENGTH = 2; export const STATE_REFERENCE_LENGTH = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH; export const TX_CONTEXT_LENGTH = 2 + GAS_SETTINGS_LENGTH; diff --git a/yarn-project/circuits.js/src/hints/build_note_hash_read_request_hints.test.ts b/yarn-project/circuits.js/src/hints/build_note_hash_read_request_hints.test.ts index 7c2f508e4fb..fa15e1b15ed 100644 --- a/yarn-project/circuits.js/src/hints/build_note_hash_read_request_hints.test.ts +++ b/yarn-project/circuits.js/src/hints/build_note_hash_read_request_hints.test.ts @@ -6,12 +6,14 @@ import { type Tuple } from '@aztec/foundation/serialize'; import { MAX_NEW_NOTE_HASHES_PER_TX, MAX_NOTE_HASH_READ_REQUESTS_PER_TX } from '../constants.gen.js'; import { siloNoteHash } from '../hash/index.js'; import { - NoteHashContext, + NoteHash, type NoteHashReadRequestHints, NoteHashReadRequestHintsBuilder, PendingReadHint, - ReadRequestContext, + ReadRequest, ReadRequestStatus, + type ScopedNoteHash, + ScopedReadRequest, SettledReadHint, } from '../structs/index.js'; import { buildNoteHashReadRequestHints } from './build_note_hash_read_request_hints.js'; @@ -25,8 +27,8 @@ describe('buildNoteHashReadRequestHints', () => { getNoteHashMembershipWitness: (leafIndex: bigint) => settledLeafIndexes.includes(leafIndex) ? ({} as any) : undefined, }; - let noteHashReadRequests: Tuple; - let noteHashes: Tuple; + let noteHashReadRequests: Tuple; + let noteHashes: Tuple; let noteHashLeafIndexMap: Map = new Map(); let expectedHints: NoteHashReadRequestHints; let numReadRequests = 0; @@ -36,12 +38,9 @@ describe('buildNoteHashReadRequestHints', () => { const innerNoteHash = (index: number) => index + 9999; const makeReadRequest = (value: number, counter = 2) => - new ReadRequestContext(new Fr(value), counter, contractAddress); + new ReadRequest(new Fr(value), counter).scope(contractAddress); - function makeNoteHash(value: number, counter = 1) { - const siloedValue = siloNoteHash(contractAddress, new Fr(value)); - return new NoteHashContext(siloedValue, counter, 0); - } + const makeNoteHash = (value: number, counter = 1) => new NoteHash(new Fr(value), counter).scope(0, contractAddress); const readPendingNoteHash = ({ noteHashIndex, @@ -68,7 +67,7 @@ describe('buildNoteHashReadRequestHints', () => { } = {}) => { const value = settledNoteHashes[hintIndex]; noteHashLeafIndexMap.set(value.toBigInt(), settledLeafIndexes[hintIndex]); - noteHashReadRequests[readRequestIndex] = new ReadRequestContext(value, 1, contractAddress); + noteHashReadRequests[readRequestIndex] = new ReadRequest(value, 1).scope(contractAddress); expectedHints.readRequestStatuses[readRequestIndex] = ReadRequestStatus.settled(hintIndex); expectedHints.settledReadHints[hintIndex] = new SettledReadHint(readRequestIndex, {} as any, value); numReadRequests++; @@ -79,7 +78,7 @@ describe('buildNoteHashReadRequestHints', () => { buildNoteHashReadRequestHints(oracle, noteHashReadRequests, noteHashes, noteHashLeafIndexMap); beforeEach(() => { - noteHashReadRequests = makeTuple(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, ReadRequestContext.empty); + noteHashReadRequests = makeTuple(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, ScopedReadRequest.empty); noteHashes = makeTuple(MAX_NEW_NOTE_HASHES_PER_TX, i => makeNoteHash(innerNoteHash(i))); noteHashLeafIndexMap = new Map(); expectedHints = NoteHashReadRequestHintsBuilder.empty(); @@ -121,7 +120,7 @@ describe('buildNoteHashReadRequestHints', () => { it('throws if cannot find a match in pending set and in the tree', async () => { readPendingNoteHash({ noteHashIndex: 2 }); // Tweak the value of the read request. - noteHashReadRequests[0].value = new Fr(123); + noteHashReadRequests[0].readRequest.value = new Fr(123); await expect(() => buildHints()).rejects.toThrow('Read request is reading an unknown note hash.'); }); }); diff --git a/yarn-project/circuits.js/src/hints/build_note_hash_read_request_hints.ts b/yarn-project/circuits.js/src/hints/build_note_hash_read_request_hints.ts index 0364333d56e..4fc62f76216 100644 --- a/yarn-project/circuits.js/src/hints/build_note_hash_read_request_hints.ts +++ b/yarn-project/circuits.js/src/hints/build_note_hash_read_request_hints.ts @@ -5,20 +5,18 @@ import { type MAX_NOTE_HASH_READ_REQUESTS_PER_TX, type NOTE_HASH_TREE_HEIGHT, } from '../constants.gen.js'; -import { siloNoteHash } from '../hash/index.js'; import { type MembershipWitness, - type NoteHashContext, NoteHashReadRequestHintsBuilder, - type ReadRequestContext, + type ScopedNoteHash, + type ScopedReadRequest, } from '../structs/index.js'; import { countAccumulatedItems, getNonEmptyItems } from '../utils/index.js'; -function isValidNoteHashReadRequest(readRequest: ReadRequestContext, noteHash: NoteHashContext) { - // TODO(#6122) +function isValidNoteHashReadRequest(readRequest: ScopedReadRequest, noteHash: ScopedNoteHash) { return ( - // noteHash.value.equals(readRequest.value) && - noteHash.counter < readRequest.counter && + noteHash.contractAddress.equals(readRequest.contractAddress) && + readRequest.counter > noteHash.counter && (noteHash.nullifierCounter === 0 || noteHash.nullifierCounter > readRequest.counter) ); } @@ -27,15 +25,15 @@ export async function buildNoteHashReadRequestHints( oracle: { getNoteHashMembershipWitness(leafIndex: bigint): Promise>; }, - noteHashReadRequests: Tuple, - noteHashes: Tuple, + noteHashReadRequests: Tuple, + noteHashes: Tuple, noteHashLeafIndexMap: Map, ) { const builder = new NoteHashReadRequestHintsBuilder(); const numReadRequests = countAccumulatedItems(noteHashReadRequests); - const noteHashMap: Map = new Map(); + const noteHashMap: Map = new Map(); getNonEmptyItems(noteHashes).forEach((noteHash, index) => { const value = noteHash.value.toBigInt(); const arr = noteHashMap.get(value) ?? []; @@ -45,17 +43,15 @@ export async function buildNoteHashReadRequestHints( for (let i = 0; i < numReadRequests; ++i) { const readRequest = noteHashReadRequests[i]; - // TODO(#2847): Read request value shouldn't have been siloed by apps. const value = readRequest.value; - // But reads for transient note hash are not siloed. - const siloedValue = siloNoteHash(readRequest.contractAddress, readRequest.value); const pendingNoteHash = noteHashMap - .get(siloedValue.toBigInt()) + .get(value.toBigInt()) ?.find(n => isValidNoteHashReadRequest(readRequest, n.noteHash)); if (pendingNoteHash !== undefined) { builder.addPendingReadRequest(i, pendingNoteHash.index); } else { + // TODO(#2847): Read request value for settled note hash shouldn't have been siloed by apps. const leafIndex = noteHashLeafIndexMap.get(value.toBigInt()); if (leafIndex === undefined) { throw new Error('Read request is reading an unknown note hash.'); diff --git a/yarn-project/circuits.js/src/hints/build_nullifier_non_existent_read_request_hints.test.ts b/yarn-project/circuits.js/src/hints/build_nullifier_non_existent_read_request_hints.test.ts index 7d4040e35c8..89a2fb7ed6d 100644 --- a/yarn-project/circuits.js/src/hints/build_nullifier_non_existent_read_request_hints.test.ts +++ b/yarn-project/circuits.js/src/hints/build_nullifier_non_existent_read_request_hints.test.ts @@ -5,7 +5,12 @@ import { Fr } from '@aztec/foundation/fields'; import { MAX_NEW_NULLIFIERS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX } from '../constants.gen.js'; import { siloNullifier } from '../hash/index.js'; -import { Nullifier, NullifierNonExistentReadRequestHintsBuilder, ReadRequestContext } from '../structs/index.js'; +import { + Nullifier, + NullifierNonExistentReadRequestHintsBuilder, + ReadRequest, + ScopedReadRequest, +} from '../structs/index.js'; import { buildNullifierNonExistentReadRequestHints } from './build_nullifier_non_existent_read_request_hints.js'; describe('buildNullifierNonExistentReadRequestHints', () => { @@ -13,13 +18,13 @@ describe('buildNullifierNonExistentReadRequestHints', () => { const oracle = { getLowNullifierMembershipWitness: () => ({ membershipWitness: {}, leafPreimage: {} } as any), }; - const nonExistentReadRequests = makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ReadRequestContext.empty); + const nonExistentReadRequests = makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ScopedReadRequest.empty); let nullifiers = makeTuple(MAX_NEW_NULLIFIERS_PER_TX, Nullifier.empty); const innerNullifier = (index: number) => index + 1; const makeReadRequest = (value: number, counter = 2) => - new ReadRequestContext(new Fr(value), counter, contractAddress); + new ReadRequest(new Fr(value), counter).scope(contractAddress); const makeNullifier = (value: number, counter = 1) => { const siloedValue = siloNullifier(contractAddress, new Fr(value)); diff --git a/yarn-project/circuits.js/src/hints/build_nullifier_non_existent_read_request_hints.ts b/yarn-project/circuits.js/src/hints/build_nullifier_non_existent_read_request_hints.ts index c2f65701402..5bb6fa3eb76 100644 --- a/yarn-project/circuits.js/src/hints/build_nullifier_non_existent_read_request_hints.ts +++ b/yarn-project/circuits.js/src/hints/build_nullifier_non_existent_read_request_hints.ts @@ -12,7 +12,7 @@ import { siloNullifier } from '../hash/index.js'; import { Nullifier } from '../structs/index.js'; import { type MembershipWitness } from '../structs/membership_witness.js'; import { NullifierNonExistentReadRequestHintsBuilder } from '../structs/non_existent_read_request_hints.js'; -import { type ReadRequestContext } from '../structs/read_request.js'; +import { type ScopedReadRequest } from '../structs/read_request.js'; import { countAccumulatedItems } from '../utils/index.js'; interface NullifierMembershipWitnessWithPreimage { @@ -53,7 +53,7 @@ export async function buildNullifierNonExistentReadRequestHints( oracle: { getLowNullifierMembershipWitness(nullifier: Fr): Promise; }, - nullifierNonExistentReadRequests: Tuple, + nullifierNonExistentReadRequests: Tuple, pendingNullifiers: Tuple, ) { const { sortedValues, sortedIndexHints } = sortNullifiersByValues(pendingNullifiers); diff --git a/yarn-project/circuits.js/src/hints/build_nullifier_read_request_hints.test.ts b/yarn-project/circuits.js/src/hints/build_nullifier_read_request_hints.test.ts index 5297a84f5ad..bec3d9d5a8b 100644 --- a/yarn-project/circuits.js/src/hints/build_nullifier_read_request_hints.test.ts +++ b/yarn-project/circuits.js/src/hints/build_nullifier_read_request_hints.test.ts @@ -4,15 +4,16 @@ import { Fr } from '@aztec/foundation/fields'; import { type Tuple } from '@aztec/foundation/serialize'; import { MAX_NEW_NULLIFIERS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX } from '../constants.gen.js'; -import { siloNullifier } from '../hash/index.js'; import { Nullifier, type NullifierReadRequestHints, NullifierReadRequestHintsBuilder, PendingReadHint, - ReadRequestContext, + ReadRequest, ReadRequestState, ReadRequestStatus, + type ScopedNullifier, + ScopedReadRequest, SettledReadHint, } from '../structs/index.js'; import { buildNullifierReadRequestHints } from './build_nullifier_read_request_hints.js'; @@ -23,8 +24,8 @@ describe('buildNullifierReadRequestHints', () => { const oracle = { getNullifierMembershipWitness: () => ({ membershipWitness: {}, leafPreimage: {} } as any), }; - let nullifierReadRequests: Tuple; - let nullifiers: Tuple; + let nullifierReadRequests: Tuple; + let nullifiers: Tuple; let expectedHints: NullifierReadRequestHints; let numReadRequests = 0; let numPendingReads = 0; @@ -33,12 +34,10 @@ describe('buildNullifierReadRequestHints', () => { const innerNullifier = (index: number) => index + 1; const makeReadRequest = (value: number, counter = 2) => - new ReadRequestContext(new Fr(value), counter, contractAddress); + new ReadRequest(new Fr(value), counter).scope(contractAddress); - function makeNullifier(value: number, counter = 1) { - const siloedValue = siloNullifier(contractAddress, new Fr(value)); - return new Nullifier(siloedValue, counter, Fr.ZERO); - } + const makeNullifier = (value: number, counter = 1) => + new Nullifier(new Fr(value), counter, Fr.ZERO).scope(contractAddress); const readPendingNullifier = ({ nullifierIndex, @@ -73,7 +72,7 @@ describe('buildNullifierReadRequestHints', () => { const buildHints = () => buildNullifierReadRequestHints(oracle, nullifierReadRequests, nullifiers); beforeEach(() => { - nullifierReadRequests = makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ReadRequestContext.empty); + nullifierReadRequests = makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ScopedReadRequest.empty); nullifiers = makeTuple(MAX_NEW_NULLIFIERS_PER_TX, i => makeNullifier(innerNullifier(i))); expectedHints = NullifierReadRequestHintsBuilder.empty(); numReadRequests = 0; diff --git a/yarn-project/circuits.js/src/hints/build_nullifier_read_request_hints.ts b/yarn-project/circuits.js/src/hints/build_nullifier_read_request_hints.ts index 3b17bd9d3b5..9a1cbb38ae8 100644 --- a/yarn-project/circuits.js/src/hints/build_nullifier_read_request_hints.ts +++ b/yarn-project/circuits.js/src/hints/build_nullifier_read_request_hints.ts @@ -1,20 +1,24 @@ +import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { padArrayEnd } from '@aztec/foundation/collection'; import { type Fr } from '@aztec/foundation/fields'; import { type Tuple } from '@aztec/foundation/serialize'; import { type IndexedTreeLeafPreimage } from '@aztec/foundation/trees'; import { type MAX_NEW_NULLIFIERS_PER_TX, - type MAX_NULLIFIER_READ_REQUESTS_PER_TX, + MAX_NULLIFIER_READ_REQUESTS_PER_TX, type NULLIFIER_TREE_HEIGHT, } from '../constants.gen.js'; -import { siloNullifier } from '../hash/index.js'; +import { siloNullifier } from '../hash/hash.js'; import { type MembershipWitness, - type Nullifier, + Nullifier, NullifierReadRequestHintsBuilder, - type ReadRequestContext, + ReadRequest, + type ScopedNullifier, + ScopedReadRequest, } from '../structs/index.js'; -import { countAccumulatedItems } from '../utils/index.js'; +import { countAccumulatedItems, getNonEmptyItems } from '../utils/index.js'; interface NullifierMembershipWitnessWithPreimage { membershipWitness: MembershipWitness; @@ -25,26 +29,36 @@ export async function buildNullifierReadRequestHints( oracle: { getNullifierMembershipWitness(nullifier: Fr): Promise; }, - nullifierReadRequests: Tuple, - nullifiers: Tuple, + nullifierReadRequests: Tuple, + nullifiers: Tuple, + siloed = false, ) { const builder = new NullifierReadRequestHintsBuilder(); const numReadRequests = countAccumulatedItems(nullifierReadRequests); - const nullifierIndexMap: Map = new Map(); - nullifiers.forEach((n, i) => nullifierIndexMap.set(n.value.toBigInt(), i)); + const nullifierMap: Map = new Map(); + getNonEmptyItems(nullifiers).forEach((nullifier, index) => { + const value = nullifier.value.toBigInt(); + const arr = nullifierMap.get(value) ?? []; + arr.push({ nullifier, index }); + nullifierMap.set(value, arr); + }); for (let i = 0; i < numReadRequests; ++i) { const readRequest = nullifierReadRequests[i]; - // TODO - Should be comparing un-siloed values and contract addresses. - const value = siloNullifier(readRequest.contractAddress, readRequest.value); + const pendingNullifier = nullifierMap + .get(readRequest.value.toBigInt()) + ?.find( + ({ nullifier }) => + nullifier.contractAddress.equals(readRequest.contractAddress) && readRequest.counter > nullifier.counter, + ); - const pendingValueIndex = nullifierIndexMap.get(value.toBigInt()); - if (pendingValueIndex !== undefined) { - builder.addPendingReadRequest(i, pendingValueIndex); + if (pendingNullifier !== undefined) { + builder.addPendingReadRequest(i, pendingNullifier.index); } else { - const membershipWitnessWithPreimage = await oracle.getNullifierMembershipWitness(value); + const siloedValue = siloed ? readRequest.value : siloNullifier(readRequest.contractAddress, readRequest.value); + const membershipWitnessWithPreimage = await oracle.getNullifierMembershipWitness(siloedValue); builder.addSettledReadRequest( i, membershipWitnessWithPreimage.membershipWitness, @@ -54,3 +68,27 @@ export async function buildNullifierReadRequestHints( } return builder.toHints(); } + +export function buildSiloedNullifierReadRequestHints( + oracle: { + getNullifierMembershipWitness(nullifier: Fr): Promise; + }, + nullifierReadRequests: Tuple, + nullifiers: Tuple, +) { + // Nullifiers outputted from public kernels are already siloed while read requests are not. + // Siloing the read request values and set the contract addresses to zero to find the matching nullifier contexts. + const siloedReadRequests = padArrayEnd( + getNonEmptyItems(nullifierReadRequests).map(r => + new ReadRequest(siloNullifier(r.contractAddress, r.value), r.counter).scope(AztecAddress.ZERO), + ), + ScopedReadRequest.empty(), + MAX_NULLIFIER_READ_REQUESTS_PER_TX, + ); + + const scopedNullifiers = nullifiers.map(n => + new Nullifier(n.value, n.counter, n.noteHash).scope(AztecAddress.ZERO), + ) as Tuple; + + return buildNullifierReadRequestHints(oracle, siloedReadRequests, scopedNullifiers, true); +} diff --git a/yarn-project/circuits.js/src/hints/build_transient_data_hints.test.ts b/yarn-project/circuits.js/src/hints/build_transient_data_hints.test.ts index a0d4e3fee60..783ea56c885 100644 --- a/yarn-project/circuits.js/src/hints/build_transient_data_hints.test.ts +++ b/yarn-project/circuits.js/src/hints/build_transient_data_hints.test.ts @@ -1,22 +1,24 @@ -import { Fr, NoteHashContext, Nullifier } from '@aztec/circuits.js'; +import { AztecAddress, Fr, NoteHash, Nullifier, type ScopedNoteHash, type ScopedNullifier } from '@aztec/circuits.js'; import { buildTransientDataHints } from './build_transient_data_hints.js'; describe('buildTransientDataHints', () => { - let noteHashes: NoteHashContext[]; - let nullifiers: Nullifier[]; + const contractAddress = AztecAddress.fromBigInt(987654n); + + let noteHashes: ScopedNoteHash[]; + let nullifiers: ScopedNullifier[]; beforeEach(() => { noteHashes = [ - new NoteHashContext(new Fr(11), 100, 700), - new NoteHashContext(new Fr(22), 200, 0), - new NoteHashContext(new Fr(33), 300, 500), + new NoteHash(new Fr(11), 100).scope(700, contractAddress), + new NoteHash(new Fr(22), 200).scope(0, contractAddress), + new NoteHash(new Fr(33), 300).scope(500, contractAddress), ]; nullifiers = [ - new Nullifier(new Fr(44), 400, new Fr(0)), - new Nullifier(new Fr(55), 500, new Fr(33)), - new Nullifier(new Fr(66), 600, new Fr(0)), - new Nullifier(new Fr(77), 700, new Fr(11)), + new Nullifier(new Fr(44), 400, new Fr(0)).scope(contractAddress), + new Nullifier(new Fr(55), 500, new Fr(33)).scope(contractAddress), + new Nullifier(new Fr(66), 600, new Fr(0)).scope(contractAddress), + new Nullifier(new Fr(77), 700, new Fr(11)).scope(contractAddress), ]; }); @@ -32,7 +34,14 @@ describe('buildTransientDataHints', () => { }); it('throws if note hash does not match', () => { - nullifiers[1].noteHash = new Fr(11); + nullifiers[1].nullifier.noteHash = new Fr(11); expect(() => buildTransientDataHints(noteHashes, nullifiers)).toThrow('Hinted note hash does not match.'); }); + + it('throws if contract address does not match', () => { + nullifiers[1].contractAddress = AztecAddress.fromBigInt(123456n); + expect(() => buildTransientDataHints(noteHashes, nullifiers)).toThrow( + 'Contract address of hinted note hash does not match.', + ); + }); }); diff --git a/yarn-project/circuits.js/src/hints/build_transient_data_hints.ts b/yarn-project/circuits.js/src/hints/build_transient_data_hints.ts index bee36948fd7..a9664d6e5ce 100644 --- a/yarn-project/circuits.js/src/hints/build_transient_data_hints.ts +++ b/yarn-project/circuits.js/src/hints/build_transient_data_hints.ts @@ -1,10 +1,10 @@ -import { type NoteHashContext, type Nullifier, countAccumulatedItems } from '@aztec/circuits.js'; +import { type ScopedNoteHash, type ScopedNullifier, countAccumulatedItems } from '@aztec/circuits.js'; import { makeTuple } from '@aztec/foundation/array'; import { type Tuple } from '@aztec/foundation/serialize'; export function buildTransientDataHints( - noteHashes: Tuple, - nullifiers: Tuple, + noteHashes: Tuple, + nullifiers: Tuple, noteHashesLength: NOTE_HASHES_LEN = noteHashes.length as NOTE_HASHES_LEN, nullifiersLength: NULLIFIERS_LEN = nullifiers.length as NULLIFIERS_LEN, ): [Tuple, Tuple] { @@ -31,9 +31,12 @@ export function buildTransientDataHints`; +exports[`PrivateCallStackItem computes empty item hash 1`] = `Fr<0x2a1bab3d40feb5234df51a7a6665998920119fd60f5c1e4d9ff3f1128a5f8f81>`; -exports[`PrivateCallStackItem computes hash 1`] = `Fr<0x0efad8edafef07ee5165f01a51dec26edc7fd28f55eff90478d86f8a95a5352b>`; +exports[`PrivateCallStackItem computes hash 1`] = `Fr<0x1368f96c8d186bfc35d8dc71a0ac006d12e25cfa9fdf12bd3bd5af001049933f>`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap index a01d735ecb7..54ef2021ca4 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`PrivateCircuitPublicInputs computes empty inputs hash 1`] = `Fr<0x249d46b5a3e35f6489e793cd604e375634d4bfdac762ec06b5f8f03016bb4257>`; +exports[`PrivateCircuitPublicInputs computes empty inputs hash 1`] = `Fr<0x09cc3ed80b2171f093828087431d66777514912b4e7baddb418ab5f1ddbbfd5a>`; -exports[`PrivateCircuitPublicInputs hash matches snapshot 1`] = `Fr<0x2f33953d4e47a0ebbe6ae3f4785ada5d107383e82038e7caf27cc37fdb69a088>`; +exports[`PrivateCircuitPublicInputs hash matches snapshot 1`] = `Fr<0x03dee3f2b52e26410a7a69b1c67e7aee5012d9acd53c85f72ab83917e1f4a8f6>`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap index 4a2e6a33179..0ccb386246e 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap @@ -1,9 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`PublicCallStackItem Computes a callstack item hash 1`] = `"0x1122a7d7e6174b7e5d111c8eb0233564d3a1ffd755afc7ce4b594d738e2770d7"`; +exports[`PublicCallStackItem Computes a callstack item hash 1`] = `"0x0f7624c0d5ea65fcec318c4d34cb3fcbf9c67435aebbf1548b3c90ef641424f8"`; -exports[`PublicCallStackItem Computes a callstack item request hash 1`] = `"0x1595b195f0faa3a492109039dc807b291d0edd81a5e3a380866d5098ffd505dd"`; +exports[`PublicCallStackItem Computes a callstack item request hash 1`] = `"0x1177a69fbc37f0ebdf290025414ff72504497840f174896bd427d0f30ec21c55"`; -exports[`PublicCallStackItem computes empty item hash 1`] = `Fr<0x302550c2014c51737798139c9a80af984fa23be608c9758de295181944dddf66>`; +exports[`PublicCallStackItem computes empty item hash 1`] = `Fr<0x020b98dcc882881a349edfd43044d58c8703fdcfc9d4b250b799d951608dcd6b>`; -exports[`PublicCallStackItem computes hash 1`] = `Fr<0x1682642d96f9873ed85f245b4ca2ec93d2a0e11ba8e3d614f94ba409030af2c9>`; +exports[`PublicCallStackItem computes hash 1`] = `Fr<0x18d2b726728360b534121bb15accd1059f7df38225e76768e64d3e3040122440>`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/public_circuit_public_inputs.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/public_circuit_public_inputs.test.ts.snap index 6cf756de088..834668caf75 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/public_circuit_public_inputs.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/public_circuit_public_inputs.test.ts.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`PublicCircuitPublicInputs computes empty inputs hash 1`] = `Fr<0x1a2da219bb2e3ac24519fd844365c4f656fc3ba8c58f2960706d25bceb4d1769>`; +exports[`PublicCircuitPublicInputs computes empty inputs hash 1`] = `Fr<0x132559f41b7adc7388e0cd52b91fd6837c296b2f9ec1b6d2ed046f7a56db18f8>`; -exports[`PublicCircuitPublicInputs hash matches snapshot 1`] = `Fr<0x05db8cb4a08d8d1f5b0f38b2ef50f0bf70b4ed33099f649062326084197f1b79>`; +exports[`PublicCircuitPublicInputs hash matches snapshot 1`] = `Fr<0x0ac3cb8eb6605fc7aa83e9420eb988c1f6c9a5dcc2457c133216624bc6932619>`; diff --git a/yarn-project/circuits.js/src/structs/kernel/private_accumulated_data.ts b/yarn-project/circuits.js/src/structs/kernel/private_accumulated_data.ts index 6d074a9e6a8..3d0029b199b 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_accumulated_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_accumulated_data.ts @@ -13,8 +13,9 @@ import { MAX_UNENCRYPTED_LOGS_PER_TX, } from '../../constants.gen.js'; import { CallRequest } from '../call_request.js'; -import { NoteHashContext } from '../note_hash.js'; -import { Nullifier } from '../nullifier.js'; +import { ScopedL2ToL1Message } from '../l2_to_l1_message.js'; +import { ScopedNoteHash } from '../note_hash.js'; +import { ScopedNullifier } from '../nullifier.js'; import { SideEffect } from '../side_effects.js'; /** @@ -26,15 +27,15 @@ export class PrivateAccumulatedData { /** * The new note hashes made in this transaction. */ - public newNoteHashes: Tuple, + public newNoteHashes: Tuple, /** * The new nullifiers made in this transaction. */ - public newNullifiers: Tuple, + public newNullifiers: Tuple, /** * All the new L2 to L1 messages created in this transaction. */ - public newL2ToL1Msgs: Tuple, + public newL2ToL1Msgs: Tuple, /** * Accumulated encrypted logs hash from all the previous kernel iterations. * Note: Represented as a tuple of 2 fields in order to fit in all of the 256 bits of sha256 hash. @@ -90,9 +91,9 @@ export class PrivateAccumulatedData { static fromBuffer(buffer: Buffer | BufferReader): PrivateAccumulatedData { const reader = BufferReader.asReader(buffer); return new PrivateAccumulatedData( - reader.readArray(MAX_NEW_NOTE_HASHES_PER_TX, NoteHashContext), - reader.readArray(MAX_NEW_NULLIFIERS_PER_TX, Nullifier), - reader.readArray(MAX_NEW_L2_TO_L1_MSGS_PER_TX, Fr), + reader.readArray(MAX_NEW_NOTE_HASHES_PER_TX, ScopedNoteHash), + reader.readArray(MAX_NEW_NULLIFIERS_PER_TX, ScopedNullifier), + reader.readArray(MAX_NEW_L2_TO_L1_MSGS_PER_TX, ScopedL2ToL1Message), reader.readArray(MAX_ENCRYPTED_LOGS_PER_TX, SideEffect), reader.readArray(MAX_UNENCRYPTED_LOGS_PER_TX, SideEffect), Fr.fromBuffer(reader), @@ -113,9 +114,9 @@ export class PrivateAccumulatedData { static empty() { return new PrivateAccumulatedData( - makeTuple(MAX_NEW_NOTE_HASHES_PER_TX, NoteHashContext.empty), - makeTuple(MAX_NEW_NULLIFIERS_PER_TX, Nullifier.empty), - makeTuple(MAX_NEW_L2_TO_L1_MSGS_PER_TX, Fr.zero), + makeTuple(MAX_NEW_NOTE_HASHES_PER_TX, ScopedNoteHash.empty), + makeTuple(MAX_NEW_NULLIFIERS_PER_TX, ScopedNullifier.empty), + makeTuple(MAX_NEW_L2_TO_L1_MSGS_PER_TX, ScopedL2ToL1Message.empty), makeTuple(MAX_ENCRYPTED_LOGS_PER_TX, SideEffect.empty), makeTuple(MAX_UNENCRYPTED_LOGS_PER_TX, SideEffect.empty), Fr.zero(), diff --git a/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_private_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_private_inputs.ts index 8fa1de2c2ac..36ecd40f5c7 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_private_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_private_inputs.ts @@ -10,8 +10,8 @@ import { } from '../../constants.gen.js'; import { type GrumpkinPrivateKey } from '../../types/grumpkin_private_key.js'; import { countAccumulatedItems } from '../../utils/index.js'; -import { NoteHashContext } from '../note_hash.js'; -import { Nullifier } from '../nullifier.js'; +import { ScopedNoteHash } from '../note_hash.js'; +import { ScopedNullifier } from '../nullifier.js'; import { type NoteHashReadRequestHints, type NullifierReadRequestHints, @@ -23,8 +23,8 @@ import { PrivateKernelData } from './private_kernel_data.js'; export class PrivateKernelTailOutputs { constructor( - public noteHashes: Tuple, - public nullifiers: Tuple, + public noteHashes: Tuple, + public nullifiers: Tuple, ) {} toBuffer() { @@ -34,8 +34,8 @@ export class PrivateKernelTailOutputs { static fromBuffer(buffer: Buffer | BufferReader) { const reader = BufferReader.asReader(buffer); return new PrivateKernelTailOutputs( - reader.readArray(MAX_NEW_NOTE_HASHES_PER_TX, NoteHashContext), - reader.readArray(MAX_NEW_NULLIFIERS_PER_TX, Nullifier), + reader.readArray(MAX_NEW_NOTE_HASHES_PER_TX, ScopedNoteHash), + reader.readArray(MAX_NEW_NULLIFIERS_PER_TX, ScopedNullifier), ); } } @@ -66,7 +66,7 @@ export class PrivateKernelTailHints { /* * The sorted new note hashes. */ - public sortedNewNoteHashes: Tuple, + public sortedNewNoteHashes: Tuple, /** * The sorted new note hashes indexes. Maps original to sorted. */ @@ -74,7 +74,7 @@ export class PrivateKernelTailHints { /** * The sorted new nullifiers. Maps original to sorted. */ - public sortedNewNullifiers: Tuple, + public sortedNewNullifiers: Tuple, /** * The sorted new nullifiers indexes. */ @@ -128,9 +128,9 @@ export class PrivateKernelTailHints { reader.readObject({ fromBuffer: noteHashReadRequestHintsFromBuffer }), reader.readObject({ fromBuffer: nullifierReadRequestHintsFromBuffer }), reader.readArray(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, GrumpkinScalar), - reader.readArray(MAX_NEW_NOTE_HASHES_PER_TX, NoteHashContext), + reader.readArray(MAX_NEW_NOTE_HASHES_PER_TX, ScopedNoteHash), reader.readNumbers(MAX_NEW_NOTE_HASHES_PER_TX), - reader.readArray(MAX_NEW_NULLIFIERS_PER_TX, Nullifier), + reader.readArray(MAX_NEW_NULLIFIERS_PER_TX, ScopedNullifier), reader.readNumbers(MAX_NEW_NULLIFIERS_PER_TX), reader.readArray(MAX_ENCRYPTED_LOGS_PER_TX, SideEffect), reader.readNumbers(MAX_ENCRYPTED_LOGS_PER_TX), diff --git a/yarn-project/circuits.js/src/structs/l2_to_l1_message.ts b/yarn-project/circuits.js/src/structs/l2_to_l1_message.ts index ef4bb082386..8d5a1e214d4 100644 --- a/yarn-project/circuits.js/src/structs/l2_to_l1_message.ts +++ b/yarn-project/circuits.js/src/structs/l2_to_l1_message.ts @@ -1,3 +1,4 @@ +import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; @@ -5,14 +6,14 @@ import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/ import { L2_TO_L1_MESSAGE_LENGTH } from '../constants.gen.js'; export class L2ToL1Message { - constructor(public recipient: EthAddress, public content: Fr) {} + constructor(public recipient: EthAddress, public content: Fr, public counter: number) {} /** * Creates an empty L2ToL1Message with default values. * @returns An instance of L2ToL1Message with empty fields. */ static empty(): L2ToL1Message { - return new L2ToL1Message(EthAddress.ZERO, Fr.zero()); + return new L2ToL1Message(EthAddress.ZERO, Fr.zero(), 0); } /** @@ -21,7 +22,9 @@ export class L2ToL1Message { * @returns True if both recipient and content are equal. */ equals(other: L2ToL1Message): boolean { - return this.recipient.equals(other.recipient) && this.content.equals(other.content); + return ( + this.recipient.equals(other.recipient) && this.content.equals(other.content) && this.counter === other.counter + ); } /** @@ -29,7 +32,7 @@ export class L2ToL1Message { * @returns The buffer. */ toBuffer(): Buffer { - return serializeToBuffer(this.recipient, this.content); + return serializeToBuffer(this.recipient, this.content, this.counter); } /** @@ -37,7 +40,7 @@ export class L2ToL1Message { * @returns An array of fields representing the serialized message. */ toFields(): Fr[] { - const fields = [this.recipient.toField(), this.content]; + const fields = [this.recipient.toField(), this.content, new Fr(this.counter)]; if (fields.length !== L2_TO_L1_MESSAGE_LENGTH) { throw new Error( `Invalid number of fields for L2ToL1Message. Expected ${L2_TO_L1_MESSAGE_LENGTH}, got ${fields.length}`, @@ -53,7 +56,7 @@ export class L2ToL1Message { */ static fromFields(fields: Fr[] | FieldReader): L2ToL1Message { const reader = FieldReader.asReader(fields); - return new L2ToL1Message(reader.readObject(EthAddress), reader.readField()); + return new L2ToL1Message(reader.readObject(EthAddress), reader.readField(), reader.readU32()); } /** @@ -63,7 +66,7 @@ export class L2ToL1Message { */ static fromBuffer(buffer: Buffer | BufferReader): L2ToL1Message { const reader = BufferReader.asReader(buffer); - return new L2ToL1Message(reader.readObject(EthAddress), reader.readObject(Fr)); + return new L2ToL1Message(reader.readObject(EthAddress), reader.readObject(Fr), reader.readNumber()); } /** @@ -71,6 +74,31 @@ export class L2ToL1Message { * @returns True if both recipient and content are zero. */ isEmpty(): boolean { - return this.recipient.isZero() && this.content.isZero(); + return this.recipient.isZero() && this.content.isZero() && !this.counter; + } +} + +export class ScopedL2ToL1Message { + constructor(public message: L2ToL1Message, public contractAddress: AztecAddress) {} + + static empty() { + return new ScopedL2ToL1Message(L2ToL1Message.empty(), AztecAddress.ZERO); + } + + equals(other: ScopedL2ToL1Message): boolean { + return this.message.equals(other.message) && this.contractAddress.equals(other.contractAddress); + } + + toBuffer(): Buffer { + return serializeToBuffer(this.message, this.contractAddress); + } + + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new ScopedL2ToL1Message(reader.readObject(L2ToL1Message), reader.readObject(AztecAddress)); + } + + isEmpty(): boolean { + return this.message.isEmpty() && this.contractAddress.isZero(); } } diff --git a/yarn-project/circuits.js/src/structs/note_hash.ts b/yarn-project/circuits.js/src/structs/note_hash.ts index dfe63e8c720..824b788e275 100644 --- a/yarn-project/circuits.js/src/structs/note_hash.ts +++ b/yarn-project/circuits.js/src/structs/note_hash.ts @@ -1,3 +1,4 @@ +import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; @@ -35,38 +36,54 @@ export class NoteHash { toString(): string { return `value=${this.value} counter=${this.counter}`; } + + scope(nullifierCounter: number, contractAddress: AztecAddress) { + return new ScopedNoteHash(this, nullifierCounter, contractAddress); + } } -export class NoteHashContext implements Ordered { - constructor(public value: Fr, public counter: number, public nullifierCounter: number) {} +export class ScopedNoteHash implements Ordered { + constructor(public noteHash: NoteHash, public nullifierCounter: number, public contractAddress: AztecAddress) {} + + get counter() { + return this.noteHash.counter; + } + + get value() { + return this.noteHash.value; + } toFields(): Fr[] { - return [this.value, new Fr(this.counter), new Fr(this.nullifierCounter)]; + return [...this.noteHash.toFields(), new Fr(this.nullifierCounter), this.contractAddress.toField()]; } static fromFields(fields: Fr[] | FieldReader) { const reader = FieldReader.asReader(fields); - return new NoteHashContext(reader.readField(), reader.readU32(), reader.readU32()); + return new ScopedNoteHash( + reader.readObject(NoteHash), + reader.readU32(), + AztecAddress.fromField(reader.readField()), + ); } isEmpty() { - return this.value.isZero() && !this.counter && !this.nullifierCounter; + return this.noteHash.isEmpty() && !this.nullifierCounter && this.contractAddress.isZero(); } static empty() { - return new NoteHashContext(Fr.zero(), 0, 0); + return new ScopedNoteHash(NoteHash.empty(), 0, AztecAddress.ZERO); } toBuffer(): Buffer { - return serializeToBuffer(this.value, this.counter, this.nullifierCounter); + return serializeToBuffer(this.noteHash, this.nullifierCounter, this.contractAddress); } static fromBuffer(buffer: Buffer | BufferReader) { const reader = BufferReader.asReader(buffer); - return new NoteHashContext(Fr.fromBuffer(reader), reader.readNumber(), reader.readNumber()); + return new ScopedNoteHash(NoteHash.fromBuffer(reader), reader.readNumber(), AztecAddress.fromBuffer(reader)); } toString(): string { - return `value=${this.value} counter=${this.counter} nullifierCounter=${this.nullifierCounter}`; + return `noteHash=${this.noteHash} nullifierCounter=${this.nullifierCounter} contractAddress=${this.contractAddress}`; } } diff --git a/yarn-project/circuits.js/src/structs/nullifier.ts b/yarn-project/circuits.js/src/structs/nullifier.ts index 176628d5e1d..7f1e73477e1 100644 --- a/yarn-project/circuits.js/src/structs/nullifier.ts +++ b/yarn-project/circuits.js/src/structs/nullifier.ts @@ -1,3 +1,4 @@ +import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; @@ -35,4 +36,54 @@ export class Nullifier implements Ordered { toString(): string { return `value=${this.value} counter=${this.counter} noteHash=${this.noteHash}`; } + + scope(contractAddress: AztecAddress) { + return new ScopedNullifier(this, contractAddress); + } +} + +export class ScopedNullifier implements Ordered { + constructor(public nullifier: Nullifier, public contractAddress: AztecAddress) {} + + get counter() { + return this.nullifier.counter; + } + + get value() { + return this.nullifier.value; + } + + get nullifiedNoteHash() { + return this.nullifier.noteHash; + } + + toFields(): Fr[] { + return [...this.nullifier.toFields(), this.contractAddress.toField()]; + } + + static fromFields(fields: Fr[] | FieldReader) { + const reader = FieldReader.asReader(fields); + return new ScopedNullifier(reader.readObject(Nullifier), AztecAddress.fromField(reader.readField())); + } + + isEmpty() { + return this.nullifier.isEmpty() && this.contractAddress.isZero(); + } + + static empty() { + return new ScopedNullifier(Nullifier.empty(), AztecAddress.ZERO); + } + + toBuffer(): Buffer { + return serializeToBuffer(this.nullifier, this.contractAddress); + } + + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new ScopedNullifier(Nullifier.fromBuffer(reader), AztecAddress.fromBuffer(reader)); + } + + toString(): string { + return `nullifier=${this.nullifier} contractAddress=${this.contractAddress}`; + } } diff --git a/yarn-project/circuits.js/src/structs/nullifier_key_validation_request.ts b/yarn-project/circuits.js/src/structs/nullifier_key_validation_request.ts index c145e0d2e82..2d1fa9813b5 100644 --- a/yarn-project/circuits.js/src/structs/nullifier_key_validation_request.ts +++ b/yarn-project/circuits.js/src/structs/nullifier_key_validation_request.ts @@ -3,8 +3,8 @@ import { Fr, Point } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { - NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_LENGTH, NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH, + SCOPED_NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH, } from '../constants.gen.js'; /** @@ -58,61 +58,44 @@ export class NullifierKeyValidationRequest { /** * Request for validating a nullifier key pair used in the app. */ -export class NullifierKeyValidationRequestContext { - constructor( - /** - * Public key of the nullifier key (Npk_m). - */ - public readonly masterNullifierPublicKey: Point, - /** - * App-siloed nullifier secret key (nsk_app*). - */ - public readonly appNullifierSecretKey: Fr, - /** - * The storage contract address the nullifier key is for. - */ - public readonly contractAddress: AztecAddress, - ) {} +export class ScopedNullifierKeyValidationRequest { + constructor(public readonly request: NullifierKeyValidationRequest, public readonly contractAddress: AztecAddress) {} toBuffer() { - return serializeToBuffer(this.masterNullifierPublicKey, this.appNullifierSecretKey, this.contractAddress); + return serializeToBuffer(this.request, this.contractAddress); } static fromBuffer(buffer: Buffer | BufferReader) { const reader = BufferReader.asReader(buffer); - return new NullifierKeyValidationRequestContext( - Point.fromBuffer(reader), - Fr.fromBuffer(reader), + return new ScopedNullifierKeyValidationRequest( + NullifierKeyValidationRequest.fromBuffer(reader), AztecAddress.fromBuffer(reader), ); } toFields(): Fr[] { - const fields = [this.masterNullifierPublicKey.toFields(), this.appNullifierSecretKey, this.contractAddress].flat(); - if (fields.length !== NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_LENGTH) { + const fields = [...this.request.toFields(), this.contractAddress]; + if (fields.length !== SCOPED_NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH) { throw new Error( - `Invalid number of fields for NullifierKeyValidationRequestContext. Expected ${NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_LENGTH}, got ${fields.length}`, + `Invalid number of fields for ScopedNullifierKeyValidationRequest. Expected ${SCOPED_NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH}, got ${fields.length}`, ); } return fields; } - static fromFields(fields: Fr[] | FieldReader): NullifierKeyValidationRequestContext { + static fromFields(fields: Fr[] | FieldReader): ScopedNullifierKeyValidationRequest { const reader = FieldReader.asReader(fields); - return new NullifierKeyValidationRequestContext( - Point.fromFields(reader), - reader.readField(), + return new ScopedNullifierKeyValidationRequest( + NullifierKeyValidationRequest.fromFields(reader), AztecAddress.fromFields(reader), ); } isEmpty() { - return ( - this.masterNullifierPublicKey.isZero() && this.appNullifierSecretKey.isZero() && this.contractAddress.isZero() - ); + return this.request.isEmpty() && this.contractAddress.isZero(); } static empty() { - return new NullifierKeyValidationRequestContext(Point.ZERO, Fr.ZERO, AztecAddress.ZERO); + return new ScopedNullifierKeyValidationRequest(NullifierKeyValidationRequest.empty(), AztecAddress.ZERO); } } diff --git a/yarn-project/circuits.js/src/structs/read_request.ts b/yarn-project/circuits.js/src/structs/read_request.ts index 1f47f967c6d..60127af7c0d 100644 --- a/yarn-project/circuits.js/src/structs/read_request.ts +++ b/yarn-project/circuits.js/src/structs/read_request.ts @@ -60,43 +60,42 @@ export class ReadRequest { static empty(): ReadRequest { return new ReadRequest(Fr.zero(), 0); } + + scope(contractAddress: AztecAddress) { + return new ScopedReadRequest(this, contractAddress); + } } /** * ReadRequest with context of the contract emitting the request. */ -export class ReadRequestContext { - constructor( - /** - * The value being read. - */ - public value: Fr, - /** - * The counter. - */ - public counter: number, - /** - * The address of the contract emitting the request. - */ - public contractAddress: AztecAddress, - ) {} +export class ScopedReadRequest { + constructor(public readRequest: ReadRequest, public contractAddress: AztecAddress) {} + + get value() { + return this.readRequest.value; + } + + get counter() { + return this.readRequest.counter; + } /** * Serialize this as a buffer. * @returns The buffer. */ toBuffer(): Buffer { - return serializeToBuffer(this.value, this.counter, this.contractAddress); + return serializeToBuffer(this.readRequest, this.contractAddress); } /** * Deserializes from a buffer or reader, corresponding to a write in cpp. * @param buffer - Buffer or reader to read from. - * @returns A new instance of ReadRequestContext. + * @returns A new instance of ScopedReadRequest. */ static fromBuffer(buffer: Buffer | BufferReader) { const reader = BufferReader.asReader(buffer); - return new ReadRequestContext(Fr.fromBuffer(reader), reader.readNumber(), AztecAddress.fromBuffer(reader)); + return new ScopedReadRequest(ReadRequest.fromBuffer(reader), AztecAddress.fromBuffer(reader)); } /** @@ -104,12 +103,12 @@ export class ReadRequestContext { * @returns The array of fields. */ toFields(): Fr[] { - return [this.value, new Fr(this.counter), this.contractAddress.toField()]; + return [...this.readRequest.toFields(), this.contractAddress.toField()]; } static fromFields(fields: Fr[] | FieldReader) { const reader = FieldReader.asReader(fields); - return new ReadRequestContext(reader.readField(), reader.readU32(), AztecAddress.fromField(reader.readField())); + return new ScopedReadRequest(reader.readObject(ReadRequest), AztecAddress.fromField(reader.readField())); } /** @@ -117,14 +116,14 @@ export class ReadRequestContext { * @returns True if the value, note hash and counter are all zero. */ isEmpty() { - return this.value.isZero() && !this.counter && this.contractAddress.isZero(); + return this.readRequest.isEmpty() && this.contractAddress.isZero(); } /** * Returns an empty instance of side-effect. * @returns Side-effect with value, note hash and counter being zero. */ - static empty(): ReadRequestContext { - return new ReadRequestContext(Fr.zero(), 0, AztecAddress.ZERO); + static empty(): ScopedReadRequest { + return new ScopedReadRequest(ReadRequest.empty(), AztecAddress.ZERO); } } diff --git a/yarn-project/circuits.js/src/structs/validation_requests.ts b/yarn-project/circuits.js/src/structs/validation_requests.ts index 839c08e7815..6d33a5b5865 100644 --- a/yarn-project/circuits.js/src/structs/validation_requests.ts +++ b/yarn-project/circuits.js/src/structs/validation_requests.ts @@ -10,9 +10,9 @@ import { MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_PUBLIC_DATA_READS_PER_TX, } from '../constants.gen.js'; -import { NullifierKeyValidationRequestContext } from './nullifier_key_validation_request.js'; +import { ScopedNullifierKeyValidationRequest } from './nullifier_key_validation_request.js'; import { PublicDataRead } from './public_data_read_request.js'; -import { ReadRequestContext } from './read_request.js'; +import { ScopedReadRequest } from './read_request.js'; import { RollupValidationRequests } from './rollup_validation_requests.js'; /** @@ -28,23 +28,23 @@ export class ValidationRequests { /** * All the read requests made in this transaction. */ - public noteHashReadRequests: Tuple, + public noteHashReadRequests: Tuple, /** * All the nullifier read requests made in this transaction. */ - public nullifierReadRequests: Tuple, + public nullifierReadRequests: Tuple, /** * The nullifier read requests made in this transaction. */ public nullifierNonExistentReadRequests: Tuple< - ReadRequestContext, + ScopedReadRequest, typeof MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX >, /** * All the nullifier key validation requests made in this transaction. */ public nullifierKeyValidationRequests: Tuple< - NullifierKeyValidationRequestContext, + ScopedNullifierKeyValidationRequest, typeof MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX >, /** @@ -77,10 +77,10 @@ export class ValidationRequests { const reader = BufferReader.asReader(buffer); return new ValidationRequests( reader.readObject(RollupValidationRequests), - reader.readArray(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, ReadRequestContext), - reader.readArray(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ReadRequestContext), - reader.readArray(MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, ReadRequestContext), - reader.readArray(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, NullifierKeyValidationRequestContext), + reader.readArray(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, ScopedReadRequest), + reader.readArray(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ScopedReadRequest), + reader.readArray(MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, ScopedReadRequest), + reader.readArray(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, ScopedNullifierKeyValidationRequest), reader.readArray(MAX_PUBLIC_DATA_READS_PER_TX, PublicDataRead), ); } @@ -97,10 +97,10 @@ export class ValidationRequests { static empty() { return new ValidationRequests( RollupValidationRequests.empty(), - makeTuple(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, ReadRequestContext.empty), - makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ReadRequestContext.empty), - makeTuple(MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, ReadRequestContext.empty), - makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, NullifierKeyValidationRequestContext.empty), + makeTuple(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, ScopedReadRequest.empty), + makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ScopedReadRequest.empty), + makeTuple(MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, ScopedReadRequest.empty), + makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, ScopedNullifierKeyValidationRequest.empty), makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, PublicDataRead.empty), ); } diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index 2f48780c24f..6dc5712a2fa 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -54,7 +54,6 @@ import { MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, - MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_DATA_HINTS, @@ -75,10 +74,8 @@ import { NUM_BASE_PARITY_PER_ROOT_PARITY, NUM_MSGS_PER_BASE_PARITY, NoteHash, - NoteHashContext, Nullifier, NullifierKeyValidationRequest, - NullifierKeyValidationRequestContext, NullifierLeafPreimage, NullifierNonExistentReadRequestHintsBuilder, NullifierReadRequestHintsBuilder, @@ -90,12 +87,9 @@ import { PartialStateReference, Point, PreviousRollupData, - PrivateAccumulatedData, PrivateCallData, PrivateCallStackItem, PrivateCircuitPublicInputs, - PrivateKernelCircuitPublicInputs, - PrivateKernelData, PrivateKernelTailCircuitPublicInputs, Proof, PublicAccumulatedData, @@ -116,13 +110,14 @@ import { RECURSIVE_PROOF_LENGTH, ROLLUP_VK_TREE_HEIGHT, ReadRequest, - ReadRequestContext, RevertCode, RollupTypes, RootParityInput, RootParityInputs, RootRollupInputs, RootRollupPublicInputs, + ScopedNullifierKeyValidationRequest, + ScopedReadRequest, SideEffect, StateDiffHints, StateReference, @@ -160,10 +155,6 @@ function makeNoteHash(seed: number) { return new NoteHash(fr(seed), seed + 1); } -function makeNoteHashContext(seed: number) { - return new NoteHashContext(fr(seed), seed + 1, seed + 2); -} - function makeNullifier(seed: number) { return new Nullifier(fr(seed), seed + 1, fr(seed + 2)); } @@ -207,8 +198,8 @@ function makeReadRequest(n: number): ReadRequest { return new ReadRequest(new Fr(BigInt(n)), n + 1); } -function makeReadRequestContext(n: number): ReadRequestContext { - return new ReadRequestContext(new Fr(BigInt(n)), n + 1, AztecAddress.fromBigInt(BigInt(n + 2))); +function makeScopedReadRequest(n: number): ScopedReadRequest { + return new ScopedReadRequest(makeReadRequest(n), AztecAddress.fromBigInt(BigInt(n + 2))); } /** @@ -220,13 +211,8 @@ function makeNullifierKeyValidationRequest(seed: number): NullifierKeyValidation return new NullifierKeyValidationRequest(makePoint(seed), fr(seed + 2)); } -/** - * Creates arbitrary NullifierKeyValidationRequestContext from the given seed. - * @param seed - The seed to use for generating the NullifierKeyValidationRequestContext. - * @returns A NullifierKeyValidationRequestContext. - */ -function makeNullifierKeyValidationRequestContext(seed: number): NullifierKeyValidationRequestContext { - return new NullifierKeyValidationRequestContext(makePoint(seed), fr(seed + 2), makeAztecAddress(seed + 4)); +function makeScopedNullifierKeyValidationRequest(seed: number): ScopedNullifierKeyValidationRequest { + return new ScopedNullifierKeyValidationRequest(makeNullifierKeyValidationRequest(seed), makeAztecAddress(seed + 4)); } /** @@ -284,10 +270,10 @@ export function makeContractStorageRead(seed = 1): ContractStorageRead { export function makeValidationRequests(seed = 1) { return new ValidationRequests( makeRollupValidationRequests(seed), - makeTuple(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, makeReadRequestContext, seed + 0x80), - makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, makeReadRequestContext, seed + 0x90), - makeTuple(MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, makeReadRequestContext, seed + 0x95), - makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, makeNullifierKeyValidationRequestContext, seed + 0x100), + makeTuple(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, makeScopedReadRequest, seed + 0x80), + makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, makeScopedReadRequest, seed + 0x90), + makeTuple(MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, makeScopedReadRequest, seed + 0x95), + makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, makeScopedNullifierKeyValidationRequest, seed + 0x100), makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, makePublicDataRead, seed + 0xe00), ); } @@ -357,27 +343,6 @@ export function makePublicAccumulatedData(seed = 1, full = false): PublicAccumul ); } -/** - * Creates arbitrary accumulated data. - * @param seed - The seed to use for generating the accumulated data. - * @returns An accumulated data. - */ -export function makePrivateAccumulatedData(seed = 1, full = false) { - const tupleGenerator = full ? makeTuple : makeHalfFullTuple; - - return new PrivateAccumulatedData( - tupleGenerator(MAX_NEW_NOTE_HASHES_PER_TX, makeNoteHashContext, seed + 0x120, NoteHashContext.empty), - tupleGenerator(MAX_NEW_NULLIFIERS_PER_TX, makeNullifier, seed + 0x200, Nullifier.empty), - tupleGenerator(MAX_NEW_L2_TO_L1_MSGS_PER_TX, fr, seed + 0x600, Fr.zero), - tupleGenerator(MAX_ENCRYPTED_LOGS_PER_TX, makeNewSideEffect, seed + 0x700, SideEffect.empty), // encrypted logs hashes - tupleGenerator(MAX_UNENCRYPTED_LOGS_PER_TX, makeNewSideEffect, seed + 0x800, SideEffect.empty), // unencrypted logs hashes - fr(seed + 0x900), // encrypted_log_preimages_length - fr(seed + 0xa00), // unencrypted_log_preimages_length - tupleGenerator(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, makeCallRequest, seed + 0x400, CallRequest.empty), - tupleGenerator(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, makeCallRequest, seed + 0x500, CallRequest.empty), - ); -} - /** * Creates arbitrary aggregation object. * @param seed - The seed to use for generating the aggregation object. @@ -474,22 +439,6 @@ export function makePublicKernelCircuitPublicInputs( ); } -/** - * Creates arbitrary private kernel inner circuit public inputs. - * @param seed - The seed to use for generating the kernel circuit public inputs. - * @returns Private kernel circuit public inputs. - */ -export function makePrivateKernelCircuitPublicInputs(seed = 1, full = true): PrivateKernelCircuitPublicInputs { - return new PrivateKernelCircuitPublicInputs( - makeAggregationObject(seed), - fr(seed + 0x100), - makeValidationRequests(seed), - makePrivateAccumulatedData(seed, full), - makeConstantData(seed + 0x100), - makeCallRequest(seed + 0x200), - ); -} - /** * Creates arbitrary private kernel tail circuit public inputs. * @param seed - The seed to use for generating the kernel circuit public inputs. @@ -642,22 +591,6 @@ export function makeRollupKernelData(seed = 1, kernelPublicInputs?: KernelCircui ); } -/** - * Makes arbitrary previous kernel data. - * @param seed - The seed to use for generating the previous kernel data. - * @param inputs - The kernel public inputs to use for generating the private kernel inner data. - * @returns A previous kernel data. - */ -export function makePrivateKernelInnerData(seed = 1, inputs?: PrivateKernelCircuitPublicInputs): PrivateKernelData { - return new PrivateKernelData( - inputs ?? makePrivateKernelCircuitPublicInputs(seed, true), - new Proof(Buffer.alloc(16, seed + 0x80)), - makeVerificationKey(), - 0x42, - makeTuple(VK_TREE_HEIGHT, fr, 0x1000), - ); -} - /** * Makes arbitrary proof. * @param seed - The seed to use for generating/mocking the proof. @@ -1107,7 +1040,7 @@ export function makeL2ToL1Message(seed = 0): L2ToL1Message { const recipient = EthAddress.fromField(new Fr(seed)); const content = new Fr(seed + 1); - return new L2ToL1Message(recipient, content); + return new L2ToL1Message(recipient, content, seed + 2); } /** diff --git a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts index ed2295e907c..ec844c1a3d6 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -27,7 +27,7 @@ import { Header, KernelCircuitPublicInputs, type KernelData, - type L2ToL1Message, + L2ToL1Message, type LeafDataReadHint, MAX_ENCRYPTED_LOGS_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, @@ -51,11 +51,9 @@ import { NUM_BYTES_PER_SHA256, type NonMembershipHint, NoteHash, - NoteHashContext, type NoteHashReadRequestHints, Nullifier, NullifierKeyValidationRequest, - NullifierKeyValidationRequestContext, type NullifierLeafPreimage, type NullifierNonExistentReadRequestHints, type NullifierReadRequestHints, @@ -96,7 +94,6 @@ import { type PublicKernelTailCircuitPrivateInputs, type RECURSIVE_PROOF_LENGTH, ReadRequest, - ReadRequestContext, type ReadRequestStatus, type RecursiveProof, RevertCode, @@ -105,6 +102,11 @@ import { type RootParityInputs, type RootRollupInputs, RootRollupPublicInputs, + ScopedL2ToL1Message, + ScopedNoteHash, + ScopedNullifier, + ScopedNullifierKeyValidationRequest, + ScopedReadRequest, type SettledReadHint, SideEffect, type StateDiffHints, @@ -150,12 +152,10 @@ import type { EthAddress as NoirEthAddress, Field as NoirField, GrumpkinPoint as NoirPoint, - NoteHashContext as NoteHashContextNoir, NoteHashLeafPreimage as NoteHashLeafPreimageNoir, NoteHash as NoteHashNoir, NoteHashReadRequestHints as NoteHashReadRequestHintsNoir, NoteHashSettledReadHint as NoteHashSettledReadHintNoir, - NullifierKeyValidationRequestContext as NullifierKeyValidationRequestContextNoir, NullifierKeyValidationRequest as NullifierKeyValidationRequestNoir, NullifierLeafPreimage as NullifierLeafPreimageNoir, Nullifier as NullifierNoir, @@ -195,7 +195,6 @@ import type { PublicKernelData as PublicKernelDataNoir, PublicKernelSetupCircuitPrivateInputs as PublicKernelSetupCircuitPrivateInputsNoir, PublicKernelTailCircuitPrivateInputs as PublicKernelTailCircuitPrivateInputsNoir, - ReadRequestContext as ReadRequestContextNoir, ReadRequest as ReadRequestNoir, ReadRequestStatus as ReadRequestStatusNoir, RollupValidationRequests as RollupValidationRequestsNoir, @@ -203,6 +202,11 @@ import type { RootRollupInputs as RootRollupInputsNoir, RootRollupParityInput as RootRollupParityInputNoir, RootRollupPublicInputs as RootRollupPublicInputsNoir, + ScopedL2ToL1Message as ScopedL2ToL1MessageNoir, + ScopedNoteHash as ScopedNoteHashNoir, + ScopedNullifierKeyValidationRequest as ScopedNullifierKeyValidationRequestNoir, + ScopedNullifier as ScopedNullifierNoir, + ScopedReadRequest as ScopedReadRequestNoir, SideEffect as SideEffectNoir, StateDiffHints as StateDiffHintsNoir, StateReference as StateReferenceNoir, @@ -534,19 +538,19 @@ function mapNoteHashFromNoir(noteHash: NoteHashNoir) { return new NoteHash(mapFieldFromNoir(noteHash.value), mapNumberFromNoir(noteHash.counter)); } -function mapNoteHashContextToNoir(noteHash: NoteHashContext): NoteHashContextNoir { +function mapScopedNoteHashToNoir(noteHash: ScopedNoteHash): ScopedNoteHashNoir { return { - value: mapFieldToNoir(noteHash.value), - counter: mapNumberToNoir(noteHash.counter), + note_hash: mapNoteHashToNoir(noteHash.noteHash), nullifier_counter: mapNumberToNoir(noteHash.nullifierCounter), + contract_address: mapAztecAddressToNoir(noteHash.contractAddress), }; } -function mapNoteHashContextFromNoir(noteHash: NoteHashContextNoir) { - return new NoteHashContext( - mapFieldFromNoir(noteHash.value), - mapNumberFromNoir(noteHash.counter), +function mapScopedNoteHashFromNoir(noteHash: ScopedNoteHashNoir) { + return new ScopedNoteHash( + mapNoteHashFromNoir(noteHash.note_hash), mapNumberFromNoir(noteHash.nullifier_counter), + mapAztecAddressFromNoir(noteHash.contract_address), ); } @@ -566,6 +570,20 @@ function mapNullifierFromNoir(nullifier: NullifierNoir) { ); } +function mapScopedNullifierToNoir(nullifier: ScopedNullifier): ScopedNullifierNoir { + return { + nullifier: mapNullifierToNoir(nullifier.nullifier), + contract_address: mapAztecAddressToNoir(nullifier.contractAddress), + }; +} + +function mapScopedNullifierFromNoir(nullifier: ScopedNullifierNoir) { + return new ScopedNullifier( + mapNullifierFromNoir(nullifier.nullifier), + mapAztecAddressFromNoir(nullifier.contract_address), + ); +} + /** * Maps a SideEffect to a noir side effect. * @param sideEffect - The SideEffect. @@ -608,16 +626,10 @@ export function mapReadRequestFromNoir(readRequest: ReadRequestNoir): ReadReques return new ReadRequest(mapFieldFromNoir(readRequest.value), mapNumberFromNoir(readRequest.counter)); } -/** - * Maps a ReadRequestContext to a noir ReadRequestContext. - * @param readRequestContext - The read request context. - * @returns The noir ReadRequestContext. - */ -export function mapReadRequestContextToNoir(readRequestContext: ReadRequestContext): ReadRequestContextNoir { +function mapScopedReadRequestToNoir(scopedReadRequest: ScopedReadRequest): ScopedReadRequestNoir { return { - value: mapFieldToNoir(readRequestContext.value), - counter: mapNumberToNoir(readRequestContext.counter), - contract_address: mapAztecAddressToNoir(readRequestContext.contractAddress), + read_request: mapReadRequestToNoir(scopedReadRequest.readRequest), + contract_address: mapAztecAddressToNoir(scopedReadRequest.contractAddress), }; } @@ -626,11 +638,10 @@ export function mapReadRequestContextToNoir(readRequestContext: ReadRequestConte * @param readRequest - The noir ReadRequest. * @returns The TS ReadRequest. */ -export function mapReadRequestContextFromNoir(readRequestContext: ReadRequestContextNoir): ReadRequestContext { - return new ReadRequestContext( - mapFieldFromNoir(readRequestContext.value), - mapNumberFromNoir(readRequestContext.counter), - mapAztecAddressFromNoir(readRequestContext.contract_address), +export function mapScopedReadRequestFromNoir(scoped: ScopedReadRequestNoir): ScopedReadRequest { + return new ScopedReadRequest( + mapReadRequestFromNoir(scoped.read_request), + mapAztecAddressFromNoir(scoped.contract_address), ); } @@ -662,32 +673,20 @@ export function mapNullifierKeyValidationRequestFromNoir( ); } -/** - * Maps a NullifierKeyValidationRequest to a noir NullifierKeyValidationRequest. - * @param request - The NullifierKeyValidationRequest. - * @returns The noir NullifierKeyValidationRequest. - */ -export function mapNullifierKeyValidationRequestContextToNoir( - request: NullifierKeyValidationRequestContext, -): NullifierKeyValidationRequestContextNoir { +function mapScopedNullifierKeyValidationRequestToNoir( + request: ScopedNullifierKeyValidationRequest, +): ScopedNullifierKeyValidationRequestNoir { return { - master_nullifier_public_key: mapPointToNoir(request.masterNullifierPublicKey), - app_nullifier_secret_key: mapFieldToNoir(request.appNullifierSecretKey), + request: mapNullifierKeyValidationRequestToNoir(request.request), contract_address: mapAztecAddressToNoir(request.contractAddress), }; } -/** - * Maps a noir NullifierKeyValidationRequestContext to NullifierKeyValidationRequestContext. - * @param request - The noir NullifierKeyValidationRequestContext. - * @returns The TS NullifierKeyValidationRequestContext. - */ -export function mapNullifierKeyValidationRequestContextFromNoir( - request: NullifierKeyValidationRequestContextNoir, -): NullifierKeyValidationRequestContext { - return new NullifierKeyValidationRequestContext( - mapPointFromNoir(request.master_nullifier_public_key), - mapFieldFromNoir(request.app_nullifier_secret_key), +function mapScopedNullifierKeyValidationRequestFromNoir( + request: ScopedNullifierKeyValidationRequestNoir, +): ScopedNullifierKeyValidationRequest { + return new ScopedNullifierKeyValidationRequest( + mapNullifierKeyValidationRequestFromNoir(request.request), mapAztecAddressFromNoir(request.contract_address), ); } @@ -701,6 +700,29 @@ export function mapL2ToL1MessageToNoir(message: L2ToL1Message): L2ToL1MessageNoi return { recipient: mapEthAddressToNoir(message.recipient), content: mapFieldToNoir(message.content), + counter: mapNumberToNoir(message.counter), + }; +} + +function mapL2ToL1MessageFromNoir(message: L2ToL1MessageNoir) { + return new L2ToL1Message( + mapEthAddressFromNoir(message.recipient), + mapFieldFromNoir(message.content), + mapNumberFromNoir(message.counter), + ); +} + +function mapScopedL2ToL1MessageFromNoir(message: ScopedL2ToL1MessageNoir) { + return new ScopedL2ToL1Message( + mapL2ToL1MessageFromNoir(message.message), + mapAztecAddressFromNoir(message.contract_address), + ); +} + +function mapScopedL2ToL1MessageToNoir(message: ScopedL2ToL1Message): ScopedL2ToL1MessageNoir { + return { + message: mapL2ToL1MessageToNoir(message.message), + contract_address: mapAztecAddressToNoir(message.contractAddress), }; } @@ -966,15 +988,15 @@ function mapPublicDataReadRequestHintsToNoir(hints: PublicDataReadRequestHints): function mapValidationRequestsToNoir(requests: ValidationRequests): ValidationRequestsNoir { return { for_rollup: mapRollupValidationRequestsToNoir(requests.forRollup), - note_hash_read_requests: mapTuple(requests.noteHashReadRequests, mapReadRequestContextToNoir), - nullifier_read_requests: mapTuple(requests.nullifierReadRequests, mapReadRequestContextToNoir), + note_hash_read_requests: mapTuple(requests.noteHashReadRequests, mapScopedReadRequestToNoir), + nullifier_read_requests: mapTuple(requests.nullifierReadRequests, mapScopedReadRequestToNoir), nullifier_non_existent_read_requests: mapTuple( requests.nullifierNonExistentReadRequests, - mapReadRequestContextToNoir, + mapScopedReadRequestToNoir, ), nullifier_key_validation_requests: mapTuple( requests.nullifierKeyValidationRequests, - mapNullifierKeyValidationRequestContextToNoir, + mapScopedNullifierKeyValidationRequestToNoir, ), public_data_reads: mapTuple(requests.publicDataReads, mapPublicDataReadToNoir), }; @@ -986,22 +1008,22 @@ function mapValidationRequestsFromNoir(requests: ValidationRequestsNoir): Valida mapTupleFromNoir( requests.note_hash_read_requests, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, - mapReadRequestContextFromNoir, + mapScopedReadRequestFromNoir, ), mapTupleFromNoir( requests.nullifier_read_requests, MAX_NULLIFIER_READ_REQUESTS_PER_TX, - mapReadRequestContextFromNoir, + mapScopedReadRequestFromNoir, ), mapTupleFromNoir( requests.nullifier_non_existent_read_requests, MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, - mapReadRequestContextFromNoir, + mapScopedReadRequestFromNoir, ), mapTupleFromNoir( requests.nullifier_key_validation_requests, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, - mapNullifierKeyValidationRequestContextFromNoir, + mapScopedNullifierKeyValidationRequestFromNoir, ), mapTupleFromNoir(requests.public_data_reads, MAX_PUBLIC_DATA_READS_PER_TX, mapPublicDataReadFromNoir), ); @@ -1011,9 +1033,13 @@ export function mapPrivateAccumulatedDataFromNoir( privateAccumulatedData: PrivateAccumulatedDataNoir, ): PrivateAccumulatedData { return new PrivateAccumulatedData( - mapTupleFromNoir(privateAccumulatedData.new_note_hashes, MAX_NEW_NOTE_HASHES_PER_TX, mapNoteHashContextFromNoir), - mapTupleFromNoir(privateAccumulatedData.new_nullifiers, MAX_NEW_NULLIFIERS_PER_TX, mapNullifierFromNoir), - mapTupleFromNoir(privateAccumulatedData.new_l2_to_l1_msgs, MAX_NEW_L2_TO_L1_MSGS_PER_TX, mapFieldFromNoir), + mapTupleFromNoir(privateAccumulatedData.new_note_hashes, MAX_NEW_NOTE_HASHES_PER_TX, mapScopedNoteHashFromNoir), + mapTupleFromNoir(privateAccumulatedData.new_nullifiers, MAX_NEW_NULLIFIERS_PER_TX, mapScopedNullifierFromNoir), + mapTupleFromNoir( + privateAccumulatedData.new_l2_to_l1_msgs, + MAX_NEW_L2_TO_L1_MSGS_PER_TX, + mapScopedL2ToL1MessageFromNoir, + ), mapTupleFromNoir(privateAccumulatedData.encrypted_logs_hashes, MAX_ENCRYPTED_LOGS_PER_TX, mapSideEffectFromNoir), mapTupleFromNoir( privateAccumulatedData.unencrypted_logs_hashes, @@ -1037,9 +1063,9 @@ export function mapPrivateAccumulatedDataFromNoir( export function mapPrivateAccumulatedDataToNoir(data: PrivateAccumulatedData): PrivateAccumulatedDataNoir { return { - new_note_hashes: mapTuple(data.newNoteHashes, mapNoteHashContextToNoir), - new_nullifiers: mapTuple(data.newNullifiers, mapNullifierToNoir), - new_l2_to_l1_msgs: mapTuple(data.newL2ToL1Msgs, mapFieldToNoir), + new_note_hashes: mapTuple(data.newNoteHashes, mapScopedNoteHashToNoir), + new_nullifiers: mapTuple(data.newNullifiers, mapScopedNullifierToNoir), + new_l2_to_l1_msgs: mapTuple(data.newL2ToL1Msgs, mapScopedL2ToL1MessageToNoir), encrypted_logs_hashes: mapTuple(data.encryptedLogsHashes, mapSideEffectToNoir), unencrypted_logs_hashes: mapTuple(data.unencryptedLogsHashes, mapSideEffectToNoir), encrypted_log_preimages_length: mapFieldToNoir(data.encryptedLogPreimagesLength), @@ -1375,8 +1401,8 @@ export function mapPrivateKernelInnerCircuitPrivateInputsToNoir( function mapPrivateKernelTailOutputsToNoir(inputs: PrivateKernelTailOutputs): PrivateKernelTailOutputsNoir { return { - note_hashes: mapTuple(inputs.noteHashes, mapNoteHashContextToNoir), - nullifiers: mapTuple(inputs.nullifiers, mapNullifierToNoir), + note_hashes: mapTuple(inputs.noteHashes, mapScopedNoteHashToNoir), + nullifiers: mapTuple(inputs.nullifiers, mapScopedNullifierToNoir), }; } @@ -1390,9 +1416,9 @@ function mapPrivateKernelTailHintsToNoir(inputs: PrivateKernelTailHints): Privat note_hash_read_request_hints: mapNoteHashReadRequestHintsToNoir(inputs.noteHashReadRequestHints), nullifier_read_request_hints: mapNullifierReadRequestHintsToNoir(inputs.nullifierReadRequestHints), master_nullifier_secret_keys: mapTuple(inputs.masterNullifierSecretKeys, mapGrumpkinPrivateKeyToNoir), - sorted_new_note_hashes: mapTuple(inputs.sortedNewNoteHashes, mapNoteHashContextToNoir), + sorted_new_note_hashes: mapTuple(inputs.sortedNewNoteHashes, mapScopedNoteHashToNoir), sorted_new_note_hashes_indexes: mapTuple(inputs.sortedNewNoteHashesIndexes, mapNumberToNoir), - sorted_new_nullifiers: mapTuple(inputs.sortedNewNullifiers, mapNullifierToNoir), + sorted_new_nullifiers: mapTuple(inputs.sortedNewNullifiers, mapScopedNullifierToNoir), sorted_new_nullifiers_indexes: mapTuple(inputs.sortedNewNullifiersIndexes, mapNumberToNoir), sorted_encrypted_log_hashes: mapTuple(inputs.sortedEncryptedLogHashes, mapSideEffectToNoir), sorted_encrypted_log_hashes_indexes: mapTuple(inputs.sortedEncryptedLogHashesIndexes, mapNumberToNoir), diff --git a/yarn-project/pxe/src/kernel_prover/kernel_prover.test.ts b/yarn-project/pxe/src/kernel_prover/kernel_prover.test.ts index 6c9bb7f2065..58f29d4ceda 100644 --- a/yarn-project/pxe/src/kernel_prover/kernel_prover.test.ts +++ b/yarn-project/pxe/src/kernel_prover/kernel_prover.test.ts @@ -6,11 +6,11 @@ import { MAX_NEW_NOTE_HASHES_PER_TX, MembershipWitness, NoteHash, - NoteHashContext, PrivateCallStackItem, PrivateCircuitPublicInputs, PrivateKernelCircuitPublicInputs, PrivateKernelTailCircuitPublicInputs, + ScopedNoteHash, type TxRequest, VK_TREE_HEIGHT, VerificationKey, @@ -35,6 +35,8 @@ describe('Kernel Prover', () => { let prover: KernelProver; let dependencies: { [name: string]: string[] } = {}; + const contractAddress = AztecAddress.fromBigInt(987654n); + const notesAndSlots: NoteAndSlot[] = Array(10) .fill(null) .map(() => ({ @@ -78,9 +80,12 @@ describe('Kernel Prover', () => { const createProofOutput = (newNoteIndices: number[]) => { const publicInputs = PrivateKernelCircuitPublicInputs.empty(); - const noteHashes = makeTuple(MAX_NEW_NOTE_HASHES_PER_TX, NoteHashContext.empty); + const noteHashes = makeTuple(MAX_NEW_NOTE_HASHES_PER_TX, ScopedNoteHash.empty); for (let i = 0; i < newNoteIndices.length; i++) { - noteHashes[i] = new NoteHashContext(generateFakeSiloedCommitment(notesAndSlots[newNoteIndices[i]]), 0, 0); + noteHashes[i] = new NoteHash(generateFakeSiloedCommitment(notesAndSlots[newNoteIndices[i]]), 0).scope( + 0, + contractAddress, + ); } publicInputs.end.newNoteHashes = noteHashes; diff --git a/yarn-project/pxe/src/kernel_prover/private_inputs_builders/build_private_kernel_tail_hints.ts b/yarn-project/pxe/src/kernel_prover/private_inputs_builders/build_private_kernel_tail_hints.ts index ffa4eef1b9d..efef31f153a 100644 --- a/yarn-project/pxe/src/kernel_prover/private_inputs_builders/build_private_kernel_tail_hints.ts +++ b/yarn-project/pxe/src/kernel_prover/private_inputs_builders/build_private_kernel_tail_hints.ts @@ -9,11 +9,11 @@ import { type MAX_UNENCRYPTED_LOGS_PER_TX, MembershipWitness, NULLIFIER_TREE_HEIGHT, - type Nullifier, - type NullifierKeyValidationRequestContext, type PrivateKernelCircuitPublicInputs, PrivateKernelTailHints, - type ReadRequestContext, + type ScopedNullifier, + type ScopedNullifierKeyValidationRequest, + type ScopedReadRequest, type SideEffect, type SideEffectType, buildNoteHashReadRequestHints, @@ -49,8 +49,8 @@ function sortSideEffects( } function getNullifierReadRequestHints( - nullifierReadRequests: Tuple, - nullifiers: Tuple, + nullifierReadRequests: Tuple, + nullifiers: Tuple, oracle: ProvingDataOracle, ) { const getNullifierMembershipWitness = async (nullifier: Fr) => { @@ -75,14 +75,14 @@ function getNullifierReadRequestHints( async function getMasterNullifierSecretKeys( nullifierKeyValidationRequests: Tuple< - NullifierKeyValidationRequestContext, + ScopedNullifierKeyValidationRequest, typeof MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX >, oracle: ProvingDataOracle, ) { const keys = makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, GrumpkinScalar.zero); for (let i = 0; i < nullifierKeyValidationRequests.length; ++i) { - const request = nullifierKeyValidationRequests[i]; + const request = nullifierKeyValidationRequests[i].request; if (request.isEmpty()) { break; } diff --git a/yarn-project/pxe/src/kernel_prover/private_inputs_builders/build_private_kernel_tail_outputs.ts b/yarn-project/pxe/src/kernel_prover/private_inputs_builders/build_private_kernel_tail_outputs.ts index ab2594b7b62..91d8cd8be0a 100644 --- a/yarn-project/pxe/src/kernel_prover/private_inputs_builders/build_private_kernel_tail_outputs.ts +++ b/yarn-project/pxe/src/kernel_prover/private_inputs_builders/build_private_kernel_tail_outputs.ts @@ -1,28 +1,28 @@ import { MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, - NoteHashContext, - Nullifier, PrivateKernelTailOutputs, + ScopedNoteHash, + ScopedNullifier, } from '@aztec/circuits.js'; import { padArrayEnd } from '@aztec/foundation/collection'; import { type Tuple } from '@aztec/foundation/serialize'; export function buildPrivateKernelTailOutputs( - prevNoteHashes: Tuple, - prevNullifiers: Tuple, + prevNoteHashes: Tuple, + prevNullifiers: Tuple, ) { // Propagate note hashes that are not linked to a nullifier. // Note that note hashes can't link to the first nullifier (counter == 0). const noteHashes = padArrayEnd( prevNoteHashes.filter(n => !n.nullifierCounter), - NoteHashContext.empty(), + ScopedNoteHash.empty(), MAX_NEW_NOTE_HASHES_PER_TX, ); const nullifiers = padArrayEnd( - prevNullifiers.filter(n => n.noteHash.isZero()), - Nullifier.empty(), + prevNullifiers.filter(n => n.nullifiedNoteHash.isZero()), + ScopedNullifier.empty(), MAX_NEW_NULLIFIERS_PER_TX, ); diff --git a/yarn-project/simulator/src/avm/journal/journal.test.ts b/yarn-project/simulator/src/avm/journal/journal.test.ts index 8a42f1e6796..ea08c9a6387 100644 --- a/yarn-project/simulator/src/avm/journal/journal.test.ts +++ b/yarn-project/simulator/src/avm/journal/journal.test.ts @@ -153,7 +153,7 @@ describe('journal', () => { journal.writeL1Message(recipient, msgHash); const journalUpdates = journal.flush(); - expect(journalUpdates.newL1Messages).toEqual([{ recipient, content: msgHash }]); + expect(journalUpdates.newL1Messages).toEqual([expect.objectContaining({ recipient, content: msgHash })]); }); }); @@ -260,8 +260,8 @@ describe('journal', () => { ), ]); expect(journalUpdates.newL1Messages).toEqual([ - { recipient, content: commitment }, - { recipient, content: commitmentT1 }, + expect.objectContaining({ recipient, content: commitment }), + expect.objectContaining({ recipient, content: commitmentT1 }), ]); expect(journalUpdates.nullifierChecks).toEqual([ expect.objectContaining({ nullifier: commitment, exists: true }), @@ -403,7 +403,7 @@ describe('journal', () => { Buffer.concat(log.data.map(f => f.toBuffer())), ), ]); - expect(journalUpdates.newL1Messages).toEqual([{ recipient, content: commitment }]); + expect(journalUpdates.newL1Messages).toEqual([expect.objectContaining({ recipient, content: commitment })]); }); it('Can fork and merge journals', () => { diff --git a/yarn-project/simulator/src/avm/journal/journal.ts b/yarn-project/simulator/src/avm/journal/journal.ts index 3a47c4adebb..7bea5f1c42a 100644 --- a/yarn-project/simulator/src/avm/journal/journal.ts +++ b/yarn-project/simulator/src/avm/journal/journal.ts @@ -285,7 +285,7 @@ export class AvmPersistableStateManager { public writeL1Message(recipient: EthAddress | Fr, content: Fr) { this.log.debug(`L1Messages(${recipient}) += ${content}.`); const recipientAddress = recipient instanceof EthAddress ? recipient : EthAddress.fromField(recipient); - const message = new L2ToL1Message(recipientAddress, content); + const message = new L2ToL1Message(recipientAddress, content, 0); this.newL1Messages.push(message); // TRANSITIONAL: This should be removed once the kernel handles and entire enqueued call per circuit diff --git a/yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts b/yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts index 88c7cadd138..376f64a8cd9 100644 --- a/yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts @@ -465,7 +465,9 @@ describe('Accrued Substate', () => { ).execute(context); const journalState = context.persistableState.flush(); - expect(journalState.newL1Messages).toEqual([{ recipient: EthAddress.fromField(recipient), content }]); + expect(journalState.newL1Messages).toEqual([ + expect.objectContaining({ recipient: EthAddress.fromField(recipient), content }), + ]); }); }); diff --git a/yarn-project/simulator/src/public/hints_builder.ts b/yarn-project/simulator/src/public/hints_builder.ts index b0cb14e33fb..0d83cd44db4 100644 --- a/yarn-project/simulator/src/public/hints_builder.ts +++ b/yarn-project/simulator/src/public/hints_builder.ts @@ -15,11 +15,11 @@ import { type PublicDataRead, type PublicDataTreeLeafPreimage, type PublicDataUpdateRequest, - type ReadRequestContext, + type ScopedReadRequest, buildNullifierNonExistentReadRequestHints, - buildNullifierReadRequestHints, buildPublicDataHints, buildPublicDataReadRequestHints, + buildSiloedNullifierReadRequestHints, } from '@aztec/circuits.js'; import { type Tuple } from '@aztec/foundation/serialize'; import { type IndexedTreeId, type MerkleTreeOperations } from '@aztec/world-state'; @@ -28,14 +28,14 @@ export class HintsBuilder { constructor(private db: MerkleTreeOperations) {} getNullifierReadRequestHints( - nullifierReadRequests: Tuple, + nullifierReadRequests: Tuple, pendingNullifiers: Tuple, ) { - return buildNullifierReadRequestHints(this, nullifierReadRequests, pendingNullifiers); + return buildSiloedNullifierReadRequestHints(this, nullifierReadRequests, pendingNullifiers); } getNullifierNonExistentReadRequestHints( - nullifierNonExistentReadRequests: Tuple, + nullifierNonExistentReadRequests: Tuple, pendingNullifiers: Tuple, ) { return buildNullifierNonExistentReadRequestHints(this, nullifierNonExistentReadRequests, pendingNullifiers); diff --git a/yarn-project/simulator/src/public/index.test.ts b/yarn-project/simulator/src/public/index.test.ts index 0a00456b62e..54973bdc18e 100644 --- a/yarn-project/simulator/src/public/index.test.ts +++ b/yarn-project/simulator/src/public/index.test.ts @@ -8,7 +8,6 @@ import { GlobalVariables, type Header, L1_TO_L2_MSG_TREE_HEIGHT, - L2ToL1Message, NULLIFIER_TREE_HEIGHT, NullifierLeaf, NullifierLeafPreimage, @@ -400,10 +399,8 @@ describe('ACIR public execution simulator', () => { // Assert the l2 to l1 message was created expect(result.newL2ToL1Messages.length).toEqual(1); - - const expectedNewMessage = new L2ToL1Message(portalContractAddress, pedersenHash(params)); - - expect(result.newL2ToL1Messages[0]).toEqual(expectedNewMessage); + expect(result.newL2ToL1Messages[0].recipient).toEqual(portalContractAddress); + expect(result.newL2ToL1Messages[0].content).toEqual(pedersenHash(params)); }); it('Should be able to create a nullifier from the public context', async () => {