From 1f28b3a622e603f47f88b20361abef559952a5af Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Wed, 15 May 2024 16:44:24 +0100 Subject: [PATCH] feat: validate counters (#6365) Please read [contributing guidelines](CONTRIBUTING.md) and remove this line. --- .../aztec/src/context/private_context.nr | 9 +- .../aztec/src/context/public_context.nr | 2 +- .../src/private_call_data_validator.nr | 219 ++++- .../src/private_kernel_init.nr | 42 +- .../src/private_kernel_inner.nr | 40 +- .../crates/private-kernel-lib/src/tests.nr | 8 + .../private_call_data_validator_builder.nr | 776 +----------------- .../tests/validate_against_call_request.nr | 83 ++ .../src/tests/validate_against_tx_request.nr | 65 ++ .../src/tests/validate_arrays.nr | 136 +++ .../src/tests/validate_as_first_call.nr | 238 ++++++ .../src/tests/validate_call.nr | 98 +++ .../src/tests/validate_call_requests.nr | 282 +++++++ .../src/tests/validate_contract_address.nr | 62 ++ .../src/tests/validate_counters.nr | 227 +++++ .../crates/types/src/abis/call_request.nr | 15 +- .../crates/types/src/abis/note_hash.nr | 6 + .../crates/types/src/abis/nullifier.nr | 6 + .../crates/types/src/abis/read_request.nr | 8 +- .../types/src/messaging/l2_to_l1_message.nr | 6 + .../crates/types/src/tests/fixture_builder.nr | 4 +- .../src/tests/private_call_data_builder.nr | 102 +-- .../private_circuit_public_inputs_builder.nr | 144 +++- ...vate_kernel_init_circuit_private_inputs.ts | 29 +- .../src/type_conversion.ts | 12 +- .../pxe/src/kernel_prover/kernel_prover.ts | 16 +- .../build_private_kernel_init_hints.ts | 39 + .../private_inputs_builders/index.ts | 1 + .../src/client/private_execution.test.ts | 2 +- yarn-project/simulator/src/public/executor.ts | 3 +- 30 files changed, 1756 insertions(+), 924 deletions(-) create mode 100644 noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_against_call_request.nr create mode 100644 noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_against_tx_request.nr create mode 100644 noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_arrays.nr create mode 100644 noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_as_first_call.nr create mode 100644 noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_call.nr create mode 100644 noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_call_requests.nr create mode 100644 noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_contract_address.nr create mode 100644 noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_counters.nr create mode 100644 yarn-project/pxe/src/kernel_prover/private_inputs_builders/build_private_kernel_init_hints.ts diff --git a/noir-projects/aztec-nr/aztec/src/context/private_context.nr b/noir-projects/aztec-nr/aztec/src/context/private_context.nr index ac174898373..9768e71fcf0 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -108,15 +108,10 @@ impl ContextInterface for PrivateContext { impl PrivateContext { pub fn new(inputs: PrivateContextInputs, args_hash: Field) -> PrivateContext { - let side_effect_counter = inputs.start_side_effect_counter; - let mut min_revertible_side_effect_counter = 0; - if is_empty(inputs.call_context.msg_sender) { - min_revertible_side_effect_counter = side_effect_counter; - } PrivateContext { inputs, - side_effect_counter, - min_revertible_side_effect_counter, + side_effect_counter: inputs.start_side_effect_counter + 1, + min_revertible_side_effect_counter: 0, is_fee_payer: false, args_hash, return_hash: 0, diff --git a/noir-projects/aztec-nr/aztec/src/context/public_context.nr b/noir-projects/aztec-nr/aztec/src/context/public_context.nr index c5d436e3cd1..569d8716206 100644 --- a/noir-projects/aztec-nr/aztec/src/context/public_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/public_context.nr @@ -58,7 +58,7 @@ impl PublicContext { pub fn new(inputs: PublicContextInputs, args_hash: Field) -> PublicContext { PublicContext { inputs, - side_effect_counter: inputs.start_side_effect_counter, + side_effect_counter: inputs.start_side_effect_counter + 1, args_hash, return_hash: 0, nullifier_read_requests: BoundedVec::new(), diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_call_data_validator.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_call_data_validator.nr index 774b66b306e..0a43701e29a 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_call_data_validator.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_call_data_validator.nr @@ -1,7 +1,7 @@ use dep::types::{ abis::{ call_context::CallContext, call_request::CallRequest, private_call_stack_item::PrivateCallStackItem, - private_kernel::private_call_data::PrivateCallData + private_kernel::private_call_data::PrivateCallData, side_effect::Ordered }, address::{AztecAddress, PartialAddress}, contract_class_id::ContractClassId, hash::{private_functions_root_from_siblings, stdlib_recursion_verification_key_compress_native_vk}, @@ -50,9 +50,92 @@ fn validate_call_request(request: CallRequest, hash: Field, caller: PrivateCallS } } -fn validate_call_requests(call_requests: [CallRequest; N], hashes: [Field; N], caller: PrivateCallStackItem) { +fn validate_incrementing_counters_within_range( + counter_start: u32, + counter_end: u32, + items: [T; N], + num_items: u64 +) where T: Ordered { + let mut prev_counter = counter_start; + let mut should_check = true; for i in 0..N { - validate_call_request(call_requests[i], hashes[i], caller); + should_check &= i != num_items; + if should_check { + let item = items[i]; + assert( + item.counter() > prev_counter, "counter must be larger than the counter of the previous item" + ); + prev_counter = item.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: [CallRequest; N], + num_items: u64 +) { + let mut prev_counter = counter_start; + let mut should_check = true; + for i in 0..N { + should_check &= i != num_items; + if should_check { + let item = items[i]; + assert( + item.start_side_effect_counter > prev_counter, "start counter must be larger than the end counter of the previous call" + ); + assert( + item.end_side_effect_counter > item.start_side_effect_counter, "nested call has incorrect counter range" + ); + prev_counter = item.end_side_effect_counter; + } + } + assert( + prev_counter < counter_end, "end counter must be smaller than the end counter of the parent call" + ); +} + +fn validate_split_private_call_requests( + min_revertible_side_effect_counter: u32, + first_revertible_call_request_index: u64, + call_requests: [CallRequest; N], + num_call_requests: u64 +) { + if first_revertible_call_request_index != 0 { + let last_non_revertible_call_request_index = first_revertible_call_request_index - 1; + let call_request = call_requests[last_non_revertible_call_request_index]; + assert( + min_revertible_side_effect_counter > call_request.end_side_effect_counter, "min_revertible_side_effect_counter must be greater than the end counter of the last non revertible call" + ); + } + if first_revertible_call_request_index != num_call_requests { + let call_request = call_requests[first_revertible_call_request_index]; + assert( + min_revertible_side_effect_counter <= call_request.start_side_effect_counter, "min_revertible_side_effect_counter must be less than or equal to the start counter of the first revertible call" + ); + } +} + +fn validate_split_public_call_requests( + min_revertible_side_effect_counter: u32, + first_revertible_call_request_index: u64, + call_requests: [CallRequest; N], + num_call_requests: u64 +) { + if first_revertible_call_request_index != 0 { + let last_non_revertible_call_request_index = first_revertible_call_request_index - 1; + let call_request = call_requests[last_non_revertible_call_request_index]; + assert( + min_revertible_side_effect_counter > call_request.counter(), "min_revertible_side_effect_counter must be greater than the counter of the last non revertible call" + ); + } + if first_revertible_call_request_index != num_call_requests { + let call_request = call_requests[first_revertible_call_request_index]; + assert( + min_revertible_side_effect_counter <= call_request.counter(), "min_revertible_side_effect_counter must be less than or equal to the counter of the first revertible call" + ); } } @@ -86,6 +169,34 @@ impl PrivateCallDataValidator { self.validate_private_call_requests(); self.validate_public_call_requests(); self.validate_teardown_call_request(); + self.validate_counters(); + } + + pub fn validate_as_first_call( + self, + first_revertible_private_call_request_index: u64, + first_revertible_public_call_request_index: u64 + ) { + let public_inputs = self.data.call_stack_item.public_inputs; + let call_context = public_inputs.call_context; + assert(call_context.is_delegate_call == false, "Users cannot make a delegatecall"); + assert(call_context.is_static_call == false, "Users cannot make a static call"); + + let min_revertible_side_effect_counter = public_inputs.min_revertible_side_effect_counter; + // No need to check that the min_revertible_side_effect_counter falls in the counter range of the private call. + // It is valid as long as it does not fall in the middle of any nested call. + validate_split_private_call_requests( + min_revertible_side_effect_counter, + first_revertible_private_call_request_index, + self.data.private_call_stack, + self.array_lengths.private_call_stack_hashes + ); + validate_split_public_call_requests( + min_revertible_side_effect_counter, + first_revertible_public_call_request_index, + self.data.public_call_stack, + self.array_lengths.public_call_stack_hashes + ); } // Confirm that the TxRequest (user's intent) matches the private call being executed. @@ -103,11 +214,6 @@ impl PrivateCallDataValidator { assert_eq( tx_request.tx_context, call_stack_item.public_inputs.tx_context, "tx_context in tx_request must match tx_context in call_stack_item" ); - - // If checking against TxRequest, it must be the first call, which has the following restrictions. - let call_context = call_stack_item.public_inputs.call_context; - assert(call_context.is_delegate_call == false, "Users cannot make a delegatecall"); - assert(call_context.is_static_call == false, "Users cannot make a static call"); } pub fn validate_against_call_request(self, request: CallRequest) { @@ -205,19 +311,19 @@ impl PrivateCallDataValidator { } fn validate_private_call_requests(self) { - validate_call_requests( - self.data.private_call_stack, - self.data.call_stack_item.public_inputs.private_call_stack_hashes, - self.data.call_stack_item - ); + let call_requests = self.data.private_call_stack; + let hashes = self.data.call_stack_item.public_inputs.private_call_stack_hashes; + for i in 0..call_requests.len() { + validate_call_request(call_requests[i], hashes[i], self.data.call_stack_item); + } } fn validate_public_call_requests(self) { - validate_call_requests( - self.data.public_call_stack, - self.data.call_stack_item.public_inputs.public_call_stack_hashes, - self.data.call_stack_item - ); + let call_requests = self.data.public_call_stack; + let hashes = self.data.call_stack_item.public_inputs.public_call_stack_hashes; + for i in 0..call_requests.len() { + validate_call_request(call_requests[i], hashes[i], self.data.call_stack_item); + } } fn validate_teardown_call_request(self) { @@ -227,4 +333,81 @@ impl PrivateCallDataValidator { self.data.call_stack_item ); } + + fn validate_counters(self) { + let public_inputs = self.data.call_stack_item.public_inputs; + let counter_start = public_inputs.start_side_effect_counter; + let counter_end = public_inputs.end_side_effect_counter; + + assert(counter_start < counter_end, "private call has incorrect counter range"); + + validate_incrementing_counters_within_range( + counter_start, + counter_end, + public_inputs.note_hash_read_requests, + self.array_lengths.note_hash_read_requests + ); + validate_incrementing_counters_within_range( + counter_start, + counter_end, + public_inputs.nullifier_read_requests, + self.array_lengths.nullifier_read_requests + ); + validate_incrementing_counters_within_range( + counter_start, + counter_end, + public_inputs.new_note_hashes, + self.array_lengths.new_note_hashes + ); + validate_incrementing_counters_within_range( + counter_start, + counter_end, + public_inputs.new_nullifiers, + self.array_lengths.new_nullifiers + ); + validate_incrementing_counters_within_range( + counter_start, + counter_end, + public_inputs.new_l2_to_l1_msgs, + self.array_lengths.new_l2_to_l1_msgs + ); + validate_incrementing_counters_within_range( + counter_start, + counter_end, + public_inputs.encrypted_logs_hashes, + self.array_lengths.encrypted_logs_hashes + ); + validate_incrementing_counters_within_range( + counter_start, + counter_end, + public_inputs.unencrypted_logs_hashes, + self.array_lengths.unencrypted_logs_hashes + ); + validate_incrementing_counter_ranges_within_range( + counter_start, + counter_end, + self.data.private_call_stack, + self.array_lengths.private_call_stack_hashes + ); + + // Validate the public call requests by checking their start counters only, as their end counters are unknown. + validate_incrementing_counters_within_range( + counter_start, + counter_end, + self.data.public_call_stack, + self.array_lengths.public_call_stack_hashes + ); + + let teardown_call_request_count = if self.data.public_teardown_call_request.hash == 0 { + 0 + } else { + 1 + }; + validate_incrementing_counters_within_range( + counter_start, + counter_end, + [self.data.public_teardown_call_request], + teardown_call_request_count + ); + } } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr index 2e76640a611..51e163f494e 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr @@ -13,6 +13,8 @@ use dep::types::{ struct PrivateKernelInitHints { note_hash_nullifier_counters: [u32; MAX_NEW_NOTE_HASHES_PER_CALL], + first_revertible_private_call_request_index: u64, + first_revertible_public_call_request_index: u64 } // Initialization struct for private inputs to the private kernel @@ -29,6 +31,10 @@ impl PrivateKernelInitCircuitPrivateInputs { let privateCallDataValidator = PrivateCallDataValidator::new(self.private_call); privateCallDataValidator.validate(); + privateCallDataValidator.validate_as_first_call( + self.hints.first_revertible_private_call_request_index, + self.hints.first_revertible_public_call_request_index + ); privateCallDataValidator.validate_against_tx_request(self.tx_request); let private_call_public_inputs = self.private_call.call_stack_item.public_inputs; @@ -67,7 +73,11 @@ mod tests { pub fn new() -> Self { let private_call = PrivateCallDataBuilder::new(); let tx_request = private_call.build_tx_request(); - let hints = PrivateKernelInitHints { note_hash_nullifier_counters: [0; MAX_NEW_NOTE_HASHES_PER_CALL] }; + let hints = PrivateKernelInitHints { + note_hash_nullifier_counters: [0; MAX_NEW_NOTE_HASHES_PER_CALL], + first_revertible_private_call_request_index: 0, + first_revertible_public_call_request_index: 0 + }; PrivateKernelInitInputsBuilder { tx_request, private_call, hints } } @@ -92,13 +102,13 @@ mod tests { let encrypted_log_preimages_length = [100, 75]; let unencrypted_logs_hashes = [26, 46]; let unencrypted_log_preimages_length = [50, 25]; - builder.private_call.set_encrypted_logs(encrypted_logs_hashes[0], encrypted_log_preimages_length[0]); - builder.private_call.set_unencrypted_logs( + builder.private_call.public_inputs.add_encrypted_log(encrypted_logs_hashes[0], encrypted_log_preimages_length[0]); + builder.private_call.public_inputs.add_unencrypted_log( unencrypted_logs_hashes[0], unencrypted_log_preimages_length[0] ); - builder.private_call.set_encrypted_logs(encrypted_logs_hashes[1], encrypted_log_preimages_length[1]); - builder.private_call.set_unencrypted_logs( + builder.private_call.public_inputs.add_encrypted_log(encrypted_logs_hashes[1], encrypted_log_preimages_length[1]); + builder.private_call.public_inputs.add_unencrypted_log( unencrypted_logs_hashes[1], unencrypted_log_preimages_length[1] ); @@ -133,7 +143,7 @@ mod tests { #[test] fn propagate_max_block_number_request() { let mut builder = PrivateKernelInitInputsBuilder::new(); - builder.private_call.set_tx_max_block_number(42); + builder.private_call.public_inputs.set_tx_max_block_number(42); let public_inputs = builder.execute(); assert_eq(public_inputs.validation_requests.for_rollup.max_block_number.unwrap(), 42); @@ -144,10 +154,8 @@ mod tests { let mut builder = PrivateKernelInitInputsBuilder::new(); let storage_contract_address = builder.private_call.public_inputs.call_context.storage_contract_address; - let request_0 = ReadRequest { value: 123, counter: 4567 }; - builder.private_call.public_inputs.note_hash_read_requests.push(request_0); - let request_1 = ReadRequest { value: 777888, counter: 90 }; - builder.private_call.public_inputs.note_hash_read_requests.push(request_1); + builder.private_call.public_inputs.append_note_hash_read_requests(2); + let new_read_requests = builder.private_call.public_inputs.note_hash_read_requests.storage; let public_inputs = builder.execute(); @@ -155,11 +163,11 @@ mod tests { assert_eq(array_length(end_note_hash_read_requests), 2); let request = end_note_hash_read_requests[0]; - assert_eq(request.read_request, request_0); + assert_eq(request.read_request, new_read_requests[0]); assert_eq(request.contract_address, storage_contract_address); let request = end_note_hash_read_requests[1]; - assert_eq(request.read_request, request_1); + assert_eq(request.read_request, new_read_requests[1]); assert_eq(request.contract_address, storage_contract_address); } @@ -168,10 +176,8 @@ mod tests { let mut builder = PrivateKernelInitInputsBuilder::new(); let storage_contract_address = builder.private_call.public_inputs.call_context.storage_contract_address; - let request_0 = ReadRequest { value: 123, counter: 4567 }; - builder.private_call.public_inputs.nullifier_read_requests.push(request_0); - let request_1 = ReadRequest { value: 777888, counter: 90 }; - builder.private_call.public_inputs.nullifier_read_requests.push(request_1); + builder.private_call.public_inputs.append_nullifier_read_requests(2); + let requests = builder.private_call.public_inputs.nullifier_read_requests.storage; let public_inputs = builder.execute(); @@ -179,11 +185,11 @@ mod tests { assert_eq(array_length(end_nullifier_read_requests), 2); let request = end_nullifier_read_requests[0]; - assert_eq(request.read_request, request_0); + assert_eq(request.read_request, requests[0]); assert_eq(request.contract_address, storage_contract_address); let request = end_nullifier_read_requests[1]; - assert_eq(request.read_request, request_1); + assert_eq(request.read_request, requests[1]); assert_eq(request.contract_address, storage_contract_address); } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr index 2ac2e0f2e97..b4d4090f5b5 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr @@ -117,7 +117,7 @@ mod tests { let mut builder = PrivateKernelInnerInputsBuilder::new(); // The current call stack has 1 note_hash; - builder.private_call.public_inputs.new_note_hashes.push(NoteHash { value: 4321, counter: 0 }); + builder.private_call.public_inputs.append_new_note_hashes(1); // Mock the previous new note hashes to be full, therefore no more note_hashes can be added. builder.previous_kernel.append_new_note_hashes(MAX_NEW_NOTE_HASHES_PER_TX); @@ -128,12 +128,7 @@ mod tests { #[test] fn propagate_note_hashes_with_nullifier_counters() { let mut builder = PrivateKernelInnerInputsBuilder::new(); - let note_hashes = [ - NoteHash { value: 12, counter: 3 }, - NoteHash { value: 45, counter: 6 }, - NoteHash { value: 78, counter: 9 } - ]; - builder.private_call.public_inputs.new_note_hashes.extend_from_array(note_hashes); + builder.private_call.public_inputs.append_new_note_hashes(3); builder.hints.note_hash_nullifier_counters[0] = 10; builder.hints.note_hash_nullifier_counters[2] = 20; @@ -147,8 +142,9 @@ mod tests { #[test(should_fail_with="Invalid nullifier counter")] fn propagate_note_hashes_with_incorrect_nullifier_counters_fails() { let mut builder = PrivateKernelInnerInputsBuilder::new(); - builder.private_call.public_inputs.new_note_hashes.push(NoteHash { value: 12, counter: 3 }); - builder.hints.note_hash_nullifier_counters[0] = 2; // Less than the note hash's counter 3. + builder.private_call.public_inputs.append_new_note_hashes(2); + let note_hash_counter = builder.private_call.public_inputs.new_note_hashes.get(1).counter; + builder.hints.note_hash_nullifier_counters[1] = note_hash_counter - 1; builder.failed(); } @@ -165,7 +161,7 @@ mod tests { #[test] fn propagate_max_block_number_request() { let mut builder = PrivateKernelInnerInputsBuilder::new(); - builder.private_call.set_tx_max_block_number(42); + builder.private_call.public_inputs.set_tx_max_block_number(42); let public_inputs = builder.execute(); assert_eq(public_inputs.validation_requests.for_rollup.max_block_number.unwrap(), 42); @@ -177,7 +173,7 @@ mod tests { builder.previous_kernel.max_block_number = MaxBlockNumber::new(13); // A private call requesting a larger max_block_number should not change the current one as that constraint is // already satisfied. - builder.private_call.set_tx_max_block_number(42); + builder.private_call.public_inputs.set_tx_max_block_number(42); let public_inputs = builder.execute(); assert_eq(public_inputs.validation_requests.for_rollup.max_block_number.unwrap(), 13); @@ -188,10 +184,10 @@ mod tests { let mut builder = PrivateKernelInnerInputsBuilder::new(); builder.previous_kernel.append_note_hash_read_requests(2); - let prev_requests = builder.previous_kernel.note_hash_read_requests; + let prev_requests = builder.previous_kernel.note_hash_read_requests.storage; - let cur_requests = [ReadRequest { value: 123, counter: 4567 }, ReadRequest { value: 777888, counter: 90 }]; - builder.private_call.public_inputs.note_hash_read_requests.extend_from_array(cur_requests); + builder.private_call.public_inputs.append_note_hash_read_requests(2); + let cur_requests = builder.private_call.public_inputs.note_hash_read_requests.storage; let cur_storage_contract_address = builder.private_call.public_inputs.call_context.storage_contract_address; let public_inputs = builder.execute(); @@ -199,8 +195,8 @@ mod tests { let end_note_hash_read_requests = public_inputs.validation_requests.note_hash_read_requests; assert_eq(array_length(end_note_hash_read_requests), 4); - assert_eq(end_note_hash_read_requests[0], prev_requests.storage[0]); - assert_eq(end_note_hash_read_requests[1], prev_requests.storage[1]); + assert_eq(end_note_hash_read_requests[0], prev_requests[0]); + assert_eq(end_note_hash_read_requests[1], prev_requests[1]); let request = end_note_hash_read_requests[2]; assert_eq(request.read_request, cur_requests[0]); @@ -220,8 +216,8 @@ mod tests { let encrypted_log_preimages_length = 100; let unencrypted_logs_hash = 26; let unencrypted_log_preimages_length = 50; - builder.private_call.set_encrypted_logs(encrypted_logs_hash, encrypted_log_preimages_length); - builder.private_call.set_unencrypted_logs(unencrypted_logs_hash, unencrypted_log_preimages_length); + builder.private_call.public_inputs.add_encrypted_log(encrypted_logs_hash, encrypted_log_preimages_length); + builder.private_call.public_inputs.add_unencrypted_log(unencrypted_logs_hash, unencrypted_log_preimages_length); // Logs for the previous call stack. let prev_encrypted_logs_hash = 80; @@ -250,19 +246,25 @@ mod tests { } #[test] - unconstrained fn propagate_fee_payer() { + unconstrained fn propagate_fee_payer_init_succeeds() { let mut builder = PrivateKernelInnerInputsBuilder::new(); let fee_payer = builder.private_call.public_inputs.call_context.storage_contract_address; builder.private_call.public_inputs.is_fee_payer = true; let public_inputs = builder.execute(); assert_eq(public_inputs.fee_payer, fee_payer); + } + #[test] + unconstrained fn propagate_fee_payer_not_set_succeeds() { // Check that the fee payer is not set if is_fee_payer is false let mut builder = PrivateKernelInnerInputsBuilder::new(); assert_eq(builder.private_call.public_inputs.is_fee_payer, false); let public_inputs = builder.execute(); assert_eq(public_inputs.fee_payer, AztecAddress::empty()); + } + #[test] + unconstrained fn propagate_fee_payer_carry_forward_succeeds() { // Check that we carry forward if the fee payer is already set let mut builder = PrivateKernelInnerInputsBuilder::new(); let fee_payer = AztecAddress::from_field(123); diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests.nr index e92b7e1016a..e2af8ade73b 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests.nr @@ -1 +1,9 @@ mod private_call_data_validator_builder; +mod validate_against_call_request; +mod validate_against_tx_request; +mod validate_arrays; +mod validate_as_first_call; +mod validate_call; +mod validate_call_requests; +mod validate_contract_address; +mod validate_counters; diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_call_data_validator_builder.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_call_data_validator_builder.nr index 8802b64d81e..c76216a9635 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_call_data_validator_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/private_call_data_validator_builder.nr @@ -1,23 +1,28 @@ use crate::private_call_data_validator::PrivateCallDataValidator; use dep::types::{ - abis::{ - call_request::CallRequest, caller_context::CallerContext, note_hash::NoteHash, nullifier::Nullifier, - nullifier_key_validation_request::NullifierKeyValidationRequest, read_request::ReadRequest, - side_effect::SideEffect -}, - address::{AztecAddress, EthAddress}, grumpkin_point::GrumpkinPoint, - messaging::l2_to_l1_message::L2ToL1Message, - tests::private_call_data_builder::PrivateCallDataBuilder, transaction::tx_request::TxRequest + abis::call_request::CallRequest, tests::private_call_data_builder::PrivateCallDataBuilder, + transaction::tx_request::TxRequest }; struct PrivateCallDataValidatorBuilder { private_call: PrivateCallDataBuilder, + first_revertible_private_call_request_index: u64, + first_revertible_public_call_request_index: u64 } impl PrivateCallDataValidatorBuilder { pub fn new() -> Self { - let private_call = PrivateCallDataBuilder::new(); - PrivateCallDataValidatorBuilder { private_call } + let default_counter_start = 23; + PrivateCallDataValidatorBuilder::new_with_counter(default_counter_start) + } + + pub fn new_with_counter(counter: u32) -> Self { + let private_call = PrivateCallDataBuilder::new_with_counter(counter); + PrivateCallDataValidatorBuilder { + private_call, + first_revertible_private_call_request_index: 0, + first_revertible_public_call_request_index: 0 + } } pub fn is_delegate_call(&mut self) -> Self { @@ -35,6 +40,14 @@ impl PrivateCallDataValidatorBuilder { PrivateCallDataValidator::new(private_call).validate(); } + pub fn validate_as_first_call(self) { + let private_call = self.private_call.finish(); + PrivateCallDataValidator::new(private_call).validate_as_first_call( + self.first_revertible_private_call_request_index, + self.first_revertible_public_call_request_index + ); + } + pub fn validate_against_tx_request(self, request: TxRequest) { let private_call = self.private_call.finish(); PrivateCallDataValidator::new(private_call).validate_against_tx_request(request); @@ -45,746 +58,3 @@ impl PrivateCallDataValidatorBuilder { PrivateCallDataValidator::new(private_call).validate_against_call_request(request); } } - -/** - * validate_arrays - */ - -#[test(should_fail_with="invalid array")] -fn validate_arrays_malformed_note_hash_read_requests_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.public_inputs.note_hash_read_requests.extend_from_array( - [ - ReadRequest::empty(), - ReadRequest { value: 9123, counter: 1 } - ] - ); - - builder.validate(); -} - -#[test(should_fail_with="invalid array")] -fn validate_arrays_malformed_nullifier_read_requests_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.public_inputs.nullifier_read_requests.extend_from_array( - [ - ReadRequest::empty(), - ReadRequest { value: 9123, counter: 1 } - ] - ); - - builder.validate(); -} - -// Enable this test if MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL is greater than 1. -// #[test(should_fail_with="invalid array")] -// fn validate_arrays_malformed_nullifier_key_validation_requests_fails() { -// let mut builder = PrivateCallDataValidatorBuilder::new(); - -// builder.private_call.public_inputs.nullifier_key_validation_requests.extend_from_array( -// [ -// NullifierKeyValidationRequest::empty(), -// NullifierKeyValidationRequest { master_nullifier_public_key: GrumpkinPoint { x: 12, y: 34 }, app_nullifier_secret_key: 5 } -// ] -// ); - -// builder.validate(); -// } - -#[test(should_fail_with="invalid array")] -fn validate_arrays_malformed_note_hashes_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.public_inputs.new_note_hashes.extend_from_array( - [ - NoteHash::empty(), - NoteHash { value: 9123, counter: 1 } - ] - ); - - builder.validate(); -} - -#[test(should_fail_with="invalid array")] -fn validate_arrays_malformed_nullifiers_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.public_inputs.new_nullifiers.extend_from_array( - [ - Nullifier::empty(), - Nullifier { value: 9123, note_hash: 0, counter: 1 } - ] - ); - - builder.validate(); -} - -#[test(should_fail_with="invalid array")] -fn validate_arrays_malformed_l2_to_l1_msgs_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.public_inputs.new_l2_to_l1_msgs.extend_from_array( - [ - L2ToL1Message::empty(), - L2ToL1Message { recipient: EthAddress::from_field(6), content: 9123, counter: 0 } - ] - ); - - builder.validate(); -} - -#[test(should_fail_with="invalid array")] -fn validate_arrays_malformed_private_call_stack_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.public_inputs.private_call_stack_hashes.extend_from_array([0, 9123]); - - builder.validate(); -} - -#[test(should_fail_with="invalid array")] -fn validate_arrays_malformed_public_call_stack_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.public_inputs.public_call_stack_hashes.extend_from_array([0, 9123]); - - builder.validate(); -} - -#[test(should_fail_with="invalid array")] -fn validate_arrays_malformed_encrypted_logs_hashes_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.public_inputs.encrypted_logs_hashes.extend_from_array( - [ - SideEffect { value: 0, counter: 0 }, - SideEffect { value: 9123, counter: 1 } - ] - ); - - builder.validate(); -} - -#[test(should_fail_with="invalid array")] -fn validate_arrays_malformed_unencrypted_logs_hashes_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.public_inputs.unencrypted_logs_hashes.extend_from_array( - [ - SideEffect { value: 0, counter: 0 }, - SideEffect { value: 9123, counter: 1 } - ] - ); - - builder.validate(); -} - -/** - * validate_contract_address - */ - -#[test(should_fail_with="contract address cannot be zero")] -fn validate_contract_address_zero_storage_contract_address_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - // Set (storage) contract_address to 0 - builder.private_call.contract_address = AztecAddress::zero(); - builder.private_call.public_inputs.call_context.storage_contract_address = AztecAddress::zero(); - - builder.validate(); -} - -#[test(should_fail_with="computed contract address does not match expected one")] -fn validate_contract_address_incorrect_function_leaf_index_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - // Set the leaf index of the function leaf to a wrong value (the correct value + 1). - let leaf_index = builder.private_call.function_leaf_membership_witness.leaf_index; - builder.private_call.function_leaf_membership_witness.leaf_index = leaf_index + 1; - - builder.validate(); -} - -#[test(should_fail_with="computed contract address does not match expected one")] -fn validate_contract_address_incorrect_function_leaf_sibling_path_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - // Set the first value of the sibling path to a wrong value (the correct value + 1). - let sibling_path_0 = builder.private_call.function_leaf_membership_witness.sibling_path[0]; - builder.private_call.function_leaf_membership_witness.sibling_path[0] = sibling_path_0 + 1; - - builder.validate(); -} - -#[test(should_fail_with="computed contract address does not match expected one")] -fn validate_contract_address_incorrect_contract_class_preimage_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.contract_class_artifact_hash = builder.private_call.contract_class_artifact_hash + 1; - - builder.validate(); -} - -#[test(should_fail_with="computed contract address does not match expected one")] -fn validate_contract_address_incorrect_partial_address_preimage_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.salted_initialization_hash.inner = builder.private_call.salted_initialization_hash.inner + 1; - - builder.validate(); -} - -#[test(should_fail_with="computed contract address does not match expected one")] -fn validate_contract_address_incorrect_address_preimage_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.public_keys_hash.inner = builder.private_call.public_keys_hash.inner + 1; - - builder.validate(); -} - -/** - * validate_call - */ - -#[test] -fn validate_call_is_regular_succeeds() { - let builder = PrivateCallDataValidatorBuilder::new(); - builder.validate(); -} - -#[test(should_fail_with="call stack storage address does not match expected contract address")] -fn validate_call_is_regular_mismatch_storage_contract_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - // Change the storage contract address to be a different value. - builder.private_call.public_inputs.call_context.storage_contract_address.inner += 1; - - builder.validate(); -} - -#[test] -fn validate_call_is_delegate_succeeds() { - let builder = PrivateCallDataValidatorBuilder::new().is_delegate_call(); - builder.validate(); -} - -#[test(should_fail_with="current contract address must not match storage contract address for delegate calls")] -fn validate_call_is_delegate_call_from_same_contract_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new().is_delegate_call(); - - // Change the caller's storage contract address to be the same as the contract address. - builder.private_call.public_inputs.call_context.storage_contract_address = builder.private_call.contract_address; - - builder.validate(); -} - -#[test] -fn validate_call_is_static_succeeds() { - let mut builder = PrivateCallDataValidatorBuilder::new().is_static_call(); - builder.validate(); -} - -#[test(should_fail_with="call stack storage address does not match expected contract address")] -fn validate_call_is_static_mismatch_storage_contract_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new().is_static_call(); - - // Change the storage contract address to be a different value. - builder.private_call.public_inputs.call_context.storage_contract_address.inner += 1; - - builder.validate(); -} - -#[test(should_fail_with="new_note_hashes must be empty for static calls")] -fn validate_call_is_static_creating_note_hashes_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new().is_static_call(); - - builder.private_call.public_inputs.new_note_hashes.push(NoteHash { value: 1, counter: 0 }); - - builder.validate(); -} - -#[test(should_fail_with="new_nullifiers must be empty for static calls")] -fn validate_call_is_static_creating_nullifiers_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new().is_static_call(); - - builder.private_call.public_inputs.new_nullifiers.push(Nullifier { value: 1, counter: 0, note_hash: 0 }); - - builder.validate(); -} - -#[test(should_fail_with="new_l2_to_l1_msgs must be empty for static calls")] -fn validate_call_is_static_creating_l2_to_l1_msgs_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new().is_static_call(); - - builder.private_call.public_inputs.new_l2_to_l1_msgs.push(L2ToL1Message { recipient: EthAddress::from_field(6), content: 9123, counter: 0 }); - - builder.validate(); -} - -#[test(should_fail_with="encrypted_logs_hashes must be empty for static calls")] -fn validate_call_is_static_creating_encrypted_logs_hashes_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new().is_static_call(); - - builder.private_call.public_inputs.encrypted_logs_hashes.push(SideEffect { value: 9123, counter: 1 }); - - builder.validate(); -} - -#[test(should_fail_with="unencrypted_logs_hashes must be empty for static calls")] -fn validate_call_is_static_creating_unencrypted_logs_hashes_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new().is_static_call(); - - builder.private_call.public_inputs.unencrypted_logs_hashes.push(SideEffect { value: 9123, counter: 1 }); - - builder.validate(); -} - -/** - * validate_private_call_requests - */ - -#[test] -fn validate_private_call_requests_succeeds() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.append_private_call_requests(2, false); - - builder.validate(); -} - -#[test] -fn validate_private_call_requests_delegate_calls_succeeds() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.append_private_call_requests(2, true); - - builder.validate(); -} - -#[test(should_fail_with="call stack hash does not match call request hash")] -fn validate_private_call_requests_incorrect_hash_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.append_private_call_requests(2, false); - let mut call_request = builder.private_call.private_call_stack.pop(); - // Change the hash to be a different value. - call_request.hash += 1; - builder.private_call.private_call_stack.push(call_request); - - builder.validate(); -} - -#[test(should_fail_with="invalid caller")] -fn validate_private_call_requests_incorrect_caller_address_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.append_private_call_requests(1, false); - let mut call_request = builder.private_call.private_call_stack.pop(); - // Change the caller contract address to be a different value. - call_request.caller_contract_address.inner += 1; - builder.private_call.private_call_stack.push(call_request); - - builder.validate(); -} - -#[test(should_fail_with="invalid caller")] -fn validate_private_call_requests_incorrect_caller_storage_contract_address_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.append_private_call_requests(1, true); - let mut call_request = builder.private_call.private_call_stack.pop(); - // Change the storage contract to be a different value. - call_request.caller_context.storage_contract_address.inner += 1; - builder.private_call.private_call_stack.push(call_request); - - builder.validate(); -} - -#[test(should_fail_with="invalid caller")] -fn validate_private_call_requests_incorrect_caller_msg_sender_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.append_private_call_requests(1, true); - let mut call_request = builder.private_call.private_call_stack.pop(); - // Change the msg_sender to be a different value. - call_request.caller_context.msg_sender.inner += 1; - builder.private_call.private_call_stack.push(call_request); - - builder.validate(); -} - -#[test(should_fail_with="call requests length does not match the expected length")] -fn validate_private_call_requests_fewer_hashes_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.append_private_call_requests(2, false); - // Remove one call stack item hash. - let _ = builder.private_call.public_inputs.private_call_stack_hashes.pop(); - - builder.validate(); -} - -#[test(should_fail_with="call stack hash does not match call request hash")] -fn validate_private_call_requests_more_hashes_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.append_private_call_requests(2, false); - // Add one random call stack item hash. - builder.private_call.public_inputs.private_call_stack_hashes.push(9123); - - builder.validate(); -} - -/** - * validate_public_call_requests - */ - -#[test] -fn validate_public_call_requests_succeeds() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.append_public_call_requests(2, false); - - builder.validate(); -} - -#[test] -fn validate_public_call_requests_delegate_calls_succeeds() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.append_public_call_requests(2, true); - - builder.validate(); -} - -#[test(should_fail_with="call stack hash does not match call request hash")] -fn validate_public_call_requests_incorrect_hash_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.append_public_call_requests(2, false); - let mut call_request = builder.private_call.public_call_stack.pop(); - // Change the hash to be a different value. - call_request.hash += 1; - builder.private_call.public_call_stack.push(call_request); - - builder.validate(); -} - -#[test(should_fail_with="invalid caller")] -fn validate_public_call_requests_incorrect_caller_address_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.append_public_call_requests(1, false); - let mut call_request = builder.private_call.public_call_stack.pop(); - // Change the caller contract address to be a different value. - call_request.caller_contract_address.inner += 1; - builder.private_call.public_call_stack.push(call_request); - - builder.validate(); -} - -#[test(should_fail_with="invalid caller")] -fn validate_public_call_requests_incorrect_caller_storage_contract_address_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.append_public_call_requests(1, true); - let mut call_request = builder.private_call.public_call_stack.pop(); - // Change the storage contract to be a different value. - call_request.caller_context.storage_contract_address.inner += 1; - builder.private_call.public_call_stack.push(call_request); - - builder.validate(); -} - -#[test(should_fail_with="invalid caller")] -fn validate_public_call_requests_incorrect_caller_msg_sender_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.append_public_call_requests(1, true); - let mut call_request = builder.private_call.public_call_stack.pop(); - // Change the msg_sender to be a different value. - call_request.caller_context.msg_sender.inner += 1; - builder.private_call.public_call_stack.push(call_request); - - builder.validate(); -} - -#[test(should_fail_with="call requests length does not match the expected length")] -fn validate_public_call_requests_fewer_hashes_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.append_public_call_requests(2, false); - // Remove one call stack item hash. - let _ = builder.private_call.public_inputs.public_call_stack_hashes.pop(); - - builder.validate(); -} - -#[test(should_fail_with="call stack hash does not match call request hash")] -fn validate_public_call_requests_more_hashes_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.append_public_call_requests(2, false); - // Add one random call stack item hash. - builder.private_call.public_inputs.public_call_stack_hashes.push(9123); - - builder.validate(); -} - -/** - * validate_teardown_call_request - */ - -#[test] -fn validate_teardown_call_request_succeeds() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.add_teaddown_call_request(false); - - builder.validate(); -} - -#[test] -fn validate_teardown_call_request_delegate_calls_succeeds() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.add_teaddown_call_request(true); - - builder.validate(); -} - -#[test(should_fail_with="call stack hash does not match call request hash")] -fn validate_teardown_call_request_incorrect_hash_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.add_teaddown_call_request(true); - // Change the hash to be a different value. - builder.private_call.public_teardown_call_request.hash += 1; - - builder.validate(); -} - -#[test(should_fail_with="invalid caller")] -fn validate_teardown_call_request_incorrect_caller_address_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.add_teaddown_call_request(true); - // Change the caller contract address to be a different value. - builder.private_call.public_teardown_call_request.caller_contract_address.inner += 1; - - builder.validate(); -} - -#[test(should_fail_with="invalid caller")] -fn validate_teardown_call_request_incorrect_caller_storage_contract_address_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.add_teaddown_call_request(true); - // Change the storage contract to be a different value. - builder.private_call.public_teardown_call_request.caller_context.storage_contract_address.inner += 1; - - builder.validate(); -} - -#[test(should_fail_with="invalid caller")] -fn validate_teardown_call_request_incorrect_caller_msg_sender_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.add_teaddown_call_request(true); - // Change the msg_sender to be a different value. - builder.private_call.public_teardown_call_request.caller_context.msg_sender.inner += 1; - - builder.validate(); -} - -#[test(should_fail_with="call requests length does not match the expected length")] -fn validate_teardown_call_request_fewer_hashes_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.add_teaddown_call_request(true); - // Remove the call stack item hash. - builder.private_call.public_inputs.public_teardown_function_hash = 0; - - builder.validate(); -} - -#[test(should_fail_with="call stack hash does not match call request hash")] -fn validate_teardown_call_request_more_hashes_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new(); - - builder.private_call.add_teaddown_call_request(true); - // Remove the call request. - builder.private_call.public_teardown_call_request = CallRequest::empty(); - - builder.validate(); -} - -/** - * validate_against_tx_request - */ - -#[test] -fn validate_against_tx_request_succeeds() { - let builder = PrivateCallDataValidatorBuilder::new(); - - let request = builder.private_call.build_tx_request(); - - builder.validate_against_tx_request(request); -} - -#[test(should_fail_with="origin address does not match call stack items contract address")] -fn validate_against_tx_request_mismatch_contract_address_fails() { - let builder = PrivateCallDataValidatorBuilder::new(); - - let mut request = builder.private_call.build_tx_request(); - // Tweak the origin to be a different value. - request.origin.inner += 1; - - builder.validate_against_tx_request(request); -} - -#[test(should_fail_with="tx_request function_data must match call_stack_item function_data")] -fn validate_against_tx_request_mismatch_function_data_fails() { - let builder = PrivateCallDataValidatorBuilder::new(); - - let mut request = builder.private_call.build_tx_request(); - // Tweak the function selector to be a different value. - request.function_data.selector.inner += 1; - - builder.validate_against_tx_request(request); -} - -#[test(should_fail_with="noir function args passed to tx_request must match args in the call_stack_item")] -fn validate_against_tx_request_mismatch_args_hash_fails() { - let builder = PrivateCallDataValidatorBuilder::new(); - - let mut request = builder.private_call.build_tx_request(); - // Tweak the args hash to be a different value. - request.args_hash += 1; - - builder.validate_against_tx_request(request); -} - -#[test(should_fail_with="tx_context in tx_request must match tx_context in call_stack_item")] -fn validate_against_tx_request_mismatch_chain_id_fails() { - let builder = PrivateCallDataValidatorBuilder::new(); - - let mut request = builder.private_call.build_tx_request(); - // Tweak the chain id to be a different value. - request.tx_context.chain_id += 1; - - builder.validate_against_tx_request(request); -} - -#[test(should_fail_with="tx_context in tx_request must match tx_context in call_stack_item")] -fn validate_against_tx_request_mismatch_version_fails() { - let builder = PrivateCallDataValidatorBuilder::new(); - - let mut request = builder.private_call.build_tx_request(); - // Tweak the version to be a different value. - request.tx_context.version += 1; - - builder.validate_against_tx_request(request); -} - -#[test(should_fail_with="Users cannot make a static call")] -fn validate_against_tx_request_static_call_fails() { - let builder = PrivateCallDataValidatorBuilder::new().is_static_call(); - let request = builder.private_call.build_tx_request(); - builder.validate_against_tx_request(request); -} - -#[test(should_fail_with="Users cannot make a delegatecall")] -fn validate_against_tx_request_delegate_call_fails() { - let builder = PrivateCallDataValidatorBuilder::new().is_delegate_call(); - let request = builder.private_call.build_tx_request(); - builder.validate_against_tx_request(request); -} - -/** - * validate_against_call_request - */ - -#[test] -fn validate_against_call_request_succeeds() { - let builder = PrivateCallDataValidatorBuilder::new(); - - let request = builder.private_call.build_call_request(); - - builder.validate_against_call_request(request); -} - -#[test] -fn validate_against_call_request_delegate_call_succeeds() { - let builder = PrivateCallDataValidatorBuilder::new().is_delegate_call(); - - let request = builder.private_call.build_call_request(); - - builder.validate_against_call_request(request); -} - -#[test] -fn validate_against_call_request_static_call_succeeds() { - let builder = PrivateCallDataValidatorBuilder::new().is_static_call(); - - let request = builder.private_call.build_call_request(); - - builder.validate_against_call_request(request); -} - -#[test(should_fail_with="calculated private_call_hash does not match provided private_call_hash at the top of the call stack")] -fn validate_against_call_request_mismatch_hash_fails() { - let builder = PrivateCallDataValidatorBuilder::new(); - - let mut request = builder.private_call.build_call_request(); - // Tweak the hash to be a different value. - request.hash += 1; - - builder.validate_against_call_request(request); -} - -#[test(should_fail_with="caller context cannot be empty for delegate calls")] -fn validate_against_call_request_empty_caller_context_for_delegate_calls_fails() { - let builder = PrivateCallDataValidatorBuilder::new().is_delegate_call(); - - let mut request = builder.private_call.build_call_request(); - request.caller_context = CallerContext::empty(); - - builder.validate_against_call_request(request); -} - -#[test(should_fail_with="call stack msg_sender does not match expected msg_sender for delegate calls")] -fn validate_against_call_request_incorrect_msg_sender_for_delegate_call_fails() { - let builder = PrivateCallDataValidatorBuilder::new().is_delegate_call(); - - let mut request = builder.private_call.build_call_request(); - // Tweak the msg_sender to be a different value. - request.caller_context.msg_sender.inner += 1; - - builder.validate_against_call_request(request); -} - -#[test(should_fail_with="call stack storage address does not match expected contract address for delegate calls")] -fn validate_against_call_request_incorrect_storage_contract_address_for_delegate_call_fails() { - let builder = PrivateCallDataValidatorBuilder::new().is_delegate_call(); - - let mut request = builder.private_call.build_call_request(); - // Tweak the storage contract address to be a different value. - request.caller_context.storage_contract_address.inner += 1; - - builder.validate_against_call_request(request); -} - -#[test(should_fail_with="call stack msg_sender does not match caller contract address")] -fn validate_against_call_request_incorrect_msg_sender_for_regular_call_fails() { - let builder = PrivateCallDataValidatorBuilder::new(); - - let mut request = builder.private_call.build_call_request(); - // Tweak the caller's contract address to be a different value. - request.caller_contract_address.inner += 1; - - builder.validate_against_call_request(request); -} diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_against_call_request.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_against_call_request.nr new file mode 100644 index 00000000000..87dd96f84ed --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_against_call_request.nr @@ -0,0 +1,83 @@ +use crate::tests::private_call_data_validator_builder::PrivateCallDataValidatorBuilder; +use dep::types::abis::caller_context::CallerContext; + +#[test] +fn validate_against_call_request_succeeds() { + let builder = PrivateCallDataValidatorBuilder::new(); + + let request = builder.private_call.build_call_request(); + + builder.validate_against_call_request(request); +} + +#[test] +fn validate_against_call_request_delegate_call_succeeds() { + let builder = PrivateCallDataValidatorBuilder::new().is_delegate_call(); + + let request = builder.private_call.build_call_request(); + + builder.validate_against_call_request(request); +} + +#[test] +fn validate_against_call_request_static_call_succeeds() { + let builder = PrivateCallDataValidatorBuilder::new().is_static_call(); + + let request = builder.private_call.build_call_request(); + + builder.validate_against_call_request(request); +} + +#[test(should_fail_with="calculated private_call_hash does not match provided private_call_hash at the top of the call stack")] +fn validate_against_call_request_mismatch_hash_fails() { + let builder = PrivateCallDataValidatorBuilder::new(); + + let mut request = builder.private_call.build_call_request(); + // Tweak the hash to be a different value. + request.hash += 1; + + builder.validate_against_call_request(request); +} + +#[test(should_fail_with="caller context cannot be empty for delegate calls")] +fn validate_against_call_request_empty_caller_context_for_delegate_calls_fails() { + let builder = PrivateCallDataValidatorBuilder::new().is_delegate_call(); + + let mut request = builder.private_call.build_call_request(); + request.caller_context = CallerContext::empty(); + + builder.validate_against_call_request(request); +} + +#[test(should_fail_with="call stack msg_sender does not match expected msg_sender for delegate calls")] +fn validate_against_call_request_incorrect_msg_sender_for_delegate_call_fails() { + let builder = PrivateCallDataValidatorBuilder::new().is_delegate_call(); + + let mut request = builder.private_call.build_call_request(); + // Tweak the msg_sender to be a different value. + request.caller_context.msg_sender.inner += 1; + + builder.validate_against_call_request(request); +} + +#[test(should_fail_with="call stack storage address does not match expected contract address for delegate calls")] +fn validate_against_call_request_incorrect_storage_contract_address_for_delegate_call_fails() { + let builder = PrivateCallDataValidatorBuilder::new().is_delegate_call(); + + let mut request = builder.private_call.build_call_request(); + // Tweak the storage contract address to be a different value. + request.caller_context.storage_contract_address.inner += 1; + + builder.validate_against_call_request(request); +} + +#[test(should_fail_with="call stack msg_sender does not match caller contract address")] +fn validate_against_call_request_incorrect_msg_sender_for_regular_call_fails() { + let builder = PrivateCallDataValidatorBuilder::new(); + + let mut request = builder.private_call.build_call_request(); + // Tweak the caller's contract address to be a different value. + request.caller_contract_address.inner += 1; + + builder.validate_against_call_request(request); +} diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_against_tx_request.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_against_tx_request.nr new file mode 100644 index 00000000000..6c02f0bff56 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_against_tx_request.nr @@ -0,0 +1,65 @@ +use crate::tests::private_call_data_validator_builder::PrivateCallDataValidatorBuilder; + +#[test] +fn validate_against_tx_request_succeeds() { + let builder = PrivateCallDataValidatorBuilder::new(); + + let request = builder.private_call.build_tx_request(); + + builder.validate_against_tx_request(request); +} + +#[test(should_fail_with="origin address does not match call stack items contract address")] +fn validate_against_tx_request_mismatch_contract_address_fails() { + let builder = PrivateCallDataValidatorBuilder::new(); + + let mut request = builder.private_call.build_tx_request(); + // Tweak the origin to be a different value. + request.origin.inner += 1; + + builder.validate_against_tx_request(request); +} + +#[test(should_fail_with="tx_request function_data must match call_stack_item function_data")] +fn validate_against_tx_request_mismatch_function_data_fails() { + let builder = PrivateCallDataValidatorBuilder::new(); + + let mut request = builder.private_call.build_tx_request(); + // Tweak the function selector to be a different value. + request.function_data.selector.inner += 1; + + builder.validate_against_tx_request(request); +} + +#[test(should_fail_with="noir function args passed to tx_request must match args in the call_stack_item")] +fn validate_against_tx_request_mismatch_args_hash_fails() { + let builder = PrivateCallDataValidatorBuilder::new(); + + let mut request = builder.private_call.build_tx_request(); + // Tweak the args hash to be a different value. + request.args_hash += 1; + + builder.validate_against_tx_request(request); +} + +#[test(should_fail_with="tx_context in tx_request must match tx_context in call_stack_item")] +fn validate_against_tx_request_mismatch_chain_id_fails() { + let builder = PrivateCallDataValidatorBuilder::new(); + + let mut request = builder.private_call.build_tx_request(); + // Tweak the chain id to be a different value. + request.tx_context.chain_id += 1; + + builder.validate_against_tx_request(request); +} + +#[test(should_fail_with="tx_context in tx_request must match tx_context in call_stack_item")] +fn validate_against_tx_request_mismatch_version_fails() { + let builder = PrivateCallDataValidatorBuilder::new(); + + let mut request = builder.private_call.build_tx_request(); + // Tweak the version to be a different value. + request.tx_context.version += 1; + + builder.validate_against_tx_request(request); +} diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_arrays.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_arrays.nr new file mode 100644 index 00000000000..048511b151c --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_arrays.nr @@ -0,0 +1,136 @@ +use crate::tests::private_call_data_validator_builder::PrivateCallDataValidatorBuilder; +use dep::types::{ + abis::{note_hash::NoteHash, nullifier::Nullifier, read_request::ReadRequest, side_effect::SideEffect}, + address::EthAddress, grumpkin_point::GrumpkinPoint, messaging::l2_to_l1_message::L2ToL1Message +}; + +#[test(should_fail_with="invalid array")] +fn validate_arrays_malformed_note_hash_read_requests_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.public_inputs.note_hash_read_requests.extend_from_array( + [ + ReadRequest::empty(), + ReadRequest { value: 9123, counter: 1 } + ] + ); + + builder.validate(); +} + +#[test(should_fail_with="invalid array")] +fn validate_arrays_malformed_nullifier_read_requests_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.public_inputs.nullifier_read_requests.extend_from_array( + [ + ReadRequest::empty(), + ReadRequest { value: 9123, counter: 1 } + ] + ); + + builder.validate(); +} + +// Enable this test if MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL is greater than 1. +// #[test(should_fail_with="invalid array")] +// fn validate_arrays_malformed_nullifier_key_validation_requests_fails() { +// let mut builder = PrivateCallDataValidatorBuilder::new(); + +// builder.private_call.public_inputs.nullifier_key_validation_requests.extend_from_array( +// [ +// NullifierKeyValidationRequest::empty(), +// NullifierKeyValidationRequest { master_nullifier_public_key: GrumpkinPoint { x: 12, y: 34 }, app_nullifier_secret_key: 5 } +// ] +// ); + +// builder.validate(); +// } + +#[test(should_fail_with="invalid array")] +fn validate_arrays_malformed_note_hashes_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.public_inputs.new_note_hashes.extend_from_array( + [ + NoteHash::empty(), + NoteHash { value: 9123, counter: 1 } + ] + ); + + builder.validate(); +} + +#[test(should_fail_with="invalid array")] +fn validate_arrays_malformed_nullifiers_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.public_inputs.new_nullifiers.extend_from_array( + [ + Nullifier::empty(), + Nullifier { value: 9123, note_hash: 0, counter: 1 } + ] + ); + + builder.validate(); +} + +#[test(should_fail_with="invalid array")] +fn validate_arrays_malformed_l2_to_l1_msgs_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.public_inputs.new_l2_to_l1_msgs.extend_from_array( + [ + L2ToL1Message::empty(), + L2ToL1Message { recipient: EthAddress::from_field(6), content: 9123, counter: 0 } + ] + ); + + builder.validate(); +} + +#[test(should_fail_with="invalid array")] +fn validate_arrays_malformed_private_call_stack_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.public_inputs.private_call_stack_hashes.extend_from_array([0, 9123]); + + builder.validate(); +} + +#[test(should_fail_with="invalid array")] +fn validate_arrays_malformed_public_call_stack_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.public_inputs.public_call_stack_hashes.extend_from_array([0, 9123]); + + builder.validate(); +} + +#[test(should_fail_with="invalid array")] +fn validate_arrays_malformed_encrypted_logs_hashes_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.public_inputs.encrypted_logs_hashes.extend_from_array( + [ + SideEffect { value: 0, counter: 0 }, + SideEffect { value: 9123, counter: 1 } + ] + ); + + builder.validate(); +} + +#[test(should_fail_with="invalid array")] +fn validate_arrays_malformed_unencrypted_logs_hashes_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.public_inputs.unencrypted_logs_hashes.extend_from_array( + [ + SideEffect { value: 0, counter: 0 }, + SideEffect { value: 9123, counter: 1 } + ] + ); + + builder.validate(); +} diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_as_first_call.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_as_first_call.nr new file mode 100644 index 00000000000..852de8b834b --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_as_first_call.nr @@ -0,0 +1,238 @@ +use crate::tests::private_call_data_validator_builder::PrivateCallDataValidatorBuilder; +use dep::types::constants::MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL; +use dep::types::abis::call_request::CallRequest; + +impl PrivateCallDataValidatorBuilder { + pub fn new_first_call() -> Self { + PrivateCallDataValidatorBuilder::new_with_counter(0) + } + + pub fn split_calls(&mut self, counter: u32) { + self.private_call.public_inputs.min_revertible_side_effect_counter = counter; + self.first_revertible_private_call_request_index = self.private_call.private_call_stack.len(); + self.first_revertible_public_call_request_index = self.private_call.public_call_stack.len(); + } + + pub fn add_private_call_request(&mut self, counter_start: u32, counter_end: u32) { + let index = self.private_call.private_call_stack.len(); + self.private_call.append_private_call_requests(1, false); + self.private_call.private_call_stack.storage[index].start_side_effect_counter = counter_start; + self.private_call.private_call_stack.storage[index].end_side_effect_counter = counter_end; + self.private_call.public_inputs.counter_end = counter_end + 1; + } + + pub fn add_public_call_request(&mut self, counter_start: u32) { + let index = self.private_call.public_call_stack.len(); + self.private_call.append_public_call_requests(1, false); + self.private_call.public_call_stack.storage[index].start_side_effect_counter = counter_start; + self.private_call.public_call_stack.storage[index].end_side_effect_counter = 0; + self.private_call.public_inputs.counter_end = counter_start + 1; + } +} + +#[test] +fn validate_as_first_call_regular_call_succeeds() { + let builder = PrivateCallDataValidatorBuilder::new(); + builder.validate_as_first_call(); +} + +#[test(should_fail_with="Users cannot make a static call")] +fn validate_as_first_call_static_call_fails() { + let builder = PrivateCallDataValidatorBuilder::new().is_static_call(); + builder.validate_as_first_call(); +} + +#[test(should_fail_with="Users cannot make a delegatecall")] +fn validate_as_first_call_delegate_call_fails() { + let builder = PrivateCallDataValidatorBuilder::new().is_delegate_call(); + builder.validate_as_first_call(); +} + +/** + * Splitting call requests. + */ + +#[test] +fn validate_as_first_call_split_private_calls_succeeds() { + let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); + + builder.add_private_call_request(20, 30); + builder.add_private_call_request(40, 50); + builder.split_calls(60); + builder.add_private_call_request(60, 70); + + builder.validate_as_first_call(); +} + +#[test] +fn validate_as_first_call_split_private_empty_revertible_succeeds() { + let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); + + builder.add_private_call_request(20, 30); + builder.add_private_call_request(40, 50); + builder.split_calls(51); + + builder.validate_as_first_call(); +} + +#[test] +fn validate_as_first_call_split_private_empty_non_revertible_succeeds() { + let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); + + builder.split_calls(20); + builder.add_private_call_request(20, 30); + builder.add_private_call_request(40, 50); + + builder.validate_as_first_call(); +} + +#[test] +fn validate_as_first_call_split_private_full_non_revertible_succeeds() { + let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); + + builder.private_call.append_private_call_requests(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, false); + builder.split_calls(builder.private_call.public_inputs.counter_end); + + builder.validate_as_first_call(); +} + +#[test] +fn validate_as_first_call_split_private_calls_less_than_first_revertible_success() { + let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); + + builder.add_private_call_request(20, 30); + builder.add_private_call_request(40, 50); + // Tweak the counter to be less than the start counter of the first revertible call. + builder.split_calls(59); + builder.add_private_call_request(60, 70); + + builder.validate_as_first_call(); +} + +#[test(should_fail_with="min_revertible_side_effect_counter must be greater than the end counter of the last non revertible call")] +fn validate_as_first_call_split_private_calls_less_than_last_non_revertible_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); + + builder.add_private_call_request(20, 30); + builder.add_private_call_request(40, 50); + // Tweak the counter to be less than the end counter of the last non-revertible call. + builder.split_calls(49); + builder.add_private_call_request(60, 70); + + builder.validate_as_first_call(); +} + +#[test(should_fail_with="min_revertible_side_effect_counter must be greater than the end counter of the last non revertible call")] +fn validate_as_first_call_split_private_calls_equal_last_non_revertible_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); + + builder.add_private_call_request(20, 30); + builder.add_private_call_request(40, 50); + // Tweak the counter to equal the end counter of the last non-revertible call. + builder.split_calls(50); + + builder.validate_as_first_call(); +} + +#[test(should_fail_with="min_revertible_side_effect_counter must be less than or equal to the start counter of the first revertible call")] +fn validate_as_first_call_split_private_calls_greater_than_first_revertible_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); + + builder.add_private_call_request(20, 30); + builder.add_private_call_request(40, 50); + // Tweak the counter to be greater than the start counter of the first revertible call. + builder.split_calls(61); + builder.add_private_call_request(60, 70); + + builder.validate_as_first_call(); +} + +#[test] +fn validate_as_first_call_split_private_calls_0_succeeds() { + let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); + + // Set the counter to be 0. + builder.split_calls(0); + builder.add_private_call_request(20, 30); + builder.add_private_call_request(40, 50); + + builder.validate_as_first_call(); +} + +#[test(should_fail_with="min_revertible_side_effect_counter must be greater than the end counter of the last non revertible call")] +fn validate_as_first_call_split_private_calls_0_wrong_hint_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); + + builder.split_calls(0); + // Set the index hint to be 1. + builder.first_revertible_private_call_request_index = 1; + builder.add_private_call_request(20, 30); + builder.add_private_call_request(40, 50); + + builder.validate_as_first_call(); +} + +#[test(should_fail_with="min_revertible_side_effect_counter must be less than or equal to the start counter of the first revertible call")] +fn validate_as_first_call_split_private_calls_index_hint_greater_than_len_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); + + builder.add_private_call_request(20, 30); + builder.add_private_call_request(40, 50); + builder.split_calls(51); + // Increase the index by 1. + builder.first_revertible_private_call_request_index += 1; + + builder.validate_as_first_call(); +} + +#[test] +fn validate_as_first_call_split_public_calls_succeeds() { + let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); + + builder.add_public_call_request(20); + builder.add_public_call_request(30); + builder.split_calls(40); + builder.add_public_call_request(40); + + builder.validate_as_first_call(); +} + +#[test(should_fail_with="min_revertible_side_effect_counter must be greater than the counter of the last non revertible call")] +fn validate_as_first_call_split_public_calls_less_than_last_non_revertible_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); + + builder.add_public_call_request(20); + builder.add_public_call_request(30); + // Tweak the counter to be less than the end counter of the last non-revertible call. + builder.split_calls(29); + builder.add_public_call_request(40); + + builder.validate_as_first_call(); +} + +#[test] +fn validate_as_first_call_split_private_public_mix_succeeds() { + let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); + + builder.add_private_call_request(20, 30); + builder.add_public_call_request(40); + builder.split_calls(50); + builder.add_public_call_request(50); + builder.add_private_call_request(60, 70); + + builder.validate_as_first_call(); +} + +#[test(should_fail_with="min_revertible_side_effect_counter must be less than or equal to the counter of the first revertible call")] +fn validate_as_first_call_split_private_public_mix_falls_in_revertible_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); + + builder.add_private_call_request(20, 30); + builder.add_public_call_request(40); + // Tweak the counter to be greater than the start counter of the next call. + builder.split_calls(51); + builder.add_public_call_request(50); + builder.add_private_call_request(60, 70); + + builder.validate_as_first_call(); +} diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_call.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_call.nr new file mode 100644 index 00000000000..947e7895c6d --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_call.nr @@ -0,0 +1,98 @@ +use crate::tests::private_call_data_validator_builder::PrivateCallDataValidatorBuilder; +use dep::types::{ + abis::{note_hash::NoteHash, nullifier::Nullifier, side_effect::SideEffect}, address::EthAddress, + messaging::l2_to_l1_message::L2ToL1Message +}; + +#[test] +fn validate_call_is_regular_succeeds() { + let builder = PrivateCallDataValidatorBuilder::new(); + builder.validate(); +} + +#[test(should_fail_with="call stack storage address does not match expected contract address")] +fn validate_call_is_regular_mismatch_storage_contract_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + // Change the storage contract address to be a different value. + builder.private_call.public_inputs.call_context.storage_contract_address.inner += 1; + + builder.validate(); +} + +#[test] +fn validate_call_is_delegate_succeeds() { + let builder = PrivateCallDataValidatorBuilder::new().is_delegate_call(); + builder.validate(); +} + +#[test(should_fail_with="current contract address must not match storage contract address for delegate calls")] +fn validate_call_is_delegate_call_from_same_contract_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new().is_delegate_call(); + + // Change the caller's storage contract address to be the same as the contract address. + builder.private_call.public_inputs.call_context.storage_contract_address = builder.private_call.contract_address; + + builder.validate(); +} + +#[test] +fn validate_call_is_static_succeeds() { + let mut builder = PrivateCallDataValidatorBuilder::new().is_static_call(); + builder.validate(); +} + +#[test(should_fail_with="call stack storage address does not match expected contract address")] +fn validate_call_is_static_mismatch_storage_contract_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new().is_static_call(); + + // Change the storage contract address to be a different value. + builder.private_call.public_inputs.call_context.storage_contract_address.inner += 1; + + builder.validate(); +} + +#[test(should_fail_with="new_note_hashes must be empty for static calls")] +fn validate_call_is_static_creating_note_hashes_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new().is_static_call(); + + builder.private_call.public_inputs.new_note_hashes.push(NoteHash { value: 1, counter: 0 }); + + builder.validate(); +} + +#[test(should_fail_with="new_nullifiers must be empty for static calls")] +fn validate_call_is_static_creating_nullifiers_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new().is_static_call(); + + builder.private_call.public_inputs.new_nullifiers.push(Nullifier { value: 1, counter: 0, note_hash: 0 }); + + builder.validate(); +} + +#[test(should_fail_with="new_l2_to_l1_msgs must be empty for static calls")] +fn validate_call_is_static_creating_l2_to_l1_msgs_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new().is_static_call(); + + builder.private_call.public_inputs.new_l2_to_l1_msgs.push(L2ToL1Message { recipient: EthAddress::from_field(6), content: 9123, counter: 0 }); + + builder.validate(); +} + +#[test(should_fail_with="encrypted_logs_hashes must be empty for static calls")] +fn validate_call_is_static_creating_encrypted_logs_hashes_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new().is_static_call(); + + builder.private_call.public_inputs.encrypted_logs_hashes.push(SideEffect { value: 9123, counter: 1 }); + + builder.validate(); +} + +#[test(should_fail_with="unencrypted_logs_hashes must be empty for static calls")] +fn validate_call_is_static_creating_unencrypted_logs_hashes_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new().is_static_call(); + + builder.private_call.public_inputs.unencrypted_logs_hashes.push(SideEffect { value: 9123, counter: 1 }); + + builder.validate(); +} diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_call_requests.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_call_requests.nr new file mode 100644 index 00000000000..8747c02df9d --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_call_requests.nr @@ -0,0 +1,282 @@ +use crate::tests::private_call_data_validator_builder::PrivateCallDataValidatorBuilder; +use dep::types::abis::call_request::CallRequest; + +/** + * validate_private_call_requests + */ + +#[test] +fn validate_private_call_requests_succeeds() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.append_private_call_requests(2, false); + + builder.validate(); +} + +#[test] +fn validate_private_call_requests_delegate_calls_succeeds() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.append_private_call_requests(2, true); + + builder.validate(); +} + +#[test(should_fail_with="call stack hash does not match call request hash")] +fn validate_private_call_requests_incorrect_hash_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.append_private_call_requests(2, false); + let mut call_request = builder.private_call.private_call_stack.pop(); + // Change the hash to be a different value. + call_request.hash += 1; + builder.private_call.private_call_stack.push(call_request); + + builder.validate(); +} + +#[test(should_fail_with="invalid caller")] +fn validate_private_call_requests_incorrect_caller_address_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.append_private_call_requests(1, false); + let mut call_request = builder.private_call.private_call_stack.pop(); + // Change the caller contract address to be a different value. + call_request.caller_contract_address.inner += 1; + builder.private_call.private_call_stack.push(call_request); + + builder.validate(); +} + +#[test(should_fail_with="invalid caller")] +fn validate_private_call_requests_incorrect_caller_storage_contract_address_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.append_private_call_requests(1, true); + let mut call_request = builder.private_call.private_call_stack.pop(); + // Change the storage contract to be a different value. + call_request.caller_context.storage_contract_address.inner += 1; + builder.private_call.private_call_stack.push(call_request); + + builder.validate(); +} + +#[test(should_fail_with="invalid caller")] +fn validate_private_call_requests_incorrect_caller_msg_sender_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.append_private_call_requests(1, true); + let mut call_request = builder.private_call.private_call_stack.pop(); + // Change the msg_sender to be a different value. + call_request.caller_context.msg_sender.inner += 1; + builder.private_call.private_call_stack.push(call_request); + + builder.validate(); +} + +#[test(should_fail_with="call requests length does not match the expected length")] +fn validate_private_call_requests_fewer_hashes_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.append_private_call_requests(2, false); + // Remove one call stack item hash. + let _ = builder.private_call.public_inputs.private_call_stack_hashes.pop(); + + builder.validate(); +} + +#[test(should_fail_with="call stack hash does not match call request hash")] +fn validate_private_call_requests_more_hashes_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.append_private_call_requests(2, false); + // Add one random call stack item hash. + builder.private_call.public_inputs.private_call_stack_hashes.push(9123); + + builder.validate(); +} + +/** + * validate_public_call_requests + */ + +#[test] +fn validate_public_call_requests_succeeds() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.append_public_call_requests(2, false); + + builder.validate(); +} + +#[test] +fn validate_public_call_requests_delegate_calls_succeeds() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.append_public_call_requests(2, true); + + builder.validate(); +} + +#[test(should_fail_with="call stack hash does not match call request hash")] +fn validate_public_call_requests_incorrect_hash_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.append_public_call_requests(2, false); + let mut call_request = builder.private_call.public_call_stack.pop(); + // Change the hash to be a different value. + call_request.hash += 1; + builder.private_call.public_call_stack.push(call_request); + + builder.validate(); +} + +#[test(should_fail_with="invalid caller")] +fn validate_public_call_requests_incorrect_caller_address_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.append_public_call_requests(1, false); + let mut call_request = builder.private_call.public_call_stack.pop(); + // Change the caller contract address to be a different value. + call_request.caller_contract_address.inner += 1; + builder.private_call.public_call_stack.push(call_request); + + builder.validate(); +} + +#[test(should_fail_with="invalid caller")] +fn validate_public_call_requests_incorrect_caller_storage_contract_address_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.append_public_call_requests(1, true); + let mut call_request = builder.private_call.public_call_stack.pop(); + // Change the storage contract to be a different value. + call_request.caller_context.storage_contract_address.inner += 1; + builder.private_call.public_call_stack.push(call_request); + + builder.validate(); +} + +#[test(should_fail_with="invalid caller")] +fn validate_public_call_requests_incorrect_caller_msg_sender_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.append_public_call_requests(1, true); + let mut call_request = builder.private_call.public_call_stack.pop(); + // Change the msg_sender to be a different value. + call_request.caller_context.msg_sender.inner += 1; + builder.private_call.public_call_stack.push(call_request); + + builder.validate(); +} + +#[test(should_fail_with="call requests length does not match the expected length")] +fn validate_public_call_requests_fewer_hashes_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.append_public_call_requests(2, false); + // Remove one call stack item hash. + let _ = builder.private_call.public_inputs.public_call_stack_hashes.pop(); + + builder.validate(); +} + +#[test(should_fail_with="call stack hash does not match call request hash")] +fn validate_public_call_requests_more_hashes_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.append_public_call_requests(2, false); + // Add one random call stack item hash. + builder.private_call.public_inputs.public_call_stack_hashes.push(9123); + + builder.validate(); +} + +/** + * validate_teardown_call_request + */ + +#[test] +fn validate_teardown_call_request_succeeds() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.add_teaddown_call_request(false); + + builder.validate(); +} + +#[test] +fn validate_teardown_call_request_delegate_calls_succeeds() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.add_teaddown_call_request(true); + + builder.validate(); +} + +#[test(should_fail_with="call stack hash does not match call request hash")] +fn validate_teardown_call_request_incorrect_hash_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.add_teaddown_call_request(true); + // Change the hash to be a different value. + builder.private_call.public_teardown_call_request.hash += 1; + + builder.validate(); +} + +#[test(should_fail_with="invalid caller")] +fn validate_teardown_call_request_incorrect_caller_address_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.add_teaddown_call_request(true); + // Change the caller contract address to be a different value. + builder.private_call.public_teardown_call_request.caller_contract_address.inner += 1; + + builder.validate(); +} + +#[test(should_fail_with="invalid caller")] +fn validate_teardown_call_request_incorrect_caller_storage_contract_address_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.add_teaddown_call_request(true); + // Change the storage contract to be a different value. + builder.private_call.public_teardown_call_request.caller_context.storage_contract_address.inner += 1; + + builder.validate(); +} + +#[test(should_fail_with="invalid caller")] +fn validate_teardown_call_request_incorrect_caller_msg_sender_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.add_teaddown_call_request(true); + // Change the msg_sender to be a different value. + builder.private_call.public_teardown_call_request.caller_context.msg_sender.inner += 1; + + builder.validate(); +} + +#[test(should_fail_with="call requests length does not match the expected length")] +fn validate_teardown_call_request_fewer_hashes_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.add_teaddown_call_request(true); + // Remove the call stack item hash. + builder.private_call.public_inputs.public_teardown_function_hash = 0; + + builder.validate(); +} + +#[test(should_fail_with="call stack hash does not match call request hash")] +fn validate_teardown_call_request_more_hashes_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.add_teaddown_call_request(true); + // Remove the call request. + builder.private_call.public_teardown_call_request = CallRequest::empty(); + + builder.validate(); +} diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_contract_address.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_contract_address.nr new file mode 100644 index 00000000000..9e9228c6c21 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_contract_address.nr @@ -0,0 +1,62 @@ +use crate::tests::private_call_data_validator_builder::PrivateCallDataValidatorBuilder; +use dep::types::address::AztecAddress; + +#[test(should_fail_with="contract address cannot be zero")] +fn validate_contract_address_zero_storage_contract_address_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + // Set (storage) contract_address to 0 + builder.private_call.contract_address = AztecAddress::zero(); + builder.private_call.public_inputs.call_context.storage_contract_address = AztecAddress::zero(); + + builder.validate(); +} + +#[test(should_fail_with="computed contract address does not match expected one")] +fn validate_contract_address_incorrect_function_leaf_index_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + // Set the leaf index of the function leaf to a wrong value (the correct value + 1). + let leaf_index = builder.private_call.function_leaf_membership_witness.leaf_index; + builder.private_call.function_leaf_membership_witness.leaf_index = leaf_index + 1; + + builder.validate(); +} + +#[test(should_fail_with="computed contract address does not match expected one")] +fn validate_contract_address_incorrect_function_leaf_sibling_path_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + // Set the first value of the sibling path to a wrong value (the correct value + 1). + let sibling_path_0 = builder.private_call.function_leaf_membership_witness.sibling_path[0]; + builder.private_call.function_leaf_membership_witness.sibling_path[0] = sibling_path_0 + 1; + + builder.validate(); +} + +#[test(should_fail_with="computed contract address does not match expected one")] +fn validate_contract_address_incorrect_contract_class_preimage_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.contract_class_artifact_hash = builder.private_call.contract_class_artifact_hash + 1; + + builder.validate(); +} + +#[test(should_fail_with="computed contract address does not match expected one")] +fn validate_contract_address_incorrect_partial_address_preimage_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.salted_initialization_hash.inner = builder.private_call.salted_initialization_hash.inner + 1; + + builder.validate(); +} + +#[test(should_fail_with="computed contract address does not match expected one")] +fn validate_contract_address_incorrect_address_preimage_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.public_keys_hash.inner = builder.private_call.public_keys_hash.inner + 1; + + builder.validate(); +} diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_counters.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_counters.nr new file mode 100644 index 00000000000..d18493899b7 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_counters.nr @@ -0,0 +1,227 @@ +use crate::tests::private_call_data_validator_builder::PrivateCallDataValidatorBuilder; + +/** + * Private call. + */ + +#[test] +fn validate_counters_private_call_succeeds() { + let builder = PrivateCallDataValidatorBuilder::new_with_counter(23); + builder.validate(); +} + +#[test] +fn validate_counters_private_call_from_0_counter_succeeds() { + let builder = PrivateCallDataValidatorBuilder::new_with_counter(0); + builder.validate(); +} + +#[test(should_fail_with="private call has incorrect counter range")] +fn validate_counters_private_call_no_counter_range_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.public_inputs.counter_end = builder.private_call.public_inputs.counter_start; + + builder.validate(); +} + +#[test(should_fail_with="private call has incorrect counter range")] +fn validate_counters_private_call_negative_call_counter_range_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.public_inputs.counter_end = builder.private_call.public_inputs.counter_start - 1; + + builder.validate(); +} + +/** + * Note hashes + */ + +#[test] +fn validate_counters_note_hashes_succeeds() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.public_inputs.append_new_note_hashes(2); + + builder.validate(); +} + +#[test(should_fail_with="counter must be larger than the counter of the previous item")] +fn validate_counters_note_hash_counter_same_as_call_counter_start_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.public_inputs.append_new_note_hashes(1); + // Tweak the counter of the first note hash to EQUAL the start counter of the call. + builder.private_call.public_inputs.new_note_hashes.storage[0].counter = builder.private_call.public_inputs.counter_start; + + builder.validate(); +} + +#[test(should_fail_with="counter must be larger than the counter of the previous item")] +fn validate_counters_note_hash_counter_smaller_than_call_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.public_inputs.append_new_note_hashes(1); + // Tweak the counter of the first note hash to be LESS than the start counter of the call. + builder.private_call.public_inputs.new_note_hashes.storage[0].counter = builder.private_call.public_inputs.counter_start - 1; + + builder.validate(); +} + +#[test(should_fail_with="counter must be larger than the counter of the previous item")] +fn validate_counters_note_hash_identical_counters_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.public_inputs.append_new_note_hashes(2); + let counter_start = builder.private_call.public_inputs.counter_start; + // Tweak the counter of the second note hash to EQUAL the counter of the first note hash. + builder.private_call.public_inputs.new_note_hashes.storage[0].counter = counter_start + 1; + builder.private_call.public_inputs.new_note_hashes.storage[1].counter = counter_start + 1; + + builder.validate(); +} + +#[test(should_fail_with="counter must be larger than the counter of the previous item")] +fn validate_counters_note_hash_unordered_counters_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.public_inputs.append_new_note_hashes(2); + let counter_start = builder.private_call.public_inputs.counter_start; + // Tweak the counter of the second note hash to be LESS than the counter of the first note hash. + builder.private_call.public_inputs.new_note_hashes.storage[0].counter = counter_start + 2; + builder.private_call.public_inputs.new_note_hashes.storage[1].counter = counter_start + 1; + + builder.validate(); +} + +#[test(should_fail_with="counter must be smaller than the end counter of the call")] +fn validate_counters_note_hash_counter_larger_than_call_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.public_inputs.append_new_note_hashes(2); + // Tweak the counter of the second note hash to be GREATER than the end counter of the call. + builder.private_call.public_inputs.new_note_hashes.storage[1].counter = builder.private_call.public_inputs.counter_end + 1; + + builder.validate(); +} + +#[test(should_fail_with="counter must be smaller than the end counter of the call")] +fn validate_counters_note_hash_counter_same_as_call_counter_end_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.public_inputs.append_new_note_hashes(2); + // Tweak the counter of the second note hash to EQUAL the end counter of the call. + builder.private_call.public_inputs.new_note_hashes.storage[1].counter = builder.private_call.public_inputs.counter_end; + + builder.validate(); +} + +/** + * Private call requests. + */ + +#[test] +fn validate_counters_private_call_requests_succeeds() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.append_private_call_requests(2, false); + + builder.validate(); +} + +#[test(should_fail_with="start counter must be larger than the end counter of the previous call")] +fn validate_counters_private_call_requests_less_than_call_start_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.append_private_call_requests(1, false); + // Tweak the start counter of the first nested call to be LESS than the start counter of the call. + let counter_start = builder.private_call.public_inputs.counter_start; + builder.private_call.private_call_stack.storage[0].start_side_effect_counter = counter_start - 1; + + builder.validate(); +} + +#[test(should_fail_with="start counter must be larger than the end counter of the previous call")] +fn validate_counters_private_call_requests_equal_call_start_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.append_private_call_requests(1, false); + // Tweak the start counter of the call to EQUAL the start counter of the first nested call. + let counter_start = builder.private_call.public_inputs.counter_start; + builder.private_call.private_call_stack.storage[0].start_side_effect_counter = counter_start; + + builder.validate(); +} + +#[test(should_fail_with="start counter must be larger than the end counter of the previous call")] +fn validate_counters_private_call_requests_less_than_previous_end_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.append_private_call_requests(2, false); + // Tweak the start counter of the second nested call to be LESS than the end counter of the first nested call. + let counter_end = builder.private_call.private_call_stack.get(0).end_side_effect_counter; + builder.private_call.private_call_stack.storage[1].start_side_effect_counter = counter_end - 1; + + builder.validate(); +} + +#[test(should_fail_with="start counter must be larger than the end counter of the previous call")] +fn validate_counters_private_call_requests_same_as_previous_end_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.append_private_call_requests(2, false); + // Tweak the start counter of the second nested call to EQUAL the end counter of the first nested call. + let counter_end = builder.private_call.private_call_stack.get(0).end_side_effect_counter; + builder.private_call.private_call_stack.storage[1].start_side_effect_counter = counter_end; + + builder.validate(); +} + +#[test(should_fail_with="nested call has incorrect counter range")] +fn validate_counters_private_call_requests_end_less_than_start_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.append_private_call_requests(1, false); + // Tweak the end counter of the first nested call to be LESS than its start counter. + let counter_start = builder.private_call.private_call_stack.get(0).start_side_effect_counter; + builder.private_call.private_call_stack.storage[0].end_side_effect_counter = counter_start - 1; + + builder.validate(); +} + +#[test(should_fail_with="nested call has incorrect counter range")] +fn validate_counters_private_call_requests_end_equal_start_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.append_private_call_requests(1, false); + // Tweak the end counter of the first nested call to EQUAL its start counter. + let counter_start = builder.private_call.private_call_stack.get(0).start_side_effect_counter; + builder.private_call.private_call_stack.storage[0].end_side_effect_counter = counter_start; + + builder.validate(); +} + +#[test(should_fail_with="end counter must be smaller than the end counter of the parent call")] +fn validate_counters_private_call_requests_greater_than_call_end_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.append_private_call_requests(1, false); + // Tweak the end counter of the nested call to be GREATER than the end counter of the call. + let counter_end = builder.private_call.public_inputs.counter_end; + builder.private_call.private_call_stack.storage[0].end_side_effect_counter = counter_end + 1; + + builder.validate(); +} + +#[test(should_fail_with="end counter must be smaller than the end counter of the parent call")] +fn validate_counters_private_call_requests_equal_call_end_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new(); + + builder.private_call.append_private_call_requests(1, false); + // Tweak the end counter of the nested call to EQUAL the end counter of the call. + let counter_end = builder.private_call.public_inputs.counter_end; + builder.private_call.private_call_stack.storage[0].end_side_effect_counter = counter_end; + + builder.validate(); +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/call_request.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/call_request.nr index fe4a440a52d..32e56c9511c 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/call_request.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/call_request.nr @@ -1,9 +1,8 @@ -use crate::address::AztecAddress; use dep::std::cmp::Eq; -use crate::traits::{Empty, Serialize, Deserialize}; -use crate::abis::caller_context::CallerContext; -use crate::constants::CALL_REQUEST_LENGTH; -use crate::utils::reader::Reader; +use crate::{ + abis::{caller_context::CallerContext, side_effect::Ordered}, address::AztecAddress, + constants::CALL_REQUEST_LENGTH, traits::{Empty, Serialize, Deserialize}, utils::reader::Reader +}; struct CallRequest { hash: Field, @@ -13,6 +12,12 @@ struct CallRequest { end_side_effect_counter: u32, } +impl Ordered for CallRequest { + fn counter(self) -> u32 { + self.start_side_effect_counter + } +} + impl Eq for CallRequest { fn eq(self, call_request: CallRequest) -> bool { (call_request.hash == self.hash) diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/note_hash.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/note_hash.nr index a41f3daa1cc..9155ab0ee39 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/note_hash.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/note_hash.nr @@ -11,6 +11,12 @@ struct NoteHash { counter: u32, } +impl Ordered for NoteHash { + fn counter(self) -> u32 { + self.counter + } +} + impl Eq for NoteHash { fn eq(self, other: NoteHash) -> bool { (self.value == other.value) diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/nullifier.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/nullifier.nr index b7f95facb3c..35578309de5 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/nullifier.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/nullifier.nr @@ -10,6 +10,12 @@ struct Nullifier { note_hash: Field, } +impl Ordered for Nullifier { + fn counter(self) -> u32 { + self.counter + } +} + impl OrderedValue for Nullifier { fn value(self) -> Field { self.value diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/read_request.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/read_request.nr index c8a0286ce3e..a7fa741e761 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/read_request.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/read_request.nr @@ -1,5 +1,5 @@ use crate::{ - traits::{Empty, Serialize, Deserialize}, address::AztecAddress, + abis::side_effect::Ordered, traits::{Empty, Serialize, Deserialize}, address::AztecAddress, constants::{READ_REQUEST_LENGTH, SCOPED_READ_REQUEST_LEN}, utils::{arrays::array_concat, reader::Reader} }; @@ -10,6 +10,12 @@ struct ReadRequest { counter: u32, } +impl Ordered for ReadRequest { + fn counter(self) -> u32 { + self.counter + } +} + impl Eq for ReadRequest { fn eq(self, read_request: ReadRequest) -> bool { (self.value == read_request.value) diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/messaging/l2_to_l1_message.nr b/noir-projects/noir-protocol-circuits/crates/types/src/messaging/l2_to_l1_message.nr index a16cbb1f153..8168fbf739a 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/messaging/l2_to_l1_message.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/messaging/l2_to_l1_message.nr @@ -11,6 +11,12 @@ struct L2ToL1Message { counter: u32, } +impl Ordered for L2ToL1Message { + fn counter(self) -> u32 { + self.counter + } +} + impl Empty for L2ToL1Message { fn empty() -> Self { Self { diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr index c8d4f452bc1..7f547e5b351 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixture_builder.nr @@ -185,7 +185,7 @@ impl FixtureBuilder { validation_requests.finish() } - pub fn to_private_circuit_public_inputs(self) -> PrivateKernelCircuitPublicInputs { + pub fn to_private_kernel_circuit_public_inputs(self) -> PrivateKernelCircuitPublicInputs { let end = self.to_private_accumulated_data(); let validation_requests = self.to_validation_requests(); let constants = self.to_constant_data(); @@ -201,7 +201,7 @@ impl FixtureBuilder { } pub fn to_private_kernel_data(self) -> PrivateKernelData { - let public_inputs = self.to_private_circuit_public_inputs(); + let public_inputs = self.to_private_kernel_circuit_public_inputs(); PrivateKernelData { public_inputs, proof: self.proof, vk: self.vk, vk_index: self.vk_index, vk_path: self.vk_path } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr index 68154e67806..5268ac1eea6 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr @@ -36,7 +36,11 @@ struct PrivateCallDataBuilder { impl PrivateCallDataBuilder { pub fn new() -> Self { - let public_inputs = PrivateCircuitPublicInputsBuilder::new(); + PrivateCallDataBuilder::new_with_counter(0) + } + + pub fn new_with_counter(counter: u32) -> Self { + let public_inputs = PrivateCircuitPublicInputsBuilder::new_with_counter(counter); let contract_data = fixtures::contracts::default_contract; let contract_function = fixtures::contract_functions::default_private_function; @@ -63,14 +67,12 @@ impl PrivateCallDataBuilder { } pub fn is_delegate_call(&mut self) -> Self { - self.public_inputs.call_context.is_delegate_call = true; - self.public_inputs.call_context.storage_contract_address = fixtures::contracts::parent_contract.address; - self.public_inputs.call_context.msg_sender = fixtures::MSG_SENDER; + let _ = self.public_inputs.is_delegate_call(); *self } pub fn is_static_call(&mut self) -> Self { - self.public_inputs.call_context.is_static_call = true; + let _ = self.public_inputs.is_static_call(); *self } @@ -99,85 +101,39 @@ impl PrivateCallDataBuilder { hash, caller_contract_address: self.public_inputs.call_context.msg_sender, caller_context, - start_side_effect_counter: 0, - end_side_effect_counter: 0 + start_side_effect_counter: self.public_inputs.counter_start, + end_side_effect_counter: self.public_inputs.counter_end } } pub fn append_private_call_requests(&mut self, num_requests: u64, is_delegate_call: bool) { - let (hashes, call_requests) = self.generate_call_requests(self.private_call_stack, num_requests, is_delegate_call); - self.public_inputs.private_call_stack_hashes.extend_from_bounded_vec(hashes); - self.private_call_stack.extend_from_bounded_vec(call_requests); - } - - pub fn append_public_call_requests(&mut self, num_requests: u64, is_delegate_call: bool) { - let (hashes, call_requests) = self.generate_call_requests(self.public_call_stack, num_requests, is_delegate_call); - self.public_inputs.public_call_stack_hashes.extend_from_bounded_vec(hashes); - self.public_call_stack.extend_from_bounded_vec(call_requests); - } - - pub fn add_teaddown_call_request(&mut self, is_delegate_call: bool) { - let hash = 99887654; - self.public_inputs.public_teardown_function_hash = hash; - self.public_teardown_call_request = self.generate_call_request(hash, is_delegate_call); - } - - fn generate_call_requests( - self, - requests: BoundedVec, - num_requests: u64, - is_delegate_call: bool - ) -> (BoundedVec, BoundedVec) { - let value_offset = requests.len(); - let mut call_requests: BoundedVec = BoundedVec::new(); - let mut hashes: BoundedVec = BoundedVec::new(); - let mut exceeded_len = false; - for i in 0..N { - exceeded_len |= i == num_requests; - if !exceeded_len { - // The default hash is its index + 7788. - let hash = (value_offset + 7788) as Field; - let request = self.generate_call_request(hash, is_delegate_call); - hashes.push(hash); - call_requests.push(request); + let hash_offset = 7070 + self.private_call_stack.len(); + for i in 0..self.private_call_stack.max_len() { + if i < num_requests { + let hash = (hash_offset + i) as Field; + let request = self.public_inputs.generate_call_request(hash, is_delegate_call); + self.private_call_stack.push(request); + self.public_inputs.add_private_call_request(hash); } } - (hashes, call_requests) } - fn generate_call_request(self, hash: Field, is_delegate_call: bool) -> CallRequest { - let mut caller_context = CallerContext::empty(); - if is_delegate_call { - let call_context = self.public_inputs.call_context; - caller_context.msg_sender = call_context.msg_sender; - caller_context.storage_contract_address = call_context.storage_contract_address; - } - CallRequest { - hash, - caller_contract_address: self.contract_address, - caller_context, - // TODO: populate these - start_side_effect_counter: 0, - end_side_effect_counter: 0 + pub fn append_public_call_requests(&mut self, num_requests: u64, is_delegate_call: bool) { + let hash_offset = 7070 + self.public_call_stack.len() as Field; + for i in 0..self.public_call_stack.max_len() { + if i < num_requests { + let hash = hash_offset + i as Field; + let request = self.public_inputs.generate_call_request(hash, is_delegate_call); + self.public_call_stack.push(request); + self.public_inputs.add_public_call_request(hash); + } } } - pub fn set_tx_max_block_number(&mut self, max_block_number: u32) { - self.public_inputs.max_block_number = MaxBlockNumber::new(max_block_number); - } - - pub fn set_encrypted_logs(&mut self, hash: Field, preimages_length: Field) { - // Counter set as 0 for testing, like note read requests - let side_effect = SideEffect { value: hash, counter: 0 }; - self.public_inputs.encrypted_logs_hashes.push(side_effect); - self.public_inputs.encrypted_log_preimages_length += preimages_length; - } - - pub fn set_unencrypted_logs(&mut self, hash: Field, preimages_length: Field) { - // Counter set as 0 for testing, like note read requests - let side_effect = SideEffect { value: hash, counter: 0 }; - self.public_inputs.unencrypted_logs_hashes.push(side_effect); - self.public_inputs.unencrypted_log_preimages_length += preimages_length; + pub fn add_teaddown_call_request(&mut self, is_delegate_call: bool) { + let hash = 909090; + self.public_teardown_call_request = self.public_inputs.generate_call_request(hash, is_delegate_call); + self.public_inputs.add_teardown_call_request(hash); } fn build_call_stack_item(self) -> PrivateCallStackItem { diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_circuit_public_inputs_builder.nr index 0a47abc4014..20dd2efc32e 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_circuit_public_inputs_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_circuit_public_inputs_builder.nr @@ -1,8 +1,8 @@ use crate::{ abis::{ - call_context::CallContext, gas_settings::GasSettings, gas::Gas, max_block_number::MaxBlockNumber, - note_hash::NoteHash, nullifier::Nullifier, - nullifier_key_validation_request::NullifierKeyValidationRequest, + call_context::CallContext, call_request::CallRequest, caller_context::CallerContext, + gas_settings::GasSettings, gas::Gas, max_block_number::MaxBlockNumber, note_hash::NoteHash, + nullifier::Nullifier, nullifier_key_validation_request::NullifierKeyValidationRequest, private_circuit_public_inputs::PrivateCircuitPublicInputs, read_request::ReadRequest, side_effect::SideEffect }, @@ -21,6 +21,7 @@ use crate::{ }; struct PrivateCircuitPublicInputsBuilder { + contract_address: AztecAddress, call_context: CallContext, args_hash: Field, @@ -55,43 +56,147 @@ struct PrivateCircuitPublicInputsBuilder { version: Field, gas_settings: GasSettings, + + counter_start: u32, + counter_end: u32, } impl PrivateCircuitPublicInputsBuilder { pub fn new() -> Self { - let mut public_inputs = PrivateCircuitPublicInputsBuilder::empty(); + PrivateCircuitPublicInputsBuilder::new_with_counter(0) + } - let args_hash = 0; + pub fn new_with_counter(counter: u32) -> Self { + let mut public_inputs = PrivateCircuitPublicInputsBuilder::empty(); let contract_data = fixtures::contracts::default_contract; - let contract_function = fixtures::contract_functions::default_private_function; let function_data = contract_function.data; - let contract_address = contract_data.address; - let call_context = CallContext { + public_inputs.contract_address = contract_address; + + public_inputs.call_context = CallContext { msg_sender: fixtures::contracts::parent_contract.address, storage_contract_address: contract_address, function_selector: function_data.selector, is_delegate_call: false, is_static_call: false, - side_effect_counter: 0 + side_effect_counter: counter }; - public_inputs.call_context = call_context; - public_inputs.args_hash = args_hash; + public_inputs.chain_id = 0; public_inputs.version = 1; public_inputs.gas_settings = GasSettings::default(); - public_inputs.public_teardown_function_hash = 0; + public_inputs.counter_start = counter; + public_inputs.counter_end = counter + 1; public_inputs } + pub fn is_delegate_call(&mut self) -> Self { + self.call_context.is_delegate_call = true; + self.call_context.storage_contract_address = fixtures::contracts::parent_contract.address; + self.call_context.msg_sender = fixtures::MSG_SENDER; + *self + } + + pub fn is_static_call(&mut self) -> Self { + self.call_context.is_static_call = true; + *self + } + pub fn build_tx_context(self) -> TxContext { TxContext::new(self.chain_id, self.version, self.gas_settings) } + pub fn end_setup(&mut self) { + self.min_revertible_side_effect_counter = self.counter_end; + } + + pub fn set_tx_max_block_number(&mut self, max_block_number: u32) { + self.max_block_number = MaxBlockNumber::new(max_block_number); + } + + pub fn append_note_hash_read_requests(&mut self, num_reads: u64) { + let value_offset = self.note_hash_read_requests.len(); + for i in 0..self.note_hash_read_requests.max_len() { + if i < num_reads { + let read_request = ReadRequest { value: (value_offset + i + 987) as Field, counter: self.next_counter() }; + self.note_hash_read_requests.push(read_request); + } + } + } + + pub fn append_nullifier_read_requests(&mut self, num_reads: u64) { + let value_offset = self.nullifier_read_requests.len(); + for i in 0..self.nullifier_read_requests.max_len() { + if i < num_reads { + let read_request = ReadRequest { value: (value_offset + i + 3344) as Field, counter: self.next_counter() }; + self.nullifier_read_requests.push(read_request); + } + } + } + + pub fn add_new_note_hash(&mut self, value: Field) { + self.new_note_hashes.push(NoteHash { value, counter: self.next_counter() }); + } + + pub fn append_new_note_hashes(&mut self, count: u64) { + let value_offset = self.new_note_hashes.len(); + for i in 0..self.new_note_hashes.max_len() { + if i < count { + let mocked_value = 123123 + value_offset as Field; + self.add_new_note_hash(mocked_value); + } + } + } + + pub fn add_encrypted_log(&mut self, hash: Field, preimages_length: Field) { + let side_effect = SideEffect { value: hash, counter: self.next_counter() }; + self.encrypted_logs_hashes.push(side_effect); + self.encrypted_log_preimages_length += preimages_length; + } + + pub fn add_unencrypted_log(&mut self, hash: Field, preimages_length: Field) { + let side_effect = SideEffect { value: hash, counter: self.next_counter() }; + self.unencrypted_logs_hashes.push(side_effect); + self.unencrypted_log_preimages_length += preimages_length; + } + + pub fn generate_call_request(self, hash: Field, is_delegate_call: bool) -> CallRequest { + let mut caller_context = CallerContext::empty(); + if is_delegate_call { + caller_context.msg_sender = self.call_context.msg_sender; + caller_context.storage_contract_address = self.call_context.storage_contract_address; + } + CallRequest { + hash, + caller_contract_address: self.contract_address, + caller_context, + start_side_effect_counter: self.counter_end, + end_side_effect_counter: self.counter_end + 1 + } + } + + pub fn add_private_call_request(&mut self, hash: Field) { + let _ = self.next_counter(); // Increment for creating the call. + self.private_call_stack_hashes.push(hash); + let _ = self.next_counter(); // Increment for ending the call. + } + + pub fn add_public_call_request(&mut self, hash: Field) { + let _ = self.next_counter(); // Increment for creating the call + self.public_call_stack_hashes.push(hash); + let _ = self.next_counter(); // Increment for ending the call. + } + + pub fn add_teardown_call_request(&mut self, hash: Field) { + let _ = self.next_counter(); // Increment for creating the call + self.public_teardown_function_hash = hash; + let _ = self.next_counter(); // Increment for ending the call. + } + pub fn finish(self) -> PrivateCircuitPublicInputs { PrivateCircuitPublicInputs { call_context: self.call_context, @@ -109,8 +214,8 @@ impl PrivateCircuitPublicInputsBuilder { public_call_stack_hashes: self.public_call_stack_hashes.storage, public_teardown_function_hash: self.public_teardown_function_hash, new_l2_to_l1_msgs: self.new_l2_to_l1_msgs.storage, - start_side_effect_counter: self.call_context.side_effect_counter, - end_side_effect_counter: 10, + start_side_effect_counter: self.counter_start, + end_side_effect_counter: self.counter_end, encrypted_logs_hashes: self.encrypted_logs_hashes.storage, unencrypted_logs_hashes: self.unencrypted_logs_hashes.storage, encrypted_log_preimages_length: self.encrypted_log_preimages_length, @@ -119,11 +224,18 @@ impl PrivateCircuitPublicInputsBuilder { tx_context: self.build_tx_context() } } + + fn next_counter(&mut self) -> u32 { + let counter = self.counter_end; + self.counter_end += 1; + counter + } } impl Empty for PrivateCircuitPublicInputsBuilder { fn empty() -> Self { PrivateCircuitPublicInputsBuilder { + contract_address: AztecAddress::empty(), call_context: CallContext::empty(), args_hash: 0, returns_hash: 0, @@ -146,7 +258,9 @@ impl Empty for PrivateCircuitPublicInputsBuilder { historical_header: Header::empty(), chain_id: 0, version: 0, - gas_settings: GasSettings::empty() + gas_settings: GasSettings::empty(), + counter_start: 0, + counter_end: 0 } } } diff --git a/yarn-project/circuits.js/src/structs/kernel/private_kernel_init_circuit_private_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/private_kernel_init_circuit_private_inputs.ts index 5c1a65956ec..7262cc7b1b5 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_kernel_init_circuit_private_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_kernel_init_circuit_private_inputs.ts @@ -1,8 +1,29 @@ -import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { BufferReader, type Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; +import { MAX_NEW_NOTE_HASHES_PER_CALL } from '../../constants.gen.js'; import { TxRequest } from '../tx_request.js'; import { PrivateCallData } from './private_call_data.js'; -import { PrivateKernelInnerHints } from './private_kernel_inner_circuit_private_inputs.js'; + +export class PrivateKernelInitHints { + constructor( + public noteHashNullifierCounters: Tuple, + public firstRevertiblePrivateCallRequestIndex: number, + public firstRevertiblePublicCallRequestIndex: number, + ) {} + + toBuffer() { + return serializeToBuffer(this.noteHashNullifierCounters); + } + + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new PrivateKernelInitHints( + reader.readNumbers(MAX_NEW_NOTE_HASHES_PER_CALL), + reader.readNumber(), + reader.readNumber(), + ); + } +} /** * Input to the private kernel circuit - initial call. @@ -17,7 +38,7 @@ export class PrivateKernelInitCircuitPrivateInputs { * Private calldata corresponding to this iteration of the kernel. */ public privateCall: PrivateCallData, - public hints: PrivateKernelInnerHints, + public hints: PrivateKernelInitHints, ) {} /** @@ -38,7 +59,7 @@ export class PrivateKernelInitCircuitPrivateInputs { return new PrivateKernelInitCircuitPrivateInputs( reader.readObject(TxRequest), reader.readObject(PrivateCallData), - reader.readObject(PrivateKernelInnerHints), + reader.readObject(PrivateKernelInitHints), ); } } 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 1df2a44e2de..ba9787b5840 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -72,6 +72,7 @@ import { PrivateKernelCircuitPublicInputs, type PrivateKernelData, type PrivateKernelInitCircuitPrivateInputs, + type PrivateKernelInitHints, type PrivateKernelInnerCircuitPrivateInputs, type PrivateKernelInnerHints, type PrivateKernelTailCircuitPrivateInputs, @@ -175,6 +176,7 @@ import type { PrivateKernelCircuitPublicInputs as PrivateKernelCircuitPublicInputsNoir, PrivateKernelData as PrivateKernelDataNoir, PrivateKernelInitCircuitPrivateInputs as PrivateKernelInitCircuitPrivateInputsNoir, + PrivateKernelInitHints as PrivateKernelInitHintsNoir, PrivateKernelInnerCircuitPrivateInputs as PrivateKernelInnerCircuitPrivateInputsNoir, PrivateKernelInnerHints as PrivateKernelInnerHintsNoir, PrivateKernelTailCircuitPrivateInputs as PrivateKernelTailCircuitPrivateInputsNoir, @@ -1379,6 +1381,14 @@ export function mapPrivateKernelTailCircuitPublicInputsForPublicFromNoir( ); } +function mapPrivateKernelInitHintsToNoir(inputs: PrivateKernelInitHints): PrivateKernelInitHintsNoir { + return { + note_hash_nullifier_counters: mapTuple(inputs.noteHashNullifierCounters, mapNumberToNoir), + first_revertible_private_call_request_index: mapNumberToNoir(inputs.firstRevertiblePrivateCallRequestIndex), + first_revertible_public_call_request_index: mapNumberToNoir(inputs.firstRevertiblePublicCallRequestIndex), + }; +} + function mapPrivateKernelInnerHintsToNoir(inputs: PrivateKernelInnerHints): PrivateKernelInnerHintsNoir { return { note_hash_nullifier_counters: mapTuple(inputs.noteHashNullifierCounters, mapNumberToNoir), @@ -1391,7 +1401,7 @@ export function mapPrivateKernelInitCircuitPrivateInputsToNoir( return { tx_request: mapTxRequestToNoir(inputs.txRequest), private_call: mapPrivateCallDataToNoir(inputs.privateCall), - hints: mapPrivateKernelInnerHintsToNoir(inputs.hints), + hints: mapPrivateKernelInitHintsToNoir(inputs.hints), }; } diff --git a/yarn-project/pxe/src/kernel_prover/kernel_prover.ts b/yarn-project/pxe/src/kernel_prover/kernel_prover.ts index aa180e23b03..9048a6f9e6e 100644 --- a/yarn-project/pxe/src/kernel_prover/kernel_prover.ts +++ b/yarn-project/pxe/src/kernel_prover/kernel_prover.ts @@ -26,6 +26,7 @@ import { pushTestData } from '@aztec/foundation/testing'; import { type ExecutionResult, collectNoteHashLeafIndexMap, collectNullifiedNoteHashCounters } from '@aztec/simulator'; import { + buildPrivateKernelInitHints, buildPrivateKernelInnerHints, buildPrivateKernelTailHints, buildPrivateKernelTailOutputs, @@ -95,16 +96,21 @@ export class KernelProver { proofOutput.verificationKey, ); - const hints = buildPrivateKernelInnerHints( - currentExecution.callStackItem.publicInputs, - noteHashNullifierCounterMap, - ); - if (firstIteration) { + const hints = buildPrivateKernelInitHints( + currentExecution.callStackItem.publicInputs, + noteHashNullifierCounterMap, + privateCallRequests, + publicCallRequests, + ); const proofInput = new PrivateKernelInitCircuitPrivateInputs(txRequest, privateCallData, hints); pushTestData('private-kernel-inputs-init', proofInput); output = await this.proofCreator.createProofInit(proofInput); } else { + const hints = buildPrivateKernelInnerHints( + currentExecution.callStackItem.publicInputs, + noteHashNullifierCounterMap, + ); const previousVkMembershipWitness = await this.oracle.getVkMembershipWitness(output.verificationKey); const previousKernelData = new PrivateKernelData( output.publicInputs, diff --git a/yarn-project/pxe/src/kernel_prover/private_inputs_builders/build_private_kernel_init_hints.ts b/yarn-project/pxe/src/kernel_prover/private_inputs_builders/build_private_kernel_init_hints.ts new file mode 100644 index 00000000000..fb6a95f5fd9 --- /dev/null +++ b/yarn-project/pxe/src/kernel_prover/private_inputs_builders/build_private_kernel_init_hints.ts @@ -0,0 +1,39 @@ +import { + type CallRequest, + type MAX_NEW_NOTE_HASHES_PER_CALL, + type PrivateCircuitPublicInputs, + PrivateKernelInitHints, + countAccumulatedItems, +} from '@aztec/circuits.js'; +import { type Tuple } from '@aztec/foundation/serialize'; + +export function buildPrivateKernelInitHints( + publicInputs: PrivateCircuitPublicInputs, + noteHashNullifierCounterMap: Map, + privateCallRequests: CallRequest[], + publicCallRequests: CallRequest[], +) { + const nullifierCounters = publicInputs.newNoteHashes.map( + n => noteHashNullifierCounterMap.get(n.counter) ?? 0, + ) as Tuple; + + const minRevertibleCounter = publicInputs.minRevertibleSideEffectCounter; + let firstRevertiblePrivateCallRequestIndex = privateCallRequests.findIndex( + r => r.startSideEffectCounter >= minRevertibleCounter, + ); + if (firstRevertiblePrivateCallRequestIndex === -1) { + firstRevertiblePrivateCallRequestIndex = countAccumulatedItems(privateCallRequests); + } + let firstRevertiblePublicCallRequestIndex = publicCallRequests.findIndex( + r => r.startSideEffectCounter >= minRevertibleCounter, + ); + if (firstRevertiblePublicCallRequestIndex === -1) { + firstRevertiblePublicCallRequestIndex = countAccumulatedItems(publicCallRequests); + } + + return new PrivateKernelInitHints( + nullifierCounters, + firstRevertiblePrivateCallRequestIndex, + firstRevertiblePublicCallRequestIndex, + ); +} diff --git a/yarn-project/pxe/src/kernel_prover/private_inputs_builders/index.ts b/yarn-project/pxe/src/kernel_prover/private_inputs_builders/index.ts index ae00ec7a4f0..477ce51240f 100644 --- a/yarn-project/pxe/src/kernel_prover/private_inputs_builders/index.ts +++ b/yarn-project/pxe/src/kernel_prover/private_inputs_builders/index.ts @@ -1,3 +1,4 @@ +export { buildPrivateKernelInitHints } from './build_private_kernel_init_hints.js'; export { buildPrivateKernelInnerHints } from './build_private_kernel_inner_hints.js'; export { buildPrivateKernelTailHints } from './build_private_kernel_tail_hints.js'; export { buildPrivateKernelTailOutputs } from './build_private_kernel_tail_outputs.js'; diff --git a/yarn-project/simulator/src/client/private_execution.test.ts b/yarn-project/simulator/src/client/private_execution.test.ts index a106c825c6f..a09bfdbe780 100644 --- a/yarn-project/simulator/src/client/private_execution.test.ts +++ b/yarn-project/simulator/src/client/private_execution.test.ts @@ -836,7 +836,7 @@ describe('Private Execution test suite', () => { functionSelector: childSelector, isDelegateCall: false, isStaticCall: false, - sideEffectCounter: 1, + sideEffectCounter: 2, }), parentCallContext: CallContext.from({ msgSender: parentAddress, diff --git a/yarn-project/simulator/src/public/executor.ts b/yarn-project/simulator/src/public/executor.ts index 2576bdd29da..7404e15237a 100644 --- a/yarn-project/simulator/src/public/executor.ts +++ b/yarn-project/simulator/src/public/executor.ts @@ -82,7 +82,8 @@ async function executeTopLevelPublicFunctionAvm( for (const nullifier of executionContext.pendingNullifiers) { worldStateJournal.nullifiers.cache.appendSiloed(nullifier.value); } - worldStateJournal.trace.accessCounter = startSideEffectCounter; + // All the subsequent side effects will have a counter larger than the call's start counter. + worldStateJournal.trace.accessCounter = startSideEffectCounter + 1; const executionEnv = createAvmExecutionEnvironment( executionContext.execution,