From 74e2caf70407a5727953f87ba6a887a3e08e1c0c Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Tue, 31 Oct 2023 22:31:07 +0000 Subject: [PATCH] Migrate ordering kernel cpp tests. --- .../src/private_kernel_inner.nr | 49 +-- .../src/private_kernel_ordering.nr | 350 ++++++++++++++++++ .../src/tests/testing_harness.nr | 39 ++ 3 files changed, 403 insertions(+), 35 deletions(-) diff --git a/yarn-project/noir-private-kernel/src/crates/private-kernel-lib/src/private_kernel_inner.nr b/yarn-project/noir-private-kernel/src/crates/private-kernel-lib/src/private_kernel_inner.nr index 2ce17a2d48b1..86e0fd511814 100644 --- a/yarn-project/noir-private-kernel/src/crates/private-kernel-lib/src/private_kernel_inner.nr +++ b/yarn-project/noir-private-kernel/src/crates/private-kernel-lib/src/private_kernel_inner.nr @@ -3,7 +3,6 @@ use crate::common; use crate::mocked::{Proof, AggregationObject, verify_previous_kernel_state}; use crate::transaction::request::TxRequest; use crate::abis::{ - combined_constant_data::CombinedConstantData, previous_kernel_data::PreviousKernelData, private_kernel::private_call_data::PrivateCallData, new_contract_data::NewContractData, @@ -97,33 +96,24 @@ impl PrivateKernelInputsInner { mod tests { use crate::private_kernel_inner::PrivateKernelInputsInner; use crate::abis::{ - kernel_circuit_public_inputs::{KernelCircuitPublicInputs, KernelCircuitPublicInputsBuilder}, private_circuit_public_inputs::PrivateCircuitPublicInputs, read_request_membership_witness::ReadRequestMembershipWitness, - combined_constant_data::CombinedConstantData, - previous_kernel_data::PreviousKernelData, }; use crate::tests::{ testing_harness::{ + create_previous_kernel_data, create_private_call_data, generate_read_requests, - build_tx_request, PrivateAppInputs, non_zero_items, - build_tx_context, }, - apps::deposit::{ - deposit_app, - DepositParams, + apps::{ + constructor::constructor_app, + deposit::deposit_app, }, - apps::constructor::{ - constructor_app, - ConstructorParams, - } }; use crate::address::Address; - use crate::hash::{compute_logs_hash, NUM_FIELDS_PER_SHA256}; - use crate::utils::uint128::U128; + use crate::hash::compute_logs_hash; use dep::aztec::constants_gen::{ MAX_READ_REQUESTS_PER_CALL, MAX_READ_REQUESTS_PER_TX, @@ -146,32 +136,21 @@ mod tests { app_params: T, ) -> PrivateKernelInputsInner { let msg_sender = Address::from_field(27); - let (private_call, contract_deployment_data) = create_private_call_data( + let params = dep::std::unsafe::zeroed(); + let previous_kernel = create_previous_kernel_data( + false, + constructor_app, + params, + msg_sender, + ); + + let (private_call, _) = create_private_call_data( false, function, app_params, msg_sender, ); - let tx_context = build_tx_context(false, contract_deployment_data); - - let mut previous_kernel: PreviousKernelData = dep::std::unsafe::zeroed(); - previous_kernel.public_inputs.constants = CombinedConstantData { - block_data: private_call.call_stack_item.public_inputs().historical_block_data, - tx_context, - }; - - previous_kernel.public_inputs.is_private = true; - previous_kernel.public_inputs.end.encrypted_logs_hash = [0,0]; - previous_kernel.public_inputs.end.unencrypted_logs_hash = [0,0]; - previous_kernel.public_inputs.end.encrypted_log_preimages_length = 0; - previous_kernel.public_inputs.end.unencrypted_log_preimages_length = 0; - - previous_kernel.public_inputs.end.new_nullifiers[0] = 321; // 0th nullifier must be non-zero. - previous_kernel.public_inputs.end.nullified_commitments[0] = EMPTY_NULLIFIED_COMMITMENT; - - previous_kernel.public_inputs.end.private_call_stack[0] = private_call.call_stack_item.hash(); - PrivateKernelInputsInner { previous_kernel, private_call, diff --git a/yarn-project/noir-private-kernel/src/crates/private-kernel-lib/src/private_kernel_ordering.nr b/yarn-project/noir-private-kernel/src/crates/private-kernel-lib/src/private_kernel_ordering.nr index f2c216f7dfd6..681ad16bcbc5 100644 --- a/yarn-project/noir-private-kernel/src/crates/private-kernel-lib/src/private_kernel_ordering.nr +++ b/yarn-project/noir-private-kernel/src/crates/private-kernel-lib/src/private_kernel_ordering.nr @@ -69,6 +69,7 @@ impl PrivateKernelInputsOrdering { let mut new_nullifiers = public_inputs.end.new_nullifiers.storage; for n_idx in 0..MAX_NEW_NULLIFIERS_PER_TX { + // TODO - should not be able to squash the first nullifier. let nullified_commitment = nullified_commitments[n_idx]; let nullifier_commitment_hint = nullifier_commitment_hints[n_idx]; let hint_pos = nullifier_commitment_hint as u64; @@ -153,3 +154,352 @@ impl PrivateKernelInputsOrdering { public_inputs.to_final() } } + +mod tests { + use crate::abis::{ + private_circuit_public_inputs::PrivateCircuitPublicInputs, + read_request_membership_witness::ReadRequestMembershipWitness, + }; + use crate::address::Address; + use crate::hash::{ + compute_commitment_nonce, + compute_unique_commitment, + }; + use crate::private_kernel_ordering::PrivateKernelInputsOrdering; + use crate::tests::{ + apps::constructor::constructor_app, + testing_harness::{ + create_previous_kernel_data, + non_zero_items, + PrivateAppInputs, + }, + }; + use dep::aztec::constants_gen::{ + MAX_READ_REQUESTS_PER_TX, + MAX_NEW_COMMITMENTS_PER_TX, + MAX_NEW_NULLIFIERS_PER_TX, + EMPTY_NULLIFIED_COMMITMENT, + MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, + MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, + MAX_NEW_L2_TO_L1_MSGS_PER_TX, + }; + use crate::utils::{ + bounded_vec::BoundedVec, + }; + + fn build_inputs( + function: fn (PrivateAppInputs, T) -> PrivateCircuitPublicInputs, + app_params: T, + ) -> PrivateKernelInputsOrdering { + let msg_sender = Address::from_field(27); + let previous_kernel = create_previous_kernel_data( + false, + function, + app_params, + msg_sender, + ); + + let read_commitment_hints = [0; MAX_READ_REQUESTS_PER_TX]; + let nullifier_commitment_hints = [0; MAX_NEW_NULLIFIERS_PER_TX]; + + PrivateKernelInputsOrdering { + previous_kernel, + read_commitment_hints, + nullifier_commitment_hints, + } + } + + fn generate_unique_siloed_commitments( + private_inputs: PrivateKernelInputsOrdering, + siloed_commitments: [Field; MAX_NEW_COMMITMENTS_PER_TX], + squashed_indices: [Field; N], + ) -> [Field; MAX_NEW_COMMITMENTS_PER_TX] { + let mut valid_indices = [true; MAX_NEW_COMMITMENTS_PER_TX]; + for i in 0..N { + valid_indices[squashed_indices[i]] = false; + } + + let mut unique_siloed_commitments = BoundedVec::new(0); + let first_nullifier = private_inputs.previous_kernel.public_inputs.end.new_nullifiers[0]; + for i in 0..MAX_NEW_COMMITMENTS_PER_TX { + let siloed_commitment = siloed_commitments[i]; + if (siloed_commitment != 0) & valid_indices[i] { + let idx = unique_siloed_commitments.len(); + let nonce = compute_commitment_nonce(first_nullifier, idx); + let unique_siloed_commitment = compute_unique_commitment(nonce, siloed_commitment); + unique_siloed_commitments.push(unique_siloed_commitment); + } + } + + unique_siloed_commitments.storage + } + + fn mock_new_commitments(private_inputs: &mut PrivateKernelInputsOrdering, num_new_commitments: Field) -> ( + [Field; MAX_NEW_COMMITMENTS_PER_TX], + [Field; MAX_NEW_COMMITMENTS_PER_TX], + ) { + let mut new_commitments = [0; MAX_NEW_COMMITMENTS_PER_TX]; + for i in 0..MAX_NEW_COMMITMENTS_PER_TX { + if i as u64 < num_new_commitments as u64 { + let siloed_commitment = i + 623; + new_commitments[i] = siloed_commitment; + } + } + + private_inputs.previous_kernel.public_inputs.end.new_commitments = new_commitments; + + let unique_siloed_commitments = generate_unique_siloed_commitments(*private_inputs, new_commitments, []); + + (new_commitments, unique_siloed_commitments) + } + + fn mock_new_nullifiers(private_inputs: &mut PrivateKernelInputsOrdering, num_extra_nullifier: Field) -> [Field; MAX_NEW_NULLIFIERS_PER_TX] { + let mut new_nullifiers = [0; MAX_NEW_NULLIFIERS_PER_TX]; + let first_nullifier = private_inputs.previous_kernel.public_inputs.end.new_nullifiers[0]; + new_nullifiers[0] = first_nullifier; + + for i in 1..MAX_NEW_NULLIFIERS_PER_TX { + if i as u64 <= num_extra_nullifier as u64 { + // Set a random value that's different to the first nullifier. + new_nullifiers[i] = first_nullifier + i; + } + } + + private_inputs.previous_kernel.public_inputs.end.new_nullifiers = new_nullifiers; + + new_nullifiers + } + + #[test] + fn native_matching_one_read_request_to_commitment_works() { + let params = dep::std::unsafe::zeroed(); + let mut private_inputs = build_inputs(constructor_app, params); + + let (new_commitments, unique_siloed_commitments) = mock_new_commitments(&mut private_inputs, 1); + private_inputs.read_commitment_hints[0] = 0; + private_inputs.previous_kernel.public_inputs.end.read_requests[0] = new_commitments[0]; + + let public_inputs = private_inputs.native_private_kernel_circuit_ordering(); + assert(non_zero_items(public_inputs.end.new_commitments) == 1); + assert(public_inputs.end.new_commitments[0] == unique_siloed_commitments[0]); + } + + #[test] + fn native_matching_some_read_requests_to_commitments_works() { + let params = dep::std::unsafe::zeroed(); + let mut private_inputs = build_inputs(constructor_app, params); + + let (new_commitments, unique_siloed_commitments) = mock_new_commitments(&mut private_inputs, MAX_NEW_COMMITMENTS_PER_TX); + // Read the commitment at index 1; + private_inputs.read_commitment_hints[0] = 1; + private_inputs.previous_kernel.public_inputs.end.read_requests[0] = new_commitments[1]; + // Read the commitment at index 3; + private_inputs.read_commitment_hints[1] = 3; + private_inputs.previous_kernel.public_inputs.end.read_requests[1] = new_commitments[3]; + + let public_inputs = private_inputs.native_private_kernel_circuit_ordering(); + assert(non_zero_items(public_inputs.end.new_commitments) == MAX_NEW_COMMITMENTS_PER_TX as u64); + for i in 0..MAX_NEW_COMMITMENTS_PER_TX { + assert(public_inputs.end.new_commitments[i] == unique_siloed_commitments[i]); + } + } + + #[test(should_fail_with="read request is transient but does not match any commitment")] + fn native_read_request_unknown_fails() { + let params = dep::std::unsafe::zeroed(); + let mut private_inputs = build_inputs(constructor_app, params); + + let (new_commitments, _) = mock_new_commitments(&mut private_inputs, 1); + private_inputs.read_commitment_hints[0] = 0; + // The read request does not match the commitment at index 0; + private_inputs.previous_kernel.public_inputs.end.read_requests[0] = new_commitments[0] + 1; + + private_inputs.native_private_kernel_circuit_ordering(); + } + + #[test] + fn native_squash_one_of_one_transient_matches_works() { + let params = dep::std::unsafe::zeroed(); + let mut private_inputs = build_inputs(constructor_app, params); + + let (new_commitments, _) = mock_new_commitments(&mut private_inputs, 1); + let new_nullifiers = mock_new_nullifiers(&mut private_inputs, 2); + // The nullifier at index 1 is nullifying the commitment at index 0; + let transient_nullifier_index = 1; + let nullified_commitment_index = 0; + private_inputs.previous_kernel.public_inputs.end.nullified_commitments[transient_nullifier_index] = new_commitments[nullified_commitment_index]; + private_inputs.nullifier_commitment_hints[transient_nullifier_index] = nullified_commitment_index; + + let public_inputs = private_inputs.native_private_kernel_circuit_ordering(); + assert(non_zero_items(public_inputs.end.new_commitments) == 0); + assert(non_zero_items(public_inputs.end.new_nullifiers) == 2); + assert(public_inputs.end.new_nullifiers[0] == new_nullifiers[0]); + assert(public_inputs.end.new_nullifiers[1] == new_nullifiers[2]); + } + + #[test] + fn native_squash_one_of_two_transient_matches_works() { + let params = dep::std::unsafe::zeroed(); + let mut private_inputs = build_inputs(constructor_app, params); + + let (new_commitments, _) = mock_new_commitments(&mut private_inputs, 2); + let new_nullifiers = mock_new_nullifiers(&mut private_inputs, 2); + // The nullifier at index 1 is nullifying the commitment at index 0; + let transient_nullifier_index = 1; + let nullified_commitment_index = 0; + private_inputs.previous_kernel.public_inputs.end.nullified_commitments[transient_nullifier_index] = new_commitments[nullified_commitment_index]; + private_inputs.nullifier_commitment_hints[transient_nullifier_index] = nullified_commitment_index; + + // The 0th commitment is chopped. + let unique_siloed_commitments = generate_unique_siloed_commitments(private_inputs, new_commitments, [0]); + + let public_inputs = private_inputs.native_private_kernel_circuit_ordering(); + assert(non_zero_items(public_inputs.end.new_commitments) == 1); + assert(public_inputs.end.new_commitments[0] == unique_siloed_commitments[0]); + assert(non_zero_items(public_inputs.end.new_nullifiers) == 2); + assert(public_inputs.end.new_nullifiers[0] == new_nullifiers[0]); + assert(public_inputs.end.new_nullifiers[1] == new_nullifiers[2]); + } + + #[test] + fn native_squash_two_of_two_transient_matches_works() { + let params = dep::std::unsafe::zeroed(); + let mut private_inputs = build_inputs(constructor_app, params); + + let (new_commitments, _) = mock_new_commitments(&mut private_inputs, 2); + let new_nullifiers = mock_new_nullifiers(&mut private_inputs, 2); + // The nullifier at index 1 is nullifying the commitment at index 1; + private_inputs.previous_kernel.public_inputs.end.nullified_commitments[1] = new_commitments[1]; + private_inputs.nullifier_commitment_hints[1] = 1; + // The nullifier at index 2 is nullifying the commitment at index 0; + private_inputs.previous_kernel.public_inputs.end.nullified_commitments[2] = new_commitments[0]; + private_inputs.nullifier_commitment_hints[2] = 0; + + let public_inputs = private_inputs.native_private_kernel_circuit_ordering(); + assert(non_zero_items(public_inputs.end.new_commitments) == 0); + assert(non_zero_items(public_inputs.end.new_nullifiers) == 1); + assert(public_inputs.end.new_nullifiers[0] == new_nullifiers[0]); + } + + #[test] + fn native_empty_nullified_commitment_means_persistent_nullifier_0() { + let params = dep::std::unsafe::zeroed(); + let mut private_inputs = build_inputs(constructor_app, params); + + mock_new_commitments(&mut private_inputs, 2); + mock_new_nullifiers(&mut private_inputs, 2); + + let public_inputs = private_inputs.native_private_kernel_circuit_ordering(); + assert(non_zero_items(public_inputs.end.new_commitments) == 2); + assert(non_zero_items(public_inputs.end.new_nullifiers) == 3); + } + + // same as previous test, but this time there are 0 commitments! + // (Do we really need this test?) + #[test] + fn native_empty_nullified_commitment_means_persistent_nullifier_1() { + let params = dep::std::unsafe::zeroed(); + let mut private_inputs = build_inputs(constructor_app, params); + + mock_new_nullifiers(&mut private_inputs, 2); + + let public_inputs = private_inputs.native_private_kernel_circuit_ordering(); + assert(non_zero_items(public_inputs.end.new_commitments) == 0); + assert(non_zero_items(public_inputs.end.new_nullifiers) == 3); + } + + #[test(should_fail_with="The 0th nullifier in the accumulated nullifier array is zero")] + fn zero_0th_nullifier_fails() { + let params = dep::std::unsafe::zeroed(); + let mut private_inputs = build_inputs(constructor_app, params); + + private_inputs.previous_kernel.public_inputs.end.new_nullifiers[0] = 0; + + private_inputs.native_private_kernel_circuit_ordering(); + } + + #[test(should_fail_with="invalid array")] + fn input_validation_malformed_end_arrays_read_requests() { + let params = dep::std::unsafe::zeroed(); + let mut private_inputs = build_inputs(constructor_app, params); + + let mut malformed_read_requests = [0; MAX_READ_REQUESTS_PER_TX]; + malformed_read_requests[1] = 9123; + malformed_read_requests[3] = 12; + private_inputs.previous_kernel.public_inputs.end.read_requests = malformed_read_requests; + + private_inputs.native_private_kernel_circuit_ordering(); + } + + #[test(should_fail_with="invalid array")] + fn input_validation_malformed_end_arrays_commitments() { + let params = dep::std::unsafe::zeroed(); + let mut private_inputs = build_inputs(constructor_app, params); + + let mut malformed_commitments = [0; MAX_NEW_COMMITMENTS_PER_TX]; + malformed_commitments[1] = 9123; + private_inputs.previous_kernel.public_inputs.end.new_commitments = malformed_commitments; + + private_inputs.native_private_kernel_circuit_ordering(); + } + + #[test(should_fail_with="invalid array")] + fn input_validation_malformed_end_arrays_nullifiers() { + let params = dep::std::unsafe::zeroed(); + let mut private_inputs = build_inputs(constructor_app, params); + + let mut malformed_nullifiers = [0; MAX_NEW_NULLIFIERS_PER_TX]; + malformed_nullifiers[MAX_NEW_NULLIFIERS_PER_TX - 1] = 12; + private_inputs.previous_kernel.public_inputs.end.new_nullifiers = malformed_nullifiers; + + private_inputs.native_private_kernel_circuit_ordering(); + } + + #[test(should_fail_with="invalid array")] + fn input_validation_malformed_end_arrays_nullified_commitments() { + let params = dep::std::unsafe::zeroed(); + let mut private_inputs = build_inputs(constructor_app, params); + + let mut malformed_nullified_commitments = [0; MAX_NEW_NULLIFIERS_PER_TX]; + malformed_nullified_commitments[2] = EMPTY_NULLIFIED_COMMITMENT; + private_inputs.previous_kernel.public_inputs.end.nullified_commitments = malformed_nullified_commitments; + + private_inputs.native_private_kernel_circuit_ordering(); + } + + #[test(should_fail_with="invalid array")] + fn input_validation_malformed_end_arrays_private_call_stack() { + let params = dep::std::unsafe::zeroed(); + let mut private_inputs = build_inputs(constructor_app, params); + + let mut malformed_private_call_stack = [0; MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX]; + malformed_private_call_stack[1] = 888; + private_inputs.previous_kernel.public_inputs.end.private_call_stack = malformed_private_call_stack; + + private_inputs.native_private_kernel_circuit_ordering(); + } + + #[test(should_fail_with="invalid array")] + fn input_validation_malformed_end_arrays_public_call_stack() { + let params = dep::std::unsafe::zeroed(); + let mut private_inputs = build_inputs(constructor_app, params); + + let mut malformed_public_call_stack = [0; MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX]; + malformed_public_call_stack[1] = 888; + private_inputs.previous_kernel.public_inputs.end.public_call_stack = malformed_public_call_stack; + + private_inputs.native_private_kernel_circuit_ordering(); + } + + #[test(should_fail_with="invalid array")] + fn input_validation_malformed_end_arrays_l2_to_l1_msgs() { + let params = dep::std::unsafe::zeroed(); + let mut private_inputs = build_inputs(constructor_app, params); + + let mut malformed_l2_to_l1_msgs = [0; MAX_NEW_L2_TO_L1_MSGS_PER_TX]; + malformed_l2_to_l1_msgs[MAX_NEW_L2_TO_L1_MSGS_PER_TX - 1] = 1; + private_inputs.previous_kernel.public_inputs.end.new_l2_to_l1_msgs = malformed_l2_to_l1_msgs; + + private_inputs.native_private_kernel_circuit_ordering(); + } +} diff --git a/yarn-project/noir-private-kernel/src/crates/private-kernel-lib/src/tests/testing_harness.nr b/yarn-project/noir-private-kernel/src/crates/private-kernel-lib/src/tests/testing_harness.nr index 1b43bbce4ed9..f94410f170a6 100644 --- a/yarn-project/noir-private-kernel/src/crates/private-kernel-lib/src/tests/testing_harness.nr +++ b/yarn-project/noir-private-kernel/src/crates/private-kernel-lib/src/tests/testing_harness.nr @@ -8,6 +8,8 @@ use crate::{ deployment_data::ContractDeploymentData, }, abis::{ + combined_constant_data::CombinedConstantData, + previous_kernel_data::PreviousKernelData, private_kernel::private_call_data::PrivateCallData, historical_block_data::HistoricalBlockData, call_context::CallContext, @@ -35,6 +37,7 @@ use crate::{ use dep::aztec::{ abi::hash_args, constants_gen::{ + EMPTY_NULLIFIED_COMMITMENT, MAX_READ_REQUESTS_PER_CALL, MAX_NEW_COMMITMENTS_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, @@ -331,6 +334,42 @@ pub fn create_private_call_data( (private_call, contract_deployment_data) } +pub fn create_previous_kernel_data( + is_constructor: bool, + function: fn (PrivateAppInputs, T) -> PrivateCircuitPublicInputs, + params: T, + msg_sender: Address, +) -> PreviousKernelData { + let (private_call, contract_deployment_data) = create_private_call_data( + is_constructor, + function, + params, + msg_sender, + ); + + // Turn the private call data into the previous kernel. + let mut previous_kernel: PreviousKernelData = dep::std::unsafe::zeroed(); + + let tx_context = build_tx_context(is_constructor, contract_deployment_data); + previous_kernel.public_inputs.constants = CombinedConstantData { + block_data: private_call.call_stack_item.public_inputs().historical_block_data, + tx_context, + }; + + previous_kernel.public_inputs.is_private = true; + previous_kernel.public_inputs.end.encrypted_logs_hash = [0, 0]; + previous_kernel.public_inputs.end.unencrypted_logs_hash = [0, 0]; + previous_kernel.public_inputs.end.encrypted_log_preimages_length = 0; + previous_kernel.public_inputs.end.unencrypted_log_preimages_length = 0; + + previous_kernel.public_inputs.end.new_nullifiers[0] = 321; // 0th nullifier must be non-zero. + previous_kernel.public_inputs.end.nullified_commitments[0] = EMPTY_NULLIFIED_COMMITMENT; + + previous_kernel.public_inputs.end.private_call_stack[0] = private_call.call_stack_item.hash(); + + previous_kernel +} + pub fn generate_read_requests(how_many: u64) -> ([Field; MAX_READ_REQUESTS_PER_CALL], [ReadRequestMembershipWitness; MAX_READ_REQUESTS_PER_CALL]) { let mut read_requests = [0; MAX_READ_REQUESTS_PER_CALL]; let mut read_request_membership_witnesses: [ReadRequestMembershipWitness; MAX_READ_REQUESTS_PER_CALL] = dep::std::unsafe::zeroed();