From 8eae2d69cc452069c5a5724d499391cb345c5fef Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Mon, 13 May 2024 12:46:09 +0000 Subject: [PATCH 01/10] Validate counters. --- .../src/private_call_data_validator.nr | 143 +++- .../src/private_kernel_init.nr | 10 +- .../src/private_kernel_inner.nr | 8 +- .../crates/private-kernel-lib/src/tests.nr | 7 + .../private_call_data_validator_builder.nr | 760 +----------------- .../tests/validate_against_call_request.nr | 83 ++ .../src/tests/validate_against_tx_request.nr | 79 ++ .../src/tests/validate_arrays.nr | 136 ++++ .../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/private-kernel-lib/src/utils.nr | 1 + .../crates/types/src/abis/call_request.nr | 14 +- .../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 | 120 ++- 21 files changed, 1293 insertions(+), 869 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_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 noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/utils.nr 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 774b66b306e0..2fed3c5263b6 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,10 +50,51 @@ 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" + ); } struct ArrayLengths { @@ -86,6 +127,7 @@ impl PrivateCallDataValidator { self.validate_private_call_requests(); self.validate_public_call_requests(); self.validate_teardown_call_request(); + self.validate_counters(); } // Confirm that the TxRequest (user's intent) matches the private call being executed. @@ -205,19 +247,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 +269,79 @@ 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_incrementing_counter_ranges_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_counter_ranges_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 da6ef0cc4bac..716f0633a63f 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 @@ -92,13 +92,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 +133,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); 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 20376e9b83ab..f9b858a4815f 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 @@ -165,7 +165,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 +177,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); @@ -220,8 +220,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; 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 e92b7e1016a0..4f3680803ce4 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,8 @@ mod private_call_data_validator_builder; +mod validate_against_call_request; +mod validate_against_tx_request; +mod validate_arrays; +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 8802b64d81e4..be699832f236 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,13 +1,7 @@ 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 { @@ -16,7 +10,12 @@ struct PrivateCallDataValidatorBuilder { impl PrivateCallDataValidatorBuilder { pub fn new() -> Self { - let private_call = PrivateCallDataBuilder::new(); + 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 } } @@ -45,746 +44,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 000000000000..87dd96f84ed6 --- /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 000000000000..c86ed68de5fb --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_against_tx_request.nr @@ -0,0 +1,79 @@ +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); +} + +#[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); +} 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 000000000000..048511b151ca --- /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_call.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_call.nr new file mode 100644 index 000000000000..947e7895c6dd --- /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 000000000000..8747c02df9db --- /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 000000000000..9e9228c6c218 --- /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 000000000000..110a40025ff1 --- /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_privata_call_succeeds() { + let builder = PrivateCallDataValidatorBuilder::new_with_counter(23); + builder.validate(); +} + +#[test] +fn validate_counters_privata_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_privata_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_privata_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/private-kernel-lib/src/utils.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/utils.nr new file mode 100644 index 000000000000..f4079dcf613e --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/utils.nr @@ -0,0 +1 @@ +mod counter_range; 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 2c667c25f081..dad74d055b2d 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,8 +1,8 @@ -use crate::address::AztecAddress; use dep::std::cmp::Eq; -use crate::traits::{Empty, Serialize}; -use crate::abis::caller_context::CallerContext; -use crate::constants::CALL_REQUEST_LENGTH; +use crate::{ + abis::{caller_context::CallerContext, side_effect::Ordered}, address::AztecAddress, + constants::CALL_REQUEST_LENGTH, traits::{Empty, Serialize} +}; struct CallRequest { hash: Field, @@ -12,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 53a248718c20..e4eea3bf947b 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 da4c140d43d5..03b5e0c8a75d 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 6d3663354b05..02cbadd7bcdc 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 8f21f8e2c77f..4f1ad32e4d59 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 105a3fed3bb2..1f28fd85c71d 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 @@ -183,7 +183,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(); @@ -198,7 +198,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 68154e678067..5268ac1eea62 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 a8cc18978b80..90a547214c48 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, @@ -54,43 +55,123 @@ 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 set_tx_max_block_number(&mut self, max_block_number: u32) { + self.max_block_number = MaxBlockNumber::new(max_block_number); + } + + 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, @@ -107,8 +188,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, @@ -117,11 +198,18 @@ impl PrivateCircuitPublicInputsBuilder { tx_context: self.build_tx_context() } } + + pub 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, @@ -143,7 +231,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 } } } From 550f591bff0cec254170fa209a75127db85b263f Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Mon, 13 May 2024 15:48:41 +0000 Subject: [PATCH 02/10] Update fixtures. --- .../src/private_kernel_init.nr | 20 +++++++--------- .../src/private_kernel_inner.nr | 24 ++++++++----------- .../private_circuit_public_inputs_builder.nr | 20 ++++++++++++++++ 3 files changed, 38 insertions(+), 26 deletions(-) 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 716f0633a63f..5c6983e3a27b 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 @@ -144,10 +144,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 +153,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 +166,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 +175,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 f9b858a4815f..93dc6a3ebcf1 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(); } @@ -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]); 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 90a547214c48..85d2ea1d8e42 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 @@ -113,6 +113,26 @@ impl PrivateCircuitPublicInputsBuilder { 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() }); } From 71b9d8ef24a774a154d3a3bc9f343223c7b2e945 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Tue, 14 May 2024 09:56:32 +0000 Subject: [PATCH 03/10] Validate first call. --- .../src/private_call_data_validator.nr | 53 +++- .../src/private_kernel_init.nr | 12 +- .../crates/private-kernel-lib/src/tests.nr | 1 + .../private_call_data_validator_builder.nr | 16 +- .../src/tests/validate_against_tx_request.nr | 14 -- .../src/tests/validate_as_first_call.nr | 232 ++++++++++++++++++ .../private_circuit_public_inputs_builder.nr | 7 +- ...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 | 32 +++ .../private_inputs_builders/index.ts | 1 + 12 files changed, 393 insertions(+), 32 deletions(-) create mode 100644 noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_as_first_call.nr create mode 100644 yarn-project/pxe/src/kernel_prover/private_inputs_builders/build_private_kernel_init_hints.ts 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 2fed3c5263b6..f3370b3f2315 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 @@ -97,6 +97,27 @@ fn validate_incrementing_counter_ranges_within_range( ); } +fn validate_split_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 the start counter of the first revertible call" + ); + } +} + struct ArrayLengths { note_hash_read_requests: u64, nullifier_read_requests: u64, @@ -130,6 +151,33 @@ impl PrivateCallDataValidator { 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; + // Don't have to limit that the min_revertible_side_effect_counter has to fall in the counter range of the private call. + // It is valid as long as it does not fall in the middle of a call. + validate_split_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_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. pub fn validate_against_tx_request(self, tx_request: TxRequest) { let call_stack_item = self.data.call_stack_item; @@ -145,11 +193,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) { 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 5c6983e3a27b..2b7cdde6ff63 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 } } 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 4f3680803ce4..e2af8ade73b1 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 @@ -2,6 +2,7 @@ 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; 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 be699832f236..c76216a9635e 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 @@ -6,6 +6,8 @@ use dep::types::{ struct PrivateCallDataValidatorBuilder { private_call: PrivateCallDataBuilder, + first_revertible_private_call_request_index: u64, + first_revertible_public_call_request_index: u64 } impl PrivateCallDataValidatorBuilder { @@ -16,7 +18,11 @@ impl PrivateCallDataValidatorBuilder { pub fn new_with_counter(counter: u32) -> Self { let private_call = PrivateCallDataBuilder::new_with_counter(counter); - PrivateCallDataValidatorBuilder { private_call } + 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 { @@ -34,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); 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 index c86ed68de5fb..6c02f0bff56c 100644 --- 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 @@ -63,17 +63,3 @@ fn validate_against_tx_request_mismatch_version_fails() { 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); -} 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 000000000000..a99b9e04a968 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/tests/validate_as_first_call.nr @@ -0,0 +1,232 @@ +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 split_calls(&mut self) { + self.private_call.public_inputs.end_setup(); + 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, counter_end: 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 = counter_end; + self.private_call.public_inputs.counter_end = counter_end + 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(); +} + +#[test] +fn validate_as_first_call_split_private_calls_succeeds() { + let mut builder = PrivateCallDataValidatorBuilder::new_with_counter(10); + + builder.add_private_call_request(20, 30); + builder.add_private_call_request(40, 50); + builder.split_calls(); + 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_with_counter(10); + + builder.add_private_call_request(20, 30); + builder.add_private_call_request(40, 50); + builder.add_private_call_request(60, 70); + builder.split_calls(); + + builder.validate_as_first_call(); +} + +#[test] +fn validate_as_first_call_split_private_empty_non_revertible_succeeds() { + let mut builder = PrivateCallDataValidatorBuilder::new_with_counter(10); + + builder.split_calls(); + builder.add_private_call_request(20, 30); + builder.add_private_call_request(40, 50); + builder.add_private_call_request(60, 70); + + builder.validate_as_first_call(); +} + +#[test] +fn validate_as_first_call_split_private_full_requests_empty_revertible_succeeds() { + let mut builder = PrivateCallDataValidatorBuilder::new_with_counter(10); + + builder.private_call.append_private_call_requests(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, false); + builder.split_calls(); + + 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_falls_in_non_revertible_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new_with_counter(10); + + builder.add_private_call_request(20, 30); + builder.add_private_call_request(40, 50); + builder.split_calls(); + // Tweak the counter to be less than the end counter of the previous call. + builder.private_call.public_inputs.min_revertible_side_effect_counter = 45; + 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 the start counter of the first revertible call")] +fn validate_as_first_call_split_private_calls_falls_in_revertible_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new_with_counter(10); + + builder.add_private_call_request(20, 30); + builder.add_private_call_request(40, 50); + builder.split_calls(); + // Tweak the counter to be greater than the start counter of the next call. + builder.private_call.public_inputs.min_revertible_side_effect_counter = 65; + 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 the start counter of the first revertible call")] +fn validate_as_first_call_split_private_calls_incorrect_value_zero_index_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new_with_counter(10); + + builder.split_calls(); + // Tweak the counter to be greater than the start counter of the first call. + builder.private_call.public_inputs.min_revertible_side_effect_counter = 25; + builder.add_private_call_request(20, 30); + builder.add_private_call_request(40, 50); + 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_incorrect_value_max_index_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new_with_counter(10); + + builder.add_private_call_request(20, 30); + builder.add_private_call_request(40, 50); + builder.add_private_call_request(60, 70); + builder.split_calls(); + // Tweak the counter to be less than the end counter of the previous call. + builder.private_call.public_inputs.min_revertible_side_effect_counter = 65; + + builder.validate_as_first_call(); +} + +#[test(should_fail_with="min_revertible_side_effect_counter must be less than the start counter of the first revertible call")] +fn validate_as_first_call_split_private_calls_incorrect_index_hint_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new_with_counter(10); + + builder.add_private_call_request(20, 30); + builder.add_private_call_request(40, 50); + builder.add_private_call_request(60, 70); + builder.split_calls(); + // Index should be 3. + builder.first_revertible_private_call_request_index = 2; + + builder.validate_as_first_call(); +} + +#[test(should_fail_with="min_revertible_side_effect_counter must be less than 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_with_counter(10); + + builder.add_private_call_request(20, 30); + builder.add_private_call_request(40, 50); + builder.split_calls(); + // Index should be 2. + builder.first_revertible_private_call_request_index = 3; + + builder.validate_as_first_call(); +} + +#[test] +fn validate_as_first_call_split_public_calls_succeeds() { + let mut builder = PrivateCallDataValidatorBuilder::new_with_counter(10); + + builder.add_public_call_request(20, 30); + builder.add_public_call_request(40, 50); + builder.split_calls(); + builder.add_public_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_public_calls_falls_in_non_revertible_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new_with_counter(10); + + builder.add_public_call_request(20, 30); + builder.add_public_call_request(40, 50); + builder.split_calls(); + // Tweak the counter to be less than the end counter of the previous call. + builder.private_call.public_inputs.min_revertible_side_effect_counter = 45; + builder.add_public_call_request(60, 70); + + builder.validate_as_first_call(); +} + +#[test] +fn validate_as_first_call_split_private_public_mix_succeeds() { + let mut builder = PrivateCallDataValidatorBuilder::new_with_counter(10); + + builder.add_private_call_request(20, 30); + builder.add_private_call_request(40, 50); + builder.add_public_call_request(60, 70); + builder.split_calls(); + builder.add_private_call_request(80, 90); + builder.add_public_call_request(100, 110); + builder.add_public_call_request(120, 130); + + builder.validate_as_first_call(); +} + +#[test(should_fail_with="min_revertible_side_effect_counter must be less than the start counter of the first revertible call")] +fn validate_as_first_call_split_private_public_mix_falls_in_revertible_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new_with_counter(10); + + builder.add_private_call_request(20, 30); + builder.add_private_call_request(40, 50); + builder.add_public_call_request(60, 70); + builder.split_calls(); + // Tweak the counter to be greater than the start counter of the next call. + builder.private_call.public_inputs.min_revertible_side_effect_counter = 85; + builder.add_private_call_request(80, 90); + builder.add_public_call_request(100, 110); + builder.add_public_call_request(120, 130); + + builder.validate_as_first_call(); +} 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 85d2ea1d8e42..c9a814e1aaab 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 @@ -109,6 +109,11 @@ impl PrivateCircuitPublicInputsBuilder { TxContext::new(self.chain_id, self.version, self.gas_settings) } + pub fn end_setup(&mut self) { + let counter = self.next_counter(); + self.min_revertible_side_effect_counter = counter; + } + pub fn set_tx_max_block_number(&mut self, max_block_number: u32) { self.max_block_number = MaxBlockNumber::new(max_block_number); } @@ -219,7 +224,7 @@ impl PrivateCircuitPublicInputsBuilder { } } - pub fn next_counter(&mut self) -> u32 { + fn next_counter(&mut self) -> u32 { let counter = self.counter_end; self.counter_end += 1; counter 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 5c1a65956ec8..7262cc7b1b57 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 8172acc84830..24256a8fa330 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, @@ -1371,6 +1373,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), @@ -1383,7 +1393,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 f6b324aad45d..c2cb00d62574 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 { type ExecutionResult, collectNoteHashLeafIndexMap, collectNullifiedNote import { type KernelProofOutput, type ProofCreator } from './interface/proof_creator.js'; 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 000000000000..4e9af9ff4713 --- /dev/null +++ b/yarn-project/pxe/src/kernel_prover/private_inputs_builders/build_private_kernel_init_hints.ts @@ -0,0 +1,32 @@ +import { + type CallRequest, + type MAX_NEW_NOTE_HASHES_PER_CALL, + type PrivateCircuitPublicInputs, + PrivateKernelInitHints, +} 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; + const firstRevertiblePrivateCallRequestIndex = privateCallRequests.findIndex( + r => r.startSideEffectCounter > minRevertibleCounter, + ); + const firstRevertiblePublicCallRequestIndex = publicCallRequests.findIndex( + r => r.startSideEffectCounter > minRevertibleCounter, + ); + + 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 ae00ec7a4f0e..477ce51240f2 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'; From a903c3e4c3a4991885faccebb1992f56606ea4b6 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Tue, 14 May 2024 17:56:54 +0000 Subject: [PATCH 04/10] Fixes. --- .../aztec/src/context/private_context.nr | 9 +- .../aztec/src/context/public_context.nr | 2 +- .../src/private_call_data_validator.nr | 6 +- .../src/tests/validate_as_first_call.nr | 148 +++++++++--------- .../private_circuit_public_inputs_builder.nr | 3 +- .../build_private_kernel_init_hints.ts | 15 +- 6 files changed, 95 insertions(+), 88 deletions(-) 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 a2be4ac607ac..1a0d5809465c 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -107,15 +107,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 c5d436e3cd1c..569d87162060 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 f3370b3f2315..40de2f9fb942 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 @@ -113,7 +113,7 @@ fn validate_split_call_requests( 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 the start counter of the first revertible call" + 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" ); } } @@ -162,8 +162,8 @@ impl PrivateCallDataValidator { 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; - // Don't have to limit that the min_revertible_side_effect_counter has to fall in the counter range of the private call. - // It is valid as long as it does not fall in the middle of a call. + // 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_call_requests( min_revertible_side_effect_counter, first_revertible_private_call_request_index, 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 index a99b9e04a968..9d48e728f769 100644 --- 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 @@ -3,8 +3,12 @@ use dep::types::constants::MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL; use dep::types::abis::call_request::CallRequest; impl PrivateCallDataValidatorBuilder { - pub fn split_calls(&mut self) { - self.private_call.public_inputs.end_setup(); + 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(); } @@ -44,13 +48,17 @@ fn validate_as_first_call_delegate_call_fails() { builder.validate_as_first_call(); } +/** + * Splitting call requests. + */ + #[test] fn validate_as_first_call_split_private_calls_succeeds() { - let mut builder = PrivateCallDataValidatorBuilder::new_with_counter(10); + let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); builder.add_private_call_request(20, 30); builder.add_private_call_request(40, 50); - builder.split_calls(); + builder.split_calls(60); builder.add_private_call_request(60, 70); builder.validate_as_first_call(); @@ -58,142 +66,145 @@ fn validate_as_first_call_split_private_calls_succeeds() { #[test] fn validate_as_first_call_split_private_empty_revertible_succeeds() { - let mut builder = PrivateCallDataValidatorBuilder::new_with_counter(10); + let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); builder.add_private_call_request(20, 30); builder.add_private_call_request(40, 50); - builder.add_private_call_request(60, 70); - builder.split_calls(); + 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_with_counter(10); + let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); - builder.split_calls(); + builder.split_calls(20); builder.add_private_call_request(20, 30); builder.add_private_call_request(40, 50); - builder.add_private_call_request(60, 70); builder.validate_as_first_call(); } #[test] -fn validate_as_first_call_split_private_full_requests_empty_revertible_succeeds() { - let mut builder = PrivateCallDataValidatorBuilder::new_with_counter(10); +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.split_calls(builder.private_call.public_inputs.counter_end); 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_falls_in_non_revertible_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new_with_counter(10); +#[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); - builder.split_calls(); - // Tweak the counter to be less than the end counter of the previous call. - builder.private_call.public_inputs.min_revertible_side_effect_counter = 45; + // 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 less than the start counter of the first revertible call")] -fn validate_as_first_call_split_private_calls_falls_in_revertible_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new_with_counter(10); +#[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); - builder.split_calls(); - // Tweak the counter to be greater than the start counter of the next call. - builder.private_call.public_inputs.min_revertible_side_effect_counter = 65; + // 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 less than the start counter of the first revertible call")] -fn validate_as_first_call_split_private_calls_incorrect_value_zero_index_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new_with_counter(10); +#[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.split_calls(); - // Tweak the counter to be greater than the start counter of the first call. - builder.private_call.public_inputs.min_revertible_side_effect_counter = 25; builder.add_private_call_request(20, 30); builder.add_private_call_request(40, 50); - builder.add_private_call_request(60, 70); + // 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 greater than the end counter of the last non revertible call")] -fn validate_as_first_call_split_private_calls_incorrect_value_max_index_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new_with_counter(10); +#[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.split_calls(); - // Tweak the counter to be less than the end counter of the previous call. - builder.private_call.public_inputs.min_revertible_side_effect_counter = 65; builder.validate_as_first_call(); } -#[test(should_fail_with="min_revertible_side_effect_counter must be less than the start counter of the first revertible call")] -fn validate_as_first_call_split_private_calls_incorrect_index_hint_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new_with_counter(10); +#[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.add_private_call_request(60, 70); - builder.split_calls(); - // Index should be 3. - builder.first_revertible_private_call_request_index = 2; builder.validate_as_first_call(); } -#[test(should_fail_with="min_revertible_side_effect_counter must be less than the start counter of the first revertible 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_with_counter(10); + let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); builder.add_private_call_request(20, 30); builder.add_private_call_request(40, 50); - builder.split_calls(); - // Index should be 2. - builder.first_revertible_private_call_request_index = 3; + 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_with_counter(10); + let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); builder.add_public_call_request(20, 30); builder.add_public_call_request(40, 50); - builder.split_calls(); + builder.split_calls(60); builder.add_public_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_public_calls_falls_in_non_revertible_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new_with_counter(10); +fn validate_as_first_call_split_public_calls_less_than_fails() { + let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); builder.add_public_call_request(20, 30); builder.add_public_call_request(40, 50); - builder.split_calls(); - // Tweak the counter to be less than the end counter of the previous call. - builder.private_call.public_inputs.min_revertible_side_effect_counter = 45; + // Tweak the counter to be less than the end counter of the last non-revertible call. + builder.split_calls(49); builder.add_public_call_request(60, 70); builder.validate_as_first_call(); @@ -201,32 +212,27 @@ fn validate_as_first_call_split_public_calls_falls_in_non_revertible_fails() { #[test] fn validate_as_first_call_split_private_public_mix_succeeds() { - let mut builder = PrivateCallDataValidatorBuilder::new_with_counter(10); + let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); builder.add_private_call_request(20, 30); - builder.add_private_call_request(40, 50); builder.add_public_call_request(60, 70); - builder.split_calls(); - builder.add_private_call_request(80, 90); - builder.add_public_call_request(100, 110); - builder.add_public_call_request(120, 130); + builder.split_calls(80); + builder.add_public_call_request(80, 90); + builder.add_private_call_request(100, 110); builder.validate_as_first_call(); } -#[test(should_fail_with="min_revertible_side_effect_counter must be less than the start counter of the first revertible 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_public_mix_falls_in_revertible_fails() { - let mut builder = PrivateCallDataValidatorBuilder::new_with_counter(10); + let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); builder.add_private_call_request(20, 30); - builder.add_private_call_request(40, 50); builder.add_public_call_request(60, 70); - builder.split_calls(); // Tweak the counter to be greater than the start counter of the next call. - builder.private_call.public_inputs.min_revertible_side_effect_counter = 85; - builder.add_private_call_request(80, 90); - builder.add_public_call_request(100, 110); - builder.add_public_call_request(120, 130); + builder.split_calls(81); + builder.add_public_call_request(80, 90); + builder.add_private_call_request(100, 110); builder.validate_as_first_call(); } 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 9e7b19a5f555..20dd2efc32e4 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 @@ -111,8 +111,7 @@ impl PrivateCircuitPublicInputsBuilder { } pub fn end_setup(&mut self) { - let counter = self.next_counter(); - self.min_revertible_side_effect_counter = counter; + self.min_revertible_side_effect_counter = self.counter_end; } pub fn set_tx_max_block_number(&mut self, max_block_number: u32) { 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 index 4e9af9ff4713..fb6a95f5fd9b 100644 --- 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 @@ -3,6 +3,7 @@ import { type MAX_NEW_NOTE_HASHES_PER_CALL, type PrivateCircuitPublicInputs, PrivateKernelInitHints, + countAccumulatedItems, } from '@aztec/circuits.js'; import { type Tuple } from '@aztec/foundation/serialize'; @@ -17,12 +18,18 @@ export function buildPrivateKernelInitHints( ) as Tuple; const minRevertibleCounter = publicInputs.minRevertibleSideEffectCounter; - const firstRevertiblePrivateCallRequestIndex = privateCallRequests.findIndex( - r => r.startSideEffectCounter > minRevertibleCounter, + let firstRevertiblePrivateCallRequestIndex = privateCallRequests.findIndex( + r => r.startSideEffectCounter >= minRevertibleCounter, ); - const firstRevertiblePublicCallRequestIndex = publicCallRequests.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, From 93344bd3c91e3f1c15349c9e96b8b0b96a2dd300 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Wed, 15 May 2024 09:50:40 +0000 Subject: [PATCH 05/10] Break up tests. --- .../crates/private-kernel-lib/src/private_kernel_inner.nr | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) 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 b26f9f487c21..b4d4090f5b56 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 @@ -246,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); From 40a3b72c389675d692efbe1c002024b99e16f648 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Wed, 15 May 2024 10:47:08 +0000 Subject: [PATCH 06/10] Remove redundant file. --- .../crates/private-kernel-lib/src/utils.nr | 1 - 1 file changed, 1 deletion(-) delete mode 100644 noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/utils.nr diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/utils.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/utils.nr deleted file mode 100644 index f4079dcf613e..000000000000 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/utils.nr +++ /dev/null @@ -1 +0,0 @@ -mod counter_range; From 5c50cce76256defbe5fc03c6b5e2d4d63d43794b Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Wed, 15 May 2024 11:18:04 +0000 Subject: [PATCH 07/10] Fix checks for public call requests. --- .../src/private_call_data_validator.nr | 33 +++++++++++--- .../src/tests/validate_as_first_call.nr | 44 +++++++++---------- 2 files changed, 50 insertions(+), 27 deletions(-) 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 40de2f9fb942..0a43701e29a0 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 @@ -97,7 +97,7 @@ fn validate_incrementing_counter_ranges_within_range( ); } -fn validate_split_call_requests( +fn validate_split_private_call_requests( min_revertible_side_effect_counter: u32, first_revertible_call_request_index: u64, call_requests: [CallRequest; N], @@ -118,6 +118,27 @@ fn validate_split_call_requests( } } +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" + ); + } +} + struct ArrayLengths { note_hash_read_requests: u64, nullifier_read_requests: u64, @@ -164,13 +185,13 @@ impl PrivateCallDataValidator { 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_call_requests( + 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_call_requests( + validate_split_public_call_requests( min_revertible_side_effect_counter, first_revertible_public_call_request_index, self.data.public_call_stack, @@ -368,7 +389,9 @@ impl PrivateCallDataValidator { self.data.private_call_stack, self.array_lengths.private_call_stack_hashes ); - validate_incrementing_counter_ranges_within_range( + + // 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, @@ -380,7 +403,7 @@ impl PrivateCallDataValidator { } else { 1 }; - validate_incrementing_counter_ranges_within_range( + validate_incrementing_counters_within_range( counter_start, counter_end, [self.data.public_teardown_call_request], 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 index 9d48e728f769..852de8b834bf 100644 --- 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 @@ -21,12 +21,12 @@ impl PrivateCallDataValidatorBuilder { self.private_call.public_inputs.counter_end = counter_end + 1; } - pub fn add_public_call_request(&mut self, counter_start: u32, counter_end: u32) { + 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 = counter_end; - self.private_call.public_inputs.counter_end = counter_end + 1; + self.private_call.public_call_stack.storage[index].end_side_effect_counter = 0; + self.private_call.public_inputs.counter_end = counter_start + 1; } } @@ -189,23 +189,23 @@ fn validate_as_first_call_split_private_calls_index_hint_greater_than_len_fails( fn validate_as_first_call_split_public_calls_succeeds() { let mut builder = PrivateCallDataValidatorBuilder::new_first_call(); - builder.add_public_call_request(20, 30); - builder.add_public_call_request(40, 50); - builder.split_calls(60); - builder.add_public_call_request(60, 70); + 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 end counter of the last non revertible call")] -fn validate_as_first_call_split_public_calls_less_than_fails() { +#[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, 30); - builder.add_public_call_request(40, 50); + 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(49); - builder.add_public_call_request(60, 70); + builder.split_calls(29); + builder.add_public_call_request(40); builder.validate_as_first_call(); } @@ -215,24 +215,24 @@ 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(60, 70); - builder.split_calls(80); - builder.add_public_call_request(80, 90); - builder.add_private_call_request(100, 110); + 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 start counter of the first revertible 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(60, 70); + builder.add_public_call_request(40); // Tweak the counter to be greater than the start counter of the next call. - builder.split_calls(81); - builder.add_public_call_request(80, 90); - builder.add_private_call_request(100, 110); + builder.split_calls(51); + builder.add_public_call_request(50); + builder.add_private_call_request(60, 70); builder.validate_as_first_call(); } From 277b1beb26834285a6f27067abd5081a4980a53d Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Wed, 15 May 2024 11:56:42 +0000 Subject: [PATCH 08/10] Fix tests. --- yarn-project/simulator/src/client/private_execution.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn-project/simulator/src/client/private_execution.test.ts b/yarn-project/simulator/src/client/private_execution.test.ts index a106c825c6fb..a09bfdbe780b 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, From 788af351cb90550aa2150a2873531de11ab17111 Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Wed, 15 May 2024 14:25:32 +0000 Subject: [PATCH 09/10] Fix typo. --- .../private-kernel-lib/src/tests/validate_counters.nr | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 index 110a40025ff1..d18493899b7a 100644 --- 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 @@ -5,19 +5,19 @@ use crate::tests::private_call_data_validator_builder::PrivateCallDataValidatorB */ #[test] -fn validate_counters_privata_call_succeeds() { +fn validate_counters_private_call_succeeds() { let builder = PrivateCallDataValidatorBuilder::new_with_counter(23); builder.validate(); } #[test] -fn validate_counters_privata_call_from_0_counter_succeeds() { +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_privata_call_no_counter_range_fails() { +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; @@ -26,7 +26,7 @@ fn validate_counters_privata_call_no_counter_range_fails() { } #[test(should_fail_with="private call has incorrect counter range")] -fn validate_counters_privata_call_negative_call_counter_range_fails() { +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; From e84da8f9eb04a38be4ae42b763209b90b40a944d Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Wed, 15 May 2024 14:43:11 +0000 Subject: [PATCH 10/10] Ensure all side effects have counters larger than call. --- yarn-project/simulator/src/public/executor.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/yarn-project/simulator/src/public/executor.ts b/yarn-project/simulator/src/public/executor.ts index 2576bdd29da8..7404e15237a1 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,