diff --git a/noir-projects/aztec-nr/aztec/src/encrypted_logs/encrypted_note_emission.nr b/noir-projects/aztec-nr/aztec/src/encrypted_logs/encrypted_note_emission.nr index 3b9122568b99..e66e76620225 100644 --- a/noir-projects/aztec-nr/aztec/src/encrypted_logs/encrypted_note_emission.nr +++ b/noir-projects/aztec-nr/aztec/src/encrypted_logs/encrypted_note_emission.nr @@ -4,7 +4,7 @@ use crate::{ }; use dep::protocol_types::{ hash::sha256_to_field, address::AztecAddress, point::Point, abis::note_hash::NoteHash, - constants::MAX_NOTE_HASHES_PER_CALL, utils::arrays::find_index + constants::MAX_NOTE_HASHES_PER_CALL }; unconstrained fn compute_unconstrained( @@ -61,13 +61,8 @@ fn emit_with_keys( let note_hash_counter = note_header.note_hash_counter; let storage_slot = note_header.storage_slot; - let note_exists_index = find_index( - context.note_hashes.storage, - |n: NoteHash| n.counter == note_hash_counter - ); - assert( - note_exists_index as u32 != MAX_NOTE_HASHES_PER_CALL, "Can only emit a note log for an existing note." - ); + let note_exists = context.note_hashes.storage.any(|n: NoteHash| n.counter == note_hash_counter); + assert(note_exists, "Can only emit a note log for an existing note."); let contract_address: AztecAddress = context.this_address(); let ovsk_app: Field = context.request_ovsk_app(ovpk.hash()); diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/previous_kernel_validator/previous_kernel_validator_hints.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/previous_kernel_validator/previous_kernel_validator_hints.nr index f2106337cae6..dc6bc18aae53 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/previous_kernel_validator/previous_kernel_validator_hints.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/previous_kernel_validator/previous_kernel_validator_hints.nr @@ -1,6 +1,6 @@ use dep::types::{ abis::{kernel_circuit_public_inputs::PrivateKernelCircuitPublicInputs, note_hash::ScopedNoteHash}, - constants::{MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX}, utils::arrays::find_index + constants::{MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX}, utils::arrays::find_index_hint }; struct PreviousKernelValidatorHints { @@ -13,7 +13,7 @@ unconstrained pub fn generate_previous_kernel_validator_hints(previous_kernel: P let nullifiers = previous_kernel.end.nullifiers; for i in 0..nullifiers.len() { let nullified_note_hash = nullifiers[i].nullifier.note_hash; - let note_hash_index = find_index( + let note_hash_index = find_index_hint( note_hashes, |n: ScopedNoteHash| n.value() == nullified_note_hash ); diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/private_call_data_validator.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/private_call_data_validator.nr index dec6d9d005b5..ae0463425d36 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/private_call_data_validator.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/private_call_data_validator.nr @@ -15,19 +15,9 @@ use dep::types::{ address::{AztecAddress, PartialAddress}, contract_class_id::ContractClassId, constants::MAX_FIELD_VALUE, hash::{private_functions_root_from_siblings, stdlib_recursion_verification_key_compress_native_vk}, - traits::is_empty, transaction::tx_request::TxRequest, utils::arrays::find_index + traits::is_empty, transaction::tx_request::TxRequest, utils::arrays::find_index_hint }; -unconstrained fn match_log_to_note( - note_log: NoteLogHash, - accumulated_note_hashes: [ScopedNoteHash; N] -) -> u32 { - find_index( - accumulated_note_hashes, - |n: ScopedNoteHash| n.counter() == note_log.note_hash_counter - ) -} - unconstrained fn find_first_revertible_private_call_request_index(public_inputs: PrivateCircuitPublicInputs) -> u32 { find_first_revertible_item_index( public_inputs.min_revertible_side_effect_counter, @@ -60,7 +50,12 @@ fn validate_call_context( } } -fn validate_incrementing_counters_within_range(counter_start: u32, counter_end: u32, items: [T; N], num_items: u32) where T: Ordered { +fn validate_incrementing_counters_within_range( + counter_start: u32, + counter_end: u32, + items: [T; N], + num_items: u32 +) where T: Ordered { let mut prev_counter = counter_start; let mut should_check = true; for i in 0..N { @@ -76,12 +71,7 @@ fn validate_incrementing_counters_within_range(counter_start: u32, counter assert(prev_counter < counter_end, "counter must be smaller than the end counter of the call"); } -fn validate_incrementing_counter_ranges_within_range( - counter_start: u32, - counter_end: u32, - items: [T; N], - num_items: u32 -) where T: RangeOrdered { +fn validate_incrementing_counter_ranges_within_range(counter_start: u32, counter_end: u32, items: [T; N], num_items: u32) where T: RangeOrdered { let mut prev_counter = counter_start; let mut should_check = true; for i in 0..N { @@ -111,7 +101,7 @@ impl PrivateCallDataValidator { PrivateCallDataValidator { data, array_lengths } } - pub fn validate(self, accumulated_note_hashes: [ScopedNoteHash; N]) { + pub fn validate(self, accumulated_note_hashes: [ScopedNoteHash; N]) { self.validate_contract_address(); self.validate_call(); self.validate_private_call_requests(); @@ -138,7 +128,7 @@ impl PrivateCallDataValidator { tx_request.origin, call_stack_item.contract_address, "origin address does not match call stack items contract address" ); assert_eq( - tx_request.function_data.hash(), call_stack_item.function_data.hash(), "tx_request function_data must match call_stack_item function_data" + tx_request.function_data, call_stack_item.function_data, "tx_request function_data must match call_stack_item function_data" ); assert_eq( tx_request.args_hash, call_stack_item.public_inputs.args_hash, "noir function args passed to tx_request must match args in the call_stack_item" @@ -394,7 +384,7 @@ impl PrivateCallDataValidator { ); } - fn validate_note_logs(self, accumulated_note_hashes: [ScopedNoteHash; N]) { + fn validate_note_logs(self, accumulated_note_hashes: [ScopedNoteHash; N]) { let note_logs = self.data.call_stack_item.public_inputs.note_encrypted_logs_hashes; let num_logs = self.array_lengths.note_encrypted_logs_hashes; let storage_contract_address = self.data.call_stack_item.public_inputs.call_context.storage_contract_address; @@ -402,10 +392,14 @@ impl PrivateCallDataValidator { for i in 0..note_logs.len() { should_check &= i != num_logs; if should_check { - let note_index = match_log_to_note(note_logs[i], accumulated_note_hashes); + let note_log = note_logs[i]; + let note_index = find_index_hint( + accumulated_note_hashes, + |n: ScopedNoteHash| n.counter() == note_log.note_hash_counter + ); assert(note_index != N, "could not find note hash linked to note log"); assert_eq( - note_logs[i].note_hash_counter, accumulated_note_hashes[note_index].counter(), "could not find note hash linked to note log" + note_log.note_hash_counter, accumulated_note_hashes[note_index].counter(), "could not find note hash linked to note log" ); // If the note_index points to an empty note hash, the following check will fail. assert_eq( diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/reset_output_composer.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/reset_output_composer.nr index 6da82f388187..39495cade166 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/reset_output_composer.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/reset_output_composer.nr @@ -1,11 +1,15 @@ mod reset_output_hints; use crate::components::reset_output_composer::{reset_output_hints::{generate_reset_output_hints, ResetOutputHints}}; +use dep::reset_kernel_lib::{ + KeyValidationHint, NoteHashReadRequestHints, NullifierReadRequestHints, TransientDataIndexHint, + PrivateValidationRequestProcessor +}; use dep::types::{ abis::{ kernel_circuit_public_inputs::PrivateKernelCircuitPublicInputs, log_hash::{NoteLogHash, ScopedEncryptedLogHash}, note_hash::ScopedNoteHash, - nullifier::ScopedNullifier + nullifier::ScopedNullifier, validation_requests::PrivateValidationRequests }, address::AztecAddress, constants::{ @@ -15,64 +19,83 @@ use dep::types::{ hash::{mask_encrypted_log_hash, silo_note_hash, silo_nullifier}, utils::arrays::sort_by_counters_asc }; -struct PrivateKernelResetOutputs { - note_hashes: [ScopedNoteHash; MAX_NOTE_HASHES_PER_TX], - nullifiers: [ScopedNullifier; MAX_NULLIFIERS_PER_TX], - note_encrypted_log_hashes: [NoteLogHash; MAX_NOTE_ENCRYPTED_LOGS_PER_TX], - encrypted_log_hashes: [ScopedEncryptedLogHash; MAX_ENCRYPTED_LOGS_PER_TX], -} - -struct ResetOutputComposer { +struct ResetOutputComposer< + let NH_RR_PENDING: u32, + let NH_RR_SETTLED: u32, + let NLL_RR_PENDING: u32, + let NLL_RR_SETTLED: u32, + let KEY_VALIDATION_REQUESTS: u32, +> { previous_kernel: PrivateKernelCircuitPublicInputs, + validation_request_processor: PrivateValidationRequestProcessor, note_hash_siloing_amount: u32, nullifier_siloing_amount: u32, encrypted_log_siloing_amount: u32, hints: ResetOutputHints, } -impl ResetOutputComposer { - pub fn new( +impl< + let NH_RR_PENDING: u32, + let NH_RR_SETTLED: u32, + let NLL_RR_PENDING: u32, + let NLL_RR_SETTLED: u32, + let KEY_VALIDATION_REQUESTS: u32, +> ResetOutputComposer< + NH_RR_PENDING, + NH_RR_SETTLED, + NLL_RR_PENDING, + NLL_RR_SETTLED, + KEY_VALIDATION_REQUESTS, +> { + pub fn new( previous_kernel: PrivateKernelCircuitPublicInputs, - transient_nullifier_indexes_for_note_hashes: [u32; MAX_NOTE_HASHES_PER_TX], - transient_note_hash_indexes_for_nullifiers: [u32; MAX_NULLIFIERS_PER_TX], + validation_request_processor: PrivateValidationRequestProcessor, + transient_data_index_hints: [TransientDataIndexHint; TRANSIENT_DATA_AMOUNT], note_hash_siloing_amount: u32, nullifier_siloing_amount: u32, encrypted_log_siloing_amount: u32 ) -> Self { - let hints = generate_reset_output_hints( + let hints = generate_reset_output_hints(previous_kernel, transient_data_index_hints); + ResetOutputComposer { previous_kernel, - transient_nullifier_indexes_for_note_hashes, - transient_note_hash_indexes_for_nullifiers - ); - ResetOutputComposer { previous_kernel, note_hash_siloing_amount, nullifier_siloing_amount, encrypted_log_siloing_amount, hints } + validation_request_processor, + note_hash_siloing_amount, + nullifier_siloing_amount, + encrypted_log_siloing_amount, + hints + } } - pub fn finish(self) -> PrivateKernelResetOutputs { - let note_hashes = if self.note_hash_siloing_amount == 0 { + pub fn finish(self) -> PrivateKernelCircuitPublicInputs { + let mut output = self.previous_kernel; + + output.validation_requests = self.validation_request_processor.compose(); + + output.end.note_hashes = if self.note_hash_siloing_amount == 0 { self.hints.kept_note_hashes } else { self.get_sorted_siloed_note_hashes() }; - let nullifiers = if self.nullifier_siloing_amount == 0 { + output.end.nullifiers = if self.nullifier_siloing_amount == 0 { self.hints.kept_nullifiers } else { self.get_sorted_siloed_nullifiers() }; - let note_encrypted_log_hashes = if self.note_hash_siloing_amount == 0 { + output.end.note_encrypted_logs_hashes = if self.note_hash_siloing_amount == 0 { self.hints.kept_note_encrypted_log_hashes } else { self.get_sorted_note_encrypted_log_hashes() }; - let encrypted_log_hashes = if self.encrypted_log_siloing_amount == 0 { + output.end.encrypted_logs_hashes = if self.encrypted_log_siloing_amount == 0 { self.previous_kernel.end.encrypted_logs_hashes } else { self.get_sorted_masked_encrypted_log_hashes() }; - PrivateKernelResetOutputs { note_hashes, nullifiers, note_encrypted_log_hashes, encrypted_log_hashes } + output } fn get_sorted_siloed_note_hashes(self) -> [ScopedNoteHash; MAX_NOTE_HASHES_PER_TX] { diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/reset_output_composer/reset_output_hints.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/reset_output_composer/reset_output_hints.nr index bc1e171be4f6..9f7ec5b34e7f 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/reset_output_composer/reset_output_hints.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/reset_output_composer/reset_output_hints.nr @@ -5,6 +5,7 @@ use crate::components::reset_output_composer::reset_output_hints::{ get_transient_or_propagated_note_hash_indexes_for_logs::get_transient_or_propagated_note_hash_indexes_for_logs, squash_transient_data::squash_transient_data }; +use dep::reset_kernel_lib::TransientDataIndexHint; use dep::types::{ abis::{ kernel_circuit_public_inputs::PrivateKernelCircuitPublicInputs, log_hash::NoteLogHash, @@ -32,17 +33,15 @@ struct ResetOutputHints { sorted_encrypted_log_hash_indexes: [u32; MAX_ENCRYPTED_LOGS_PER_TX], } -pub fn generate_reset_output_hints( +unconstrained pub fn generate_reset_output_hints( previous_kernel: PrivateKernelCircuitPublicInputs, - transient_nullifier_indexes_for_note_hashes: [u32; MAX_NOTE_HASHES_PER_TX], - transient_note_hash_indexes_for_nullifiers: [u32; MAX_NULLIFIERS_PER_TX] + transient_data_index_hints: [TransientDataIndexHint; NUM_TRANSIENT_DATA_INDEX_HINTS] ) -> ResetOutputHints { let (kept_note_hashes, kept_nullifiers, kept_note_encrypted_log_hashes) = squash_transient_data( previous_kernel.end.note_hashes, previous_kernel.end.nullifiers, previous_kernel.end.note_encrypted_logs_hashes, - transient_nullifier_indexes_for_note_hashes, - transient_note_hash_indexes_for_nullifiers + transient_data_index_hints ); // note_hashes @@ -56,7 +55,8 @@ pub fn generate_reset_output_hints( let transient_or_propagated_note_hash_indexes_for_logs = get_transient_or_propagated_note_hash_indexes_for_logs( previous_kernel.end.note_encrypted_logs_hashes, previous_kernel.end.note_hashes, - kept_note_hashes + kept_note_hashes, + transient_data_index_hints ); // encrypted_log_hashes diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/reset_output_composer/reset_output_hints/get_transient_or_propagated_note_hash_indexes_for_logs.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/reset_output_composer/reset_output_hints/get_transient_or_propagated_note_hash_indexes_for_logs.nr index 8a07d134d28e..a96feb849b17 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/reset_output_composer/reset_output_hints/get_transient_or_propagated_note_hash_indexes_for_logs.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/reset_output_composer/reset_output_hints/get_transient_or_propagated_note_hash_indexes_for_logs.nr @@ -1,9 +1,11 @@ -use dep::types::{abis::{log_hash::NoteLogHash, note_hash::ScopedNoteHash}}; +use dep::reset_kernel_lib::TransientDataIndexHint; +use dep::types::{abis::{log_hash::NoteLogHash, note_hash::ScopedNoteHash}, utils::arrays::find_index_hint}; -pub fn get_transient_or_propagated_note_hash_indexes_for_logs( +unconstrained pub fn get_transient_or_propagated_note_hash_indexes_for_logs( note_logs: [NoteLogHash; NUM_LOGS], note_hashes: [ScopedNoteHash; NUM_NOTE_HASHES], - expected_note_hashes: [ScopedNoteHash; NUM_NOTE_HASHES] + expected_note_hashes: [ScopedNoteHash; NUM_NOTE_HASHES], + transient_data_index_hints: [TransientDataIndexHint; NUM_INDEX_HINTS] ) -> [u32; NUM_LOGS] { let mut indexes = [0; NUM_LOGS]; for i in 0..note_logs.len() { @@ -18,7 +20,7 @@ pub fn get_transient_or_propagated_note_hash_indexes_for_logs( +unconstrained pub fn squash_transient_data( note_hashes: [ScopedNoteHash; M], nullifiers: [ScopedNullifier; N], logs: [NoteLogHash; P], - transient_nullifier_indexes_for_note_hashes: [u32; M], - transient_note_hash_indexes_for_nullifiers: [u32; N] + transient_data_index_hints: [TransientDataIndexHint; NUM_TRANSIENT_DATA_INDEX_HINTS] ) -> ([ScopedNoteHash; M], [ScopedNullifier; N], [NoteLogHash; P]) { + let mut transient_nullifier_indexes_for_note_hashes = [N; M]; + let mut transient_note_hash_indexes_for_nullifiers = [M; N]; + for i in 0..transient_data_index_hints.len() { + let hint = transient_data_index_hints[i]; + if hint.note_hash_index != M { + transient_nullifier_indexes_for_note_hashes[hint.note_hash_index] = hint.nullifier_index; + transient_note_hash_indexes_for_nullifiers[hint.nullifier_index] = hint.note_hash_index; + } + } + let mut propagated_note_hashes = BoundedVec::new(); for i in 0..note_hashes.len() { if transient_nullifier_indexes_for_note_hashes[i] == N { diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/reset_output_validator.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/reset_output_validator.nr index 2bac6e399bf0..0beb838941c1 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/reset_output_validator.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/components/reset_output_validator.nr @@ -1,35 +1,46 @@ -use crate::components::{reset_output_composer::{PrivateKernelResetOutputs, ResetOutputHints}}; -use dep::reset_kernel_lib::verify_squashed_transient_data; +use crate::components::{reset_output_composer::ResetOutputHints}; +use dep::reset_kernel_lib::{PrivateValidationRequestProcessor, TransientDataIndexHint, verify_squashed_transient_data}; use dep::types::{ abis::{ kernel_circuit_public_inputs::PrivateKernelCircuitPublicInputs, log_hash::{NoteLogHash, ScopedEncryptedLogHash}, note_hash::ScopedNoteHash, nullifier::ScopedNullifier }, - constants::{MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX}, hash::{mask_encrypted_log_hash, silo_note_hash, silo_nullifier}, traits::is_empty, utils::arrays::{assert_sorted_transformed_value_array, assert_sorted_transformed_value_array_capped_size} }; -struct ResetOutputValidator { - output: PrivateKernelResetOutputs, +struct ResetOutputValidator< + let NH_RR_PENDING: u32, + let NH_RR_SETTLED: u32, + let NLL_RR_PENDING: u32, + let NLL_RR_SETTLED: u32, + let KEY_VALIDATION_REQUESTS: u32, + let NUM_TRANSIENT_DATA_INDEX_HINTS: u32 +> { + output: PrivateKernelCircuitPublicInputs, previous_kernel: PrivateKernelCircuitPublicInputs, - transient_nullifier_indexes_for_note_hashes: [u32; MAX_NOTE_HASHES_PER_TX], - transient_note_hash_indexes_for_nullifiers: [u32; MAX_NULLIFIERS_PER_TX], - split_counter: u32, + validation_request_processor: PrivateValidationRequestProcessor, + transient_data_index_hints: [TransientDataIndexHint; NUM_TRANSIENT_DATA_INDEX_HINTS], note_hash_siloing_amount: u32, nullifier_siloing_amount: u32, encrypted_log_siloing_amount: u32, hints: ResetOutputHints, } -impl ResetOutputValidator { +impl< + let NH_RR_PENDING: u32, + let NH_RR_SETTLED: u32, + let NLL_RR_PENDING: u32, + let NLL_RR_SETTLED: u32, + let KEY_VALIDATION_REQUESTS: u32, + let NUM_TRANSIENT_DATA_INDEX_HINTS: u32 +> ResetOutputValidator { pub fn new( - output: PrivateKernelResetOutputs, + output: PrivateKernelCircuitPublicInputs, previous_kernel: PrivateKernelCircuitPublicInputs, - transient_nullifier_indexes_for_note_hashes: [u32; MAX_NOTE_HASHES_PER_TX], - transient_note_hash_indexes_for_nullifiers: [u32; MAX_NULLIFIERS_PER_TX], - split_counter: u32, + validation_request_processor: PrivateValidationRequestProcessor, + transient_data_index_hints: [TransientDataIndexHint; NUM_TRANSIENT_DATA_INDEX_HINTS], note_hash_siloing_amount: u32, nullifier_siloing_amount: u32, encrypted_log_siloing_amount: u32, @@ -38,9 +49,8 @@ impl ResetOutputValidator { ResetOutputValidator { output, previous_kernel, - transient_nullifier_indexes_for_note_hashes, - transient_note_hash_indexes_for_nullifiers, - split_counter, + validation_request_processor, + transient_data_index_hints, note_hash_siloing_amount, nullifier_siloing_amount, encrypted_log_siloing_amount, @@ -49,6 +59,10 @@ impl ResetOutputValidator { } pub fn validate(self) { + self.validate_unchanged_data(); + + self.validation_request_processor.validate(self.output.validation_requests); + verify_squashed_transient_data( self.previous_kernel.end.note_hashes, self.previous_kernel.end.nullifiers, @@ -56,31 +70,56 @@ impl ResetOutputValidator { self.hints.kept_note_hashes, self.hints.kept_nullifiers, self.hints.kept_note_encrypted_log_hashes, - self.transient_nullifier_indexes_for_note_hashes, - self.transient_note_hash_indexes_for_nullifiers, + self.transient_data_index_hints, self.hints.transient_or_propagated_note_hash_indexes_for_logs, - self.split_counter + self.output.validation_requests.split_counter.unwrap_unchecked() ); + self.validate_sorted_siloed_data(); + } + + fn validate_unchanged_data(self) { + assert_eq(self.output.constants, self.previous_kernel.constants); + + assert_eq( + self.output.min_revertible_side_effect_counter, self.previous_kernel.min_revertible_side_effect_counter + ); + + assert_eq(self.output.public_teardown_call_request, self.previous_kernel.public_teardown_call_request); + + assert_eq(self.output.fee_payer, self.previous_kernel.fee_payer); + + // accumulated_data + assert_eq(self.output.end.l2_to_l1_msgs, self.previous_kernel.end.l2_to_l1_msgs); + assert_eq(self.output.end.unencrypted_logs_hashes, self.previous_kernel.end.unencrypted_logs_hashes); + assert_eq(self.output.end.public_call_requests, self.previous_kernel.end.public_call_requests); + assert_eq(self.output.end.private_call_stack, self.previous_kernel.end.private_call_stack); + } + + fn validate_sorted_siloed_data(self) { + // note_hashes + // note_encrypted_logs_hashes if self.note_hash_siloing_amount == 0 { - assert_eq(self.output.note_hashes, self.hints.kept_note_hashes, "output note hashes mismatch"); + assert_eq(self.output.end.note_hashes, self.hints.kept_note_hashes, "output note hashes mismatch"); assert_eq( - self.output.note_encrypted_log_hashes, self.hints.kept_note_encrypted_log_hashes, "output note logs mismatch" + self.output.end.note_encrypted_logs_hashes, self.hints.kept_note_encrypted_log_hashes, "output note logs mismatch" ); } else { self.validate_sorted_siloed_note_hashes(); self.validate_sorted_note_logs(); } + // nullifiers if self.nullifier_siloing_amount == 0 { - assert_eq(self.output.nullifiers, self.hints.kept_nullifiers, "output nullifiers mismatch"); + assert_eq(self.output.end.nullifiers, self.hints.kept_nullifiers, "output nullifiers mismatch"); } else { self.validate_sorted_siloed_nullifiers(); } + // encrypted_logs_hashes if self.encrypted_log_siloing_amount == 0 { assert_eq( - self.output.encrypted_log_hashes, self.previous_kernel.end.encrypted_logs_hashes, "output encrypted logs mismatch" + self.output.end.encrypted_logs_hashes, self.previous_kernel.end.encrypted_logs_hashes, "output encrypted logs mismatch" ); } else { self.validate_sorted_masked_encrypted_logs(); @@ -99,9 +138,9 @@ impl ResetOutputValidator { // Check siloing. let kept_note_hashes = self.hints.kept_note_hashes; - let siloed_note_hashes = self.output.note_hashes; + let siloed_note_hashes = self.output.end.note_hashes; let sorted_indexes = self.hints.sorted_note_hash_indexes; - let tx_hash = self.output.nullifiers[0].value(); // First nullifier is tx hash. + let tx_hash = self.output.end.nullifiers[0].value(); // First nullifier is tx hash. for i in 0..kept_note_hashes.len() { if i < self.note_hash_siloing_amount { let note_hash = kept_note_hashes[i]; @@ -111,7 +150,7 @@ impl ResetOutputValidator { assert_eq(siloed_note_hash.value(), siloed_value, "incorrect siloed note hashes"); } else { // Don't have to check empty items here. - // assert_sorted_transformed_value_array_capped_size ensures that there are the same amount of empty items padded in kept_note_hashes and in self.output.note_hashes. + // assert_sorted_transformed_value_array_capped_size ensures that there are the same amount of empty items padded in kept_note_hashes and in self.output.end.note_hashes. } } @@ -130,7 +169,7 @@ impl ResetOutputValidator { // silo_nullifier() will return the already-siloed value if contract address is zero. assert_sorted_transformed_value_array_capped_size( self.hints.kept_nullifiers, - self.output.nullifiers, + self.output.end.nullifiers, |prev: ScopedNullifier, out: ScopedNullifier| (out.value() == silo_nullifier(prev)) & (out.counter() == prev.counter()) & @@ -156,7 +195,7 @@ impl ResetOutputValidator { // Consider adding a constant for it only when this becomes too costly. assert_sorted_transformed_value_array( self.hints.kept_note_encrypted_log_hashes, - self.output.note_encrypted_log_hashes, + self.output.end.note_encrypted_logs_hashes, |prev: NoteLogHash, out: NoteLogHash| (out.value == prev.value) & (out.length == prev.length) & @@ -171,7 +210,7 @@ impl ResetOutputValidator { // If run repeatedly, it will return the masked contract address when randomness becomes 0. assert_sorted_transformed_value_array_capped_size( self.previous_kernel.end.encrypted_logs_hashes, - self.output.encrypted_log_hashes, + self.output.end.encrypted_logs_hashes, |prev: ScopedEncryptedLogHash, out: ScopedEncryptedLogHash| (out.contract_address == mask_encrypted_log_hash(prev)) & (out.log_hash.value == prev.log_hash.value) & diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_reset.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_reset.nr index 499ccbf757bf..e64fb83cbde8 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_reset.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_reset.nr @@ -1,10 +1,10 @@ use crate::components::{ - reset_output_composer::{PrivateKernelResetOutputs, ResetOutputComposer, ResetOutputHints}, + reset_output_composer::{ResetOutputComposer, ResetOutputHints}, reset_output_validator::ResetOutputValidator }; use dep::reset_kernel_lib::{ KeyValidationHint, NoteHashReadRequestHints, NullifierReadRequestHints, - PrivateValidationRequestProcessor + PrivateValidationRequestProcessor, TransientDataIndexHint }; use dep::types::{ abis::private_kernel_data::PrivateKernelData, @@ -17,31 +17,38 @@ global ALLOWED_PREVIOUS_CIRCUITS = [ PRIVATE_KERNEL_INNER_INDEX, ]; -struct PrivateKernelResetHints { - transient_nullifier_indexes_for_note_hashes: [u32; MAX_NOTE_HASHES_PER_TX], - transient_note_hash_indexes_for_nullifiers: [u32; MAX_NULLIFIERS_PER_TX], +struct PrivateKernelResetHints { note_hash_read_request_hints: NoteHashReadRequestHints, nullifier_read_request_hints: NullifierReadRequestHints, key_validation_hints: [KeyValidationHint; KEY_VALIDATION_REQUESTS], + transient_data_index_hints: [TransientDataIndexHint; TRANSIENT_DATA_AMOUNT], validation_requests_split_counter: u32, } -struct PrivateKernelResetCircuitPrivateInputs { +struct PrivateKernelResetCircuitPrivateInputs { previous_kernel: PrivateKernelData, - hints: PrivateKernelResetHints, + hints: PrivateKernelResetHints, } -impl PrivateKernelResetCircuitPrivateInputs { +impl< + let NH_RR_PENDING: u32, + let NH_RR_SETTLED: u32, + let NLL_RR_PENDING: u32, + let NLL_RR_SETTLED: u32, + let KEY_VALIDATION_REQUESTS: u32, + let TRANSIENT_DATA_AMOUNT: u32 +> PrivateKernelResetCircuitPrivateInputs { unconstrained fn generate_output( self, + validation_request_processor: PrivateValidationRequestProcessor, note_hash_siloing_amount: u32, nullifier_siloing_amount: u32, encrypted_log_siloing_amount: u32 - ) -> (PrivateKernelResetOutputs, ResetOutputHints) { + ) -> (PrivateKernelCircuitPublicInputs, ResetOutputHints) { let composer = ResetOutputComposer::new( self.previous_kernel.public_inputs, - self.hints.transient_nullifier_indexes_for_note_hashes, - self.hints.transient_note_hash_indexes_for_nullifiers, + validation_request_processor, + self.hints.transient_data_index_hints, note_hash_siloing_amount, nullifier_siloing_amount, encrypted_log_siloing_amount @@ -55,8 +62,22 @@ impl PrivateKernelCircuitPublicInputs { + let previous_public_inputs = self.previous_kernel.public_inputs; + let validation_request_processor = 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.note_hashes, + note_hash_tree_root: previous_public_inputs.constants.historical_header.state.partial.note_hash_tree.root, + nullifier_read_request_hints: self.hints.nullifier_read_request_hints, + pending_nullifiers: previous_public_inputs.end.nullifiers, + nullifier_tree_root: previous_public_inputs.constants.historical_header.state.partial.nullifier_tree.root, + key_validation_hints: self.hints.key_validation_hints, + validation_requests_split_counter: self.hints.validation_requests_split_counter + }; + // Generate output. let (output, output_hints) = self.generate_output( + validation_request_processor, note_hash_siloing_amount, nullifier_siloing_amount, encrypted_log_siloing_amount @@ -68,27 +89,13 @@ impl { previous_kernel: FixtureBuilder, - transient_nullifier_indexes_for_note_hashes: [u32; MAX_NOTE_HASHES_PER_TX], - transient_note_hash_indexes_for_nullifiers: [u32; MAX_NULLIFIERS_PER_TX], - note_hash_read_request_hints_builder: NoteHashReadRequestHintsBuilder, - nullifier_read_request_hints_builder: NullifierReadRequestHintsBuilder, + transient_data_index_hints: [TransientDataIndexHint; NUM_INDEX_HINTS], + note_hash_read_request_hints_builder: NoteHashReadRequestHintsBuilder<6, 3>, + nullifier_read_request_hints_builder: NullifierReadRequestHintsBuilder<5, 2>, validation_requests_split_counter: u32, note_hash_siloing_amount: u32, nullifier_siloing_amount: u32, encrypted_log_siloing_amount: u32, } - impl PrivateKernelResetInputsBuilder { - pub fn new() -> Self { + impl PrivateKernelResetInputsBuilder { + pub fn new() -> PrivateKernelResetInputsBuilder<6> { let mut previous_kernel = FixtureBuilder::new().in_vk_tree(PRIVATE_KERNEL_INNER_INDEX); previous_kernel.set_first_nullifier(); PrivateKernelResetInputsBuilder { previous_kernel, - transient_nullifier_indexes_for_note_hashes: [MAX_NULLIFIERS_PER_TX; MAX_NOTE_HASHES_PER_TX], - transient_note_hash_indexes_for_nullifiers: [MAX_NOTE_HASHES_PER_TX; MAX_NULLIFIERS_PER_TX], - note_hash_read_request_hints_builder: NoteHashReadRequestHintsBuilder::new(MAX_NOTE_HASH_READ_REQUESTS_PER_TX), - nullifier_read_request_hints_builder: NullifierReadRequestHintsBuilder::new(MAX_NULLIFIER_READ_REQUESTS_PER_TX), + transient_data_index_hints: [TransientDataIndexHint::nada(MAX_NULLIFIERS_PER_TX, MAX_NOTE_HASHES_PER_TX); 6], + note_hash_read_request_hints_builder: NoteHashReadRequestHintsBuilder::new(), + nullifier_read_request_hints_builder: NullifierReadRequestHintsBuilder::new(), validation_requests_split_counter: 0, note_hash_siloing_amount: 0, nullifier_siloing_amount: 0, @@ -195,8 +193,11 @@ mod tests { pub fn nullify_pending_note_hash(&mut self, nullifier_index: u32, note_hash_index: u32) { let note_hash = self.previous_kernel.note_hashes.get(note_hash_index).note_hash; self.previous_kernel.nullifiers.storage[nullifier_index].nullifier.note_hash = 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; + let num_hints = find_index_hint( + self.transient_data_index_hints, + |hint: TransientDataIndexHint| hint.nullifier_index == MAX_NULLIFIERS_PER_TX + ); + self.transient_data_index_hints[num_hints] = TransientDataIndexHint { nullifier_index, note_hash_index }; } pub fn compute_output_note_hashes(self, note_hashes: [ScopedNoteHash; N]) -> [ScopedNoteHash; N] { @@ -241,11 +242,10 @@ mod tests { pub fn execute(&mut self) -> PrivateKernelCircuitPublicInputs { let hints = PrivateKernelResetHints { - transient_nullifier_indexes_for_note_hashes: self.transient_nullifier_indexes_for_note_hashes, - transient_note_hash_indexes_for_nullifiers: self.transient_note_hash_indexes_for_nullifiers, note_hash_read_request_hints: self.note_hash_read_request_hints_builder.to_hints(), nullifier_read_request_hints: self.nullifier_read_request_hints_builder.to_hints(), - key_validation_hints: [KeyValidationHint::empty(); MAX_KEY_VALIDATION_REQUESTS_PER_TX], + key_validation_hints: [KeyValidationHint::nada(MAX_KEY_VALIDATION_REQUESTS_PER_TX); 2], + transient_data_index_hints: self.transient_data_index_hints, validation_requests_split_counter: self.validation_requests_split_counter }; @@ -399,7 +399,7 @@ mod tests { assert(is_empty_array(public_inputs.end.note_hashes)); // The nullifier at index 1 is chopped. - assert(array_eq(public_inputs.end.nullifiers, [nullifiers[0], nullifiers[2]])); + assert_array_eq(public_inputs.end.nullifiers, [nullifiers[0], nullifiers[2]]); assert(is_empty_array(public_inputs.end.note_encrypted_logs_hashes)); } @@ -416,13 +416,13 @@ mod tests { let public_inputs = builder.execute(); // The 0th hash is chopped. - assert(array_eq(public_inputs.end.note_hashes, [note_hashes[1]])); + assert_array_eq(public_inputs.end.note_hashes, [note_hashes[1]]); // The nullifier at index 1 is chopped. - assert(array_eq(public_inputs.end.nullifiers, [nullifiers[0], nullifiers[2]])); + assert_array_eq(public_inputs.end.nullifiers, [nullifiers[0], nullifiers[2]]); // The 0th note log is chopped. - assert(array_eq(public_inputs.end.note_encrypted_logs_hashes, [note_logs[1]])); + assert_array_eq(public_inputs.end.note_encrypted_logs_hashes, [note_logs[1]]); } #[test] @@ -440,7 +440,7 @@ mod tests { assert(is_empty_array(public_inputs.end.note_hashes)); // Only the first nullifier is left after squashing. - assert(array_eq(public_inputs.end.nullifiers, [nullifiers[0]])); + assert_array_eq(public_inputs.end.nullifiers, [nullifiers[0]]); assert(is_empty_array(public_inputs.end.note_encrypted_logs_hashes)); } @@ -475,7 +475,7 @@ mod tests { assert(is_empty_array(public_inputs.end.note_hashes)); // Only the first nullifier is left after squashing. - assert(array_eq(public_inputs.end.nullifiers, [nullifiers[0]])); + assert_array_eq(public_inputs.end.nullifiers, [nullifiers[0]]); assert(is_empty_array(public_inputs.end.note_encrypted_logs_hashes)); } @@ -486,22 +486,8 @@ mod tests { builder.previous_kernel.append_nullifiers(2); // The nullifier at index 1 is nullifying the hash at index 0; builder.nullify_pending_note_hash(1, 0); - // Change the hint for the note hash to be pointing to a different nullifier. - builder.transient_nullifier_indexes_for_note_hashes[0] = 2; - builder.failed(); - } - - #[test(should_fail_with="Invalid transient nullifier index hint")] - fn wrong_transient_nullifier_index_hint_fails() { - let mut builder = PrivateKernelResetInputsBuilder::new(); - builder.previous_kernel.append_note_hashes(2); - builder.previous_kernel.append_nullifiers(2); - // The nullifier at index 1 is nullifying the hash at index 1; - builder.nullify_pending_note_hash(1, 1); - // The nullifier at index 2 is nullifying the hash at index 0; - builder.nullify_pending_note_hash(2, 0); - // Tweak the hint to be for the hash at index 1. - builder.transient_note_hash_indexes_for_nullifiers[2] = 1; + // Change the hint to point to a different nullifier. + builder.transient_data_index_hints[0].nullifier_index = 2; builder.failed(); } @@ -556,23 +542,21 @@ mod tests { // The note hash at index 2 is chopped. let output_note_hashes = builder.compute_output_note_hashes([note_hashes[0], note_hashes[1], note_hashes[3]]); - assert(array_eq(public_inputs.end.note_hashes, output_note_hashes)); + assert_array_eq(public_inputs.end.note_hashes, output_note_hashes); // The nullifier at index 1 is chopped. let output_nullifiers = builder.compute_output_nullifiers([nullifiers[0], nullifiers[2], nullifiers[3]]); - assert(array_eq(public_inputs.end.nullifiers, output_nullifiers)); + assert_array_eq(public_inputs.end.nullifiers, output_nullifiers); // The note log at index 2 is chopped. let output_note_logs = builder.compute_output_note_logs([note_logs[0], note_logs[1], note_logs[3]]); - assert( - array_eq( - public_inputs.end.note_encrypted_logs_hashes, - output_note_logs - ) + assert_array_eq( + public_inputs.end.note_encrypted_logs_hashes, + output_note_logs ); let output_logs = builder.compute_output_encrypted_logs([encrypted_logs[0], encrypted_logs[1], encrypted_logs[2]]); - assert(array_eq(public_inputs.end.encrypted_logs_hashes, output_logs)); + assert_array_eq(public_inputs.end.encrypted_logs_hashes, output_logs); } #[test(should_fail_with="note hashes have been siloed in a previous reset")] 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 ec83a1f14152..7085b0d17790 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 @@ -63,8 +63,8 @@ mod tests { note_hash::{NoteHash, ScopedNoteHash}, nullifier::{Nullifier, ScopedNullifier}, log_hash::{LogHash, NoteLogHash} }, - address::{AztecAddress, EthAddress}, tests::fixture_builder::FixtureBuilder, - utils::{arrays::array_eq}, point::Point, + address::{AztecAddress, EthAddress}, + tests::{fixture_builder::FixtureBuilder, utils::assert_array_eq}, point::Point, constants::{BASE_ROLLUP_INDEX, PRIVATE_KERNEL_INNER_INDEX} }; @@ -181,18 +181,14 @@ mod tests { let output_nullifiers = builder.compute_output_nullifiers(nullifiers); - assert( - array_eq( - public_inputs.end_non_revertible.nullifiers, - [output_nullifiers[0], output_nullifiers[1], output_nullifiers[2]] - ) + assert_array_eq( + public_inputs.end_non_revertible.nullifiers, + [output_nullifiers[0], output_nullifiers[1], output_nullifiers[2]] ); - assert( - array_eq( - public_inputs.end.nullifiers, - [output_nullifiers[3], output_nullifiers[4]] - ) + assert_array_eq( + public_inputs.end.nullifiers, + [output_nullifiers[3], output_nullifiers[4]] ); assert_eq( @@ -226,18 +222,14 @@ mod tests { let exposed_note_hashes = builder.compute_output_note_hashes(note_hashes); - assert( - array_eq( - public_inputs.end_non_revertible.note_hashes, - [exposed_note_hashes[0], exposed_note_hashes[1]] - ) + assert_array_eq( + public_inputs.end_non_revertible.note_hashes, + [exposed_note_hashes[0], exposed_note_hashes[1]] ); - assert( - array_eq( - public_inputs.end.note_hashes, - [exposed_note_hashes[2], exposed_note_hashes[3]] - ) + assert_array_eq( + public_inputs.end.note_hashes, + [exposed_note_hashes[2], exposed_note_hashes[3]] ); assert_eq( diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/reset_output_validator_builder/mod.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/reset_output_validator_builder/mod.nr index 893d6de3e734..a71da99fa320 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/reset_output_validator_builder/mod.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/reset_output_validator_builder/mod.nr @@ -2,17 +2,25 @@ mod validate_sorted_siloed_note_hashes; mod validate_sorted_siloed_nullifiers; use crate::components::{ - reset_output_composer::{PrivateKernelResetOutputs, reset_output_hints::{generate_reset_output_hints, ResetOutputHints}}, + reset_output_composer::{reset_output_hints::{generate_reset_output_hints, ResetOutputHints}}, reset_output_validator::ResetOutputValidator }; -use dep::types::{constants::{MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX}, tests::fixture_builder::FixtureBuilder}; +use dep::reset_kernel_lib::{ + KeyValidationHint, PrivateValidationRequestProcessor, + tests::{NoteHashReadRequestHintsBuilder, NullifierReadRequestHintsBuilder}, TransientDataIndexHint +}; +use dep::types::{ + constants::{MAX_KEY_VALIDATION_REQUESTS_PER_TX, MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX}, + tests::fixture_builder::FixtureBuilder +}; struct ResetOutputValidatorBuilder { output: FixtureBuilder, previous_kernel: FixtureBuilder, - transient_nullifier_indexes_for_note_hashes: [u32; MAX_NOTE_HASHES_PER_TX], - transient_note_hash_indexes_for_nullifiers: [u32; MAX_NULLIFIERS_PER_TX], - split_counter: u32, + note_hash_read_request_hints_builder: NoteHashReadRequestHintsBuilder<6, 3>, + nullifier_read_request_hints_builder: NullifierReadRequestHintsBuilder<5, 2>, + key_validation_hints: [KeyValidationHint; 2], + transient_data_index_hints: [TransientDataIndexHint; 5], note_hash_siloing_amount: u32, nullifier_siloing_amount: u32, encrypted_log_siloing_amount: u32, @@ -24,50 +32,59 @@ impl ResetOutputValidatorBuilder { let mut previous_kernel = FixtureBuilder::new(); output.set_first_nullifier(); previous_kernel.set_first_nullifier(); + output.validation_requests_split_counter = Option::some(0); + previous_kernel.validation_requests_split_counter = Option::some(0); - let transient_nullifier_indexes_for_note_hashes = [MAX_NULLIFIERS_PER_TX; MAX_NOTE_HASHES_PER_TX]; - let transient_note_hash_indexes_for_nullifiers = [MAX_NOTE_HASHES_PER_TX; MAX_NULLIFIERS_PER_TX]; + let note_hash_read_request_hints_builder = NoteHashReadRequestHintsBuilder::new(); + let nullifier_read_request_hints_builder = NullifierReadRequestHintsBuilder::new(); + let key_validation_hints = [KeyValidationHint::nada(MAX_KEY_VALIDATION_REQUESTS_PER_TX); 2]; + let transient_data_index_hints = [TransientDataIndexHint::nada(MAX_NULLIFIERS_PER_TX, MAX_NOTE_HASHES_PER_TX); 5]; ResetOutputValidatorBuilder { output, previous_kernel, - transient_nullifier_indexes_for_note_hashes, - transient_note_hash_indexes_for_nullifiers, - split_counter: 0, + note_hash_read_request_hints_builder, + nullifier_read_request_hints_builder, + key_validation_hints, + transient_data_index_hints, note_hash_siloing_amount: 0, nullifier_siloing_amount: 0, encrypted_log_siloing_amount: 0 } } - pub fn get_hints(self) -> ResetOutputHints { + pub fn get_validation_request_processor(self) -> PrivateValidationRequestProcessor<6, 3, 5, 2, 2> { let previous_kernel = self.previous_kernel.to_private_kernel_circuit_public_inputs(); - generate_reset_output_hints( - previous_kernel, - self.transient_nullifier_indexes_for_note_hashes, - self.transient_note_hash_indexes_for_nullifiers - ) - } + let note_hash_read_request_hints = self.note_hash_read_request_hints_builder.to_hints(); + let nullifier_read_request_hints = self.nullifier_read_request_hints_builder.to_hints(); - pub fn get_output(self) -> PrivateKernelResetOutputs { - let data = self.output.to_private_accumulated_data(); - PrivateKernelResetOutputs { - note_hashes: data.note_hashes, - nullifiers: data.nullifiers, - note_encrypted_log_hashes: data.note_encrypted_logs_hashes, - encrypted_log_hashes: data.encrypted_logs_hashes + PrivateValidationRequestProcessor { + validation_requests: previous_kernel.validation_requests, + note_hash_read_request_hints, + pending_note_hashes: previous_kernel.end.note_hashes, + note_hash_tree_root: 0, + nullifier_read_request_hints, + pending_nullifiers: previous_kernel.end.nullifiers, + nullifier_tree_root: 0, + key_validation_hints: self.key_validation_hints, + validation_requests_split_counter: previous_kernel.min_revertible_side_effect_counter } } + pub fn get_hints(self) -> ResetOutputHints { + let previous_kernel = self.previous_kernel.to_private_kernel_circuit_public_inputs(); + generate_reset_output_hints(previous_kernel, self.transient_data_index_hints) + } + pub fn validate_with_hints(self, hints: ResetOutputHints) { - let output = self.get_output(); + let output = self.output.to_private_kernel_circuit_public_inputs(); let previous_kernel = self.previous_kernel.to_private_kernel_circuit_public_inputs(); + let validation_request_processor = self.get_validation_request_processor(); ResetOutputValidator::new( output, previous_kernel, - self.transient_nullifier_indexes_for_note_hashes, - self.transient_note_hash_indexes_for_nullifiers, - self.split_counter, + validation_request_processor, + self.transient_data_index_hints, self.note_hash_siloing_amount, self.nullifier_siloing_amount, self.encrypted_log_siloing_amount, diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-reset-simulated/src/main.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-reset-simulated/src/main.nr index fbe34f8558b2..e8cc201b335d 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-reset-simulated/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-reset-simulated/src/main.nr @@ -12,11 +12,12 @@ global NOTE_HASH_SETTLED_AMOUNT = MAX_NOTE_HASH_READ_REQUESTS_PER_TX; global NULLIFIER_PENDING_AMOUNT = MAX_NULLIFIER_READ_REQUESTS_PER_TX; // 128 global NULLIFIER_SETTLED_AMOUNT = MAX_NULLIFIER_READ_REQUESTS_PER_TX; global NULLIFIER_KEYS = MAX_KEY_VALIDATION_REQUESTS_PER_TX; // 64 +global TRANSIENT_DATA_AMOUNT = MAX_NULLIFIERS_PER_TX; // 64 global NOTE_HASH_SILOING_AMOUNT = MAX_NOTE_HASHES_PER_TX; // 64 global NULLIFIER_SILOING_AMOUNT = MAX_NULLIFIERS_PER_TX; // 64 global ENCRYPTED_LOG_SILOING_AMOUNT = MAX_ENCRYPTED_LOGS_PER_TX; // 8 -unconstrained fn main(input: PrivateKernelResetCircuitPrivateInputs) -> pub PrivateKernelCircuitPublicInputs { +unconstrained fn main(input: PrivateKernelResetCircuitPrivateInputs) -> pub PrivateKernelCircuitPublicInputs { input.execute( NOTE_HASH_SILOING_AMOUNT, NULLIFIER_SILOING_AMOUNT, diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-reset/src/main.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-reset/src/main.nr index 2eb141956a93..2fc1297075ab 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-reset/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-reset/src/main.nr @@ -12,12 +12,13 @@ global NOTE_HASH_SETTLED_AMOUNT = MAX_NOTE_HASH_READ_REQUESTS_PER_TX; global NULLIFIER_PENDING_AMOUNT = MAX_NULLIFIER_READ_REQUESTS_PER_TX; // 64 global NULLIFIER_SETTLED_AMOUNT = MAX_NULLIFIER_READ_REQUESTS_PER_TX; global NULLIFIER_KEYS = MAX_KEY_VALIDATION_REQUESTS_PER_TX; // 64 +global TRANSIENT_DATA_AMOUNT = MAX_NULLIFIERS_PER_TX; // 64 global NOTE_HASH_SILOING_AMOUNT = MAX_NOTE_HASHES_PER_TX; // 64 global NULLIFIER_SILOING_AMOUNT = MAX_NULLIFIERS_PER_TX; // 64 global ENCRYPTED_LOG_SILOING_AMOUNT = MAX_ENCRYPTED_LOGS_PER_TX; // 8 #[recursive] -fn main(input: PrivateKernelResetCircuitPrivateInputs) -> pub PrivateKernelCircuitPublicInputs { +fn main(input: PrivateKernelResetCircuitPrivateInputs) -> pub PrivateKernelCircuitPublicInputs { input.execute( NOTE_HASH_SILOING_AMOUNT, NULLIFIER_SILOING_AMOUNT, 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 9debf85bfe14..84279fd1003a 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 @@ -169,7 +169,7 @@ mod tests { struct PublicKernelTailCircuitPrivateInputsBuilder { previous_kernel: FixtureBuilder, previous_revertible: FixtureBuilder, - nullifier_read_request_hints_builder: NullifierReadRequestHintsBuilder, + nullifier_read_request_hints_builder: NullifierReadRequestHintsBuilder, nullifier_non_existent_read_request_hints_builder: NullifierNonExistentReadRequestHintsBuilder, public_data_read_request_hints_builder: PublicDataReadRequestHintsBuilder, public_data_hints: BoundedVec, @@ -186,7 +186,7 @@ mod tests { let mut builder = PublicKernelTailCircuitPrivateInputsBuilder { previous_kernel, previous_revertible, - nullifier_read_request_hints_builder: NullifierReadRequestHintsBuilder::new(MAX_NULLIFIER_READ_REQUESTS_PER_TX), + nullifier_read_request_hints_builder: NullifierReadRequestHintsBuilder::new(), nullifier_non_existent_read_request_hints_builder, public_data_read_request_hints_builder: PublicDataReadRequestHintsBuilder::new(MAX_PUBLIC_DATA_READS_PER_TX), public_data_hints: BoundedVec::new(), diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/lib.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/lib.nr index fbee3438a0ca..c67fa479d22d 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/lib.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/lib.nr @@ -4,7 +4,10 @@ use nullifier_read_request_reset::NullifierReadRequestHints; use private_validation_request_processor::PrivateValidationRequestProcessor; use public_data_read_request_reset::PublicDataReadRequestHints; use public_validation_request_processor::PublicValidationRequestProcessor; -use reset::{key_validation_hint::KeyValidationHint, transient_data::verify_squashed_transient_data}; +use reset::{ + key_validation_hint::KeyValidationHint, + transient_data::{TransientDataIndexHint, verify_squashed_transient_data} +}; use dep::types::data::public_data_hint::PublicDataHint; mod note_hash_read_request_reset; 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 a4dd938668be..dc33a0a443e7 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 @@ -36,176 +36,204 @@ impl SettledReadHint for NoteHashSe } } -struct NoteHashReadRequestHints { +struct NoteHashReadRequestHints { read_request_statuses: [ReadRequestStatus; MAX_NOTE_HASH_READ_REQUESTS_PER_TX], - pending_read_hints: [PendingReadHint; PENDING], - settled_read_hints: [NoteHashSettledReadHint; SETTLED], + pending_read_hints: [PendingReadHint; NUM_PENDING_HINTS], + settled_read_hints: [NoteHashSettledReadHint; NUM_SETTLED_HINTS], } mod tests { use crate::note_hash_read_request_reset::NoteHashSettledReadHint; - use crate::reset::read_request::{PendingReadHint, ReadRequestState, ReadRequestStatus, reset_read_requests}; + use crate::reset::read_request::{ + get_unverified_read_requests, PendingReadHint, ReadRequestState, ReadRequestStatus, + verify_reset_read_requests + }; use dep::types::{ address::AztecAddress, merkle_tree::MembershipWitness, - abis::{note_hash::NoteHash, note_hash_leaf_preimage::NoteHashLeafPreimage, read_request::ReadRequest}, + abis::{ + note_hash::{NoteHash, ScopedNoteHash}, note_hash_leaf_preimage::NoteHashLeafPreimage, + read_request::{ReadRequest, ScopedReadRequest} + }, constants::NOTE_HASH_TREE_HEIGHT, hash::compute_siloed_note_hash, - tests::merkle_tree_utils::NonEmptyMerkleTree + tests::{merkle_tree_utils::NonEmptyMerkleTree, utils::assert_array_eq}, traits::is_empty_array }; - global contract_address = AztecAddress::from_field(123); - - // Create 4 note hashes. 10 and 11 are settled. 12 and 13 are pending. - global note_hashes = [10, 11, 12, 13]; - global siloed_note_hashes = note_hashes.map(|n| compute_siloed_note_hash(contract_address, n)); - - // Create 5 read requests. 0 and 3 are reading settled note hashes. 1, 2 and 4 are reading pending note hashes. - global read_requests = [ - ReadRequest { value: note_hashes[1], counter: 11 }.scope(contract_address), // settled - ReadRequest { value: note_hashes[3], counter: 13 }.scope(contract_address), // pending - ReadRequest { value: note_hashes[2], counter: 39 }.scope(contract_address), // pending - ReadRequest { value: note_hashes[0], counter: 46 }.scope(contract_address), // settled - ReadRequest { value: note_hashes[3], counter: 78 }.scope(contract_address), // pending - ]; - - global pending_values = [ - NoteHash { value: note_hashes[2], counter: 2, }.scope(contract_address), - NoteHash { value: note_hashes[3], counter: 8, }.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 }, - PendingReadHint { read_request_index: 4, pending_value_index: 1 }, - ]; - - global leaf_preimages = [ - NoteHashLeafPreimage { value: siloed_note_hashes[0] }, - NoteHashLeafPreimage { value: siloed_note_hashes[1] }, - ]; - - fn read_request_statuses() -> [ReadRequestStatus; 5] { - [ - ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 0 }, - ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 0 }, - ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 1 }, - ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 1 }, - ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 2 } - ] - } - - fn build_tree() -> NonEmptyMerkleTree<2, NOTE_HASH_TREE_HEIGHT, NOTE_HASH_TREE_HEIGHT - 1, 1> { - NonEmptyMerkleTree::new( - [leaf_preimages[0].as_leaf(), leaf_preimages[1].as_leaf()], - [0; NOTE_HASH_TREE_HEIGHT], - [0; NOTE_HASH_TREE_HEIGHT - 1], - [0; 1] - ) + struct TestBuilder { + contract_address: AztecAddress, + read_requests: [ScopedReadRequest; READ_REQUEST_LEN], + read_request_statuses: [ReadRequestStatus; READ_REQUEST_LEN], + pending_values: [ScopedNoteHash; PENDING_VALUE_LEN], + pending_read_hints: [PendingReadHint; NUM_PENDING_READS], + leaf_preimages: [NoteHashLeafPreimage; NUM_SETTLED_READS], } - fn get_settled_read_hints() -> ([NoteHashSettledReadHint; 2], Field) { - let tree = build_tree(); - let hints = [ - NoteHashSettledReadHint { - read_request_index: 0, - membership_witness: MembershipWitness { leaf_index: 1, sibling_path: tree.get_sibling_path(1) }, - leaf_preimage: leaf_preimages[1] - }, - NoteHashSettledReadHint { - read_request_index: 3, - membership_witness: MembershipWitness { leaf_index: 0, sibling_path: tree.get_sibling_path(0) }, - leaf_preimage: leaf_preimages[0] + impl TestBuilder { + pub fn new() -> TestBuilder<5, 4, 3, 2> { + let contract_address = AztecAddress::from_field(123); + + // Create 4 note hashes. 10 and 11 are settled. 12 and 13 are pending. + let note_hashes = [10, 11, 12, 13]; + let siloed_note_hashes = note_hashes.map(|n| compute_siloed_note_hash(contract_address, n)); + + // Create 5 read requests. 0 and 3 are reading settled note hashes. 1, 2 and 4 are reading pending note hashes. + let read_requests = [ + ReadRequest { value: note_hashes[1], counter: 11 }.scope(contract_address),// settled + ReadRequest { value: note_hashes[3], counter: 13 }.scope(contract_address),// pending + ReadRequest { value: note_hashes[2], counter: 39 }.scope(contract_address),// pending + ReadRequest { value: note_hashes[0], counter: 46 }.scope(contract_address),// settled + ReadRequest { value: note_hashes[3], counter: 78 }.scope(contract_address)// pending + ]; + + let read_request_statuses = [ + ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 0 }, + ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 0 }, + ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 1 }, + ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 1 }, + ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 2 } + ]; + + let pending_values = [ + NoteHash { value: note_hashes[2], counter: 2 }.scope(contract_address), + NoteHash { value: note_hashes[3], counter: 8 }.scope(contract_address), + ScopedNoteHash::empty(), + ScopedNoteHash::empty() + ]; + + let pending_read_hints = [ + PendingReadHint { read_request_index: 1, pending_value_index: 1 }, + PendingReadHint { read_request_index: 2, pending_value_index: 0 }, + PendingReadHint { read_request_index: 4, pending_value_index: 1 } + ]; + + let leaf_preimages = [ + NoteHashLeafPreimage { value: siloed_note_hashes[0] }, + NoteHashLeafPreimage { value: siloed_note_hashes[1] } + ]; + + TestBuilder { + contract_address, + read_requests, + read_request_statuses, + pending_values, + pending_read_hints, + leaf_preimages } - ]; - let tree_root = tree.get_root(); - (hints, tree_root) + } + + fn build_tree(self) -> NonEmptyMerkleTree<2, NOTE_HASH_TREE_HEIGHT, NOTE_HASH_TREE_HEIGHT - 1, 1> { + NonEmptyMerkleTree::new( + [self.leaf_preimages[0].as_leaf(), self.leaf_preimages[1].as_leaf()], + [0; NOTE_HASH_TREE_HEIGHT], + [0; NOTE_HASH_TREE_HEIGHT - 1], + [0; 1] + ) + } + + pub fn get_settled_read_hints(self) -> ([NoteHashSettledReadHint; 2], Field) { + let tree = self.build_tree(); + let hints = [ + NoteHashSettledReadHint { + read_request_index: 0, + membership_witness: MembershipWitness { leaf_index: 1, sibling_path: tree.get_sibling_path(1) }, + leaf_preimage: self.leaf_preimages[1] + }, + NoteHashSettledReadHint { + read_request_index: 3, + membership_witness: MembershipWitness { leaf_index: 0, sibling_path: tree.get_sibling_path(0) }, + leaf_preimage: self.leaf_preimages[0] + } + ]; + let tree_root = tree.get_root(); + (hints, tree_root) + } + + pub fn get_unverified_read_requests(self) -> [ScopedReadRequest; READ_REQUEST_LEN] { + get_unverified_read_requests(self.read_requests, self.read_request_statuses) + } + + pub fn verify(self) { + let (settled_hints, tree_root) = self.get_settled_read_hints(); + let unverified_read_requests = self.get_unverified_read_requests(); + verify_reset_read_requests( + self.read_requests, + self.pending_values, + self.read_request_statuses, + self.pending_read_hints, + settled_hints, + tree_root, + unverified_read_requests + ); + } } #[test] - fn test_reset_read_requests_all() { - let (settled_read_hints, tree_root) = get_settled_read_hints(); - let unverified_read_requests = reset_read_requests( - read_requests, - pending_values, - read_request_statuses(), - pending_read_hints, - settled_read_hints, - tree_root - ); - assert(unverified_read_requests.len() == 0); + fn verify_reset_note_hash_read_requests_clears_all_succeeds() { + let builder = TestBuilder::new(); + + let unverified_read_requests = builder.get_unverified_read_requests(); + assert(is_empty_array(unverified_read_requests)); + + builder.verify(); } #[test] - fn test_reset_read_requests_partial() { - let mut partial_read_request_statuses = read_request_statuses(); - partial_read_request_statuses[2] = ReadRequestStatus::empty(); - partial_read_request_statuses[4] = ReadRequestStatus::empty(); - - let (settled_read_hints, tree_root) = get_settled_read_hints(); - let unverified_read_requests = reset_read_requests( - read_requests, - pending_values, - partial_read_request_statuses, - pending_read_hints, - settled_read_hints, - tree_root + fn verify_reset_note_hash_read_requests_clears_partial_succeeds() { + let mut builder = TestBuilder::new(); + + builder.read_request_statuses[2] = ReadRequestStatus::empty(); + builder.read_request_statuses[4] = ReadRequestStatus::empty(); + + let read_requests = builder.read_requests; + let unverified_read_requests = builder.get_unverified_read_requests(); + assert_array_eq( + unverified_read_requests, + [read_requests[2], read_requests[4]] ); - assert(unverified_read_requests.len() == 2); - assert(unverified_read_requests.get(0) == read_requests[2]); - assert(unverified_read_requests.get(1) == read_requests[4]); + + builder.verify(); } #[test(should_fail_with="Value of the note hash does not match read request")] - fn test_reset_note_hash_read_requests_wrong_hinted_value() { - let mut tainted_pending_values = pending_values; + fn verify_reset_note_hash_read_requests_wrong_hinted_value_fails() { + let mut builder = TestBuilder::new(); + // Tweak the value to be something different. - tainted_pending_values[0].note_hash.value += 1; - - let (settled_read_hints, tree_root) = get_settled_read_hints(); - let _ = reset_read_requests( - read_requests, - tainted_pending_values, - read_request_statuses(), - pending_read_hints, - settled_read_hints, - tree_root - ); + builder.pending_values[0].note_hash.value += 1; + + builder.verify(); + } + + #[test(should_fail_with="Contract address of the note hash does not match read request")] + fn verify_reset_note_hash_read_requests_different_contract_addresses_fails() { + let mut builder = TestBuilder::new(); + + builder.pending_values[0].contract_address.inner += 1; + + builder.verify(); } #[test(should_fail_with="Read request counter must be greater than the counter of the note hash")] - fn test_reset_note_hash_read_requests_invalid_counter() { - let hint = pending_read_hints[0]; - let pending_read = read_requests[hint.read_request_index]; - let mut tainted_pending_values = pending_values; + fn verify_reset_note_hash_read_requests_invalid_counter_fails() { + let mut builder = TestBuilder::new(); + + let hint = builder.pending_read_hints[0]; + let pending_read = builder.read_requests[hint.read_request_index]; // Tweak the counter of the value to be greater than the read request. - 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( - read_requests, - tainted_pending_values, - read_request_statuses(), - pending_read_hints, - settled_read_hints, - tree_root - ); + builder.pending_values[hint.pending_value_index].note_hash.counter = pending_read.counter() + 1; + + builder.verify(); } #[test(should_fail_with="Value of the note hash leaf does not match read request")] - fn test_reset_note_hash_read_requests_invalid_leaf() { - let (settled_read_hints, tree_root) = get_settled_read_hints(); + fn verify_reset_note_hash_read_requests_invalid_leaf_fails() { + let mut builder = TestBuilder::new(); - let mut tained_read_requests = read_requests; + let (settled_read_hints, _) = builder.get_settled_read_hints(); 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].read_request.value += 1; - - let _ = reset_read_requests( - tained_read_requests, - pending_values, - read_request_statuses(), - pending_read_hints, - settled_read_hints, - tree_root - ); + builder.read_requests[hint.read_request_index].read_request.value += 1; + + builder.verify(); } } 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 96a94d932e41..ba11d655b1cd 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 @@ -36,178 +36,197 @@ impl SettledReadHint for Nullifier } } -struct NullifierReadRequestHints { +struct NullifierReadRequestHints { read_request_statuses: [ReadRequestStatus; MAX_NULLIFIER_READ_REQUESTS_PER_TX], - pending_read_hints: [PendingReadHint; PENDING], - settled_read_hints: [NullifierSettledReadHint; SETTLED], + pending_read_hints: [PendingReadHint; NUM_PENDING_HINTS], + settled_read_hints: [NullifierSettledReadHint; NUM_SETTLED_HINTS], } mod tests { use crate::nullifier_read_request_reset::NullifierSettledReadHint; - use crate::reset::read_request::{PendingReadHint, ReadRequestState, ReadRequestStatus, reset_read_requests}; + use crate::reset::read_request::{ + get_unverified_read_requests, PendingReadHint, ReadRequestState, ReadRequestStatus, + verify_reset_read_requests + }; use dep::types::{ address::AztecAddress, - abis::{nullifier::Nullifier, nullifier_leaf_preimage::NullifierLeafPreimage, read_request::ReadRequest}, + abis::{ + nullifier::{Nullifier, ScopedNullifier}, nullifier_leaf_preimage::NullifierLeafPreimage, + read_request::{ReadRequest, ScopedReadRequest} + }, constants::NULLIFIER_TREE_HEIGHT, hash::compute_siloed_nullifier, - merkle_tree::MembershipWitness, tests::merkle_tree_utils::NonEmptyMerkleTree + merkle_tree::MembershipWitness, + tests::{merkle_tree_utils::NonEmptyMerkleTree, utils::assert_array_eq}, traits::is_empty_array }; - global contract_address = AztecAddress::from_field(123); - - // Create 4 nullifiers. 10 and 11 are settled. 12 and 13 are pending. - global inner_nullifiers = [10, 11, 12, 13]; - global nullifiers = inner_nullifiers.map(|n| compute_siloed_nullifier(contract_address, n)); - - // Create 5 read requests. 0 and 3 are reading settled nullifiers. 1, 2 and 4 are reading pending nullifiers. - global read_requests = [ - 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: 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 }, - PendingReadHint { read_request_index: 4, pending_value_index: 1 }, - ]; - - global leaf_preimages = [ - NullifierLeafPreimage { nullifier: nullifiers[0], next_nullifier: nullifiers[1], next_index: 1 }, - NullifierLeafPreimage { nullifier: nullifiers[1], next_nullifier: 0, next_index: 0 }, - ]; - - fn read_request_statuses() -> [ReadRequestStatus; 5] { - // Failed when assigned to global: - // The application panicked (crashed). Message: no entry found for key - [ - ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 0 }, - ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 0 }, - ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 1 }, - ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 1 }, - ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 2 } - ] + struct TestBuilder { + read_requests: [ScopedReadRequest; READ_REQUEST_LEN], + read_request_statuses: [ReadRequestStatus; READ_REQUEST_LEN], + pending_values: [ScopedNullifier; PENDING_VALUE_LEN], + pending_read_hints: [PendingReadHint; NUM_PENDING_READS], + leaf_preimages: [NullifierLeafPreimage; NUM_SETTLED_READS], } - fn build_tree() -> NonEmptyMerkleTree<2, NULLIFIER_TREE_HEIGHT, NULLIFIER_TREE_HEIGHT - 1, 1> { - NonEmptyMerkleTree::new( - [leaf_preimages[0].hash(), leaf_preimages[1].hash()], - [0; NULLIFIER_TREE_HEIGHT], - [0; NULLIFIER_TREE_HEIGHT - 1], - [0; 1] - ) - } + impl TestBuilder { + pub fn new() -> TestBuilder<5, 4, 3, 2> { + let contract_address = AztecAddress::from_field(123); + + // Create 4 nullifiers. 10 and 11 are settled. 12 and 13 are pending. + let inner_nullifiers = [10, 11, 12, 13]; + let nullifiers = inner_nullifiers.map(|n| compute_siloed_nullifier(contract_address, n)); + + // Create 5 read requests. 0 and 3 are reading settled nullifiers. 1, 2 and 4 are reading pending nullifiers. + let read_requests = [ + 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 + ]; + + let 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), + ScopedNullifier::empty(), + ScopedNullifier::empty() + ]; + + let pending_read_hints = [ + PendingReadHint { read_request_index: 1, pending_value_index: 1 }, + PendingReadHint { read_request_index: 2, pending_value_index: 0 }, + PendingReadHint { read_request_index: 4, pending_value_index: 1 } + ]; + + let leaf_preimages = [ + NullifierLeafPreimage { nullifier: nullifiers[0], next_nullifier: nullifiers[1], next_index: 1 }, + NullifierLeafPreimage { nullifier: nullifiers[1], next_nullifier: 0, next_index: 0 } + ]; + + let read_request_statuses = [ + ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 0 }, + ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 0 }, + ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 1 }, + ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 1 }, + ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 2 } + ]; + + TestBuilder { read_requests, read_request_statuses, pending_values, pending_read_hints, leaf_preimages } + } + + fn build_tree(self) -> NonEmptyMerkleTree<2, NULLIFIER_TREE_HEIGHT, NULLIFIER_TREE_HEIGHT - 1, 1> { + NonEmptyMerkleTree::new( + [self.leaf_preimages[0].hash(), self.leaf_preimages[1].hash()], + [0; NULLIFIER_TREE_HEIGHT], + [0; NULLIFIER_TREE_HEIGHT - 1], + [0; 1] + ) + } + + fn get_settled_read_hints(self) -> ([NullifierSettledReadHint; 2], Field) { + let tree = self.build_tree(); + let hints = [ + NullifierSettledReadHint { + read_request_index: 0, + membership_witness: MembershipWitness { leaf_index: 1, sibling_path: tree.get_sibling_path(1) }, + leaf_preimage: self.leaf_preimages[1] + }, + NullifierSettledReadHint { + read_request_index: 3, + membership_witness: MembershipWitness { leaf_index: 0, sibling_path: tree.get_sibling_path(0) }, + leaf_preimage: self.leaf_preimages[0] + } + ]; + let tree_root = tree.get_root(); + (hints, tree_root) + } - fn get_settled_read_hints() -> ([NullifierSettledReadHint; 2], Field) { - let tree = build_tree(); - let hints = [ - NullifierSettledReadHint { - read_request_index: 0, - membership_witness: MembershipWitness { leaf_index: 1, sibling_path: tree.get_sibling_path(1) }, - leaf_preimage: leaf_preimages[1] - }, - NullifierSettledReadHint { - read_request_index: 3, - membership_witness: MembershipWitness { leaf_index: 0, sibling_path: tree.get_sibling_path(0) }, - leaf_preimage: leaf_preimages[0] - } - ]; - let tree_root = tree.get_root(); - (hints, tree_root) + pub fn get_unverified_read_requests(self) -> [ScopedReadRequest; READ_REQUEST_LEN] { + get_unverified_read_requests(self.read_requests, self.read_request_statuses) + } + + pub fn verify(self) { + let (settled_hints, tree_root) = self.get_settled_read_hints(); + let unverified_read_requests = self.get_unverified_read_requests(); + verify_reset_read_requests( + self.read_requests, + self.pending_values, + self.read_request_statuses, + self.pending_read_hints, + settled_hints, + tree_root, + unverified_read_requests + ); + } } #[test] - fn test_reset_nullifier_read_requests_all() { - let (settled_read_hints, tree_root) = get_settled_read_hints(); - let unverified_read_requests = reset_read_requests( - read_requests, - pending_values, - read_request_statuses(), - pending_read_hints, - settled_read_hints, - tree_root - ); - assert(unverified_read_requests.len() == 0); + fn verify_reset_nullifier_read_requests_clears_all_succeeds() { + let builder = TestBuilder::new(); + + let unverified_read_requests = builder.get_unverified_read_requests(); + assert(is_empty_array(unverified_read_requests)); + + builder.verify(); } #[test] - fn test_reset_nullifier_read_requests_partial() { - let mut partial_read_request_statuses = read_request_statuses(); - partial_read_request_statuses[2] = ReadRequestStatus::empty(); - partial_read_request_statuses[4] = ReadRequestStatus::empty(); - - let (settled_read_hints, tree_root) = get_settled_read_hints(); - let unverified_read_requests = reset_read_requests( - read_requests, - pending_values, - partial_read_request_statuses, - pending_read_hints, - settled_read_hints, - tree_root + fn verify_reset_nullifier_read_requests_clears_partial_succeeds() { + let mut builder = TestBuilder::new(); + + builder.read_request_statuses[2] = ReadRequestStatus::empty(); + builder.read_request_statuses[4] = ReadRequestStatus::empty(); + + let read_requests = builder.read_requests; + let unverified_read_requests = builder.get_unverified_read_requests(); + assert_array_eq( + unverified_read_requests, + [read_requests[2], read_requests[4]] ); - assert(unverified_read_requests.len() == 2); - assert(unverified_read_requests.get(0) == read_requests[2]); - assert(unverified_read_requests.get(1) == read_requests[4]); + + builder.verify(); } #[test(should_fail_with="Value of the nullifier does not match read request")] - fn test_reset_nullifier_read_requests_wrong_hinted_value() { - let mut tainted_pending_values = pending_values; + fn verify_reset_nullifier_read_requests_wrong_hinted_value() { + let mut builder = TestBuilder::new(); + // Tweak the value to be something different. - tainted_pending_values[0].nullifier.value += 1; - - let (settled_read_hints, tree_root) = get_settled_read_hints(); - let _ = reset_read_requests( - read_requests, - tainted_pending_values, - read_request_statuses(), - pending_read_hints, - settled_read_hints, - tree_root - ); + builder.pending_values[0].nullifier.value += 1; + + builder.verify(); + } + + #[test(should_fail_with="Contract address of the nullifier does not match read request")] + fn verify_reset_nullifier_read_requests_different_contract_addresses_fails() { + let mut builder = TestBuilder::new(); + + builder.pending_values[0].contract_address.inner += 1; + + builder.verify(); } #[test(should_fail_with="Read request counter must be greater than the counter of the nullifier")] - fn test_reset_nullifier_read_requests_invalid_counter() { - let hint = pending_read_hints[0]; - let pending_read = read_requests[hint.read_request_index]; - let mut tainted_pending_values = pending_values; + fn verify_reset_nullifier_read_requests_invalid_counter() { + let mut builder = TestBuilder::new(); + + let hint = builder.pending_read_hints[0]; + let pending_read = builder.read_requests[hint.read_request_index]; // Tweak the counter of the value to be greater than the read request. - 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( - read_requests, - tainted_pending_values, - read_request_statuses(), - pending_read_hints, - settled_read_hints, - tree_root - ); + builder.pending_values[hint.pending_value_index].nullifier.counter = pending_read.counter() + 1; + + builder.verify(); } #[test(should_fail_with="Value of the nullifier leaf does not match read request")] - fn test_reset_nullifier_read_requests_invalid_leaf() { - let (settled_read_hints, tree_root) = get_settled_read_hints(); + fn verify_reset_nullifier_read_requests_invalid_leaf() { + let mut builder = TestBuilder::new(); - let mut tained_read_requests = read_requests; + let (settled_read_hints, _) = builder.get_settled_read_hints(); 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].read_request.value += 1; - - let _ = reset_read_requests( - tained_read_requests, - pending_values, - read_request_statuses(), - pending_read_hints, - settled_read_hints, - tree_root - ); + builder.read_requests[hint.read_request_index].read_request.value += 1; + + builder.verify(); } } 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 6614b5751187..2790cd1dc3eb 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 @@ -1,22 +1,15 @@ use crate::{ note_hash_read_request_reset::NoteHashReadRequestHints, - nullifier_read_request_reset::NullifierReadRequestHints, reset::read_request::reset_read_requests, - reset::key_validation_hint::{KeyValidationHint, reset_key_validation_requests} + nullifier_read_request_reset::NullifierReadRequestHints, + reset::read_request::{get_unverified_read_requests, verify_reset_read_requests}, + reset::key_validation_hint::{get_unverified_key_validation_requests, KeyValidationHint, verify_reset_key_validation_requests} }; use dep::types::{ - abis::{ - note_hash::ScopedNoteHash, nullifier::ScopedNullifier, - validation_requests::{PrivateValidationRequests, ScopedKeyValidationRequestAndGenerator}, - read_request::ScopedReadRequest -}, - constants::{ - MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX, MAX_KEY_VALIDATION_REQUESTS_PER_TX, - GENERATOR_INDEX__NSK_M, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX -}, - scalar::Scalar, hash::poseidon2_hash, traits::is_empty, utils::arrays::filter_array_to_bounded_vec + abis::{note_hash::ScopedNoteHash, nullifier::ScopedNullifier, validation_requests::PrivateValidationRequests}, + constants::{MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX} }; -struct PrivateValidationRequestProcessor { +struct PrivateValidationRequestProcessor { validation_requests: PrivateValidationRequests, note_hash_read_request_hints: NoteHashReadRequestHints, pending_note_hashes: [ScopedNoteHash; MAX_NOTE_HASHES_PER_TX], @@ -28,56 +21,80 @@ struct PrivateValidationRequestProcessor PrivateValidationRequestProcessor { - pub fn validate(self) -> PrivateValidationRequests { - let remaining_note_hash_read_requests = self.validate_note_hash_read_requests(); - let remaining_nullifier_read_requests = self.validate_nullifier_read_requests(); - let remaining_key_validation_requests = self.validate_keys(); +impl< + let NH_RR_PENDING: u32, + let NH_RR_SETTLED: u32, + let NLL_RR_PENDING: u32, + let NLL_RR_SETTLED: u32, + let KEY_VALIDATION_REQUESTS: u32 +> PrivateValidationRequestProcessor { + pub fn compose(self) -> PrivateValidationRequests { + let note_hash_read_requests = get_unverified_read_requests( + self.validation_requests.note_hash_read_requests, + self.note_hash_read_request_hints.read_request_statuses + ); + + let nullifier_read_requests = get_unverified_read_requests( + self.validation_requests.nullifier_read_requests, + self.nullifier_read_request_hints.read_request_statuses + ); + + let scoped_key_validation_requests_and_generators = get_unverified_key_validation_requests( + self.validation_requests.scoped_key_validation_requests_and_generators, + self.key_validation_hints + ); PrivateValidationRequests { for_rollup: self.validation_requests.for_rollup, - note_hash_read_requests: remaining_note_hash_read_requests.storage, - nullifier_read_requests: remaining_nullifier_read_requests.storage, - scoped_key_validation_requests_and_generators: remaining_key_validation_requests.storage, - split_counter: Option::some(self.validate_split_counter()) + note_hash_read_requests, + nullifier_read_requests, + scoped_key_validation_requests_and_generators, + split_counter: Option::some(self.validation_requests_split_counter) } } - fn validate_split_counter(self) -> u32 { - if self.validation_requests.split_counter.is_some() { - assert_eq( - self.validation_requests.split_counter.unwrap_unchecked(), self.validation_requests_split_counter, "mismatch hinted split counter" - ); - } - self.validation_requests_split_counter - } + pub fn validate(self, output: PrivateValidationRequests) { + assert_eq( + output.for_rollup, self.validation_requests.for_rollup, "mismatch validation request for rollup" + ); - fn validate_note_hash_read_requests(self) -> BoundedVec { - reset_read_requests( + // note_hash_read_requests + verify_reset_read_requests( self.validation_requests.note_hash_read_requests, self.pending_note_hashes, self.note_hash_read_request_hints.read_request_statuses, self.note_hash_read_request_hints.pending_read_hints, self.note_hash_read_request_hints.settled_read_hints, - self.note_hash_tree_root - ) - } + self.note_hash_tree_root, + output.note_hash_read_requests + ); - fn validate_nullifier_read_requests(self) -> BoundedVec { - reset_read_requests( + // nullifier_read_requests + verify_reset_read_requests( self.validation_requests.nullifier_read_requests, self.pending_nullifiers, self.nullifier_read_request_hints.read_request_statuses, self.nullifier_read_request_hints.pending_read_hints, self.nullifier_read_request_hints.settled_read_hints, - self.nullifier_tree_root - ) - } + self.nullifier_tree_root, + output.nullifier_read_requests + ); - fn validate_keys(self) -> BoundedVec { - reset_key_validation_requests( + // key_validation_requests + verify_reset_key_validation_requests( self.validation_requests.scoped_key_validation_requests_and_generators, - self.key_validation_hints - ) + self.key_validation_hints, + output.scoped_key_validation_requests_and_generators + ); + + // split_counter + assert_eq( + output.split_counter.unwrap(), self.validation_requests_split_counter, "mismatch split counter" + ); + if self.validation_requests.split_counter.is_some() { + assert_eq( + self.validation_requests.split_counter.unwrap_unchecked(), self.validation_requests_split_counter, "mismatch hinted split counter" + ); + } } } 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 75f0178153a7..c0d030493e25 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 @@ -1,7 +1,8 @@ use crate::{ reset::{ non_existent_read_request::reset_non_existent_read_requests, - mutable_data_read_request::reset_mutable_data_read_requests, read_request::reset_read_requests + mutable_data_read_request::reset_mutable_data_read_requests, + read_request::verify_reset_read_requests }, nullifier_read_request_reset::NullifierReadRequestHints, nullifier_non_existent_read_request_reset::NullifierNonExistentReadRequestHints, @@ -10,7 +11,8 @@ use crate::{ use dep::types::{ abis::{ kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, nullifier::Nullifier, - public_data_update_request::PublicDataUpdateRequest, validation_requests::PublicValidationRequests + public_data_update_request::PublicDataUpdateRequest, read_request::ScopedReadRequest, + validation_requests::PublicValidationRequests }, data::public_data_hint::PublicDataHint, constants::{MAX_NULLIFIERS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX}, @@ -18,7 +20,7 @@ use dep::types::{ utils::arrays::{array_merge, array_to_bounded_vec, assert_sorted_array} }; -struct PublicValidationRequestProcessor { +struct PublicValidationRequestProcessor { validation_requests: PublicValidationRequests, pending_nullifiers: [Nullifier; MAX_NULLIFIERS_PER_TX], pending_public_data_writes: [PublicDataUpdateRequest; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], @@ -26,17 +28,17 @@ struct PublicValidationRequestProcessor { nullifier_non_existent_read_request_hints: NullifierNonExistentReadRequestHints, nullifier_tree_root: Field, public_data_read_request_hints: PublicDataReadRequestHints, - public_data_hints: [PublicDataHint; N], + public_data_hints: [PublicDataHint; NUM_PUBLIC_DATA_HINTS], } -impl PublicValidationRequestProcessor { +impl PublicValidationRequestProcessor { pub fn new( public_inputs: PublicKernelCircuitPublicInputs, nullifier_read_request_hints: NullifierReadRequestHints, nullifier_non_existent_read_request_hints: NullifierNonExistentReadRequestHints, nullifier_tree_root: Field, public_data_read_request_hints: PublicDataReadRequestHints, - public_data_hints: [PublicDataHint; N] + public_data_hints: [PublicDataHint; NUM_PUBLIC_DATA_HINTS] ) -> Self { let end_non_revertible = public_inputs.end_non_revertible; let end = public_inputs.end; @@ -69,16 +71,15 @@ impl PublicValidationRequestProcessor { fn validate_nullifier_read_requests(self) { let requests = self.validation_requests.nullifier_read_requests; let hints = self.nullifier_read_request_hints; - let unverified_nullifier_read_requests = reset_read_requests( + let unverified_nullifier_read_requests = [ScopedReadRequest::empty(); MAX_NULLIFIER_READ_REQUESTS_PER_TX]; // All nullifier read requests must be verified. + verify_reset_read_requests( requests, self.pending_nullifiers, hints.read_request_statuses, hints.pending_read_hints, hints.settled_read_hints, - self.nullifier_tree_root - ); - assert( - unverified_nullifier_read_requests.len() == 0, "All nullifier read requests must be verified" + self.nullifier_tree_root, + unverified_nullifier_read_requests ); } diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/key_validation_hint.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/key_validation_hint.nr index 33b92cc2253a..5f5072fee0cb 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/key_validation_hint.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/key_validation_hint.nr @@ -1,13 +1,12 @@ use dep::types::{ - traits::{Empty, is_empty}, abis::{validation_requests::ScopedKeyValidationRequestAndGenerator}, - constants::MAX_KEY_VALIDATION_REQUESTS_PER_TX, scalar::Scalar, hash::poseidon2_hash_with_separator, - utils::arrays::filter_array_to_bounded_vec + traits::Empty, abis::{validation_requests::ScopedKeyValidationRequestAndGenerator}, scalar::Scalar, + hash::poseidon2_hash_with_separator }; use std::embedded_curve_ops::fixed_base_scalar_mul as derive_public_key; struct KeyValidationHint { sk_m: Scalar, - request_index: u64, + request_index: u32, } impl Empty for KeyValidationHint { @@ -23,46 +22,90 @@ impl Eq for KeyValidationHint { fn eq(self, other: Self) -> bool { self.sk_m.eq(other.sk_m) & self.request_index.eq(other.request_index) } +} +impl KeyValidationHint { + pub fn nada(request_len: u32) -> Self { + KeyValidationHint { sk_m: Scalar::empty(), request_index: request_len } + } } -pub fn reset_key_validation_requests( - key_validation_requests: [ScopedKeyValidationRequestAndGenerator; MAX_KEY_VALIDATION_REQUESTS_PER_TX], - key_validation_hints: [KeyValidationHint; N] -) -> BoundedVec { - let mut should_propagate = key_validation_requests.map(|req| !is_empty(req)); - for i in 0..N { - let hint = key_validation_hints[i]; - // Determining here whether a key validation request will be validated based on a hint is not a vulnerability - // because in the reset circuit we verify that there are no requests remaining to be validated. For this reason - // the circuits cannot be tricked by not providing a hint (the final check would fail). - if !is_empty(hint) { - let scoped_request = key_validation_requests[hint.request_index]; - let contract_address = scoped_request.contract_address; - let request_and_generator = scoped_request.request; - let request = request_and_generator.request; - let sk_m = hint.sk_m; - let sk_app_generator = request_and_generator.sk_app_generator; +fn verify_key_validation_request(scoped_request: ScopedKeyValidationRequestAndGenerator, sk_m: Scalar) { + let contract_address = scoped_request.contract_address; + let request_and_generator = scoped_request.request; + let request = request_and_generator.request; + let sk_app_generator = request_and_generator.sk_app_generator; - // First we check that derived public key matches master public key from request - let pk_m = derive_public_key(sk_m); - assert( - pk_m.eq(request.pk_m), "Failed to derive matching master public key from the secret key." - ); + // First we check that derived public key matches master public key from request. + let pk_m = derive_public_key(sk_m); + assert_eq(pk_m, request.pk_m, "Failed to derive matching master public key from the secret key."); - // Then we check that siloing the master secret key with the contract address gives the app secret key + // Then we check that siloing the master secret key with the contract address gives the app secret key. + let sk_app = poseidon2_hash_with_separator( + [sk_m.hi, sk_m.lo, contract_address.to_field()], + sk_app_generator + ); + assert_eq(sk_app, request.sk_app, "Failed to derive matching app secret key from the secret key."); +} - let sk_app = poseidon2_hash_with_separator( - [sk_m.hi, sk_m.lo, contract_address.to_field()], - sk_app_generator - ); - assert( - sk_app.eq(request.sk_app), "Failed to derive matching app secret key from the secret key." +unconstrained fn get_hint_indexes(hints: [KeyValidationHint; NUM_HINTS]) -> [u32; REQUEST_LEN] { + let mut hint_indexes = [NUM_HINTS; REQUEST_LEN]; + for i in 0..NUM_HINTS { + let hint = hints[i]; + if hint.request_index != REQUEST_LEN { + hint_indexes[hint.request_index] = i; + } + } + hint_indexes +} + +pub fn verify_reset_key_validation_requests( + key_validation_requests: [ScopedKeyValidationRequestAndGenerator; REQUEST_LEN], + hints: [KeyValidationHint; NUM_HINTS], + unverified_requests: [ScopedKeyValidationRequestAndGenerator; REQUEST_LEN] +) { + for i in 0..NUM_HINTS { + let hint = hints[i]; + // Determining here whether a key validation request will be validated based on a hint is not a vulnerability + // because in the tail circuit we verify that there are no requests remaining to be validated. For this reason + // the circuits cannot be tricked by not providing a hint (the final check would fail). + if hint.request_index != key_validation_requests.len() { + verify_key_validation_request(key_validation_requests[hint.request_index], hint.sk_m); + } + } + + let hint_indexes: [u32; REQUEST_LEN] = get_hint_indexes(hints); + let mut num_propagated = 0; + for i in 0..REQUEST_LEN { + let hint_index = hint_indexes[i]; + if hint_index == NUM_HINTS { + assert_eq( + unverified_requests[num_propagated], key_validation_requests[i], "mismatch propagated key validation request" ); + num_propagated += 1; + } else { + assert_eq(hints[hint_index].request_index, i, "wrong verified request index hint"); + } + } +} +unconstrained pub fn get_unverified_key_validation_requests( + key_validation_requests: [ScopedKeyValidationRequestAndGenerator; REQUEST_LEN], + hints: [KeyValidationHint; NUM_HINTS] +) -> [ScopedKeyValidationRequestAndGenerator; REQUEST_LEN] { + let mut should_propagate = [true; REQUEST_LEN]; + for i in 0..NUM_HINTS { + let hint = hints[i]; + if hint.request_index != REQUEST_LEN { should_propagate[hint.request_index] = false; } } - filter_array_to_bounded_vec(key_validation_requests, should_propagate) + let mut propagated = BoundedVec::new(); + for i in 0..REQUEST_LEN { + if should_propagate[i] { + propagated.push(key_validation_requests[i]); + } + } + propagated.storage } diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/read_request.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/read_request.nr index 3b2d251fab82..200dcd37219e 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/read_request.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/reset/read_request.nr @@ -1,8 +1,7 @@ // This will be moved to a separate Read Request Reset Circuit. use dep::types::{ abis::{read_request::ScopedReadRequest, side_effect::Readable}, - merkle_tree::{assert_check_membership, LeafPreimage, MembershipWitness}, traits::{Empty, is_empty}, - utils::arrays::filter_array_to_bounded_vec + merkle_tree::{assert_check_membership, LeafPreimage, MembershipWitness}, traits::Empty }; struct ReadRequestStateEnum { @@ -49,7 +48,7 @@ impl PendingReadHint { } } -trait SettledReadHint where LEAF_PREIMAGE: LeafPreimage { +trait SettledReadHint where LEAF_PREIMAGE: LeafPreimage { fn membership_witness(self) -> MembershipWitness; fn leaf_preimage(self) -> LEAF_PREIMAGE; fn nada(read_request_len: u32) -> Self; @@ -59,16 +58,17 @@ trait SettledReadHint where LEAF_PREIMAGE: LeafPreim // More info here: // - 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( +fn validate_pending_read_requests( read_requests: [ScopedReadRequest; READ_REQUEST_LEN], pending_values: [T; PENDING_VALUE_LEN], hints: [PendingReadHint; NUM_PENDING_READS] ) where T: Readable { for i in 0..NUM_PENDING_READS { - let read_request_index = hints[i].read_request_index; + let hint = hints[i]; + let read_request_index = hint.read_request_index; if read_request_index != READ_REQUEST_LEN { let read_request = read_requests[read_request_index]; - let pending_value = pending_values[hints[i].pending_value_index]; + let pending_value = pending_values[hint.pending_value_index]; pending_value.assert_match_read_request(read_request); } } @@ -76,7 +76,7 @@ fn validate_pending_read_requests( +fn validate_settled_read_requests( read_requests: [ScopedReadRequest; READ_REQUEST_LEN], hints: [H; NUM_SETTLED_READS], tree_root: Field @@ -84,54 +84,66 @@ fn validate_settled_read_requests + ReadValueHint, LEAF_PREIMAGE: LeafPreimage + Readable { for i in 0..NUM_SETTLED_READS { - let read_request_index = hints[i].read_request_index(); + let hint = hints[i]; + let read_request_index = hint.read_request_index(); if read_request_index != READ_REQUEST_LEN { let read_request = read_requests[read_request_index]; - let leaf_preimage = hints[i].leaf_preimage(); + let leaf_preimage = hint.leaf_preimage(); leaf_preimage.assert_match_read_request(read_request); let leaf = leaf_preimage.as_leaf(); - let witness = hints[i].membership_witness(); + let witness = hint.membership_witness(); assert_check_membership(leaf, witness.leaf_index, witness.sibling_path, tree_root); } } } -fn propagate_unverified_read_requests( +fn verify_propagated_read_requests( 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 { - let mut should_propagate = [false; READ_REQUEST_LEN]; - + settled_read_hints: [S; NUM_SETTLED_READS], + propagated_read_requests: [ScopedReadRequest; READ_REQUEST_LEN] +) where T: ReadValueHint, S: ReadValueHint { + let mut num_propagated = 0; for i in 0..READ_REQUEST_LEN { - if !is_empty(read_requests[i]) { - let status = read_request_statuses[i]; - if status.state == ReadRequestState.NADA { - should_propagate[i] = true; - } else if status.state == ReadRequestState.PENDING { - assert( - pending_read_hints[status.hint_index].read_request_index() == i, "Hinted pending read request does not match status" - ); - } else if status.state == ReadRequestState.SETTLED { - assert( - settled_read_hints[status.hint_index].read_request_index() == i, "Hinted settled read request does not match status" - ); - } + let read_request = read_requests[i]; + let status = read_request_statuses[i]; + if status.state == ReadRequestState.PENDING { + assert_eq( + pending_read_hints[status.hint_index].read_request_index(), i, "Hinted pending read request does not match status" + ); + } else if status.state == ReadRequestState.SETTLED { + assert_eq( + settled_read_hints[status.hint_index].read_request_index(), i, "Hinted settled read request does not match status" + ); + } else { + assert_eq( + propagated_read_requests[num_propagated], read_request, "mismatch propagated read request" + ); + num_propagated += 1; } } - filter_array_to_bounded_vec(read_requests, should_propagate) } -pub fn reset_read_requests( +pub fn verify_reset_read_requests< + let READ_REQUEST_LEN: u32, + P, + let PENDING_VALUE_LEN: u32, + let NUM_PENDING_READS: u32, + let NUM_SETTLED_READS: u32, + H, + TREE_HEIGHT, + LEAF_PREIMAGE +>( 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 + tree_root: Field, + propagated_read_requests: [ScopedReadRequest; READ_REQUEST_LEN] +) where P: Readable, H: SettledReadHint + ReadValueHint, LEAF_PREIMAGE: LeafPreimage + Readable { @@ -139,25 +151,41 @@ pub fn reset_read_requests( + read_requests: [ScopedReadRequest; READ_REQUEST_LEN], + read_request_statuses: [ReadRequestStatus; READ_REQUEST_LEN] +) -> [ScopedReadRequest; READ_REQUEST_LEN] { + let mut propagated_read_requests = BoundedVec::new(); + for i in 0..READ_REQUEST_LEN { + let read_request = read_requests[i]; + if read_request_statuses[i].state == ReadRequestState.NADA { + propagated_read_requests.push(read_request); + } + } + propagated_read_requests.storage } mod tests { use crate::reset::read_request::{ PendingReadHint, ReadRequestState, ReadRequestStatus, ReadValueHint, SettledReadHint, - propagate_unverified_read_requests, reset_read_requests, validate_pending_read_requests, - validate_settled_read_requests + get_unverified_read_requests, validate_pending_read_requests, validate_settled_read_requests, + verify_reset_read_requests }; use dep::types::{ address::AztecAddress, abis::{read_request::{ReadRequest, ScopedReadRequest}, side_effect::Readable}, - merkle_tree::{LeafPreimage, MembershipWitness}, tests::merkle_tree_utils::NonEmptyMerkleTree, - traits::Empty + merkle_tree::{LeafPreimage, MembershipWitness}, + tests::{merkle_tree_utils::NonEmptyMerkleTree, utils::assert_array_eq}, + traits::{Empty, is_empty_array} }; fn silo_test_value(value: Field) -> Field { @@ -235,203 +263,281 @@ mod tests { } } - global contract_address = AztecAddress::from_field(123); - - // Create 4 values. 10 and 11 are settled. 12 and 13 are pending. - global values = [10, 11, 12, 13]; - global siloed_values = values.map(|n| silo_test_value(n)); - - // Create 4 read requests. 0 and 3 are reading settled values. 1 and 2 are reading pending values. - global read_requests = [ - 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 = [ - TestValue { value: siloed_values[2], counter: 2 }, - TestValue { value: siloed_values[3], counter: 8 }, - ]; - global pending_read_hints = [ - PendingReadHint { read_request_index: 1, pending_value_index: 1 }, - PendingReadHint { read_request_index: 2, pending_value_index: 0 }, - ]; - - global leaf_preimages = [ - TestLeafPreimage { value: siloed_values[0] }, - TestLeafPreimage { value: siloed_values[1] }, - ]; - - fn build_tree() -> NonEmptyMerkleTree<2, 3, 2, 1> { - NonEmptyMerkleTree::new( - [leaf_preimages[0].as_leaf(), leaf_preimages[1].as_leaf()], - [0; 3], - [0; 2], - [0; 1] - ) - } - - fn get_settled_read_hints() -> ([TestSettledReadHint; 2], Field) { - let tree = build_tree(); - let hints = [ - TestSettledReadHint { - read_request_index: 0, - membership_witness: MembershipWitness { leaf_index: 1, sibling_path: tree.get_sibling_path(1) }, - leaf_preimage: leaf_preimages[1] - }, - TestSettledReadHint { - read_request_index: 3, - membership_witness: MembershipWitness { leaf_index: 0, sibling_path: tree.get_sibling_path(0) }, - leaf_preimage: leaf_preimages[0] - } - ]; - let tree_root = tree.get_root(); - (hints, tree_root) + struct TestBuilder { + read_requests: [ScopedReadRequest; READ_REQUEST_LEN], + read_request_statuses: [ReadRequestStatus; READ_REQUEST_LEN], + pending_values: [TestValue; PENDING_VALUE_LEN], + pending_read_hints: [PendingReadHint; NUM_PENDING_READS], + leaf_preimages: [TestLeafPreimage; NUM_SETTLED_READS], } + impl TestBuilder { + pub fn new() -> TestBuilder<4, 2, 2, 2> { + let contract_address = AztecAddress::from_field(123); + + // Create 4 values. 10 and 11 are settled. 12 and 13 are pending. + let values = [10, 11, 12, 13]; + let siloed_values = values.map(|n| silo_test_value(n)); + + // Create 4 read requests. 0 and 3 are reading settled values. 1 and 2 are reading pending values. + let read_requests = [ + 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 + ]; + + let pending_values = [ + TestValue { value: siloed_values[2], counter: 2 }, + TestValue { value: siloed_values[3], counter: 8 } + ]; + let pending_read_hints = [ + PendingReadHint { read_request_index: 1, pending_value_index: 1 }, + PendingReadHint { read_request_index: 2, pending_value_index: 0 } + ]; + + let leaf_preimages = [ + TestLeafPreimage { value: siloed_values[0] }, + TestLeafPreimage { value: siloed_values[1] } + ]; + + let read_request_statuses = [ + ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 0 }, + ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 0 }, + ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 1 }, + ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 1 } + ]; + + TestBuilder { read_requests, read_request_statuses, pending_values, pending_read_hints, leaf_preimages } + } + + fn build_tree(self) -> NonEmptyMerkleTree<2, 3, 2, 1> { + NonEmptyMerkleTree::new( + [self.leaf_preimages[0].as_leaf(), self.leaf_preimages[1].as_leaf()], + [0; 3], + [0; 2], + [0; 1] + ) + } + + pub fn get_settled_read_hints(self) -> ([TestSettledReadHint; 2], Field) { + let tree = self.build_tree(); + let hints = [ + TestSettledReadHint { + read_request_index: 0, + membership_witness: MembershipWitness { leaf_index: 1, sibling_path: tree.get_sibling_path(1) }, + leaf_preimage: self.leaf_preimages[1] + }, + TestSettledReadHint { + read_request_index: 3, + membership_witness: MembershipWitness { leaf_index: 0, sibling_path: tree.get_sibling_path(0) }, + leaf_preimage: self.leaf_preimages[0] + } + ]; + let tree_root = tree.get_root(); + (hints, tree_root) + } + + pub fn get_nada_pending_read_hint(self) -> PendingReadHint { + PendingReadHint::nada(self.read_requests.len()) + } + + pub fn get_nada_settled_read_hint(self) -> TestSettledReadHint { + TestSettledReadHint::nada(self.read_requests.len()) + } + + pub fn get_unverified_read_requests(self) -> [ScopedReadRequest; READ_REQUEST_LEN] { + get_unverified_read_requests(self.read_requests, self.read_request_statuses) + } + + pub fn validate_pending_read_requests(self) { + validate_pending_read_requests( + self.read_requests, + self.pending_values, + self.pending_read_hints + ); + } + + pub fn validate_settled_read_requests(self) { + let (settled_hints, tree_root) = self.get_settled_read_hints(); + validate_settled_read_requests(self.read_requests, settled_hints, tree_root); + } + + pub fn validate_settled_read_requests_with_hints( + self, + settled_hints: [TestSettledReadHint; 2], + tree_root: Field + ) { + validate_settled_read_requests(self.read_requests, settled_hints, tree_root); + } + + pub fn verify_with_settled_hints(self, settled_hints: [TestSettledReadHint; 2]) { + let tree = self.build_tree(); + verify_reset_read_requests( + self.read_requests, + self.pending_values, + self.read_request_statuses, + self.pending_read_hints, + settled_hints, + tree.get_root(), + self.get_unverified_read_requests() + ); + } + + pub fn verify(self) { + let (settled_hints, tree_root) = self.get_settled_read_hints(); + verify_reset_read_requests( + self.read_requests, + self.pending_values, + self.read_request_statuses, + self.pending_read_hints, + settled_hints, + tree_root, + self.get_unverified_read_requests() + ); + } + } + + /** + * validate_pending_read_requests + */ + #[test] - fn test_validate_pending_read_requests() { - validate_pending_read_requests(read_requests, pending_values, pending_read_hints); + fn validate_pending_read_requests_succeeds() { + let builder = TestBuilder::new(); + builder.validate_pending_read_requests(); } #[test] - fn test_partial_validate_pending_read_requests() { - let hints = [pending_read_hints[1]]; - validate_pending_read_requests(read_requests, pending_values, hints); + fn validate_pending_read_requests_partial_succeeds() { + let mut builder = TestBuilder::new(); + + builder.pending_read_hints[1] = builder.get_nada_pending_read_hint(); + + builder.validate_pending_read_requests(); + } + + #[test(should_fail_with="Hinted test value does not match")] + fn validate_pending_read_requests_wrong_hint_fails() { + let mut builder = TestBuilder::new(); + + builder.pending_read_hints[1].pending_value_index += 1; + + builder.validate_pending_read_requests(); } #[test(should_fail_with="Hinted test value does not match")] - fn test_validate_pending_read_requests_wrong_hint_fails() { - let mut hint = pending_read_hints[1]; - hint.pending_value_index = 1; - let hints = [hint]; - validate_pending_read_requests(read_requests, pending_values, hints); + fn validate_pending_read_requests_wrong_hint_after_nada_fails() { + let mut builder = TestBuilder::new(); + + builder.pending_read_hints[0] = builder.get_nada_pending_read_hint(); + builder.pending_read_hints[1].pending_value_index += 1; + + builder.validate_pending_read_requests(); } + /** + * validate_settled_read_requests + */ + #[test] - fn test_validate_settled_read_requests() { - let (hints, tree_root) = get_settled_read_hints(); - validate_settled_read_requests(read_requests, hints, tree_root); + fn validate_settled_read_requests_succeeds() { + let builder = TestBuilder::new(); + builder.validate_settled_read_requests(); } #[test] - fn test_partial_validate_settled_read_requests() { - let (settled_hints, tree_root) = get_settled_read_hints(); - let hints = [settled_hints[0]]; - validate_settled_read_requests(read_requests, hints, tree_root); + fn validate_settled_read_requests_partial_succeeds() { + let mut builder = TestBuilder::new(); + + let mut (settled_hints, tree_root) = builder.get_settled_read_hints(); + settled_hints[0] = builder.get_nada_settled_read_hint(); + + builder.validate_settled_read_requests_with_hints(settled_hints, tree_root); } #[test(should_fail_with="membership check failed")] - fn test_validate_settled_read_requests_wrong_witness_fails() { - let (settled_hints, tree_root) = get_settled_read_hints(); - let mut hint = settled_hints[0]; - hint.membership_witness.leaf_index += 1; - let hints = [hint]; - validate_settled_read_requests(read_requests, hints, tree_root); + fn validate_settled_read_requests_wrong_leaf_index_fails() { + let mut builder = TestBuilder::new(); + + let mut (settled_hints, tree_root) = builder.get_settled_read_hints(); + settled_hints[0].membership_witness.leaf_index += 1; + + builder.validate_settled_read_requests_with_hints(settled_hints, tree_root); } #[test(should_fail_with="Provided leaf preimage is not for target value")] - fn test_validate_settled_read_requests_wrong_preimage_value_fails() { - let (settled_hints, tree_root) = get_settled_read_hints(); - let mut hint = settled_hints[0]; - hint.leaf_preimage.value = siloed_values[0]; - let hints = [hint]; - validate_settled_read_requests(read_requests, hints, tree_root); + fn validate_settled_read_requests_wrong_preimage_value_fails() { + let mut builder = TestBuilder::new(); + + let mut (settled_hints, tree_root) = builder.get_settled_read_hints(); + settled_hints[0].leaf_preimage.value += 1; + + builder.validate_settled_read_requests_with_hints(settled_hints, tree_root); } + #[test(should_fail_with="membership check failed")] + fn validate_settled_read_requests_wrong_path_after_nada_fails() { + let mut builder = TestBuilder::new(); + + let mut (settled_hints, tree_root) = builder.get_settled_read_hints(); + settled_hints[0] = builder.get_nada_settled_read_hint(); + settled_hints[1].membership_witness.sibling_path[0] += 1; + + builder.validate_settled_read_requests_with_hints(settled_hints, tree_root); + } + + /** + * verify_reset_read_requests + */ + #[test] - fn test_propagate_unverified_read_requests() { - let read_request_statuses = [ - ReadRequestStatus::empty(), - ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 0 }, - ReadRequestStatus::empty(), - ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 0 } - ]; - let pending_read_hints = [pending_read_hints[0]]; - let (settled_read_hints, _) = get_settled_read_hints(); - let settled_read_hints = [settled_read_hints[1]]; - let unverified_read_requests = propagate_unverified_read_requests( - read_requests, - read_request_statuses, - pending_read_hints, - settled_read_hints - ); - assert(unverified_read_requests.len() == 2); - assert(unverified_read_requests.get(0) == read_requests[0]); - assert(unverified_read_requests.get(1) == read_requests[2]); + fn verify_read_requests_clears_all_succeeds() { + let builder = TestBuilder::new(); + + let unverified_read_requests = builder.get_unverified_read_requests(); + assert(is_empty_array(unverified_read_requests)); + + builder.verify(); } #[test] - fn test_propagate_unverified_read_requests_clears_all() { - let read_request_statuses = [ - ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 0 }, - ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 0 }, - ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 1 }, - ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 1 } - ]; - let (settled_read_hints, _) = get_settled_read_hints(); - let unverified_read_requests = propagate_unverified_read_requests( - read_requests, - read_request_statuses, - pending_read_hints, - settled_read_hints + fn verify_reset_read_requests_partial_succeeds() { + let mut builder = TestBuilder::new(); + + builder.read_request_statuses[0] = ReadRequestStatus::empty(); + builder.read_request_statuses[2] = ReadRequestStatus::empty(); + builder.pending_read_hints[1] = builder.get_nada_pending_read_hint(); + + let mut (settled_hints, _) = builder.get_settled_read_hints(); + settled_hints[0] = builder.get_nada_settled_read_hint(); + + let read_requests = builder.read_requests; + let unverified_read_requests = builder.get_unverified_read_requests(); + assert_array_eq( + unverified_read_requests, + [read_requests[0], read_requests[2]] ); - assert(unverified_read_requests.len() == 0); + + builder.verify_with_settled_hints(settled_hints); } #[test(should_fail_with="Hinted pending read request does not match status")] - fn test_propagate_unverified_read_requests_wrong_pending_read_status_fails() { - let read_request_statuses = [ - ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 0 }, - ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 0 }, - ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 1 }, - ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 1 } - ]; - let (settled_read_hints, _) = get_settled_read_hints(); - let _ = propagate_unverified_read_requests( - read_requests, - read_request_statuses, - pending_read_hints, - settled_read_hints - ); + fn verify_reset_read_requests_wrong_pending_read_status_fails() { + let mut builder = TestBuilder::new(); + + builder.read_request_statuses[0].state = ReadRequestState.PENDING; + + builder.verify(); } #[test(should_fail_with="Hinted settled read request does not match status")] - fn test_propagate_unverified_read_requests_wrong_settled_read_status_fails() { - let read_request_statuses = [ - ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 0 }, - ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 0 }, - ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 1 }, - ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 1 } - ]; - let (settled_read_hints, _) = get_settled_read_hints(); - let _ = propagate_unverified_read_requests( - read_requests, - read_request_statuses, - pending_read_hints, - settled_read_hints - ); - } + fn verify_reset_read_requests_wrong_settled_read_status_fails() { + let mut builder = TestBuilder::new(); - #[test] - fn test_reset_read_requests_all() { - let read_request_statuses = [ - ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 0 }, - ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 0 }, - ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 1 }, - ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 1 } - ]; - let (settled_read_hints, tree_root) = get_settled_read_hints(); - let unverified_read_requests = reset_read_requests( - read_requests, - pending_values, - read_request_statuses, - pending_read_hints, - settled_read_hints, - tree_root - ); - assert(unverified_read_requests.len() == 0); + builder.read_request_statuses[2].state = ReadRequestState.SETTLED; + + builder.verify(); } } 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 ef8e2432e955..70e62ab3d1c1 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 @@ -3,28 +3,49 @@ use dep::types::{ traits::is_empty }; -pub fn verify_squashed_transient_data( +struct TransientDataIndexHint { + nullifier_index: u32, + note_hash_index: u32, +} + +impl TransientDataIndexHint { + pub fn nada(num_nullifiers: u32, num_note_hashes: u32) -> Self { + TransientDataIndexHint { nullifier_index: num_nullifiers, note_hash_index: num_note_hashes } + } +} + +pub fn verify_squashed_transient_data_with_hint_indexes< + let NUM_NOTE_HASHES: u32, + let NUM_NULLIFIERS: u32, + let NUM_LOGS: u32, + let NUM_INDEX_HINTS: u32 +>( note_hashes: [ScopedNoteHash; NUM_NOTE_HASHES], nullifiers: [ScopedNullifier; NUM_NULLIFIERS], note_logs: [NoteLogHash; NUM_LOGS], expected_note_hashes: [ScopedNoteHash; NUM_NOTE_HASHES], expected_nullifiers: [ScopedNullifier; NUM_NULLIFIERS], expected_note_logs: [NoteLogHash; NUM_LOGS], - transient_nullifier_indexes_for_note_hashes: [u32; NUM_NOTE_HASHES], - transient_note_hash_indexes_for_nullifiers: [u32; NUM_NULLIFIERS], + transient_data_index_hints: [TransientDataIndexHint; NUM_INDEX_HINTS], transient_or_propagated_note_hash_indexes_for_logs: [u32; NUM_LOGS], - split_counter: u32 + split_counter: u32, + squashed_note_hash_hints: [bool; NUM_NOTE_HASHES], + squashed_nullifier_hints: [bool; NUM_NULLIFIERS] ) { - let mut note_hashes_kept = 0; - let mut note_hashes_removed = 0; - for i in 0..NUM_NOTE_HASHES { - let note_hash = note_hashes[i]; - let nullifier_index = transient_nullifier_indexes_for_note_hashes[i]; - if nullifier_index == NUM_NULLIFIERS { // The note hash has no corresponding nullifier. - assert_eq(expected_note_hashes[note_hashes_kept], note_hash, "Propagated note hash does not match"); - note_hashes_kept += 1; + let mut num_squashed = 0; + for i in 0..NUM_INDEX_HINTS { + let hint = transient_data_index_hints[i]; + if hint.nullifier_index == NUM_NULLIFIERS { + assert_eq(hint.note_hash_index, NUM_NOTE_HASHES, "Invalid transient data index hint"); } else { - let nullifier = nullifiers[nullifier_index]; + let nullifier = nullifiers[hint.nullifier_index]; + let note_hash = note_hashes[hint.note_hash_index]; + assert_eq( + note_hash.value(), nullifier.nullified_note_hash(), "Value of the hinted transient note hash does not match" + ); + assert_eq( + note_hash.contract_address, nullifier.contract_address, "Contract address of the hinted transient note hash does not match" + ); assert( nullifier.counter() > note_hash.counter(), "Cannot nullify a note hash created afterwards" ); @@ -34,80 +55,135 @@ pub fn verify_squashed_transient_data(transient_data_index_hints: [TransientDataIndexHint; NUM_INDEX_HINTS]) -> [bool; NUM_NOTE_HASHES] { + let mut hints = [false; NUM_NOTE_HASHES]; + for i in 0..transient_data_index_hints.len() { + let note_hash_index = transient_data_index_hints[i].note_hash_index; + if note_hash_index != NUM_NOTE_HASHES { + hints[note_hash_index] = true; + } + } + hints +} + +unconstrained pub fn get_squashed_nullifier_hints(transient_data_index_hints: [TransientDataIndexHint; NUM_INDEX_HINTS]) -> [bool; NUM_NULLIFIERS] { + let mut hints = [false; NUM_NULLIFIERS]; + for i in 0..transient_data_index_hints.len() { + let nullifier_index = transient_data_index_hints[i].nullifier_index; + if nullifier_index != NUM_NULLIFIERS { + hints[nullifier_index] = true; } } + hints +} - assert_eq( - note_hashes_removed, nullifiers_removed, "Inconsistent number of note hashes and nullifiers removed" +pub fn verify_squashed_transient_data< + let NUM_NOTE_HASHES: u32, + let NUM_NULLIFIERS: u32, + let NUM_LOGS: u32, + let NUM_INDEX_HINTS: u32 +>( + note_hashes: [ScopedNoteHash; NUM_NOTE_HASHES], + nullifiers: [ScopedNullifier; NUM_NULLIFIERS], + note_logs: [NoteLogHash; NUM_LOGS], + expected_note_hashes: [ScopedNoteHash; NUM_NOTE_HASHES], + expected_nullifiers: [ScopedNullifier; NUM_NULLIFIERS], + expected_note_logs: [NoteLogHash; NUM_LOGS], + transient_data_index_hints: [TransientDataIndexHint; NUM_INDEX_HINTS], + transient_or_propagated_note_hash_indexes_for_logs: [u32; NUM_LOGS], + split_counter: u32 +) { + let squashed_note_hash_hints = get_squashed_note_hash_hints(transient_data_index_hints); + let squashed_nullifier_hints = get_squashed_nullifier_hints(transient_data_index_hints); + verify_squashed_transient_data_with_hint_indexes( + note_hashes, + nullifiers, + note_logs, + expected_note_hashes, + expected_nullifiers, + expected_note_logs, + transient_data_index_hints, + transient_or_propagated_note_hash_indexes_for_logs, + split_counter, + squashed_note_hash_hints, + squashed_nullifier_hints ); } mod tests { - use crate::reset::transient_data::verify_squashed_transient_data; + use crate::reset::transient_data::{ + get_squashed_note_hash_hints, get_squashed_nullifier_hints, TransientDataIndexHint, + verify_squashed_transient_data, verify_squashed_transient_data_with_hint_indexes + }; use dep::types::{ abis::{note_hash::{NoteHash, ScopedNoteHash}, nullifier::{Nullifier, ScopedNullifier}, log_hash::NoteLogHash}, address::AztecAddress @@ -115,21 +191,20 @@ mod tests { global contract_address = AztecAddress::from_field(987654); - struct TestDataBuilder { + struct TestDataBuilder { note_hashes: [ScopedNoteHash; NUM_NOTE_HASHES], nullifiers: [ScopedNullifier; NUM_NULLIFIERS], note_logs: [NoteLogHash; NUM_LOGS], expected_note_hashes: [ScopedNoteHash; NUM_NOTE_HASHES], expected_nullifiers: [ScopedNullifier; NUM_NULLIFIERS], expected_note_logs: [NoteLogHash; NUM_LOGS], - transient_nullifier_indexes_for_note_hashes: [u32; NUM_NOTE_HASHES], - transient_note_hash_indexes_for_nullifiers: [u32; NUM_NULLIFIERS], + transient_data_index_hints: [TransientDataIndexHint; NUM_INDEX_HINTS], transient_or_propagated_note_hash_indexes_for_logs: [u32; NUM_LOGS], split_counter: u32, } - impl TestDataBuilder { - pub fn new() -> TestDataBuilder<5, 4, 3> { + impl TestDataBuilder { + pub fn new() -> TestDataBuilder<5, 4, 3, 2> { let note_hashes = [ NoteHash { value: 11, counter: 100 }.scope(contract_address), NoteHash { value: 22, counter: 200 }.scope(contract_address), @@ -158,9 +233,11 @@ mod tests { let mut expected_note_logs = [NoteLogHash::empty(); 3]; expected_note_logs[0] = note_logs[1]; - let transient_nullifier_indexes_for_note_hashes = [1, 4, 0, 4, 4]; - let transient_note_hash_indexes_for_nullifiers = [2, 0, 5, 5]; - let transient_or_propagated_note_hash_indexes_for_logs = [0, 0, 1]; + let transient_data_index_hints = [ + TransientDataIndexHint { nullifier_index: 0, note_hash_index: 2 }, + TransientDataIndexHint { nullifier_index: 1, note_hash_index: 0 } + ]; + let transient_or_propagated_note_hash_indexes_for_logs = [1, 0, 1]; TestDataBuilder { note_hashes, @@ -169,14 +246,13 @@ mod tests { expected_note_hashes, expected_nullifiers, expected_note_logs, - transient_nullifier_indexes_for_note_hashes, - transient_note_hash_indexes_for_nullifiers, + transient_data_index_hints, transient_or_propagated_note_hash_indexes_for_logs, split_counter: 0 } } - pub fn new_clear_all() -> TestDataBuilder<3, 3, 4> { + pub fn new_clear_all() -> TestDataBuilder<3, 3, 4, 3> { let note_hashes = [ NoteHash { value: 11, counter: 100 }.scope(contract_address), NoteHash { value: 22, counter: 200 }.scope(contract_address), @@ -201,9 +277,12 @@ mod tests { let expected_nullifiers = [ScopedNullifier::empty(); 3]; let expected_note_logs = [NoteLogHash::empty(); 4]; - let transient_nullifier_indexes_for_note_hashes = [1, 2, 0]; - let transient_note_hash_indexes_for_nullifiers = [2, 0, 1]; - let transient_or_propagated_note_hash_indexes_for_logs = [0, 2, 1, 2]; + let transient_data_index_hints = [ + TransientDataIndexHint { nullifier_index: 0, note_hash_index: 2 }, + TransientDataIndexHint { nullifier_index: 1, note_hash_index: 0 }, + TransientDataIndexHint { nullifier_index: 2, note_hash_index: 1 } + ]; + let transient_or_propagated_note_hash_indexes_for_logs = [1, 0, 2, 0]; TestDataBuilder { note_hashes, @@ -212,14 +291,13 @@ mod tests { expected_note_hashes, expected_nullifiers, expected_note_logs, - transient_nullifier_indexes_for_note_hashes, - transient_note_hash_indexes_for_nullifiers, + transient_data_index_hints, transient_or_propagated_note_hash_indexes_for_logs, split_counter: 0 } } - pub fn new_identical_note_hashes() -> TestDataBuilder<3, 3, 4> { + pub fn new_identical_note_hashes() -> TestDataBuilder<3, 3, 4, 3> { let note_hashes = [ NoteHash { value: 11, counter: 100 }.scope(contract_address), NoteHash { value: 11, counter: 200 }.scope(contract_address), @@ -243,8 +321,11 @@ mod tests { let expected_nullifiers = [nullifiers[1], ScopedNullifier::empty(), ScopedNullifier::empty()]; let expected_note_logs = [note_logs[3], NoteLogHash::empty(), NoteLogHash::empty(), NoteLogHash::empty()]; - let transient_nullifier_indexes_for_note_hashes = [0, 2, 3]; - let transient_note_hash_indexes_for_nullifiers = [0, 3, 1]; + let transient_data_index_hints = [ + TransientDataIndexHint { nullifier_index: 0, note_hash_index: 0 }, + TransientDataIndexHint { nullifier_index: 2, note_hash_index: 1 }, + TransientDataIndexHint { nullifier_index: 3, note_hash_index: 3 } + ]; let transient_or_propagated_note_hash_indexes_for_logs = [1, 1, 1, 0]; TestDataBuilder { @@ -254,27 +335,55 @@ mod tests { expected_note_hashes, expected_nullifiers, expected_note_logs, - transient_nullifier_indexes_for_note_hashes, - transient_note_hash_indexes_for_nullifiers, + transient_data_index_hints, transient_or_propagated_note_hash_indexes_for_logs, split_counter: 0 } } + pub fn get_nada_index_hint(_self: Self) -> TransientDataIndexHint { + TransientDataIndexHint { nullifier_index: NUM_NULLIFIERS, note_hash_index: NUM_NOTE_HASHES } + } + + pub fn get_hint_indexes(self) -> ([bool; NUM_NOTE_HASHES], [bool; NUM_NULLIFIERS]) { + let squashed_note_hash_hints = get_squashed_note_hash_hints(self.transient_data_index_hints); + let squashed_nullifier_hints = get_squashed_nullifier_hints(self.transient_data_index_hints); + (squashed_note_hash_hints, squashed_nullifier_hints) + } + pub fn verify(self) { - let _void = verify_squashed_transient_data( + verify_squashed_transient_data( self.note_hashes, self.nullifiers, self.note_logs, self.expected_note_hashes, self.expected_nullifiers, self.expected_note_logs, - self.transient_nullifier_indexes_for_note_hashes, - self.transient_note_hash_indexes_for_nullifiers, + self.transient_data_index_hints, self.transient_or_propagated_note_hash_indexes_for_logs, self.split_counter ); } + + pub fn verify_with_hint_indexes( + self, + squashed_note_hash_hints: [bool; NUM_NOTE_HASHES], + squashed_nullifier_hints: [bool; NUM_NULLIFIERS] + ) { + verify_squashed_transient_data_with_hint_indexes( + self.note_hashes, + self.nullifiers, + self.note_logs, + self.expected_note_hashes, + self.expected_nullifiers, + self.expected_note_logs, + self.transient_data_index_hints, + self.transient_or_propagated_note_hash_indexes_for_logs, + self.split_counter, + squashed_note_hash_hints, + squashed_nullifier_hints + ); + } } #[test] @@ -291,17 +400,21 @@ mod tests { fn succeeds_partially_propagated() { let mut builder = TestDataBuilder::new_clear_all(); - // Keep the note at index 1. - builder.transient_nullifier_indexes_for_note_hashes[1] = builder.nullifiers.len(); - builder.expected_note_hashes[0] = builder.note_hashes[1]; - - // Keep the nullifier at index 2. - builder.transient_note_hash_indexes_for_nullifiers[2] = builder.note_hashes.len(); - builder.expected_nullifiers[0] = builder.nullifiers[2]; - - // Keep the log at index 2. - builder.transient_or_propagated_note_hash_indexes_for_logs[2] = 0; // Point it to the expected not hash at index 0. - builder.expected_note_logs[0] = builder.note_logs[2]; + // Keep the nullifier at index 1 and the note hash at index 0. + let removed_hint = builder.transient_data_index_hints[0]; + assert_eq(removed_hint.nullifier_index, 0); + assert_eq(removed_hint.note_hash_index, 2); + // Update the hint to skip squashing. + builder.transient_data_index_hints[0] = builder.get_nada_index_hint(); + // Propagate the values. + builder.expected_note_hashes[0] = builder.note_hashes[removed_hint.note_hash_index]; + builder.expected_nullifiers[0] = builder.nullifiers[removed_hint.nullifier_index]; + + // Keep the logs for note hash at index 0. + builder.transient_or_propagated_note_hash_indexes_for_logs[1] = 0; // Point it to the expected not hash at index 0. + builder.transient_or_propagated_note_hash_indexes_for_logs[3] = 0; // Point it to the expected not hash at index 0. + builder.expected_note_logs[0] = builder.note_logs[1]; + builder.expected_note_logs[1] = builder.note_logs[3]; builder.verify(); } @@ -311,6 +424,17 @@ mod tests { TestDataBuilder::new_identical_note_hashes().verify(); } + #[test(should_fail_with="Invalid transient data index hint")] + fn fails_non_nada_index_hint() { + let mut builder = TestDataBuilder::new_clear_all(); + + builder.transient_data_index_hints[0] = builder.get_nada_index_hint(); + // Assign a value to the note_hash_index in a nada index hint. + builder.transient_data_index_hints[0].note_hash_index = 1; + + builder.verify(); + } + #[test(should_fail_with="Value of the hinted transient note hash does not match")] fn fails_mismatch_note_hash_value() { let mut builder = TestDataBuilder::new_clear_all(); @@ -329,11 +453,26 @@ mod tests { builder.verify(); } - #[test(should_fail_with="Empty note hash must be padded to the right")] - fn fails_unexpected_note_hash_value() { - let mut builder = TestDataBuilder::new_clear_all(); + #[test(should_fail_with="Cannot nullify a note hash created afterwards")] + fn fails_nullify_note_hash_emitted_afterwards() { + let mut builder = TestDataBuilder::new(); - builder.expected_note_hashes[2].note_hash.value = 11; + // Make the nullifier at index 1 to have a smaller counter than its note hash. + let hint = builder.transient_data_index_hints[1]; + let note_hash_counter = builder.note_hashes[hint.note_hash_index].counter(); + builder.nullifiers[hint.nullifier_index].nullifier.counter = note_hash_counter - 1; + + builder.verify(); + } + + #[test(should_fail_with="Cannot squash a non-revertible note hash with a revertible nullifier")] + fn fails_nullify_non_revertible_note_hash_with_revertible_nullifier() { + let mut builder = TestDataBuilder::new(); + + let hint = builder.transient_data_index_hints[1]; + let note_hash_counter = builder.note_hashes[hint.note_hash_index].counter(); + // Make the note hash non-revertible. + builder.split_counter = note_hash_counter + 1; builder.verify(); } @@ -356,24 +495,72 @@ mod tests { builder.verify(); } - #[test(should_fail_with="Invalid transient nullifier index hint")] - fn fails_wrong_hint_for_transient_nullifier_index() { + #[test(should_fail_with="Wrong squashed note hash hint")] + fn fails_wrong_note_hash_squashed_hint() { let mut builder = TestDataBuilder::new_clear_all(); - builder.transient_note_hash_indexes_for_nullifiers[0] = 1; + let mut (squashed_note_hash_hints, squashed_nullifier_hints) = builder.get_hint_indexes(); + squashed_note_hash_hints[0] = false; - builder.verify(); + builder.verify_with_hint_indexes(squashed_note_hash_hints, squashed_nullifier_hints); } - #[test(should_fail_with="Empty nullifier must be padded to the right")] - fn fails_unexpected_nullifier_value() { + #[test(should_fail_with="Empty note hash must be padded to the right")] + fn fails_unexpected_note_hash_value() { let mut builder = TestDataBuilder::new_clear_all(); - builder.expected_nullifiers[2].nullifier.value = 11; + builder.expected_note_hashes[2].note_hash.value = 11; builder.verify(); } + #[test(should_fail_with="Wrong squashed note hash hint")] + fn fails_propagate_note_hash_for_squashed_nullifier() { + let mut builder = TestDataBuilder::new_clear_all(); + + // Propagate the note hash at index 1. + builder.expected_note_hashes[0] = builder.note_hashes[1]; + + let mut (squashed_note_hash_hints, squashed_nullifier_hints) = builder.get_hint_indexes(); + // Set the hint to false so it's assumed the note hash has not been squashed. + squashed_note_hash_hints[1] = false; + + builder.verify_with_hint_indexes(squashed_note_hash_hints, squashed_nullifier_hints); + } + + #[test(should_fail_with="Empty note hash must be padded to the right")] + fn fails_identical_note_hashes_nullify_same_note_hash() { + let mut builder = TestDataBuilder::new_identical_note_hashes(); + + assert_eq(builder.transient_data_index_hints[1].note_hash_index, 1); + // Make the nullifier at index 2 to also nullify the note hash at index 0. + builder.transient_data_index_hints[1].note_hash_index = 0; + // Propagate the note hashes at index 1 and 2. + builder.expected_note_hashes[0] = builder.note_hashes[1]; + builder.expected_note_hashes[1] = builder.note_hashes[2]; + + let mut (squashed_note_hash_hints, squashed_nullifier_hints) = builder.get_hint_indexes(); + // Set the hint to false so it's assumed the note hash has not been squashed. + squashed_note_hash_hints[1] = false; + + builder.verify_with_hint_indexes(squashed_note_hash_hints, squashed_nullifier_hints); + } + + #[test(should_fail_with="Wrong number of note hashes removed")] + fn fails_note_hash_not_propagated() { + let mut builder = TestDataBuilder::new(); + + // Do not propagate any note hashes. + builder.expected_note_hashes[0] = ScopedNoteHash::empty(); + + let mut (squashed_note_hash_hints, squashed_nullifier_hints) = builder.get_hint_indexes(); + assert_eq(squashed_note_hash_hints[1], false); + // Set the hint to true so it's assumed the note hash has been squashed. + squashed_note_hash_hints[1] = true; + + builder.verify_with_hint_indexes(squashed_note_hash_hints, squashed_nullifier_hints); + } + #[test(should_fail_with="Propagated nullifier does not match")] fn fails_wrong_expected_nullifier_value() { let mut builder = TestDataBuilder::new(); @@ -392,26 +579,41 @@ mod tests { builder.verify(); } - #[test(should_fail_with="Cannot nullify a note hash created afterwards")] - fn fails_nullify_note_hash_emitted_afterwards() { - let mut builder = TestDataBuilder::new(); + #[test(should_fail_with="Wrong squashed nullifier hint")] + fn fails_wrong_nullifier_hint_index() { + let mut builder = TestDataBuilder::new_clear_all(); - // Make the nullifier at index 1 to have a smaller counter than its note hash. - let note_hash_counter = builder.note_hashes[builder.transient_note_hash_indexes_for_nullifiers[1]].counter(); - builder.nullifiers[1].nullifier.counter = note_hash_counter - 1; + // Propagate the nullifier at index 1. + builder.expected_nullifiers[0] = builder.nullifiers[1]; + + let mut (squashed_note_hash_hints, squashed_nullifier_hints) = builder.get_hint_indexes(); + // Set the hint to false so it's assumed the note hash has not been squashed. + squashed_nullifier_hints[1] = false; + + builder.verify_with_hint_indexes(squashed_note_hash_hints, squashed_nullifier_hints); + } + + #[test(should_fail_with="Empty nullifier must be padded to the right")] + fn fails_unexpected_nullifier_value() { + let mut builder = TestDataBuilder::new_clear_all(); + + builder.expected_nullifiers[2].nullifier.value = 11; builder.verify(); } - #[test(should_fail_with="Cannot squash a non-revertible note hash with a revertible nullifier")] - fn fails_nullify_non_revertible_note_hash_with_revertible_nullifier() { + #[test(should_fail_with="Wrong number of nullifiers removed")] + fn fails_propagate_nullifier_for_squashed_note_hash() { let mut builder = TestDataBuilder::new(); - let note_hash_counter = builder.note_hashes[builder.transient_note_hash_indexes_for_nullifiers[1]].counter(); - // Make the note hash non-revertible. - builder.split_counter = note_hash_counter + 1; + // Do not propagate any nullifiers. + builder.expected_nullifiers[0] = ScopedNullifier::empty(); - builder.verify(); + let mut (squashed_note_hash_hints, squashed_nullifier_hints) = builder.get_hint_indexes(); + // Set the hint to true so it's assumed the note hash has been squashed. + squashed_nullifier_hints[2] = true; + + builder.verify_with_hint_indexes(squashed_note_hash_hints, squashed_nullifier_hints); } #[test(should_fail_with="Empty log must be padded to the right")] @@ -441,7 +643,7 @@ mod tests { builder.verify(); } - #[test(should_fail_with="Hinted transient note log not nullified")] + #[test(should_fail_with="Value of the hinted transient note hash does not match log")] fn fails_log_not_nullified() { let mut builder = TestDataBuilder::new(); @@ -464,51 +666,7 @@ mod tests { let mut builder = TestDataBuilder::new_clear_all(); // Keep the log. - builder.expected_note_logs[0] = builder.note_logs[1]; - - builder.verify(); - } - - #[test(should_fail_with="Value of the hinted transient note hash does not match log")] - fn fails_propagate_log_whose_note_hash_has_been_nullified() { - let mut builder = TestDataBuilder::new_clear_all(); - - // Keep the log. - builder.expected_note_logs[0] = builder.note_logs[1]; - // Point the log to index 0, which is empty in expected_note_hashes, and does not match the transient_note_hash. - builder.transient_or_propagated_note_hash_indexes_for_logs[1] = 0; - - builder.verify(); - } - - #[test(should_fail_with="Invalid transient nullifier index hint")] - fn fails_propagate_more_note_hashes_than_nullifiers() { - let mut builder = TestDataBuilder::new_clear_all(); - - // Keep the note at index 1. - builder.transient_nullifier_indexes_for_note_hashes[1] = builder.nullifiers.len(); - builder.expected_note_hashes[0] = builder.note_hashes[1]; - - builder.verify(); - } - - #[test(should_fail_with="Inconsistent number of note hashes and nullifiers removed")] - fn fails_propagate_more_nullifiers_than_note_hashes() { - let mut builder = TestDataBuilder::new_clear_all(); - - // Keep the nullifier at index 2. - builder.transient_note_hash_indexes_for_nullifiers[2] = builder.note_hashes.len(); - builder.expected_nullifiers[0] = builder.nullifiers[2]; - - builder.verify(); - } - - #[test(should_fail_with="Invalid transient nullifier index hint")] - fn fails_identical_note_hashes_nullify_same_note_hash() { - let mut builder = TestDataBuilder::new_identical_note_hashes(); - - // Make the nullifier at index 2 to also nullify the note hash at index 0. - builder.transient_note_hash_indexes_for_nullifiers[2] = 0; + builder.expected_note_logs[1] = builder.note_logs[0]; builder.verify(); } diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/mod.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/mod.nr index def4fcea6aa3..dd0fa37a7cdb 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/mod.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/mod.nr @@ -2,3 +2,6 @@ mod note_hash_read_request_hints_builder; mod nullifier_non_existent_read_request_hints_builder; mod nullifier_read_request_hints_builder; mod public_data_read_request_hints_builder; + +use note_hash_read_request_hints_builder::NoteHashReadRequestHintsBuilder; +use nullifier_read_request_hints_builder::NullifierReadRequestHintsBuilder; diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/note_hash_read_request_hints_builder.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/note_hash_read_request_hints_builder.nr index 9c4e24886fb1..d50f63628c19 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/note_hash_read_request_hints_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/note_hash_read_request_hints_builder.nr @@ -4,25 +4,25 @@ use crate::{ }; use dep::types::constants::MAX_NOTE_HASH_READ_REQUESTS_PER_TX; -struct NoteHashReadRequestHintsBuilder { +struct NoteHashReadRequestHintsBuilder { read_request_statuses: [ReadRequestStatus; MAX_NOTE_HASH_READ_REQUESTS_PER_TX], - pending_read_hints: BoundedVec, - settled_read_hints: BoundedVec, + pending_read_hints: BoundedVec, + settled_read_hints: BoundedVec, } -impl NoteHashReadRequestHintsBuilder { - pub fn new(read_request_len: u32) -> Self { +impl NoteHashReadRequestHintsBuilder { + pub fn new() -> Self { NoteHashReadRequestHintsBuilder { read_request_statuses: [ReadRequestStatus::empty(); MAX_NOTE_HASH_READ_REQUESTS_PER_TX], - pending_read_hints: BoundedVec { storage: [PendingReadHint::nada(read_request_len); MAX_NOTE_HASH_READ_REQUESTS_PER_TX], len: 0 }, + pending_read_hints: BoundedVec { storage: [PendingReadHint::nada(MAX_NOTE_HASH_READ_REQUESTS_PER_TX); NUM_PENDING_HINTS], len: 0 }, settled_read_hints: BoundedVec { - storage: [NoteHashSettledReadHint::nada(read_request_len); MAX_NOTE_HASH_READ_REQUESTS_PER_TX], + storage: [NoteHashSettledReadHint::nada(MAX_NOTE_HASH_READ_REQUESTS_PER_TX); NUM_SETTLED_HINTS], len: 0 } } } - pub fn to_hints(self) -> NoteHashReadRequestHints { + pub fn to_hints(self) -> NoteHashReadRequestHints { NoteHashReadRequestHints { read_request_statuses: self.read_request_statuses, pending_read_hints: self.pending_read_hints.storage, diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/nullifier_non_existent_read_request_hints_builder.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/nullifier_non_existent_read_request_hints_builder.nr index 1d9a3e601658..a7e0d118befa 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/nullifier_non_existent_read_request_hints_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/nullifier_non_existent_read_request_hints_builder.nr @@ -6,7 +6,7 @@ use dep::types::{ NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, NULLIFIER_SUBTREE_HEIGHT }, merkle_tree::MembershipWitness, tests::{merkle_tree_utils::NonEmptyMerkleTree}, - utils::{arrays::{find_index, sort_get_sorted_hints}, field::full_field_greater_than} + utils::{arrays::{find_index_hint, sort_get_sorted_hints}, field::full_field_greater_than} }; struct NullifierNonExistentReadRequestHintsBuilder { @@ -61,7 +61,7 @@ impl NullifierNonExistentReadRequestHintsBuilder { for i in 0..MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX { if i < self.read_values.len() { let value = self.read_values.get_unchecked(i); - next_pending_value_indices[i] = find_index(sorted_pending_values, |v: Nullifier| !v.value.lt(value)); + next_pending_value_indices[i] = find_index_hint(sorted_pending_values, |v: Nullifier| !v.value.lt(value)); } } diff --git a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/nullifier_read_request_hints_builder.nr b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/nullifier_read_request_hints_builder.nr index 6fb7e753ae37..7a019b9fae28 100644 --- a/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/nullifier_read_request_hints_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/reset-kernel-lib/src/tests/nullifier_read_request_hints_builder.nr @@ -4,25 +4,25 @@ use crate::{ }; use dep::types::constants::MAX_NULLIFIER_READ_REQUESTS_PER_TX; -struct NullifierReadRequestHintsBuilder { +struct NullifierReadRequestHintsBuilder { read_request_statuses: [ReadRequestStatus; MAX_NULLIFIER_READ_REQUESTS_PER_TX], - pending_read_hints: BoundedVec, - settled_read_hints: BoundedVec, + pending_read_hints: BoundedVec, + settled_read_hints: BoundedVec, } -impl NullifierReadRequestHintsBuilder { - pub fn new(read_request_len: u32) -> Self { +impl NullifierReadRequestHintsBuilder { + pub fn new() -> Self { NullifierReadRequestHintsBuilder { read_request_statuses: [ReadRequestStatus::empty(); MAX_NULLIFIER_READ_REQUESTS_PER_TX], - pending_read_hints: BoundedVec { storage: [PendingReadHint::nada(read_request_len); MAX_NULLIFIER_READ_REQUESTS_PER_TX], len: 0 }, + pending_read_hints: BoundedVec { storage: [PendingReadHint::nada(MAX_NULLIFIER_READ_REQUESTS_PER_TX); NUM_PENDING_HINTS], len: 0 }, settled_read_hints: BoundedVec { - storage: [NullifierSettledReadHint::nada(read_request_len); MAX_NULLIFIER_READ_REQUESTS_PER_TX], + storage: [NullifierSettledReadHint::nada(MAX_NULLIFIER_READ_REQUESTS_PER_TX); NUM_SETTLED_HINTS], len: 0 } } } - pub fn to_hints(self) -> NullifierReadRequestHints { + pub fn to_hints(self) -> NullifierReadRequestHints { NullifierReadRequestHints { read_request_statuses: self.read_request_statuses, pending_read_hints: self.pending_read_hints.storage, diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/previous_rollup_data.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/previous_rollup_data.nr index a0624789b374..b0e71945b43d 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/previous_rollup_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/previous_rollup_data.nr @@ -37,9 +37,10 @@ impl Empty for PreviousRollupData { } impl PreviousRollupData { - fn validate_in_vk_tree(self, allowed_indices: [u32; N]) { - let index_hint = find_index_hint(allowed_indices, self.vk_witness.leaf_index as u32); - assert_eq(allowed_indices[index_hint], self.vk_witness.leaf_index as u32, "Invalid vk index"); + fn validate_in_vk_tree(self, allowed_indices: [u32; N]) { + let leaf_index = self.vk_witness.leaf_index as u32; + let index_hint = find_index_hint(allowed_indices, |index: u32| index == leaf_index); + assert_eq(allowed_indices[index_hint], leaf_index, "Invalid vk index"); assert_check_membership( self.vk.hash, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/call_context.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/call_context.nr index adc55d358951..698c4b116b4a 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/call_context.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/call_context.nr @@ -15,7 +15,11 @@ struct CallContext { impl Eq for CallContext { fn eq(self, other: CallContext) -> bool { - self.serialize() == other.serialize() + (self.msg_sender == other.msg_sender) & + (self.storage_contract_address == other.storage_contract_address) & + (self.function_selector == other.function_selector) & + (self.is_delegate_call == other.is_delegate_call) & + (self.is_static_call == other.is_static_call) } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_data.nr index 94e91d8d2c70..fa3ff5b485ad 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_data.nr @@ -1,7 +1,6 @@ use crate::{ - abis::function_selector::FunctionSelector, - constants::{GENERATOR_INDEX__FUNCTION_DATA, FUNCTION_DATA_LENGTH}, - hash::poseidon2_hash_with_separator, traits::{Serialize, Hash, Deserialize, Empty} + abis::function_selector::FunctionSelector, constants::FUNCTION_DATA_LENGTH, + traits::{Serialize, Deserialize, Empty} }; struct FunctionData { @@ -37,12 +36,6 @@ impl Deserialize for FunctionData { } } -impl Hash for FunctionData { - fn hash(self) -> Field { - poseidon2_hash_with_separator(self.serialize(), GENERATOR_INDEX__FUNCTION_DATA) - } -} - impl Empty for FunctionData { fn empty() -> Self { FunctionData { @@ -60,13 +53,3 @@ fn serialization_of_empty() { let deserialized = FunctionData::deserialize(serialized); assert(data.eq(deserialized)); } - -#[test] -fn empty_hash() { - let data = FunctionData::empty(); - let hash = data.hash(); - - // Value from function_data.test.ts "computes empty function data hash" test - let test_data_empty_hash = 0x2ee7682681179c2d8290a805cdeb64cc9744167fd5c801c26f1b3f9757c4eebc; - assert_eq(hash, test_data_empty_hash); -} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_data.nr index c71deeb6d0d6..6f7b04eda6e9 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_data.nr @@ -26,7 +26,7 @@ impl Verifiable for KernelData { impl KernelData { fn validate_in_vk_tree(self, allowed_indices: [u32; N]) { - let index_hint = find_index_hint(allowed_indices, self.vk_index); + let index_hint = find_index_hint(allowed_indices, |index: u32| index == self.vk_index); assert_eq(allowed_indices[index_hint], self.vk_index, "Invalid vk index"); assert_check_membership( 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 5cff83418a7b..428af577c411 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 @@ -1,9 +1,7 @@ use crate::{ abis::{function_data::FunctionData, private_circuit_public_inputs::PrivateCircuitPublicInputs}, - address::AztecAddress, - constants::{GENERATOR_INDEX__CALL_STACK_ITEM, PRIVATE_CALL_STACK_ITEM_LENGTH}, - hash::poseidon2_hash_with_separator, traits::{Deserialize, Hash, Serialize, Empty}, - utils::reader::Reader + address::AztecAddress, constants::PRIVATE_CALL_STACK_ITEM_LENGTH, + traits::{Deserialize, Serialize, Empty}, utils::reader::Reader }; struct PrivateCallStackItem { @@ -55,12 +53,6 @@ impl Deserialize for PrivateCallStackItem { } } -impl Hash for PrivateCallStackItem { - fn hash(self) -> Field { - poseidon2_hash_with_separator(self.serialize(), GENERATOR_INDEX__CALL_STACK_ITEM) - } -} - impl Empty for PrivateCallStackItem { fn empty() -> Self { PrivateCallStackItem { @@ -78,14 +70,3 @@ fn serialization_of_empty() { let deserialized = PrivateCallStackItem::deserialize(serialized); assert(item.eq(deserialized)); } - -#[test] -fn empty_hash() { - let mut item = PrivateCallStackItem::empty(); - item.function_data.is_private = true; - let hash = item.hash(); - - // Value from private_call_stack_item.test.ts "computes empty item hash" test - let test_data_empty_hash = 0x2a254c3fa6968b59e98b456f4353671a4923a4c8280fb6e142ef0071b95466be; - 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 6cfad60bd14a..a207b68842fd 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 @@ -9,13 +9,11 @@ use crate::{ MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_NOTE_HASHES_PER_CALL, MAX_NULLIFIERS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, - MAX_L2_TO_L1_MSGS_PER_CALL, PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH, - GENERATOR_INDEX__PRIVATE_CIRCUIT_PUBLIC_INPUTS, MAX_ENCRYPTED_LOGS_PER_CALL, + MAX_L2_TO_L1_MSGS_PER_CALL, PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH, MAX_ENCRYPTED_LOGS_PER_CALL, MAX_UNENCRYPTED_LOGS_PER_CALL, MAX_NOTE_ENCRYPTED_LOGS_PER_CALL }, - header::Header, hash::poseidon2_hash_with_separator, messaging::l2_to_l1_message::L2ToL1Message, - traits::{Deserialize, Hash, Serialize, Empty}, utils::reader::Reader, - transaction::tx_context::TxContext, utils::arrays::validate_array + header::Header, messaging::l2_to_l1_message::L2ToL1Message, traits::{Deserialize, Serialize, Empty}, + utils::reader::Reader, transaction::tx_context::TxContext, utils::arrays::validate_array }; struct PrivateCircuitPublicInputsArrayLengths { @@ -204,12 +202,6 @@ impl Deserialize for PrivateCircuitPublicI } } -impl Hash for PrivateCircuitPublicInputs { - fn hash(self) -> Field { - poseidon2_hash_with_separator(self.serialize(), GENERATOR_INDEX__PRIVATE_CIRCUIT_PUBLIC_INPUTS) - } -} - impl Empty for PrivateCircuitPublicInputs { fn empty() -> Self { PrivateCircuitPublicInputs { @@ -246,13 +238,3 @@ fn serialization_of_empty() { let deserialized = PrivateCircuitPublicInputs::deserialize(serialized); assert(pcpi.eq(deserialized)); } - -#[test] -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 = 0x29f35524edb1bed6c1eded107142d65ca80f46656c1c7ded71c46dbda14feec5; - assert_eq(hash, test_data_empty_hash); -} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel_data.nr index 97b011e639db..4408555bedcd 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel_data.nr @@ -17,7 +17,7 @@ struct PrivateKernelData { impl PrivateKernelData { fn validate_in_vk_tree(self, allowed_indices: [u32; N]) { - let index_hint = find_index_hint(allowed_indices, self.vk_index); + let index_hint = find_index_hint(allowed_indices, |index: u32| index == self.vk_index); assert_eq(allowed_indices[index_hint], self.vk_index, "Invalid vk index"); assert_check_membership( 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 3d57f18330a6..09673e94af0a 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 @@ -10,12 +10,12 @@ use crate::{ MAX_NOTE_HASHES_PER_CALL, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_DATA_READS_PER_CALL, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, GENERATOR_INDEX__PUBLIC_CIRCUIT_PUBLIC_INPUTS, - PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH, MAX_UNENCRYPTED_LOGS_PER_CALL + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH, + MAX_UNENCRYPTED_LOGS_PER_CALL }, - contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest}, - hash::poseidon2_hash_with_separator, header::Header, messaging::l2_to_l1_message::L2ToL1Message, - traits::{Hash, Serialize, Deserialize, Empty}, utils::reader::Reader + contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest}, header::Header, + messaging::l2_to_l1_message::L2ToL1Message, traits::{Serialize, Deserialize, Empty}, + utils::reader::Reader }; struct PublicCircuitPublicInputs { @@ -153,12 +153,6 @@ impl Deserialize for PublicCircuitPublicInp } } -impl Hash for PublicCircuitPublicInputs { - fn hash(self) -> Field { - poseidon2_hash_with_separator(self.serialize(), GENERATOR_INDEX__PUBLIC_CIRCUIT_PUBLIC_INPUTS) - } -} - impl Empty for PublicCircuitPublicInputs { fn empty() -> Self { PublicCircuitPublicInputs { @@ -196,13 +190,3 @@ fn serialization_of_empty() { let deserialized = PublicCircuitPublicInputs::deserialize(serialized); assert(pcpi.eq(deserialized)); } - -#[test] -fn empty_hash() { - let inputs = PublicCircuitPublicInputs::empty(); - let hash = inputs.hash(); - - // Value from public_circuit_public_inputs.test.ts "computes empty item hash" test - let test_data_empty_hash = 0x0ce92e52cdf4f36c4734556eca0cc66f264ac7548ab7556227bca067fc7b5e84; - assert_eq(hash, test_data_empty_hash); -} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_kernel_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_kernel_data.nr index f80afbd5b04e..655378288fd1 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_kernel_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_kernel_data.nr @@ -26,7 +26,7 @@ impl Verifiable for PublicKernelData { impl PublicKernelData { fn validate_in_vk_tree(self, allowed_indices: [u32; N]) { - let index_hint = find_index_hint(allowed_indices, self.vk_index); + let index_hint = find_index_hint(allowed_indices, |index: u32| index == self.vk_index); assert_eq(allowed_indices[index_hint], self.vk_index, "Invalid vk index"); assert_check_membership( diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/transaction/tx_context.nr b/noir-projects/noir-protocol-circuits/crates/types/src/transaction/tx_context.nr index 3c053162519b..9fa947006ca9 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/transaction/tx_context.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/transaction/tx_context.nr @@ -1,6 +1,5 @@ use crate::{ - constants::{GENERATOR_INDEX__TX_CONTEXT, TX_CONTEXT_LENGTH}, hash::poseidon2_hash_with_separator, - traits::{Deserialize, Hash, Serialize, Empty}, utils::reader::Reader, + constants::TX_CONTEXT_LENGTH, traits::{Deserialize, Serialize, Empty}, utils::reader::Reader, abis::gas_settings::GasSettings }; @@ -66,12 +65,6 @@ impl Deserialize for TxContext { } } -impl Hash for TxContext { - fn hash(self) -> Field { - poseidon2_hash_with_separator(self.serialize(), GENERATOR_INDEX__TX_CONTEXT) - } -} - #[test] fn serialization_of_empty() { let context = TxContext::empty(); @@ -79,13 +72,3 @@ fn serialization_of_empty() { let deserialized = TxContext::deserialize(serialized); assert(context.eq(deserialized)); } - -#[test] -fn empty_hash() { - let context = TxContext::empty(); - let hash = context.hash(); - - // Value from tx_context.test.ts "computes empty item hash" test - let test_data_empty_hash = 0x0b81be18198d45a61eba2c59db95ebdac35d57c9d8ab524e52f0f39417aba5fe; - assert_eq(hash, test_data_empty_hash); -} 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 5202c3700097..81e454a04459 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 @@ -34,38 +34,10 @@ pub fn array_to_bounded_vec(array: [T; N]) -> BoundedVec wh BoundedVec { storage: array, len } } -unconstrained fn filter_array_to_bounded_vec_unsafe(arr: [T; N], should_propagate: [bool; N]) -> BoundedVec { - let mut vec = BoundedVec::new(); - for i in 0..N { - if should_propagate[i] { - vec.push(arr[i]); - } - } - vec -} - -pub fn filter_array_to_bounded_vec( - arr: [T; N], - should_propagate: [bool; N] -) -> BoundedVec where T: Eq { - let vec_hint = filter_array_to_bounded_vec_unsafe(arr, should_propagate); - let mut verifying_index = 0; - +unconstrained pub fn find_index_hint(array: [T; N], find: fn[Env](T) -> bool) -> u32 { + let mut index = N; for i in 0..N { - if should_propagate[i] { - assert_eq(arr[i], vec_hint.get(verifying_index)); - verifying_index += 1; - } - } - assert_eq(verifying_index, vec_hint.len()); - - vec_hint -} - -unconstrained pub fn find_index_hint(array: [T; N], find: T) -> u32 where T: Eq { - let mut index = 0; - for i in 0..array.len() { - if array[i] == find { + if (index == N) & find(array[i]) { index = i; } } @@ -126,24 +98,6 @@ pub fn array_eq(array: [T; N], expected: [T; S]) -> b eq } -pub fn find_index(array: [T; N], find: fn[Env](T) -> bool) -> u32 { - let mut index = N; - for i in 0..N { - if (index == N) & find(array[i]) { - index = i; - } - } - index -} - -pub fn array_cp(array: [T; N]) -> [T; S] where T: Empty { - let mut result: [T; S] = [T::empty(); S]; - for i in 0..S { - result[i] = array[i]; - } - 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]; @@ -572,7 +526,7 @@ fn test_array_length_invalid_arrays() { fn find_index_greater_than_min() { let values = [10, 20, 30, 40]; let min = 22; - let index = find_index(values, |v: Field| min.lt(v)); + let index = find_index_hint(values, |v: Field| min.lt(v)); assert_eq(index, 2); } @@ -580,7 +534,7 @@ fn find_index_greater_than_min() { fn find_index_not_found() { let values = [10, 20, 30, 40]; let min = 100; - let index = find_index(values, |v: Field| min.lt(v)); + let index = find_index_hint(values, |v: Field| min.lt(v)); assert_eq(index, 4); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_split_transformed_value_arrays.nr b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_split_transformed_value_arrays.nr index 5261582b5138..8e68c32e5809 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_split_transformed_value_arrays.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_split_transformed_value_arrays.nr @@ -1,4 +1,4 @@ -use crate::{abis::side_effect::Ordered, traits::{Empty, is_empty}, utils::arrays::find_index}; +use crate::{abis::side_effect::Ordered, traits::{Empty, is_empty}, utils::arrays::find_index_hint}; pub fn assert_split_transformed_value_arrays_with_hint( sorted_array: [T; N], @@ -46,7 +46,7 @@ unconstrained fn get_num_non_revertibles( sorted_array: [T; N], split_counter: u32 ) -> u32 where T: Ordered { - find_index(sorted_array, |n: T| n.counter() >= split_counter) + find_index_hint(sorted_array, |n: T| n.counter() >= split_counter) } pub fn assert_split_transformed_value_arrays( diff --git a/noir-projects/noir-protocol-circuits/reset_variants.json b/noir-projects/noir-protocol-circuits/reset_variants.json index 9c12eb4df34b..c80e95b706e0 100644 --- a/noir-projects/noir-protocol-circuits/reset_variants.json +++ b/noir-projects/noir-protocol-circuits/reset_variants.json @@ -8,6 +8,7 @@ "NULLIFIER_PENDING_AMOUNT": 64, "NULLIFIER_SETTLED_AMOUNT": 64, "NULLIFIER_KEYS": 64, + "TRANSIENT_DATA_AMOUNT": 64, "NOTE_HASH_SILOING_AMOUNT": 0, "NULLIFIER_SILOING_AMOUNT": 0, "ENCRYPTED_LOG_SILOING_AMOUNT": 0 @@ -22,6 +23,7 @@ "NULLIFIER_PENDING_AMOUNT": 32, "NULLIFIER_SETTLED_AMOUNT": 32, "NULLIFIER_KEYS": 32, + "TRANSIENT_DATA_AMOUNT": 32, "NOTE_HASH_SILOING_AMOUNT": 32, "NULLIFIER_SILOING_AMOUNT": 32, "ENCRYPTED_LOG_SILOING_AMOUNT": 8 @@ -36,6 +38,7 @@ "NULLIFIER_PENDING_AMOUNT": 16, "NULLIFIER_SETTLED_AMOUNT": 16, "NULLIFIER_KEYS": 16, + "TRANSIENT_DATA_AMOUNT": 16, "NOTE_HASH_SILOING_AMOUNT": 16, "NULLIFIER_SILOING_AMOUNT": 16, "ENCRYPTED_LOG_SILOING_AMOUNT": 4 @@ -50,6 +53,7 @@ "NULLIFIER_PENDING_AMOUNT": 8, "NULLIFIER_SETTLED_AMOUNT": 8, "NULLIFIER_KEYS": 8, + "TRANSIENT_DATA_AMOUNT": 8, "NOTE_HASH_SILOING_AMOUNT": 8, "NULLIFIER_SILOING_AMOUNT": 8, "ENCRYPTED_LOG_SILOING_AMOUNT": 2 @@ -64,6 +68,7 @@ "NULLIFIER_PENDING_AMOUNT": 4, "NULLIFIER_SETTLED_AMOUNT": 4, "NULLIFIER_KEYS": 4, + "TRANSIENT_DATA_AMOUNT": 4, "NOTE_HASH_SILOING_AMOUNT": 4, "NULLIFIER_SILOING_AMOUNT": 4, "ENCRYPTED_LOG_SILOING_AMOUNT": 1 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 44cfd0ba60b3..ab4a63ba807a 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 @@ -7,6 +7,7 @@ import { type ScopedNoteHash, type ScopedNullifier, ScopedReadRequest, + TransientDataIndexHint, } from '@aztec/circuits.js'; import { buildTransientDataHints } from './build_transient_data_hints.js'; @@ -16,6 +17,7 @@ describe('buildTransientDataHints', () => { let noteHashes: ScopedNoteHash[]; let nullifiers: ScopedNullifier[]; + let nadaIndexHint: TransientDataIndexHint; let futureNoteHashReads: ScopedReadRequest[]; let futureNullifierReads: ScopedReadRequest[]; let noteHashNullifierCounterMap: Map; @@ -43,6 +45,7 @@ describe('buildTransientDataHints', () => { new Nullifier(new Fr(77), 600, new Fr(44)).scope(contractAddress), new Nullifier(new Fr(88), 700, new Fr(11)).scope(contractAddress), ]; + nadaIndexHint = new TransientDataIndexHint(nullifiers.length, noteHashes.length); futureNoteHashReads = [new ScopedReadRequest(new ReadRequest(new Fr(44), 351), contractAddress)]; futureNullifierReads = [new ScopedReadRequest(new ReadRequest(new Fr(66), 502), contractAddress)]; noteHashNullifierCounterMap = new Map(); @@ -60,20 +63,20 @@ describe('buildTransientDataHints', () => { }); it('builds index hints that link transient note hashes and nullifiers', () => { - const [nullifierIndexes, noteHashIndexesForNullifiers] = buildHints(); + const { numTransientData, hints } = buildHints(); // Only first one is squashed, since: // second one is not linked to a nullifier // third one's nullifier will be read // and fourth note hash will be read. - expect(nullifierIndexes).toEqual([3, 4, 4, 4, 4]); - expect(noteHashIndexesForNullifiers).toEqual([5, 5, 5, 0]); + expect(numTransientData).toBe(1); + expect(hints).toEqual([new TransientDataIndexHint(3, 0), nadaIndexHint, nadaIndexHint, nadaIndexHint]); }); it('keeps the pair if note hash does not match', () => { nullifiers[3].nullifier.noteHash = new Fr(9999); - const [nullifierIndexes, noteHashIndexesForNullifiers] = buildHints(); - expect(nullifierIndexes).toEqual([4, 4, 4, 4, 4]); - expect(noteHashIndexesForNullifiers).toEqual([5, 5, 5, 5]); + const { numTransientData, hints } = buildHints(); + expect(numTransientData).toBe(0); + expect(hints).toEqual(Array(nullifiers.length).fill(nadaIndexHint)); }); it('throws if contract address 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 97bb8cd9735d..b5386a3ed994 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 @@ -2,11 +2,12 @@ import { type ScopedNoteHash, type ScopedNullifier, type ScopedReadRequest, + TransientDataIndexHint, countAccumulatedItems, isValidNoteHashReadRequest, isValidNullifierReadRequest, } from '@aztec/circuits.js'; -import { makeTuple } from '@aztec/foundation/array'; +import { padArrayEnd } from '@aztec/foundation/collection'; import { type Tuple } from '@aztec/foundation/serialize'; import { ScopedValueCache } from './scoped_value_cache.js'; @@ -19,26 +20,17 @@ export function buildTransientDataHints, noteHashesLength: NOTE_HASHES_LEN = noteHashes.length as NOTE_HASHES_LEN, nullifiersLength: NULLIFIERS_LEN = nullifiers.length as NULLIFIERS_LEN, -): [Tuple, Tuple] { +): { numTransientData: number; hints: Tuple } { const futureNoteHashReadsMap = new ScopedValueCache(futureNoteHashReads); const futureNullifierReadsMap = new ScopedValueCache(futureNullifierReads); const nullifierIndexMap: Map = new Map(); nullifiers.forEach((n, i) => nullifierIndexMap.set(n.counter, i)); - const nullifierIndexesForNoteHashes: Tuple = makeTuple( - noteHashesLength, - () => nullifiersLength, - ); - - const noteHashIndexesForNullifiers: Tuple = makeTuple( - nullifiersLength, - () => noteHashesLength, - ); - + const hints = []; const numNoteHashes = countAccumulatedItems(noteHashes); - for (let i = 0; i < numNoteHashes; i++) { - const noteHash = noteHashes[i]; + for (let noteHashIndex = 0; noteHashIndex < numNoteHashes; noteHashIndex++) { + const noteHash = noteHashes[noteHashIndex]; const noteHashNullifierCounter = noteHashNullifierCounterMap.get(noteHash.counter); // The note hash might not be linked to a nullifier or it might be read in the future if ( @@ -75,9 +67,11 @@ export function buildTransientDataHints `; @@ -93,6 +97,7 @@ function buildPrivateResetVariantsType(variants: ResetVariant[]): string { typeof MAX_NULLIFIER_READ_REQUESTS_PER_TX, typeof MAX_NULLIFIER_READ_REQUESTS_PER_TX, typeof MAX_KEY_VALIDATION_REQUESTS_PER_TX, + typeof MAX_NULLIFIERS_PER_TX, 'full' >;`; return output; @@ -115,6 +120,9 @@ function validateVariants(variants: ResetVariant[]) { if (variant.replacements.NULLIFIER_KEYS > MAX_KEY_VALIDATION_REQUESTS_PER_TX) { throw new Error(`NULLIFIER_KEYS must be less than or equal to ${MAX_KEY_VALIDATION_REQUESTS_PER_TX}`); } + if (variant.replacements.TRANSIENT_DATA_AMOUNT > MAX_NULLIFIERS_PER_TX) { + throw new Error(`TRANSIENT_DATA_AMOUNT must be less than or equal to ${MAX_NULLIFIERS_PER_TX}`); + } if (variant.replacements.NOTE_HASH_SILOING_AMOUNT > MAX_NOTE_HASHES_PER_TX) { throw new Error(`NOTE_HASH_SILOING_AMOUNT must be less than or equal to ${MAX_NOTE_HASHES_PER_TX}`); } diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/function_data.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/function_data.test.ts.snap deleted file mode 100644 index 3415c7cc5f97..000000000000 --- a/yarn-project/circuits.js/src/structs/__snapshots__/function_data.test.ts.snap +++ /dev/null @@ -1,3 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`FunctionData computes empty function data hash 1`] = `Fr<0x2ee7682681179c2d8290a805cdeb64cc9744167fd5c801c26f1b3f9757c4eebc>`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/private_call_stack_item.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/private_call_stack_item.test.ts.snap deleted file mode 100644 index 23d4b2c253a5..000000000000 --- a/yarn-project/circuits.js/src/structs/__snapshots__/private_call_stack_item.test.ts.snap +++ /dev/null @@ -1,5 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`PrivateCallStackItem computes empty item hash 1`] = `Fr<0x2a254c3fa6968b59e98b456f4353671a4923a4c8280fb6e142ef0071b95466be>`; - -exports[`PrivateCallStackItem computes hash 1`] = `Fr<0x03a10b50b4bd17b3bd095a366f4c6cef06ddfed4f67e1e56ba31fda1beb8dd46>`; 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 deleted file mode 100644 index fc0e4b839288..000000000000 --- a/yarn-project/circuits.js/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap +++ /dev/null @@ -1,5 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`PrivateCircuitPublicInputs computes empty inputs hash 1`] = `Fr<0x29f35524edb1bed6c1eded107142d65ca80f46656c1c7ded71c46dbda14feec5>`; - -exports[`PrivateCircuitPublicInputs hash matches snapshot 1`] = `Fr<0x24e806a499332876eebde0557bc01501999ddf645df63c822b10ebba6a2c7665>`; 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 deleted file mode 100644 index 3ed1233a0dc2..000000000000 --- a/yarn-project/circuits.js/src/structs/__snapshots__/public_circuit_public_inputs.test.ts.snap +++ /dev/null @@ -1,5 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`PublicCircuitPublicInputs computes empty inputs hash 1`] = `Fr<0x0ce92e52cdf4f36c4734556eca0cc66f264ac7548ab7556227bca067fc7b5e84>`; - -exports[`PublicCircuitPublicInputs hash matches snapshot 1`] = `Fr<0x006addc726c9ad5a6339456a1345cefb4124c338651ff0dd4c7d50265ea34a2c>`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/tx_context.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/tx_context.test.ts.snap deleted file mode 100644 index 944fc3a7610c..000000000000 --- a/yarn-project/circuits.js/src/structs/__snapshots__/tx_context.test.ts.snap +++ /dev/null @@ -1,3 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`TxContext computes empty context hash 1`] = `Fr<0x0b81be18198d45a61eba2c59db95ebdac35d57c9d8ab524e52f0f39417aba5fe>`; diff --git a/yarn-project/circuits.js/src/structs/call_context.ts b/yarn-project/circuits.js/src/structs/call_context.ts index e8212315ecd2..992b66ed92b2 100644 --- a/yarn-project/circuits.js/src/structs/call_context.ts +++ b/yarn-project/circuits.js/src/structs/call_context.ts @@ -1,11 +1,10 @@ import { FunctionSelector } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; -import { poseidon2HashWithSeparator } from '@aztec/foundation/crypto'; import { type Fr } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; import { type FieldsOf } from '@aztec/foundation/types'; -import { CALL_CONTEXT_LENGTH, GeneratorIndex } from '../constants.gen.js'; +import { CALL_CONTEXT_LENGTH } from '../constants.gen.js'; /** * Call context. @@ -122,8 +121,4 @@ export class CallContext { callContext.isStaticCall === this.isStaticCall ); } - - hash(): Fr { - return poseidon2HashWithSeparator(this.toFields(), GeneratorIndex.CALL_CONTEXT); - } } diff --git a/yarn-project/circuits.js/src/structs/function_data.test.ts b/yarn-project/circuits.js/src/structs/function_data.test.ts index fa7b9add70d1..2c6b2e64a630 100644 --- a/yarn-project/circuits.js/src/structs/function_data.test.ts +++ b/yarn-project/circuits.js/src/structs/function_data.test.ts @@ -1,5 +1,5 @@ import { FunctionSelector } from '@aztec/foundation/abi'; -import { setupCustomSnapshotSerializers, updateInlineTestData } from '@aztec/foundation/testing'; +import { setupCustomSnapshotSerializers } from '@aztec/foundation/testing'; import { FUNCTION_DATA_LENGTH } from '../constants.gen.js'; import { FunctionData } from './function_data.js'; @@ -23,17 +23,4 @@ describe('FunctionData', () => { const fields = functionData.toFields(); expect(fields.length).toBe(FUNCTION_DATA_LENGTH); }); - - it('computes empty function data hash', () => { - const data = FunctionData.empty(); - const hash = data.hash(); - expect(hash).toMatchSnapshot(); - - // Run with AZTEC_GENERATE_TEST_DATA=1 to update noir test data - updateInlineTestData( - 'noir-projects/noir-protocol-circuits/crates/types/src/abis/function_data.nr', - 'test_data_empty_hash', - hash.toString(), - ); - }); }); diff --git a/yarn-project/circuits.js/src/structs/function_data.ts b/yarn-project/circuits.js/src/structs/function_data.ts index 37429cb4525f..6824824a5de7 100644 --- a/yarn-project/circuits.js/src/structs/function_data.ts +++ b/yarn-project/circuits.js/src/structs/function_data.ts @@ -1,9 +1,8 @@ import { type FunctionAbi, FunctionSelector, FunctionType } from '@aztec/foundation/abi'; -import { poseidon2HashWithSeparator } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; -import { FUNCTION_DATA_LENGTH, GeneratorIndex } from '../constants.gen.js'; +import { FUNCTION_DATA_LENGTH } from '../constants.gen.js'; import { type ContractFunctionDao } from '../types/contract_function_dao.js'; /** Function description for circuit. */ @@ -89,8 +88,4 @@ export class FunctionData { return new FunctionData(selector, isPrivate); } - - hash(): Fr { - return poseidon2HashWithSeparator(this.toFields(), GeneratorIndex.FUNCTION_DATA); - } } diff --git a/yarn-project/circuits.js/src/structs/kernel/private_kernel_reset_circuit_private_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/private_kernel_reset_circuit_private_inputs.ts index 79e4e90bb6d9..904fcccef16c 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_kernel_reset_circuit_private_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_kernel_reset_circuit_private_inputs.ts @@ -1,6 +1,5 @@ import { BufferReader, type Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; -import { MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX } from '../../constants.gen.js'; import { countAccumulatedItems } from '../../utils/index.js'; import { KeyValidationHint, @@ -9,24 +8,20 @@ import { noteHashReadRequestHintsFromBuffer, nullifierReadRequestHintsFromBuffer, } from '../read_request_hints/index.js'; +import { TransientDataIndexHint } from '../transient_data_index_hint.js'; import { PrivateKernelData } from './private_kernel_data.js'; +export { TransientDataIndexHint } from '../transient_data_index_hint.js'; + export class PrivateKernelResetHints< NH_RR_PENDING extends number, NH_RR_SETTLED extends number, NLL_RR_PENDING extends number, NLL_RR_SETTLED extends number, KEY_VALIDATION_REQUESTS extends number, + NUM_TRANSIENT_DATA_INDEX_HINTS extends number, > { constructor( - /** - * Contains hints for the transient note hashes to locate corresponding nullifiers. - */ - public transientNullifierIndexesForNoteHashes: Tuple, - /** - * Contains hints for the transient nullifiers to locate corresponding note hashes. - */ - public transientNoteHashIndexesForNullifiers: Tuple, /** * Contains hints for the transient read requests to localize corresponding commitments. */ @@ -39,6 +34,10 @@ export class PrivateKernelResetHints< * Contains hints for key validation request. */ public keyValidationHints: Tuple, + /** + * Contains hints for the transient note hashes to locate corresponding nullifiers. + */ + public transientDataIndexHints: Tuple, /** * The "final" minRevertibleSideEffectCounter of a tx, to split the data for squashing. * Not the minRevertibleSideEffectCounter at the point the reset circuit is run. @@ -48,11 +47,10 @@ export class PrivateKernelResetHints< toBuffer() { return serializeToBuffer( - this.transientNullifierIndexesForNoteHashes, - this.transientNoteHashIndexesForNullifiers, this.noteHashReadRequestHints, this.nullifierReadRequestHints, this.keyValidationHints, + this.transientDataIndexHints, this.validationRequestsSplitCounter, ); } @@ -63,28 +61,33 @@ export class PrivateKernelResetHints< NEW_NLL_RR_PENDING extends number, NEW_NLL_RR_SETTLED extends number, NEW_KEY_VALIDATION_REQUESTS extends number, + NUM_TRANSIENT_DATA_INDEX_HINTS extends number, >( numNoteHashReadRequestPending: NEW_NH_RR_PENDING, numNoteHashReadRequestSettled: NEW_NH_RR_SETTLED, numNullifierReadRequestPending: NEW_NLL_RR_PENDING, numNullifierReadRequestSettled: NEW_NLL_RR_SETTLED, numKeyValidationRequests: NEW_KEY_VALIDATION_REQUESTS, + numTransientDataIndexHints: NUM_TRANSIENT_DATA_INDEX_HINTS, ): PrivateKernelResetHints< NEW_NH_RR_PENDING, NEW_NH_RR_SETTLED, NEW_NLL_RR_PENDING, NEW_NLL_RR_SETTLED, - NEW_KEY_VALIDATION_REQUESTS + NEW_KEY_VALIDATION_REQUESTS, + NUM_TRANSIENT_DATA_INDEX_HINTS > { return new PrivateKernelResetHints( - this.transientNullifierIndexesForNoteHashes, - this.transientNoteHashIndexesForNullifiers, this.noteHashReadRequestHints.trimToSizes(numNoteHashReadRequestPending, numNoteHashReadRequestSettled), this.nullifierReadRequestHints.trimToSizes(numNullifierReadRequestPending, numNullifierReadRequestSettled), this.keyValidationHints.slice(0, numKeyValidationRequests) as Tuple< KeyValidationHint, NEW_KEY_VALIDATION_REQUESTS >, + this.transientDataIndexHints.slice(0, numTransientDataIndexHints) as Tuple< + TransientDataIndexHint, + NUM_TRANSIENT_DATA_INDEX_HINTS + >, this.validationRequestsSplitCounter, ); } @@ -99,6 +102,7 @@ export class PrivateKernelResetHints< NLL_RR_PENDING extends number, NLL_RR_SETTLED extends number, KEY_VALIDATION_REQUESTS extends number, + NUM_TRANSIENT_DATA_INDEX_HINTS extends number, >( buffer: Buffer | BufferReader, numNoteHashReadRequestPending: NH_RR_PENDING, @@ -106,11 +110,17 @@ export class PrivateKernelResetHints< numNullifierReadRequestPending: NLL_RR_PENDING, numNullifierReadRequestSettled: NLL_RR_SETTLED, numNullifierKeys: KEY_VALIDATION_REQUESTS, - ): PrivateKernelResetHints { + numTransientDataIndexHints: NUM_TRANSIENT_DATA_INDEX_HINTS, + ): PrivateKernelResetHints< + NH_RR_PENDING, + NH_RR_SETTLED, + NLL_RR_PENDING, + NLL_RR_SETTLED, + KEY_VALIDATION_REQUESTS, + NUM_TRANSIENT_DATA_INDEX_HINTS + > { const reader = BufferReader.asReader(buffer); return new PrivateKernelResetHints( - reader.readNumbers(MAX_NOTE_HASHES_PER_TX), - reader.readNumbers(MAX_NULLIFIERS_PER_TX), reader.readObject({ fromBuffer: buf => noteHashReadRequestHintsFromBuffer(buf, numNoteHashReadRequestPending, numNoteHashReadRequestSettled), @@ -120,6 +130,7 @@ export class PrivateKernelResetHints< nullifierReadRequestHintsFromBuffer(buf, numNullifierReadRequestPending, numNullifierReadRequestSettled), }), reader.readArray(numNullifierKeys, KeyValidationHint), + reader.readArray(numTransientDataIndexHints, TransientDataIndexHint), reader.readNumber(), ); } @@ -134,6 +145,7 @@ export class PrivateKernelResetCircuitPrivateInputs< NLL_RR_PENDING extends number, NLL_RR_SETTLED extends number, KEY_VALIDATION_REQUESTS extends number, + NUM_TRANSIENT_DATA_INDEX_HINTS extends number, TAG extends string, > { constructor( @@ -146,7 +158,8 @@ export class PrivateKernelResetCircuitPrivateInputs< NH_RR_SETTLED, NLL_RR_PENDING, NLL_RR_SETTLED, - KEY_VALIDATION_REQUESTS + KEY_VALIDATION_REQUESTS, + NUM_TRANSIENT_DATA_INDEX_HINTS >, public sizeTag: TAG, ) {} @@ -174,6 +187,7 @@ export class PrivateKernelResetCircuitPrivateInputs< NLL_RR_PENDING extends number, NLL_RR_SETTLED extends number, KEY_VALIDATION_REQUESTS extends number, + NUM_TRANSIENT_DATA_INDEX_HINTS extends number, TAG extends string, >( buffer: Buffer | BufferReader, @@ -182,6 +196,7 @@ export class PrivateKernelResetCircuitPrivateInputs< numNullifierReadRequestPending: NLL_RR_PENDING, numNullifierReadRequestSettled: NLL_RR_SETTLED, numNullifierKeys: KEY_VALIDATION_REQUESTS, + numTransientDataIndexHints: NUM_TRANSIENT_DATA_INDEX_HINTS, sizeTag: TAG, ): PrivateKernelResetCircuitPrivateInputs< NH_RR_PENDING, @@ -189,6 +204,7 @@ export class PrivateKernelResetCircuitPrivateInputs< NLL_RR_PENDING, NLL_RR_SETTLED, KEY_VALIDATION_REQUESTS, + NUM_TRANSIENT_DATA_INDEX_HINTS, TAG > { const reader = BufferReader.asReader(buffer); @@ -203,6 +219,7 @@ export class PrivateKernelResetCircuitPrivateInputs< numNullifierReadRequestPending, numNullifierReadRequestSettled, numNullifierKeys, + numTransientDataIndexHints, ), }), sizeTag, diff --git a/yarn-project/circuits.js/src/structs/private_call_stack_item.test.ts b/yarn-project/circuits.js/src/structs/private_call_stack_item.test.ts index 39d2b062661d..801e761699e0 100644 --- a/yarn-project/circuits.js/src/structs/private_call_stack_item.test.ts +++ b/yarn-project/circuits.js/src/structs/private_call_stack_item.test.ts @@ -1,5 +1,5 @@ import { randomInt } from '@aztec/foundation/crypto'; -import { setupCustomSnapshotSerializers, updateInlineTestData } from '@aztec/foundation/testing'; +import { setupCustomSnapshotSerializers } from '@aztec/foundation/testing'; import { PRIVATE_CALL_STACK_ITEM_LENGTH } from '../constants.gen.js'; import { makePrivateCallStackItem } from '../tests/factories.js'; @@ -29,24 +29,4 @@ describe('PrivateCallStackItem', () => { const fields = item.toFields(); expect(fields.length).toBe(PRIVATE_CALL_STACK_ITEM_LENGTH); }); - - it('computes hash', () => { - const seed = 9870243; - const item = makePrivateCallStackItem(seed); - const hash = item.hash(); - expect(hash).toMatchSnapshot(); - }); - - it('computes empty item hash', () => { - const item = PrivateCallStackItem.empty(); - const hash = item.hash(); - expect(hash).toMatchSnapshot(); - - // Run with AZTEC_GENERATE_TEST_DATA=1 to update noir test data - updateInlineTestData( - 'noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr', - 'test_data_empty_hash', - hash.toString(), - ); - }); }); diff --git a/yarn-project/circuits.js/src/structs/private_call_stack_item.ts b/yarn-project/circuits.js/src/structs/private_call_stack_item.ts index 5770f287823c..e30848e33b37 100644 --- a/yarn-project/circuits.js/src/structs/private_call_stack_item.ts +++ b/yarn-project/circuits.js/src/structs/private_call_stack_item.ts @@ -1,10 +1,9 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; -import { poseidon2HashWithSeparator } from '@aztec/foundation/crypto'; import { type Fr } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; import { type FieldsOf } from '@aztec/foundation/types'; -import { GeneratorIndex, PRIVATE_CALL_STACK_ITEM_LENGTH } from '../constants.gen.js'; +import { PRIVATE_CALL_STACK_ITEM_LENGTH } from '../constants.gen.js'; import { FunctionData } from './function_data.js'; import { PrivateCircuitPublicInputs } from './private_circuit_public_inputs.js'; @@ -83,12 +82,4 @@ export class PrivateCallStackItem { isEmpty() { return this.contractAddress.isZero() && this.functionData.isEmpty() && this.publicInputs.isEmpty(); } - - /** - * Computes this call stack item hash. - * @returns Hash. - */ - public hash(): Fr { - return poseidon2HashWithSeparator(this.toFields(), GeneratorIndex.CALL_STACK_ITEM); - } } diff --git a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.test.ts b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.test.ts index 223daf967625..fac696a23995 100644 --- a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.test.ts +++ b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.test.ts @@ -1,5 +1,5 @@ import { randomInt } from '@aztec/foundation/crypto'; -import { setupCustomSnapshotSerializers, updateInlineTestData } from '@aztec/foundation/testing'; +import { setupCustomSnapshotSerializers } from '@aztec/foundation/testing'; import { PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH } from '../constants.gen.js'; import { makePrivateCircuitPublicInputs } from '../tests/factories.js'; @@ -34,23 +34,4 @@ describe('PrivateCircuitPublicInputs', () => { const fields = inputs.toFields(); expect(fields.length).toBe(PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH); }); - - it('hash matches snapshot', () => { - const target = makePrivateCircuitPublicInputs(327); - const hash = target.hash(); - expect(hash).toMatchSnapshot(); - }); - - it('computes empty inputs hash', () => { - const inputs = PrivateCircuitPublicInputs.empty(); - const hash = inputs.hash(); - expect(hash).toMatchSnapshot(); - - // Run with AZTEC_GENERATE_TEST_DATA=1 to update noir test data - updateInlineTestData( - 'noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr', - 'test_data_empty_hash', - hash.toString(), - ); - }); }); diff --git a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts index 12d0f5e8218a..9b277dc9b4fa 100644 --- a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts @@ -1,5 +1,4 @@ import { makeTuple } from '@aztec/foundation/array'; -import { poseidon2HashWithSeparator } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader, @@ -11,7 +10,6 @@ import { import { type FieldsOf } from '@aztec/foundation/types'; import { - GeneratorIndex, MAX_ENCRYPTED_LOGS_PER_CALL, MAX_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_L2_TO_L1_MSGS_PER_CALL, @@ -322,8 +320,4 @@ export class PrivateCircuitPublicInputs { } return fields; } - - hash(): Fr { - return poseidon2HashWithSeparator(this.toFields(), GeneratorIndex.PRIVATE_CIRCUIT_PUBLIC_INPUTS); - } } diff --git a/yarn-project/circuits.js/src/structs/public_call_stack_item_compressed.ts b/yarn-project/circuits.js/src/structs/public_call_stack_item_compressed.ts index a4dbb107bc8f..8df09f6bf4a8 100644 --- a/yarn-project/circuits.js/src/structs/public_call_stack_item_compressed.ts +++ b/yarn-project/circuits.js/src/structs/public_call_stack_item_compressed.ts @@ -1,10 +1,9 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; -import { poseidon2HashWithSeparator } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; import { type FieldsOf } from '@aztec/foundation/types'; -import { GeneratorIndex, PUBLIC_CALL_STACK_ITEM_COMPRESSED_LENGTH } from '../constants.gen.js'; +import { PUBLIC_CALL_STACK_ITEM_COMPRESSED_LENGTH } from '../constants.gen.js'; import { CallContext } from './call_context.js'; import { Gas } from './gas.js'; import { RevertCode } from './revert_code.js'; @@ -110,12 +109,4 @@ export class PublicCallStackItemCompressed { this.endGasLeft.isEmpty() ); } - - /** - * Computes this call stack item hash. - * @returns Hash. - */ - public hash() { - return poseidon2HashWithSeparator(this.toFields(), GeneratorIndex.CALL_STACK_ITEM); - } } diff --git a/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.test.ts b/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.test.ts index bfca12ab0f64..7d4f900e4f22 100644 --- a/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.test.ts +++ b/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.test.ts @@ -1,5 +1,5 @@ import { randomInt } from '@aztec/foundation/crypto'; -import { setupCustomSnapshotSerializers, updateInlineTestData } from '@aztec/foundation/testing'; +import { setupCustomSnapshotSerializers } from '@aztec/foundation/testing'; import { PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH } from '../constants.gen.js'; import { makePublicCircuitPublicInputs } from '../tests/factories.js'; @@ -25,23 +25,4 @@ describe('PublicCircuitPublicInputs', () => { const fields = target.toFields(); expect(fields.length).toBe(PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH); }); - - it('hash matches snapshot', () => { - const target = makePublicCircuitPublicInputs(327); - const hash = target.hash(); - expect(hash).toMatchSnapshot(); - }); - - it('computes empty inputs hash', () => { - const inputs = PublicCircuitPublicInputs.empty(); - const hash = inputs.hash(); - expect(hash).toMatchSnapshot(); - - // Run with AZTEC_GENERATE_TEST_DATA=1 to update noir test data - updateInlineTestData( - 'noir-projects/noir-protocol-circuits/crates/types/src/abis/public_circuit_public_inputs.nr', - 'test_data_empty_hash', - hash.toString(), - ); - }); }); diff --git a/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.ts index 270e21727ef5..44e0ee9bce09 100644 --- a/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.ts @@ -1,6 +1,5 @@ import { makeTuple } from '@aztec/foundation/array'; import { AztecAddress } from '@aztec/foundation/aztec-address'; -import { poseidon2HashWithSeparator } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader, @@ -12,7 +11,6 @@ import { import { type FieldsOf } from '@aztec/foundation/types'; import { - GeneratorIndex, MAX_L1_TO_L2_MSG_READ_REQUESTS_PER_CALL, MAX_L2_TO_L1_MSGS_PER_CALL, MAX_NOTE_HASHES_PER_CALL, @@ -326,8 +324,4 @@ export class PublicCircuitPublicInputs { reader.readField(), ); } - - hash(): Fr { - return poseidon2HashWithSeparator(this.toFields(), GeneratorIndex.PUBLIC_CIRCUIT_PUBLIC_INPUTS); - } } diff --git a/yarn-project/circuits.js/src/structs/read_request_hints/key_validation_hint.ts b/yarn-project/circuits.js/src/structs/read_request_hints/key_validation_hint.ts index 99e1faedb38f..4aa08839caf9 100644 --- a/yarn-project/circuits.js/src/structs/read_request_hints/key_validation_hint.ts +++ b/yarn-project/circuits.js/src/structs/read_request_hints/key_validation_hint.ts @@ -18,7 +18,7 @@ export class KeyValidationHint { return serializeToBuffer(this.skM, this.requestIndex); } - static empty() { - return new KeyValidationHint(GrumpkinScalar.zero(), 0); + static nada(keyValidationRequestLen: number) { + return new KeyValidationHint(GrumpkinScalar.zero(), keyValidationRequestLen); } } diff --git a/yarn-project/circuits.js/src/structs/transient_data_index_hint.ts b/yarn-project/circuits.js/src/structs/transient_data_index_hint.ts new file mode 100644 index 000000000000..454734ee0fae --- /dev/null +++ b/yarn-project/circuits.js/src/structs/transient_data_index_hint.ts @@ -0,0 +1,42 @@ +import { Fr } from '@aztec/foundation/fields'; +import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; + +import { inspect } from 'util'; + +export class TransientDataIndexHint { + constructor(public nullifierIndex: number, public noteHashIndex: number) {} + + toFields(): Fr[] { + return [new Fr(this.nullifierIndex), new Fr(this.noteHashIndex)]; + } + + static fromFields(fields: Fr[] | FieldReader) { + const reader = FieldReader.asReader(fields); + return new TransientDataIndexHint(reader.readU32(), reader.readU32()); + } + + isEmpty() { + return !this.nullifierIndex && !this.noteHashIndex; + } + + static empty() { + return new TransientDataIndexHint(0, 0); + } + + toBuffer(): Buffer { + return serializeToBuffer(this.nullifierIndex, this.noteHashIndex); + } + + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new TransientDataIndexHint(reader.readNumber(), reader.readNumber()); + } + + toString(): string { + return `nullifierIndex=${this.nullifierIndex} noteHashIndex=${this.noteHashIndex}`; + } + + [inspect.custom](): string { + return `TransientDataIndexHint { ${this.toString()} }`; + } +} diff --git a/yarn-project/circuits.js/src/structs/tx_context.test.ts b/yarn-project/circuits.js/src/structs/tx_context.test.ts index 4acd8c5b4c04..1b009fafd425 100644 --- a/yarn-project/circuits.js/src/structs/tx_context.test.ts +++ b/yarn-project/circuits.js/src/structs/tx_context.test.ts @@ -1,5 +1,5 @@ import { randomInt } from '@aztec/foundation/crypto'; -import { setupCustomSnapshotSerializers, updateInlineTestData } from '@aztec/foundation/testing'; +import { setupCustomSnapshotSerializers } from '@aztec/foundation/testing'; import { TX_CONTEXT_LENGTH } from '../constants.gen.js'; import { makeTxContext } from '../tests/factories.js'; @@ -24,19 +24,4 @@ describe('TxContext', () => { const fields = context.toFields(); expect(fields.length).toBe(TX_CONTEXT_LENGTH); }); - - it('computes empty context hash', () => { - const tc = TxContext.empty(); - expect(tc.isEmpty()).toBe(true); - - const hash = tc.hash(); - expect(hash).toMatchSnapshot(); - - // Run with AZTEC_GENERATE_TEST_DATA=1 to update noir test data - updateInlineTestData( - 'noir-projects/noir-protocol-circuits/crates/types/src/transaction/tx_context.nr', - 'test_data_empty_hash', - hash.toString(), - ); - }); }); diff --git a/yarn-project/circuits.js/src/structs/tx_context.ts b/yarn-project/circuits.js/src/structs/tx_context.ts index 8210f20c96aa..a4b602b7f301 100644 --- a/yarn-project/circuits.js/src/structs/tx_context.ts +++ b/yarn-project/circuits.js/src/structs/tx_context.ts @@ -1,9 +1,8 @@ -import { poseidon2HashWithSeparator } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; import { type FieldsOf } from '@aztec/foundation/types'; -import { GeneratorIndex, TX_CONTEXT_LENGTH } from '../constants.gen.js'; +import { TX_CONTEXT_LENGTH } from '../constants.gen.js'; import { GasSettings } from './gas_settings.js'; /** @@ -89,8 +88,4 @@ export class TxContext { static getFields(fields: FieldsOf) { return [fields.chainId, fields.version, fields.gasSettings] as const; } - - hash(): Fr { - return poseidon2HashWithSeparator(this.toFields(), GeneratorIndex.TX_CONTEXT); - } } 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 4efa8b4a63c5..2e2cec4f8c7b 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -122,6 +122,7 @@ import { type SettledReadHint, type StateDiffHints, StateReference, + type TransientDataIndexHint, TxContext, type TxRequest, type VerificationKeyAsFields, @@ -234,6 +235,7 @@ import type { StateReference as StateReferenceNoir, StorageRead as StorageReadNoir, StorageUpdateRequest as StorageUpdateRequestNoir, + TransientDataIndexHint as TransientDataIndexHintNoir, TxContext as TxContextNoir, TxRequest as TxRequestNoir, } from './types/index.js'; @@ -1632,33 +1634,48 @@ export function mapPrivateKernelInnerCircuitPrivateInputsToNoir( }; } +function mapTransientDataIndexHintToNoir(indexHint: TransientDataIndexHint): TransientDataIndexHintNoir { + return { + nullifier_index: mapNumberToNoir(indexHint.nullifierIndex), + note_hash_index: mapNumberToNoir(indexHint.noteHashIndex), + }; +} + function mapPrivateKernelResetHintsToNoir< NH_RR_PENDING extends number, NH_RR_SETTLED extends number, NLL_RR_PENDING extends number, NLL_RR_SETTLED extends number, KEY_VALIDATION_REQUESTS extends number, + NUM_TRANSIENT_DATA_HINTS extends number, >( inputs: PrivateKernelResetHints< NH_RR_PENDING, NH_RR_SETTLED, NLL_RR_PENDING, NLL_RR_SETTLED, - KEY_VALIDATION_REQUESTS + KEY_VALIDATION_REQUESTS, + NUM_TRANSIENT_DATA_HINTS >, -): PrivateKernelResetHintsNoir { +): PrivateKernelResetHintsNoir< + NH_RR_PENDING, + NH_RR_SETTLED, + NLL_RR_PENDING, + NLL_RR_SETTLED, + KEY_VALIDATION_REQUESTS, + NUM_TRANSIENT_DATA_HINTS +> { return { - transient_nullifier_indexes_for_note_hashes: mapTuple( - inputs.transientNullifierIndexesForNoteHashes, - mapNumberToNoir, - ), - transient_note_hash_indexes_for_nullifiers: mapTuple(inputs.transientNoteHashIndexesForNullifiers, mapNumberToNoir), note_hash_read_request_hints: mapNoteHashReadRequestHintsToNoir(inputs.noteHashReadRequestHints), nullifier_read_request_hints: mapNullifierReadRequestHintsToNoir(inputs.nullifierReadRequestHints), key_validation_hints: inputs.keyValidationHints.map(mapKeyValidationHintToNoir) as FixedLengthArray< KeyValidationHintNoir, KEY_VALIDATION_REQUESTS >, + transient_data_index_hints: inputs.transientDataIndexHints.map(mapTransientDataIndexHintToNoir) as FixedLengthArray< + TransientDataIndexHintNoir, + NUM_TRANSIENT_DATA_HINTS + >, validation_requests_split_counter: mapNumberToNoir(inputs.validationRequestsSplitCounter), }; } @@ -1669,6 +1686,7 @@ export function mapPrivateKernelResetCircuitPrivateInputsToNoir< NLL_RR_PENDING extends number, NLL_RR_SETTLED extends number, KEY_VALIDATION_REQUESTS extends number, + NUM_TRANSIENT_DATA_HINTS extends number, TAG extends string, >( inputs: PrivateKernelResetCircuitPrivateInputs< @@ -1677,6 +1695,7 @@ export function mapPrivateKernelResetCircuitPrivateInputsToNoir< NLL_RR_PENDING, NLL_RR_SETTLED, KEY_VALIDATION_REQUESTS, + NUM_TRANSIENT_DATA_HINTS, TAG >, ): PrivateKernelResetCircuitPrivateInputsNoir< @@ -1684,7 +1703,8 @@ export function mapPrivateKernelResetCircuitPrivateInputsToNoir< NH_RR_SETTLED, NLL_RR_PENDING, NLL_RR_SETTLED, - KEY_VALIDATION_REQUESTS + KEY_VALIDATION_REQUESTS, + NUM_TRANSIENT_DATA_HINTS > { return { previous_kernel: mapPrivateKernelDataToNoir(inputs.previousKernel), diff --git a/yarn-project/pxe/src/kernel_prover/hints/build_private_kernel_reset_hints.ts b/yarn-project/pxe/src/kernel_prover/hints/build_private_kernel_reset_hints.ts index cdedebae3736..69d382edbfac 100644 --- a/yarn-project/pxe/src/kernel_prover/hints/build_private_kernel_reset_hints.ts +++ b/yarn-project/pxe/src/kernel_prover/hints/build_private_kernel_reset_hints.ts @@ -69,7 +69,9 @@ async function getMasterSecretKeysAndAppKeyGenerators( keyValidationRequests: Tuple, oracle: ProvingDataOracle, ) { - const keysHints = makeTuple(MAX_KEY_VALIDATION_REQUESTS_PER_TX, KeyValidationHint.empty); + const keysHints = makeTuple(MAX_KEY_VALIDATION_REQUESTS_PER_TX, () => + KeyValidationHint.nada(MAX_KEY_VALIDATION_REQUESTS_PER_TX), + ); let keyIndex = 0; for (let i = 0; i < keyValidationRequests.length; ++i) { @@ -158,7 +160,7 @@ export async function buildPrivateKernelResetInputs( const noteHashes = publicInputs.end.noteHashes; const nullifiers = publicInputs.end.nullifiers; - const [transientNullifierIndexesForNoteHashes, transientNoteHashIndexesForNullifiers] = buildTransientDataHints( + const { numTransientData, hints: transientDataIndexHints } = buildTransientDataHints( noteHashes, nullifiers, futureNoteHashReads, @@ -168,15 +170,9 @@ export async function buildPrivateKernelResetInputs( MAX_NULLIFIERS_PER_TX, ); - const numNoteHashes = countAccumulatedItems(noteHashes); - const remainingNoteHashes = transientNullifierIndexesForNoteHashes - .slice(0, numNoteHashes) - .reduce((remaining, index) => remaining + (index === nullifiers.length ? 1 : 0), 0); + const remainingNoteHashes = countAccumulatedItems(noteHashes) - numTransientData; - const numNullifiers = countAccumulatedItems(nullifiers); - const remainingNullifiers = transientNoteHashIndexesForNullifiers - .slice(0, numNullifiers) - .reduce((remaining, index) => remaining + (index === noteHashes.length ? 1 : 0), 0); + const remainingNullifiers = countAccumulatedItems(nullifiers) - numTransientData; const numEncryptedLogHashes = countAccumulatedItems(publicInputs.end.encryptedLogsHashes); @@ -197,16 +193,16 @@ export async function buildPrivateKernelResetInputs( hintSizes.NULLIFIER_PENDING_AMOUNT >= nullifierPendingReadHints && hintSizes.NULLIFIER_SETTLED_AMOUNT >= nullifierSettledReadHints && hintSizes.NULLIFIER_KEYS >= keysCount && + hintSizes.TRANSIENT_DATA_AMOUNT >= numTransientData && ((!shouldSilo && noSiloing) || (shouldSilo && enoughSiloing)) ) { privateInputs = new PrivateKernelResetCircuitPrivateInputs( previousKernelData, new PrivateKernelResetHints( - transientNullifierIndexesForNoteHashes, - transientNoteHashIndexesForNullifiers, noteHashReadRequestHints, nullifierReadRequestHints, keysHints, + transientDataIndexHints, validationRequestsSplitCounter, ).trimToSizes( hintSizes.NOTE_HASH_PENDING_AMOUNT, @@ -214,6 +210,7 @@ export async function buildPrivateKernelResetInputs( hintSizes.NULLIFIER_PENDING_AMOUNT, hintSizes.NULLIFIER_SETTLED_AMOUNT, hintSizes.NULLIFIER_KEYS, + hintSizes.TRANSIENT_DATA_AMOUNT, ), sizeTag, );