diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index a026721c12f9..ac060def61e3 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -128,6 +128,7 @@ library Constants { uint256 internal constant NULLIFIER_LENGTH = 3; uint256 internal constant SCOPED_NULLIFIER_LENGTH = NULLIFIER_LENGTH + 1; uint256 internal constant SIDE_EFFECT_LENGTH = 2; + uint256 internal constant ROLLUP_VALIDATION_REQUESTS_LENGTH = MAX_BLOCK_NUMBER_LENGTH; uint256 internal constant STATE_REFERENCE_LENGTH = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH; uint256 internal constant TX_CONTEXT_LENGTH = 2 + GAS_SETTINGS_LENGTH; @@ -157,6 +158,34 @@ library Constants { + 1; uint256 internal constant PRIVATE_CALL_STACK_ITEM_LENGTH = AZTEC_ADDRESS_LENGTH + FUNCTION_DATA_LENGTH + PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH; + uint256 internal constant SCOPED_READ_REQUEST_LEN = READ_REQUEST_LENGTH + 1; + uint256 internal constant PUBLIC_DATA_READ_LENGTH = 2; + uint256 internal constant VALIDATION_REQUESTS_LENGTH = ROLLUP_VALIDATION_REQUESTS_LENGTH + + (SCOPED_READ_REQUEST_LEN * MAX_NOTE_HASH_READ_REQUESTS_PER_TX) + + (SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_READ_REQUESTS_PER_TX) + + (SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX) + + (SCOPED_NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH * MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX) + + (PUBLIC_DATA_READ_LENGTH * MAX_PUBLIC_DATA_READS_PER_TX); + uint256 internal constant PUBLIC_DATA_UPDATE_REQUEST_LENGTH = 2; + uint256 internal constant COMBINED_ACCUMULATED_DATA_LENGTH = MAX_NEW_NOTE_HASHES_PER_TX + + MAX_NEW_NULLIFIERS_PER_TX + MAX_NEW_L2_TO_L1_MSGS_PER_TX + 4 + + (MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_UPDATE_REQUEST_LENGTH) + GAS_LENGTH; + uint256 internal constant COMBINED_CONSTANT_DATA_LENGTH = + HEADER_LENGTH + TX_CONTEXT_LENGTH + GLOBAL_VARIABLES_LENGTH; + uint256 internal constant CALLER_CONTEXT_LENGTH = 2 * AZTEC_ADDRESS_LENGTH; + uint256 internal constant CALL_REQUEST_LENGTH = + 1 + AZTEC_ADDRESS_LENGTH + CALLER_CONTEXT_LENGTH + 2; + uint256 internal constant PRIVATE_ACCUMULATED_DATA_LENGTH = ( + SCOPED_NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_TX + ) + (SCOPED_NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_TX) + + (MAX_NEW_L2_TO_L1_MSGS_PER_TX * SCOPED_L2_TO_L1_MESSAGE_LENGTH) + + (SIDE_EFFECT_LENGTH * MAX_ENCRYPTED_LOGS_PER_TX) + + (SIDE_EFFECT_LENGTH * MAX_UNENCRYPTED_LOGS_PER_TX) + 2 + + (CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX) + + (CALL_REQUEST_LENGTH * MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX); + uint256 internal constant PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1 + + VALIDATION_REQUESTS_LENGTH + PRIVATE_ACCUMULATED_DATA_LENGTH + COMBINED_CONSTANT_DATA_LENGTH + + CALL_REQUEST_LENGTH; uint256 internal constant ENQUEUE_PUBLIC_FUNCTION_CALL_RETURN_LENGTH = 2 + FUNCTION_DATA_LENGTH + CALL_CONTEXT_LENGTH; uint256 internal constant GET_NOTES_ORACLE_RETURN_LENGTH = 674; diff --git a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr index 1ec2152e7c3f..d42ee2119d68 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr @@ -39,7 +39,7 @@ contract SchnorrAccount { // Note: If you globally change the entrypoint signature don't forget to update default_entrypoint.ts file #[aztec(private)] #[aztec(noinitcheck)] - fn entrypoint(app_payload: pub AppPayload, fee_payload: pub FeePayload) { + fn entrypoint(app_payload: AppPayload, fee_payload: FeePayload) { let actions = AccountActions::private( &mut context, storage.approved_actions.storage_slot, diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-init/src/main.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-init/src/main.nr index 635b9da54d91..76a826137674 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-init/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-init/src/main.nr @@ -1,6 +1,7 @@ use dep::private_kernel_lib::PrivateKernelInitCircuitPrivateInputs; use dep::types::PrivateKernelCircuitPublicInputs; -fn main(input: PrivateKernelInitCircuitPrivateInputs) -> pub PrivateKernelCircuitPublicInputs { +#[recursive] +fn main(input: PrivateKernelInitCircuitPrivateInputs) -> pub PrivateKernelCircuitPublicInputs { input.native_private_kernel_circuit_initial() } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-inner/src/main.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-inner/src/main.nr index 861d229580c1..686cce6b595a 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-inner/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-inner/src/main.nr @@ -1,6 +1,7 @@ use dep::private_kernel_lib::PrivateKernelInnerCircuitPrivateInputs; use dep::types::PrivateKernelCircuitPublicInputs; -fn main(input: PrivateKernelInnerCircuitPrivateInputs) -> pub PrivateKernelCircuitPublicInputs { +#[recursive] +fn main(input: PrivateKernelInnerCircuitPrivateInputs) -> pub PrivateKernelCircuitPublicInputs { input.native_private_kernel_circuit_inner() } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/kernel_circuit_public_inputs_composer.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/kernel_circuit_public_inputs_composer.nr index 5abc9c8f4f4a..18115cc2ea67 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/kernel_circuit_public_inputs_composer.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/kernel_circuit_public_inputs_composer.nr @@ -1,7 +1,7 @@ use dep::reset_kernel_lib::verify_squashed_transient_note_hashes_and_nullifiers; use dep::types::{ abis::{ - kernel_data::PrivateKernelData, + private_kernel_data::PrivateKernelData, kernel_circuit_public_inputs::{KernelCircuitPublicInputs, PrivateKernelCircuitPublicInputsBuilder, PublicKernelCircuitPublicInputs}, note_hash::ScopedNoteHash, nullifier::ScopedNullifier, side_effect::{SideEffect, Ordered}, gas::Gas }, 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 64a08cdc7b11..bb4a7db587c7 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 @@ -1,7 +1,7 @@ use crate::{common, private_kernel_circuit_public_inputs_composer::PrivateKernelCircuitPublicInputsComposer}; use dep::types::{ abis::{ - private_kernel::private_call_data::PrivateCallData, + private_kernel::private_call_data::{PrivateCallData, verify_private_call}, kernel_circuit_public_inputs::PrivateKernelCircuitPublicInputs }, constants::MAX_NEW_NOTE_HASHES_PER_CALL, mocked::verify_private_function_proof, @@ -68,14 +68,15 @@ impl PrivateKernelInitCircuitPrivateInputs { pub fn native_private_kernel_circuit_initial(self) -> PrivateKernelCircuitPublicInputs { let private_call_public_inputs = self.private_call.call_stack_item.public_inputs; + // verify/aggregate the private call proof + verify_private_call(self.private_call); + self.validate_inputs(); common::validate_private_call_data(self.private_call); self.validate_this_private_call_against_tx_request(); - assert(verify_private_function_proof(self.private_call.proof), "Invalid private function proof."); - PrivateKernelCircuitPublicInputsComposer::new_from_tx_request(self.tx_request, private_call_public_inputs).compose( private_call_public_inputs, self.hints.note_hash_nullifier_counters, 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 6a291bafbfab..61a06ea345b8 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 @@ -1,12 +1,12 @@ use crate::{common, private_kernel_circuit_public_inputs_composer::PrivateKernelCircuitPublicInputsComposer}; use dep::types::{ abis::{ - kernel_data::PrivateKernelData, private_kernel::private_call_data::PrivateCallData, + private_kernel_data::{PrivateKernelData, verify_previous_kernel_proof}, + private_kernel::private_call_data::{PrivateCallData, verify_private_call}, kernel_circuit_public_inputs::{PrivateKernelCircuitPublicInputs, PrivateKernelCircuitPublicInputsBuilder}, side_effect::SideEffect }, - constants::MAX_NEW_NOTE_HASHES_PER_CALL, mocked::verify_previous_kernel_state, - utils::arrays::array_length + constants::MAX_NEW_NOTE_HASHES_PER_CALL, utils::arrays::array_length }; struct PrivateKernelInnerHints { @@ -30,6 +30,12 @@ impl PrivateKernelInnerCircuitPrivateInputs { let private_call_public_inputs = self.private_call.call_stack_item.public_inputs; let previous_kernel_public_inputs = self.previous_kernel.public_inputs; + // verify/aggregate the private call proof + verify_private_call(self.private_call); + + // verify/aggregate the previous kernel + verify_previous_kernel_proof(self.previous_kernel); + common::validate_previous_kernel_values(previous_kernel_public_inputs.end); self.validate_inputs(); @@ -42,12 +48,6 @@ impl PrivateKernelInnerCircuitPrivateInputs { let call_request = private_call_stack[private_call_stack_size - 1]; common::validate_call_against_request(self.private_call, call_request); - let (is_previous_state_valid, _updated_aggregation_object) = verify_previous_kernel_state( - previous_kernel_public_inputs.aggregation_object, - self.private_call.proof - ); - assert(is_previous_state_valid); - PrivateKernelCircuitPublicInputsComposer::new_from_previous_kernel(self.previous_kernel.public_inputs).compose( private_call_public_inputs, self.hints.note_hash_nullifier_counters, diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr index 2471caad0bea..51d6efd7a07c 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr @@ -1,14 +1,14 @@ use crate::kernel_circuit_public_inputs_composer::KernelCircuitPublicInputsComposer; use dep::reset_kernel_lib::{NoteHashReadRequestHints, NullifierReadRequestHints, PrivateValidationRequestProcessor}; use dep::types::{ - abis::{ - kernel_data::PrivateKernelData, kernel_circuit_public_inputs::KernelCircuitPublicInputs, - note_hash::ScopedNoteHash, nullifier::ScopedNullifier, side_effect::SideEffect -}, - constants::{ - MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_ENCRYPTED_LOGS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX -}, + abis::{ + private_kernel_data::{PrivateKernelData, verify_previous_kernel_proof}, kernel_circuit_public_inputs::KernelCircuitPublicInputs, + note_hash::ScopedNoteHash, nullifier::ScopedNullifier, side_effect::SideEffect + }, + constants::{ + MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_ENCRYPTED_LOGS_PER_TX, MAX_UNENCRYPTED_LOGS_PER_TX + }, grumpkin_private_key::GrumpkinPrivateKey, utils::arrays::array_length }; @@ -47,6 +47,9 @@ impl PrivateKernelTailCircuitPrivateInputs { array_length(previous_public_inputs.end.public_call_stack), 0, "Public call stack must be empty when executing the tail circuit" ); + // verify/aggregate the previous kernel + verify_previous_kernel_proof(self.previous_kernel); + let note_hash_tree_root = previous_public_inputs.constants.historical_header.state.partial.note_hash_tree.root; let nullifier_tree_root = previous_public_inputs.constants.historical_header.state.partial.nullifier_tree.root; PrivateValidationRequestProcessor { diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr index a16c3ea41ba6..7b7e17eba88d 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail_to_public.nr @@ -2,7 +2,7 @@ use crate::kernel_circuit_public_inputs_composer::KernelCircuitPublicInputsCompo use dep::reset_kernel_lib::{NoteHashReadRequestHints, NullifierReadRequestHints, PrivateValidationRequestProcessor}; use dep::types::{ abis::{ - kernel_data::PrivateKernelData, kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, + private_kernel_data::{PrivateKernelData, verify_previous_kernel_proof}, kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, note_hash::ScopedNoteHash, nullifier::ScopedNullifier, side_effect::SideEffect }, constants::{ @@ -47,6 +47,9 @@ impl PrivateKernelTailToPublicCircuitPrivateInputs { array_length(previous_public_inputs.end.public_call_stack) != 0, "Public call stack must not be empty when exporting public kernel data from the tail circuit" ); + // verify/aggregate the previous kernel + verify_previous_kernel_proof(self.previous_kernel); + let note_hash_tree_root = previous_public_inputs.constants.historical_header.state.partial.note_hash_tree.root; let nullifier_tree_root = previous_public_inputs.constants.historical_header.state.partial.nullifier_tree.root; PrivateValidationRequestProcessor { diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-tail-to-public/src/main.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-tail-to-public/src/main.nr index 85050fa143bd..fd35f8397f3a 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-tail-to-public/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-tail-to-public/src/main.nr @@ -1,6 +1,7 @@ use dep::private_kernel_lib::PrivateKernelTailToPublicCircuitPrivateInputs; use dep::types::PublicKernelCircuitPublicInputs; -fn main(input: PrivateKernelTailToPublicCircuitPrivateInputs) -> pub PublicKernelCircuitPublicInputs { +#[recursive] +fn main(input: PrivateKernelTailToPublicCircuitPrivateInputs) -> pub PublicKernelCircuitPublicInputs { input.execute() } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-tail/src/main.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-tail/src/main.nr index 681eaacb72d2..41485a79a2bb 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-tail/src/main.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-tail/src/main.nr @@ -1,6 +1,7 @@ use dep::private_kernel_lib::PrivateKernelTailCircuitPrivateInputs; use dep::types::KernelCircuitPublicInputs; -fn main(input: PrivateKernelTailCircuitPrivateInputs) -> pub KernelCircuitPublicInputs { +#[recursive] +fn main(input: PrivateKernelTailCircuitPrivateInputs) -> pub KernelCircuitPublicInputs { input.native_private_kernel_circuit_tail() } diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr index f8bc620c1004..e92e4c791a44 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr @@ -92,7 +92,6 @@ impl PublicKernelTailCircuitPrivateInputs { let end = self.propagate_accumulated_data(); KernelCircuitPublicInputs { - aggregation_object: previous_public_inputs.aggregation_object, rollup_validation_requests: previous_public_inputs.validation_requests.for_rollup, end, constants: previous_public_inputs.constants, diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr index 238cc1dbd131..704b1ac6e659 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr @@ -247,7 +247,7 @@ impl BaseRollupInputs { // TODO(Kev): This aggregate_proof method is duplicated in a lot of places fn aggregate_proofs(self) -> AggregationObject { // TODO: for now we simply return the aggregation object from the first proof - self.kernel_data.public_inputs.aggregation_object + AggregationObject {} } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr index 2c2a9325bcb1..9b95b164f5ac 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr @@ -27,6 +27,7 @@ mod max_block_number; mod private_kernel; mod kernel_circuit_public_inputs; mod kernel_data; +mod private_kernel_data; mod call_request; mod private_call_stack_item; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr index 1a49b8de968d..21e625826222 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr @@ -7,9 +7,9 @@ use crate::{ }, constants::{ MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, COMBINED_ACCUMULATED_DATA_LENGTH }, - utils::arrays::array_merge, traits::Empty + utils::arrays::array_merge, traits::{Empty, Serialize} }; struct CombinedAccumulatedData { @@ -82,3 +82,27 @@ impl Empty for CombinedAccumulatedData { } } } + +impl Serialize for CombinedAccumulatedData { + fn serialize(self) -> [Field; COMBINED_ACCUMULATED_DATA_LENGTH] { + let mut fields: BoundedVec = BoundedVec::new(); + + fields.extend_from_array(self.new_note_hashes); + fields.extend_from_array(self.new_nullifiers); + fields.extend_from_array(self.new_l2_to_l1_msgs); + fields.push(self.encrypted_logs_hash); + fields.push(self.unencrypted_logs_hash); + fields.push(self.encrypted_log_preimages_length); + fields.push(self.unencrypted_log_preimages_length); + + for i in 0..MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX { + fields.extend_from_array(self.public_data_update_requests[i].serialize()); + } + + fields.extend_from_array(self.gas_used.serialize()); + + assert_eq(fields.len(), COMBINED_ACCUMULATED_DATA_LENGTH); + + fields.storage + } +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data.nr index 12c19d640b1a..502acaab910d 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_data.nr @@ -3,12 +3,12 @@ use crate::{ call_request::CallRequest, gas::Gas, note_hash::ScopedNoteHash, nullifier::ScopedNullifier, side_effect::SideEffect }, - messaging::l2_to_l1_message::ScopedL2ToL1Message + traits::Serialize, messaging::l2_to_l1_message::ScopedL2ToL1Message }; use crate::constants::{ MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, MAX_ENCRYPTED_LOGS_PER_TX, - MAX_UNENCRYPTED_LOGS_PER_TX + MAX_UNENCRYPTED_LOGS_PER_TX, PRIVATE_ACCUMULATED_DATA_LENGTH }; struct PrivateAccumulatedData { @@ -27,3 +27,44 @@ struct PrivateAccumulatedData { private_call_stack: [CallRequest; MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX], public_call_stack: [CallRequest; MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX], } + +impl Serialize for PrivateAccumulatedData { + fn serialize(self) -> [Field; PRIVATE_ACCUMULATED_DATA_LENGTH] { + let mut fields: BoundedVec = BoundedVec::new(); + + for i in 0..MAX_NEW_NOTE_HASHES_PER_TX { + fields.extend_from_array(self.new_note_hashes[i].serialize()); + } + + for i in 0..MAX_NEW_NULLIFIERS_PER_TX { + fields.extend_from_array(self.new_nullifiers[i].serialize()); + } + + for i in 0..MAX_NEW_L2_TO_L1_MSGS_PER_TX { + fields.extend_from_array(self.new_l2_to_l1_msgs[i].serialize()); + } + + for i in 0..MAX_ENCRYPTED_LOGS_PER_TX { + fields.extend_from_array(self.encrypted_logs_hashes[i].serialize()); + } + + for i in 0..MAX_UNENCRYPTED_LOGS_PER_TX { + fields.extend_from_array(self.unencrypted_logs_hashes[i].serialize()); + } + + fields.push(self.encrypted_log_preimages_length); + fields.push(self.unencrypted_log_preimages_length); + + for i in 0..MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX { + fields.extend_from_array(self.private_call_stack[i].serialize()); + } + + for i in 0..MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX { + fields.extend_from_array(self.public_call_stack[i].serialize()); + } + + assert_eq(fields.len(), PRIVATE_ACCUMULATED_DATA_LENGTH); + + fields.storage + } +} 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 8eca6227d7cd..140b1967ca77 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,7 +1,8 @@ use crate::address::AztecAddress; use dep::std::cmp::Eq; -use crate::traits::Empty; +use crate::traits::{Empty, Serialize}; use crate::abis::caller_context::CallerContext; +use crate::constants::CALL_REQUEST_LENGTH; struct CallRequest { hash: Field, @@ -38,3 +39,19 @@ impl CallRequest { self.hash == 0 } } + +impl Serialize for CallRequest { + fn serialize(self) -> [Field; CALL_REQUEST_LENGTH] { + let mut fields: BoundedVec = BoundedVec::new(); + + fields.push(self.hash); + fields.extend_from_array(self.caller_contract_address.serialize()); + fields.extend_from_array(self.caller_context.serialize()); + fields.push(self.start_side_effect_counter as Field); + fields.push(self.end_side_effect_counter as Field); + + assert_eq(fields.len(), CALL_REQUEST_LENGTH); + + fields.storage + } +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/caller_context.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/caller_context.nr index 829429e4e9ea..70c929fc04a5 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/caller_context.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/caller_context.nr @@ -1,6 +1,7 @@ use crate::address::AztecAddress; use dep::std::cmp::Eq; -use crate::traits::Empty; +use crate::traits::{Empty, Serialize}; +use crate::constants::CALLER_CONTEXT_LENGTH; struct CallerContext { msg_sender: AztecAddress, @@ -28,3 +29,16 @@ impl CallerContext { self.msg_sender.is_zero() & self.storage_contract_address.is_zero() } } + +impl Serialize for CallerContext { + fn serialize(self) -> [Field; CALLER_CONTEXT_LENGTH] { + let mut fields: BoundedVec = BoundedVec::new(); + + fields.extend_from_array(self.msg_sender.serialize()); + fields.extend_from_array(self.storage_contract_address.serialize()); + + assert_eq(fields.len(), CALLER_CONTEXT_LENGTH); + + fields.storage + } +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/combined_constant_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/combined_constant_data.nr index 0d823df58d2a..2fcd910a23b4 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/combined_constant_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/combined_constant_data.nr @@ -1,7 +1,8 @@ use crate::transaction::tx_context::TxContext; use crate::header::Header; -use crate::traits::Empty; +use crate::traits::{Empty, Serialize}; use crate::abis::global_variables::GlobalVariables; +use crate::constants::COMBINED_CONSTANT_DATA_LENGTH; struct CombinedConstantData { historical_header: Header, @@ -29,3 +30,17 @@ impl Empty for CombinedConstantData { } } } + +impl Serialize for CombinedConstantData { + fn serialize(self) -> [Field; COMBINED_CONSTANT_DATA_LENGTH] { + let mut fields: BoundedVec = BoundedVec::new(); + + fields.extend_from_array(self.historical_header.serialize()); + fields.extend_from_array(self.tx_context.serialize()); + fields.extend_from_array(self.global_variables.serialize()); + + assert_eq(fields.len(), COMBINED_CONSTANT_DATA_LENGTH); + + fields.storage + } +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/kernel_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/kernel_circuit_public_inputs.nr index 5584918af235..5256f275a3ee 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/kernel_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/kernel_circuit_public_inputs.nr @@ -8,7 +8,6 @@ use crate::{ use crate::mocked::AggregationObject; struct KernelCircuitPublicInputs { - aggregation_object: AggregationObject, rollup_validation_requests: RollupValidationRequests, end: CombinedAccumulatedData, constants: CombinedConstantData, @@ -28,7 +27,6 @@ impl KernelCircuitPublicInputs { impl Empty for KernelCircuitPublicInputs { fn empty() -> Self { KernelCircuitPublicInputs { - aggregation_object: AggregationObject::empty(), rollup_validation_requests: RollupValidationRequests::empty(), end: CombinedAccumulatedData::empty(), constants: CombinedConstantData::empty(), @@ -56,7 +54,6 @@ mod tests { #[test] unconstrained fn non_empty_gas_and_fee() { let mut inputs = KernelCircuitPublicInputs { - aggregation_object: AggregationObject::empty(), rollup_validation_requests: RollupValidationRequests::empty(), end: CombinedAccumulatedData::empty(), constants: CombinedConstantData::empty(), diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs.nr index 6715590d3410..e7aee9e9d52c 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs.nr @@ -2,13 +2,29 @@ use crate::abis::{ accumulated_data::PrivateAccumulatedData, combined_constant_data::CombinedConstantData, validation_requests::ValidationRequests, call_request::CallRequest }; -use crate::mocked::AggregationObject; +use crate::constants::PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH; +use crate::traits::Serialize; struct PrivateKernelCircuitPublicInputs { - aggregation_object: AggregationObject, min_revertible_side_effect_counter: u32, validation_requests: ValidationRequests, end: PrivateAccumulatedData, constants: CombinedConstantData, public_teardown_call_request: CallRequest, } + +impl Serialize for PrivateKernelCircuitPublicInputs { + fn serialize(self) -> [Field; PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH] { + let mut fields: BoundedVec = BoundedVec::new(); + + fields.push(self.min_revertible_side_effect_counter as Field); + fields.extend_from_array(self.validation_requests.serialize()); + fields.extend_from_array(self.end.serialize()); + fields.extend_from_array(self.constants.serialize()); + fields.extend_from_array(self.public_teardown_call_request.serialize()); + + assert_eq(fields.len(), PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH); + + fields.storage + } +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs_builder.nr index a6424f53c896..aa137a82225a 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs_builder.nr @@ -17,7 +17,6 @@ use crate::{ // .finish_tail: KernelCircuitPublicInputs (from KernelCircuitPublicInputsComposer) // .finish_to_public: PublicKernelCircuitPublicInputs (from KernelCircuitPublicInputsComposer) struct PrivateKernelCircuitPublicInputsBuilder { - aggregation_object: AggregationObject, min_revertible_side_effect_counter: u32, validation_requests: ValidationRequestsBuilder, end: PrivateAccumulatedDataBuilder, @@ -28,7 +27,6 @@ struct PrivateKernelCircuitPublicInputsBuilder { impl PrivateKernelCircuitPublicInputsBuilder { pub fn finish(self) -> PrivateKernelCircuitPublicInputs { PrivateKernelCircuitPublicInputs { - aggregation_object: self.aggregation_object, min_revertible_side_effect_counter: self.min_revertible_side_effect_counter, validation_requests: self.validation_requests.finish(), end: self.end.finish(), @@ -39,7 +37,6 @@ impl PrivateKernelCircuitPublicInputsBuilder { pub fn finish_tail(self, teardown_gas: Gas) -> KernelCircuitPublicInputs { KernelCircuitPublicInputs { - aggregation_object: self.aggregation_object, rollup_validation_requests: self.validation_requests.to_rollup(), end: self.end.to_combined(teardown_gas), constants: self.constants, @@ -56,7 +53,6 @@ impl PrivateKernelCircuitPublicInputsBuilder { let (end_non_revertible, end) = self.end.split_to_public(min_revertible_side_effect_counter, teardown_gas); PublicKernelCircuitPublicInputs { - aggregation_object: self.aggregation_object, validation_requests: self.validation_requests.finish(), end_non_revertible, end, @@ -70,7 +66,6 @@ impl PrivateKernelCircuitPublicInputsBuilder { impl Empty for PrivateKernelCircuitPublicInputsBuilder { fn empty() -> Self { PrivateKernelCircuitPublicInputsBuilder { - aggregation_object: AggregationObject::empty(), min_revertible_side_effect_counter: 0 as u32, validation_requests: ValidationRequestsBuilder::empty(), end: PrivateAccumulatedDataBuilder::empty(), diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs.nr index 4687e3de77c0..8e8e4d620456 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs.nr @@ -2,10 +2,8 @@ use crate::abis::{ accumulated_data::PublicAccumulatedData, combined_constant_data::CombinedConstantData, validation_requests::{RollupValidationRequests, ValidationRequests}, call_request::CallRequest }; -use crate::mocked::AggregationObject; struct PublicKernelCircuitPublicInputs { - aggregation_object: AggregationObject, validation_requests: ValidationRequests, end_non_revertible: PublicAccumulatedData, end: PublicAccumulatedData, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr index 824f595430e6..41f92bd5f225 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr @@ -4,12 +4,10 @@ use crate::{ combined_constant_data::CombinedConstantData, kernel_circuit_public_inputs::{public_kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs}, validation_requests::ValidationRequestsBuilder, call_request::CallRequest -}, - mocked::AggregationObject, traits::Empty +}, traits::Empty }; struct PublicKernelCircuitPublicInputsBuilder { - aggregation_object: AggregationObject, validation_requests: ValidationRequestsBuilder, end_non_revertible: PublicAccumulatedDataBuilder, end: PublicAccumulatedDataBuilder, @@ -21,7 +19,6 @@ struct PublicKernelCircuitPublicInputsBuilder { impl PublicKernelCircuitPublicInputsBuilder { pub fn finish(self) -> PublicKernelCircuitPublicInputs { PublicKernelCircuitPublicInputs { - aggregation_object: self.aggregation_object, // Note that we're including both the validation_requests AND the rollup_validation requests, because this // struct is used as an input for both the public kernel and base rollup circuits. In the near future the // base rollup will only receive rollup_validation_requests, and the public kernel only validation_requests. @@ -38,7 +35,6 @@ impl PublicKernelCircuitPublicInputsBuilder { impl Empty for PublicKernelCircuitPublicInputsBuilder { fn empty() -> Self { PublicKernelCircuitPublicInputsBuilder { - aggregation_object: AggregationObject::empty(), validation_requests: ValidationRequestsBuilder::empty(), end_non_revertible: PublicAccumulatedDataBuilder::empty(), end: PublicAccumulatedDataBuilder::empty(), diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_data.nr index f0dd35e98b1c..6bdbbb4d4a5f 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_data.nr @@ -1,28 +1,6 @@ use crate::mocked::{Proof, VerificationKey}; use crate::constants::VK_TREE_HEIGHT; -use crate::abis::kernel_circuit_public_inputs::{PrivateKernelCircuitPublicInputs, PublicKernelCircuitPublicInputs, KernelCircuitPublicInputs}; - -struct PrivateKernelData { - // TODO(David): Left a note asking if we need this due to it - // already being in the proof. - public_inputs: PrivateKernelCircuitPublicInputs, - - // TODO(David): Mentions the dichotomy between a proof created for the - // circuit, which is a sequence of field elements, versus a proof - // created for solidity/native verification which is a collection of bytes. - // Kev: I've been questioning if we _need_ the sequence of field elements. - // It makes verification cheaper, though I have not tested how much cheaper. - // Removing it would also reduce complexity on the Noir side, as we have - // special methods to convert "inner proofs" into sequence of field elements. - proof: Proof, - - vk: VerificationKey, - - // TODO(Mike): left a note saying : this index and path are meant to be those of a leaf within the tree of _kernel circuit_ vks; not the tree - // of functions within the contract tree. - vk_index: u32, - vk_path: [Field; VK_TREE_HEIGHT], -} +use crate::abis::kernel_circuit_public_inputs::{PublicKernelCircuitPublicInputs, KernelCircuitPublicInputs}; struct PublicKernelData { public_inputs: PublicKernelCircuitPublicInputs, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel/private_call_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel/private_call_data.nr index 760189375dd7..7bca0c1d6161 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel/private_call_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel/private_call_data.nr @@ -1,7 +1,10 @@ -use crate::abis::{call_request::CallRequest, private_call_stack_item::PrivateCallStackItem}; use crate::address::{SaltedInitializationHash, PublicKeysHash, EthAddress}; use crate::contract_class_id::ContractClassId; -use crate::mocked::{Proof, VerificationKey}; +use crate::recursion::{verification_key::VerificationKey, proof::RecursiveProof}; +use crate::abis::{ + call_request::CallRequest, private_call_stack_item::PrivateCallStackItem, + private_circuit_public_inputs::PrivateCircuitPublicInputs +}; use crate::constants::{MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, FUNCTION_TREE_HEIGHT}; use crate::merkle_tree::membership::MembershipWitness; @@ -11,7 +14,7 @@ struct PrivateCallData { private_call_stack: [CallRequest; MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL], public_call_stack: [CallRequest; MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL], - proof: Proof, + proof: RecursiveProof, vk: VerificationKey, salted_initialization_hash: SaltedInitializationHash, @@ -22,3 +25,13 @@ struct PrivateCallData { acir_hash: Field, } + +fn verify_private_call(call: PrivateCallData) { + let inputs = PrivateCircuitPublicInputs::serialize(call.call_stack_item.public_inputs); + dep::std::verify_proof( + call.vk.key.as_slice(), + call.proof.fields.as_slice(), + inputs.as_slice(), + call.vk.hash + ); +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel_data.nr new file mode 100644 index 000000000000..9e9564ebf258 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel_data.nr @@ -0,0 +1,34 @@ +use crate::recursion::{verification_key::VerificationKey, proof::NestedRecursiveProof}; +use crate::constants::VK_TREE_HEIGHT; +use crate::abis::kernel_circuit_public_inputs::PrivateKernelCircuitPublicInputs; + +struct PrivateKernelData { + // TODO(David): Left a note asking if we need this due to it + // already being in the proof. + public_inputs: PrivateKernelCircuitPublicInputs, + + // TODO(David): Mentions the dichotomy between a proof created for the + // circuit, which is a sequence of field elements, versus a proof + // created for solidity/native verification which is a collection of bytes. + // Kev: I've been questioning if we _need_ the sequence of field elements. + // It makes verification cheaper, though I have not tested how much cheaper. + // Removing it would also reduce complexity on the Noir side, as we have + // special methods to convert "inner proofs" into sequence of field elements. + proof: NestedRecursiveProof, + vk: VerificationKey, + + // TODO(Mike): left a note saying : this index and path are meant to be those of a leaf within the tree of _kernel circuit_ vks; not the tree + // of functions within the contract tree. + vk_index: u32, + vk_path: [Field; VK_TREE_HEIGHT], +} + +fn verify_previous_kernel_proof(previous_kernel: PrivateKernelData) { + let inputs = PrivateKernelCircuitPublicInputs::serialize(previous_kernel.public_inputs); + dep::std::verify_proof( + previous_kernel.vk.key.as_slice(), + previous_kernel.proof.fields.as_slice(), + inputs.as_slice(), + previous_kernel.vk.hash + ); +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_data_read.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_data_read.nr index f790fe142c82..a434580019bf 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_data_read.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_data_read.nr @@ -1,6 +1,6 @@ -use crate::constants::GENERATOR_INDEX__PUBLIC_DATA_READ; +use crate::constants::{GENERATOR_INDEX__PUBLIC_DATA_READ, PUBLIC_DATA_READ_LENGTH}; use dep::std::cmp::Eq; -use crate::traits::{Empty, Hash}; +use crate::traits::{Empty, Hash, Serialize}; struct PublicDataRead { leaf_slot : Field, @@ -36,3 +36,9 @@ impl PublicDataRead { (self.leaf_slot == 0) & (self.value == 0) } } + +impl Serialize for PublicDataRead { + fn serialize(self) -> [Field; PUBLIC_DATA_READ_LENGTH] { + [self.leaf_slot, self.value] + } +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_data_update_request.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_data_update_request.nr index 8177f389f185..ab887214acfa 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_data_update_request.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_data_update_request.nr @@ -1,6 +1,6 @@ -use crate::constants::GENERATOR_INDEX__PUBLIC_DATA_UPDATE_REQUEST; +use crate::constants::{PUBLIC_DATA_UPDATE_REQUEST_LENGTH, GENERATOR_INDEX__PUBLIC_DATA_UPDATE_REQUEST}; use dep::std::cmp::Eq; -use crate::traits::{Empty, Hash}; +use crate::traits::{Empty, Hash, Serialize}; struct PublicDataUpdateRequest { leaf_slot : Field, @@ -37,3 +37,9 @@ impl PublicDataUpdateRequest { (self.leaf_slot == 0) & (self.new_value == 0) } } + +impl Serialize for PublicDataUpdateRequest { + fn serialize(self) -> [Field; PUBLIC_DATA_UPDATE_REQUEST_LENGTH] { + [self.leaf_slot, self.new_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 9cac3dc5c889..6d3663354b05 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,11 +1,10 @@ use crate::{ - traits::{Empty, Serialize, Deserialize}, address::AztecAddress, constants::READ_REQUEST_LENGTH, + traits::{Empty, Serialize, Deserialize}, address::AztecAddress, + constants::{READ_REQUEST_LENGTH, SCOPED_READ_REQUEST_LEN}, utils::{arrays::array_concat, reader::Reader} }; use dep::std::cmp::Eq; -global SCOPED_READ_REQUEST_SERIALIZED_LEN = READ_REQUEST_LENGTH + 1; - struct ReadRequest { value: Field, counter: u32, @@ -69,14 +68,14 @@ impl Empty for ScopedReadRequest { } } -impl Serialize for ScopedReadRequest { - fn serialize(self) -> [Field; SCOPED_READ_REQUEST_SERIALIZED_LEN] { +impl Serialize for ScopedReadRequest { + fn serialize(self) -> [Field; SCOPED_READ_REQUEST_LEN] { array_concat(self.read_request.serialize(), [self.contract_address.to_field()]) } } -impl Deserialize for ScopedReadRequest { - fn deserialize(values: [Field; SCOPED_READ_REQUEST_SERIALIZED_LEN]) -> Self { +impl Deserialize for ScopedReadRequest { + fn deserialize(values: [Field; SCOPED_READ_REQUEST_LEN]) -> Self { let mut reader = Reader::new(values); let res = Self { read_request: reader.read_struct(ReadRequest::deserialize), diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/rollup_validation_requests.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/rollup_validation_requests.nr index 258167f0bbc0..1840668e1b30 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/rollup_validation_requests.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/rollup_validation_requests.nr @@ -1,4 +1,4 @@ -use crate::{abis::max_block_number::MaxBlockNumber, traits::Empty}; +use crate::{abis::max_block_number::MaxBlockNumber, traits::{Empty, Serialize}, constants::ROLLUP_VALIDATION_REQUESTS_LENGTH}; // These are validation requests that cannot be fulfilled in the current context (private or public), and must be // instead forwarded to the rollup for it to take care of them. @@ -14,3 +14,9 @@ impl Empty for RollupValidationRequests { } } +impl Serialize for RollupValidationRequests { + fn serialize(self) -> [Field; ROLLUP_VALIDATION_REQUESTS_LENGTH] { + MaxBlockNumber::serialize(self.max_block_number) + } +} + diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests.nr index 850afddbade2..8d56adb7ea6a 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests.nr @@ -8,8 +8,8 @@ use crate::{ constants::{ MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, - MAX_PUBLIC_DATA_READS_PER_TX -} + MAX_PUBLIC_DATA_READS_PER_TX, VALIDATION_REQUESTS_LENGTH +}, traits::Serialize }; // TODO - Use specific structs for private and public: PrivateValidationRequests vs PublicValidationRequests @@ -21,3 +21,35 @@ struct ValidationRequests { nullifier_key_validation_requests: [ScopedNullifierKeyValidationRequest; MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX], public_data_reads: [PublicDataRead; MAX_PUBLIC_DATA_READS_PER_TX], } + +impl Serialize for ValidationRequests { + fn serialize(self) -> [Field; VALIDATION_REQUESTS_LENGTH] { + let mut fields: BoundedVec = BoundedVec::new(); + + fields.extend_from_array(self.for_rollup.serialize()); + + for i in 0..MAX_NOTE_HASH_READ_REQUESTS_PER_TX { + fields.extend_from_array(self.note_hash_read_requests[i].serialize()); + } + + for i in 0..MAX_NULLIFIER_READ_REQUESTS_PER_TX { + fields.extend_from_array(self.nullifier_read_requests[i].serialize()); + } + + for i in 0..MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX { + fields.extend_from_array(self.nullifier_non_existent_read_requests[i].serialize()); + } + + for i in 0..MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX { + fields.extend_from_array(self.nullifier_key_validation_requests[i].serialize()); + } + + for i in 0..MAX_PUBLIC_DATA_READS_PER_TX { + fields.extend_from_array(self.public_data_reads[i].serialize()); + } + + assert_eq(fields.len(), VALIDATION_REQUESTS_LENGTH); + + fields.storage + } +} \ No newline at end of file diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index 5e1631cc24d5..84f47f12d87f 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -167,6 +167,7 @@ global SCOPED_NOTE_HASH_LENGTH = NOTE_HASH_LENGTH + 2; global NULLIFIER_LENGTH = 3; global SCOPED_NULLIFIER_LENGTH = NULLIFIER_LENGTH + 1; global SIDE_EFFECT_LENGTH = 2; +global ROLLUP_VALIDATION_REQUESTS_LENGTH = MAX_BLOCK_NUMBER_LENGTH; global STATE_REFERENCE_LENGTH: u64 = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH; global TX_CONTEXT_LENGTH: u64 = 2 + GAS_SETTINGS_LENGTH; global TX_REQUEST_LENGTH: u64 = 2 + TX_CONTEXT_LENGTH + FUNCTION_DATA_LENGTH; @@ -175,6 +176,19 @@ global PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH: u64 = CALL_CONTEXT_LENGTH + 3 + MAX global PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH: u64 = CALL_CONTEXT_LENGTH + 2 + (READ_REQUEST_LENGTH * MAX_NULLIFIER_READ_REQUESTS_PER_CALL) + (READ_REQUEST_LENGTH * MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL) + (CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH * MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL) + (CONTRACT_STORAGE_READ_LENGTH * MAX_PUBLIC_DATA_READS_PER_CALL) + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + (NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_CALL) + (NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_CALL) + (L2_TO_L1_MESSAGE_LENGTH * MAX_NEW_L2_TO_L1_MSGS_PER_CALL) + 2 + (SIDE_EFFECT_LENGTH * MAX_UNENCRYPTED_LOGS_PER_CALL) + 1 + HEADER_LENGTH + GLOBAL_VARIABLES_LENGTH + AZTEC_ADDRESS_LENGTH + /* revert_code */ 1 + 2 * GAS_LENGTH + /* transaction_fee */ 1; global PRIVATE_CALL_STACK_ITEM_LENGTH: u64 = AZTEC_ADDRESS_LENGTH + FUNCTION_DATA_LENGTH + PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH; +global SCOPED_READ_REQUEST_LEN = READ_REQUEST_LENGTH + 1; +global PUBLIC_DATA_READ_LENGTH = 2; +global VALIDATION_REQUESTS_LENGTH = ROLLUP_VALIDATION_REQUESTS_LENGTH + (SCOPED_READ_REQUEST_LEN * MAX_NOTE_HASH_READ_REQUESTS_PER_TX) + (SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_READ_REQUESTS_PER_TX) + (SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX) + (SCOPED_NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH * MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX) + (PUBLIC_DATA_READ_LENGTH * MAX_PUBLIC_DATA_READS_PER_TX); + +global PUBLIC_DATA_UPDATE_REQUEST_LENGTH = 2; +global COMBINED_ACCUMULATED_DATA_LENGTH = MAX_NEW_NOTE_HASHES_PER_TX + MAX_NEW_NULLIFIERS_PER_TX + MAX_NEW_L2_TO_L1_MSGS_PER_TX + 4 + (MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_UPDATE_REQUEST_LENGTH) + GAS_LENGTH; +global COMBINED_CONSTANT_DATA_LENGTH = HEADER_LENGTH + TX_CONTEXT_LENGTH + GLOBAL_VARIABLES_LENGTH; + +global CALLER_CONTEXT_LENGTH = 2 * AZTEC_ADDRESS_LENGTH; +global CALL_REQUEST_LENGTH = 1 + AZTEC_ADDRESS_LENGTH + CALLER_CONTEXT_LENGTH + 2; +global PRIVATE_ACCUMULATED_DATA_LENGTH = (SCOPED_NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_TX) + (SCOPED_NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_TX) + (MAX_NEW_L2_TO_L1_MSGS_PER_TX * SCOPED_L2_TO_L1_MESSAGE_LENGTH) + (SIDE_EFFECT_LENGTH * MAX_ENCRYPTED_LOGS_PER_TX) + (SIDE_EFFECT_LENGTH * MAX_UNENCRYPTED_LOGS_PER_TX) + 2 + (CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX) + (CALL_REQUEST_LENGTH * MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX); +global PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 1 + VALIDATION_REQUESTS_LENGTH + PRIVATE_ACCUMULATED_DATA_LENGTH + COMBINED_CONSTANT_DATA_LENGTH + CALL_REQUEST_LENGTH; + global ENQUEUE_PUBLIC_FUNCTION_CALL_RETURN_LENGTH: u64 = 2 + FUNCTION_DATA_LENGTH + CALL_CONTEXT_LENGTH; global GET_NOTES_ORACLE_RETURN_LENGTH: u64 = 674; global NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP: Field = 2048; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr b/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr index efb7f6b38c33..b6efc83586f2 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr @@ -1,5 +1,5 @@ use crate::address::{AztecAddress, EthAddress}; -use crate::mocked::VerificationKey; +use crate::recursion::verification_key::VerificationKey; use crate::abis::function_selector::FunctionSelector; use crate::abis::contract_class_function_leaf_preimage::ContractClassFunctionLeafPreimage; use crate::contract_class_id::ContractClassId; 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 077007c2b5ae..b0f043c80ab2 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 @@ -5,8 +5,9 @@ use crate::{ accumulated_data::{CombinedAccumulatedData, PrivateAccumulatedData, PrivateAccumulatedDataBuilder, PublicAccumulatedData}, global_variables::GlobalVariables, combined_constant_data::CombinedConstantData, kernel_circuit_public_inputs::{KernelCircuitPublicInputs, PrivateKernelCircuitPublicInputs, PublicKernelCircuitPublicInputs}, - kernel_data::{PrivateKernelData, PublicKernelData, KernelData}, max_block_number::MaxBlockNumber, - note_hash::{NoteHash, ScopedNoteHash}, nullifier::{Nullifier, ScopedNullifier}, + kernel_data::{PublicKernelData, KernelData}, max_block_number::MaxBlockNumber, + private_kernel_data::PrivateKernelData, note_hash::{NoteHash, ScopedNoteHash}, + nullifier::{Nullifier, ScopedNullifier}, nullifier_key_validation_request::ScopedNullifierKeyValidationRequest, public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, read_request::{ReadRequest, ScopedReadRequest}, side_effect::SideEffect, @@ -23,8 +24,8 @@ use crate::{ }, hash::silo_nullifier, header::Header, messaging::l2_to_l1_message::{L2ToL1Message, ScopedL2ToL1Message}, - mocked::{AggregationObject, Proof, VerificationKey}, partial_state_reference::PartialStateReference, - tests::fixtures, transaction::tx_context::TxContext, traits::Empty + partial_state_reference::PartialStateReference, tests::fixtures, transaction::tx_context::TxContext, + traits::Empty, recursion::{verification_key::VerificationKey, proof::NestedRecursiveProof} }; struct FixtureBuilder { @@ -62,7 +63,7 @@ struct FixtureBuilder { public_data_reads: BoundedVec, // Proof. - proof: Proof, + proof: NestedRecursiveProof, vk: VerificationKey, vk_index: u32, vk_path: [Field; VK_TREE_HEIGHT], @@ -103,8 +104,8 @@ impl FixtureBuilder { nullifier_non_existent_read_requests: BoundedVec::new(), nullifier_key_validation_requests: BoundedVec::new(), public_data_reads: BoundedVec::new(), - proof: Proof {}, - vk: VerificationKey {}, + proof: NestedRecursiveProof::empty(), + vk: VerificationKey::empty(), vk_index: 0, vk_path: [0; VK_TREE_HEIGHT], revert_code: 0, @@ -188,7 +189,6 @@ impl FixtureBuilder { let constants = self.to_constant_data(); PrivateKernelCircuitPublicInputs { - aggregation_object: AggregationObject {}, min_revertible_side_effect_counter: self.min_revertible_side_effect_counter, end, validation_requests, @@ -218,7 +218,6 @@ impl FixtureBuilder { let constants = self.to_constant_data(); PublicKernelCircuitPublicInputs { - aggregation_object: AggregationObject {}, end_non_revertible, end, validation_requests, @@ -230,7 +229,13 @@ impl FixtureBuilder { pub fn to_public_kernel_data(self, revertible: bool) -> PublicKernelData { let public_inputs = self.to_public_kernel_circuit_public_inputs(revertible); - PublicKernelData { public_inputs, proof: self.proof, vk: self.vk, vk_index: self.vk_index, vk_path: self.vk_path } + PublicKernelData { + public_inputs, + proof: crate::mocked::Proof::empty(), + vk: crate::mocked::VerificationKey::empty(), + vk_index: self.vk_index, + vk_path: self.vk_path + } } pub fn to_kernel_circuit_public_inputs(self) -> KernelCircuitPublicInputs { @@ -238,19 +243,18 @@ impl FixtureBuilder { let end = self.to_combined_accumulated_data(); let constants = self.to_constant_data(); - KernelCircuitPublicInputs { - aggregation_object: AggregationObject {}, - rollup_validation_requests, - end, - constants, - start_state: self.start_state, - revert_code: self.revert_code - } + KernelCircuitPublicInputs { rollup_validation_requests, end, constants, start_state: self.start_state, revert_code: self.revert_code } } pub fn to_kernel_data(self) -> KernelData { let public_inputs = self.to_kernel_circuit_public_inputs(); - KernelData { public_inputs, proof: self.proof, vk: self.vk, vk_index: self.vk_index, vk_path: self.vk_path } + KernelData { + public_inputs, + proof: crate::mocked::Proof::empty(), + vk: crate::mocked::VerificationKey::empty(), + vk_index: self.vk_index, + vk_path: self.vk_path + } } pub fn add_new_note_hash(&mut self, value: Field) { @@ -483,7 +487,7 @@ impl Empty for FixtureBuilder { nullifier_non_existent_read_requests: BoundedVec::new(), nullifier_key_validation_requests: BoundedVec::new(), public_data_reads: BoundedVec::new(), - proof: Proof::empty(), + proof: NestedRecursiveProof::empty(), vk: VerificationKey::empty(), vk_index: 0, vk_path: [0; VK_TREE_HEIGHT], 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 a4c6a52930ef..44d060051a94 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 @@ -7,7 +7,7 @@ use crate::{ }, merkle_tree::membership::MembershipWitness, address::{AztecAddress, EthAddress, SaltedInitializationHash, PublicKeysHash}, - mocked::{Proof, VerificationKey}, + recursion::{proof::RecursiveProof, verification_key::VerificationKey}, tests::{fixtures, private_circuit_public_inputs_builder::PrivateCircuitPublicInputsBuilder}, transaction::{tx_request::TxRequest, tx_context::TxContext} }; @@ -22,7 +22,7 @@ struct PrivateCallDataBuilder { // The rest of the values of PrivateCallData. private_call_stack: BoundedVec, public_call_stack: BoundedVec, - proof: Proof, + proof: RecursiveProof, vk: VerificationKey, salted_initialization_hash: SaltedInitializationHash, public_keys_hash: PublicKeysHash, @@ -48,8 +48,8 @@ impl PrivateCallDataBuilder { function_data, private_call_stack: BoundedVec::new(), public_call_stack: BoundedVec::new(), - proof: Proof {}, - vk: VerificationKey {}, + proof: RecursiveProof::empty(), + vk: VerificationKey::empty(), function_leaf_membership_witness: contract_function.membership_witness, salted_initialization_hash: contract_data.salted_initialization_hash, public_keys_hash: contract_data.public_keys_hash, diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs index d982d864d060..d587abc94639 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs @@ -233,9 +233,7 @@ pub(crate) fn convert_black_box_call( BlackBoxFunc::RANGE => unreachable!( "ICE: `BlackBoxFunc::RANGE` calls should be transformed into a `Instruction::Cast`" ), - BlackBoxFunc::RecursiveAggregation => unimplemented!( - "ICE: `BlackBoxFunc::RecursiveAggregation` is not implemented by the Brillig VM" - ), + BlackBoxFunc::RecursiveAggregation => {} BlackBoxFunc::BigIntAdd => { if let ( [BrilligVariable::SingleAddr(lhs), BrilligVariable::SingleAddr(lhs_modulus), BrilligVariable::SingleAddr(rhs), BrilligVariable::SingleAddr(rhs_modulus)], diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index 8e143fd70ca5..e15a83aa388b 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -110,6 +110,7 @@ export const SCOPED_NOTE_HASH_LENGTH = NOTE_HASH_LENGTH + 2; export const NULLIFIER_LENGTH = 3; export const SCOPED_NULLIFIER_LENGTH = NULLIFIER_LENGTH + 1; export const SIDE_EFFECT_LENGTH = 2; +export const ROLLUP_VALIDATION_REQUESTS_LENGTH = MAX_BLOCK_NUMBER_LENGTH; export const STATE_REFERENCE_LENGTH = APPEND_ONLY_TREE_SNAPSHOT_LENGTH + PARTIAL_STATE_REFERENCE_LENGTH; export const TX_CONTEXT_LENGTH = 2 + GAS_SETTINGS_LENGTH; export const TX_REQUEST_LENGTH = 2 + TX_CONTEXT_LENGTH + FUNCTION_DATA_LENGTH; @@ -156,6 +157,41 @@ export const PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = /* transaction_fee */ 1; export const PRIVATE_CALL_STACK_ITEM_LENGTH = AZTEC_ADDRESS_LENGTH + FUNCTION_DATA_LENGTH + PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH; +export const SCOPED_READ_REQUEST_LEN = READ_REQUEST_LENGTH + 1; +export const PUBLIC_DATA_READ_LENGTH = 2; +export const VALIDATION_REQUESTS_LENGTH = + ROLLUP_VALIDATION_REQUESTS_LENGTH + + SCOPED_READ_REQUEST_LEN * MAX_NOTE_HASH_READ_REQUESTS_PER_TX + + SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_READ_REQUESTS_PER_TX + + SCOPED_READ_REQUEST_LEN * MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX + + SCOPED_NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH * MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX + + PUBLIC_DATA_READ_LENGTH * MAX_PUBLIC_DATA_READS_PER_TX; +export const PUBLIC_DATA_UPDATE_REQUEST_LENGTH = 2; +export const COMBINED_ACCUMULATED_DATA_LENGTH = + MAX_NEW_NOTE_HASHES_PER_TX + + MAX_NEW_NULLIFIERS_PER_TX + + MAX_NEW_L2_TO_L1_MSGS_PER_TX + + 4 + + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * PUBLIC_DATA_UPDATE_REQUEST_LENGTH + + GAS_LENGTH; +export const COMBINED_CONSTANT_DATA_LENGTH = HEADER_LENGTH + TX_CONTEXT_LENGTH + GLOBAL_VARIABLES_LENGTH; +export const CALLER_CONTEXT_LENGTH = 2 * AZTEC_ADDRESS_LENGTH; +export const CALL_REQUEST_LENGTH = 1 + AZTEC_ADDRESS_LENGTH + CALLER_CONTEXT_LENGTH + 2; +export const PRIVATE_ACCUMULATED_DATA_LENGTH = + SCOPED_NOTE_HASH_LENGTH * MAX_NEW_NOTE_HASHES_PER_TX + + SCOPED_NULLIFIER_LENGTH * MAX_NEW_NULLIFIERS_PER_TX + + MAX_NEW_L2_TO_L1_MSGS_PER_TX * SCOPED_L2_TO_L1_MESSAGE_LENGTH + + SIDE_EFFECT_LENGTH * MAX_ENCRYPTED_LOGS_PER_TX + + SIDE_EFFECT_LENGTH * MAX_UNENCRYPTED_LOGS_PER_TX + + 2 + + CALL_REQUEST_LENGTH * MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX + + CALL_REQUEST_LENGTH * MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX; +export const PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = + 1 + + VALIDATION_REQUESTS_LENGTH + + PRIVATE_ACCUMULATED_DATA_LENGTH + + COMBINED_CONSTANT_DATA_LENGTH + + CALL_REQUEST_LENGTH; export const ENQUEUE_PUBLIC_FUNCTION_CALL_RETURN_LENGTH = 2 + FUNCTION_DATA_LENGTH + CALL_CONTEXT_LENGTH; export const GET_NOTES_ORACLE_RETURN_LENGTH = 674; export const NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP = 2048; diff --git a/yarn-project/circuits.js/src/structs/kernel/private_call_data.ts b/yarn-project/circuits.js/src/structs/kernel/private_call_data.ts index 689f2d1d2970..1b492da9c871 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_call_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_call_data.ts @@ -6,12 +6,13 @@ import { FUNCTION_TREE_HEIGHT, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, + RECURSIVE_PROOF_LENGTH, } from '../../constants.gen.js'; import { CallRequest } from '../call_request.js'; import { MembershipWitness } from '../membership_witness.js'; import { PrivateCallStackItem } from '../private_call_stack_item.js'; -import { Proof } from '../proof.js'; -import { VerificationKey } from '../verification_key.js'; +import { RecursiveProof } from '../recursive_proof.js'; +import { VerificationKeyAsFields } from '../verification_key.js'; /** * Private call data. @@ -33,11 +34,11 @@ export class PrivateCallData { /** * The proof of the execution of this private call. */ - public proof: Proof, + public proof: RecursiveProof, /** * The verification key for the function being invoked. */ - public vk: VerificationKey, + public vk: VerificationKeyAsFields, /** * Artifact hash of the contract class for this private call. */ @@ -108,8 +109,8 @@ export class PrivateCallData { reader.readObject(PrivateCallStackItem), reader.readArray(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, CallRequest), reader.readArray(MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, CallRequest), - reader.readObject(Proof), - reader.readObject(VerificationKey), + RecursiveProof.fromBuffer(reader, RECURSIVE_PROOF_LENGTH), + reader.readObject(VerificationKeyAsFields), reader.readObject(Fr), reader.readObject(Fr), reader.readObject(Fr), diff --git a/yarn-project/circuits.js/src/structs/kernel/private_kernel_data.ts b/yarn-project/circuits.js/src/structs/kernel/private_kernel_data.ts index d7310402ee45..6293bfad56e3 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_kernel_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_kernel_data.ts @@ -2,10 +2,10 @@ import { makeTuple } from '@aztec/foundation/array'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader, type Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; -import { VK_TREE_HEIGHT } from '../../constants.gen.js'; -import { Proof, makeEmptyProof } from '../proof.js'; +import { NESTED_RECURSIVE_PROOF_LENGTH, VK_TREE_HEIGHT } from '../../constants.gen.js'; +import { RecursiveProof, makeRecursiveProof } from '../recursive_proof.js'; import { type UInt32 } from '../shared.js'; -import { VerificationKey } from '../verification_key.js'; +import { VerificationKeyAsFields } from '../verification_key.js'; import { PrivateKernelCircuitPublicInputs } from './private_kernel_circuit_public_inputs.js'; /** @@ -20,11 +20,11 @@ export class PrivateKernelData { /** * Proof of the previous kernel. */ - public proof: Proof, + public proof: RecursiveProof, /** * Verification key of the previous kernel. */ - public vk: VerificationKey, + public vk: VerificationKeyAsFields, /** * Index of the previous kernel's vk in a tree of vks. */ @@ -47,8 +47,8 @@ export class PrivateKernelData { const reader = BufferReader.asReader(buffer); return new this( reader.readObject(PrivateKernelCircuitPublicInputs), - reader.readObject(Proof), - reader.readObject(VerificationKey), + RecursiveProof.fromBuffer(reader, NESTED_RECURSIVE_PROOF_LENGTH), + reader.readObject(VerificationKeyAsFields), reader.readNumber(), reader.readArray(VK_TREE_HEIGHT, Fr), ); @@ -57,8 +57,8 @@ export class PrivateKernelData { static empty(): PrivateKernelData { return new PrivateKernelData( PrivateKernelCircuitPublicInputs.empty(), - makeEmptyProof(), - VerificationKey.makeFake(), + makeRecursiveProof(NESTED_RECURSIVE_PROOF_LENGTH), + VerificationKeyAsFields.makeFake(), 0, makeTuple(VK_TREE_HEIGHT, Fr.zero), ); diff --git a/yarn-project/circuits.js/src/structs/verification_key.ts b/yarn-project/circuits.js/src/structs/verification_key.ts index b7f47e231625..e617e48f7a93 100644 --- a/yarn-project/circuits.js/src/structs/verification_key.ts +++ b/yarn-project/circuits.js/src/structs/verification_key.ts @@ -108,6 +108,14 @@ export class VerificationKeyAsFields { static makeFake(seed = 1): VerificationKeyAsFields { return new VerificationKeyAsFields(makeTuple(VERIFICATION_KEY_LENGTH_IN_FIELDS, Fr.random, seed), Fr.random()); } + + /** + * Builds an 'empty' verification key + * @returns An 'empty' verification key + */ + static makeEmpty(): VerificationKeyAsFields { + return new VerificationKeyAsFields(makeTuple(VERIFICATION_KEY_LENGTH_IN_FIELDS, Fr.zero), Fr.zero()); + } } export class VerificationKey { diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index 6dc5712a2faf..90208fa660ac 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -729,8 +729,8 @@ export function makePrivateCallData(seed = 1): PrivateCallData { callStackItem: makePrivateCallStackItem(seed), privateCallStack: makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, makeCallRequest, seed + 0x10), publicCallStack: makeTuple(MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, makeCallRequest, seed + 0x20), - proof: new Proof(Buffer.alloc(16).fill(seed + 0x50)), - vk: makeVerificationKey(), + proof: makeRecursiveProof(RECURSIVE_PROOF_LENGTH, seed + 0x50), + vk: makeVerificationKeyAsFields(), contractClassArtifactHash: fr(seed + 0x70), contractClassPublicBytecodeCommitment: fr(seed + 0x71), publicKeysHash: fr(seed + 0x72), diff --git a/yarn-project/end-to-end/src/client_prover_integration/client_prover_integration.test.ts b/yarn-project/end-to-end/src/client_prover_integration/client_prover_integration.test.ts index ed244b2da643..2cda2f3aa0c0 100644 --- a/yarn-project/end-to-end/src/client_prover_integration/client_prover_integration.test.ts +++ b/yarn-project/end-to-end/src/client_prover_integration/client_prover_integration.test.ts @@ -5,7 +5,7 @@ import { type BBNativeProofCreator } from '@aztec/pxe'; import { ClientProverTest } from './client_prover_test.js'; async function verifyProof(circuitType: ClientProtocolArtifact, tx: Tx, proofCreator: BBNativeProofCreator) { - await expect(proofCreator.verifyProof(circuitType, tx.proof)).resolves.not.toThrow(); + await expect(proofCreator.verifyProofForProtocolCircuit(circuitType, tx.proof)).resolves.not.toThrow(); } describe('client_prover_integration', () => { 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 ec844c1a3d68..659afa884a72 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -786,8 +786,8 @@ export function mapPrivateCallDataToNoir(privateCallData: PrivateCallData): Priv call_stack_item: mapPrivateCallStackItemToNoir(privateCallData.callStackItem), private_call_stack: mapTuple(privateCallData.privateCallStack, mapCallRequestToNoir), public_call_stack: mapTuple(privateCallData.publicCallStack, mapCallRequestToNoir), - proof: {}, - vk: {}, + proof: mapRecursiveProofToNoir(privateCallData.proof), + vk: mapVerificationKeyToNoir(privateCallData.vk), function_leaf_membership_witness: mapMembershipWitnessToNoir(privateCallData.functionLeafMembershipWitness), contract_class_artifact_hash: mapFieldToNoir(privateCallData.contractClassArtifactHash), contract_class_public_bytecode_commitment: mapFieldToNoir(privateCallData.contractClassPublicBytecodeCommitment), @@ -1235,7 +1235,6 @@ export function mapPublicKernelCircuitPublicInputsToNoir( inputs: PublicKernelCircuitPublicInputs, ): PublicKernelCircuitPublicInputsNoir { return { - aggregation_object: {}, constants: mapCombinedConstantDataToNoir(inputs.constants), validation_requests: mapValidationRequestsToNoir(inputs.validationRequests), end: mapPublicAccumulatedDataToNoir(inputs.end), @@ -1258,7 +1257,6 @@ export function mapKernelCircuitPublicInputsFromNoir(inputs: KernelCircuitPublic export function mapKernelCircuitPublicInputsToNoir(inputs: KernelCircuitPublicInputs): KernelCircuitPublicInputsNoir { return { - aggregation_object: {}, rollup_validation_requests: mapRollupValidationRequestsToNoir(inputs.rollupValidationRequests), constants: mapCombinedConstantDataToNoir(inputs.constants), end: mapCombinedAccumulatedDataToNoir(inputs.end), @@ -1316,7 +1314,6 @@ export function mapPrivateKernelCircuitPublicInputsToNoir( inputs: PrivateKernelCircuitPublicInputs, ): PrivateKernelCircuitPublicInputsNoir { return { - aggregation_object: {}, constants: mapCombinedConstantDataToNoir(inputs.constants), validation_requests: mapValidationRequestsToNoir(inputs.validationRequests), end: mapPrivateAccumulatedDataToNoir(inputs.end), @@ -1333,8 +1330,8 @@ export function mapPrivateKernelCircuitPublicInputsToNoir( export function mapPrivateKernelDataToNoir(privateKernelInnerData: PrivateKernelData): PrivateKernelDataNoir { return { public_inputs: mapPrivateKernelCircuitPublicInputsToNoir(privateKernelInnerData.publicInputs), - proof: {}, - vk: {}, + proof: mapRecursiveProofToNoir(privateKernelInnerData.proof), + vk: mapVerificationKeyToNoir(privateKernelInnerData.vk), vk_index: mapFieldToNoir(new Fr(privateKernelInnerData.vkIndex)), vk_path: mapTuple(privateKernelInnerData.vkPath, mapFieldToNoir), }; @@ -1733,17 +1730,11 @@ export function mapAppendOnlyTreeSnapshotToNoir(snapshot: AppendOnlyTreeSnapshot }; } -export function mapRootRollupRecursiveProofToNoir(proof: RecursiveProof) { - return { - fields: mapTuple(proof.proof, mapFieldToNoir), - }; -} - export function mapRootRollupParityInputToNoir( rootParityInput: RootParityInput, ): RootRollupParityInputNoir { return { - proof: mapRootRollupRecursiveProofToNoir(rootParityInput.proof), + proof: mapRecursiveProofToNoir(rootParityInput.proof), verification_key: mapVerificationKeyToNoir(rootParityInput.verificationKey), public_inputs: mapParityPublicInputsToNoir(rootParityInput.publicInputs), }; @@ -1771,7 +1762,7 @@ export function mapRootRollupInputsToNoir(rootRollupInputs: RootRollupInputs): R }; } -export function mapRecursiveProofToNoir(proof: RecursiveProof) { +export function mapRecursiveProofToNoir(proof: RecursiveProof) { return { fields: mapTuple(proof.proof, mapFieldToNoir), }; diff --git a/yarn-project/pxe/src/kernel_prover/bb_prover/bb_native_proof_creator.ts b/yarn-project/pxe/src/kernel_prover/bb_prover/bb_native_proof_creator.ts index 15eed0996a9c..cfb7c5d88709 100644 --- a/yarn-project/pxe/src/kernel_prover/bb_prover/bb_native_proof_creator.ts +++ b/yarn-project/pxe/src/kernel_prover/bb_prover/bb_native_proof_creator.ts @@ -1,5 +1,6 @@ import { Fr, + NESTED_RECURSIVE_PROOF_LENGTH, type PrivateCircuitPublicInputs, type PrivateKernelCircuitPublicInputs, type PrivateKernelInitCircuitPrivateInputs, @@ -7,7 +8,10 @@ import { type PrivateKernelTailCircuitPrivateInputs, type PrivateKernelTailCircuitPublicInputs, Proof, + RECURSIVE_PROOF_LENGTH, + RecursiveProof, type VERIFICATION_KEY_LENGTH_IN_FIELDS, + VerificationKeyAsFields, } from '@aztec/circuits.js'; import { siloNoteHash } from '@aztec/circuits.js/hash'; import { randomBytes, sha256 } from '@aztec/foundation/crypto'; @@ -34,7 +38,7 @@ import { serializeWitness } from '@noir-lang/noirc_abi'; import * as proc from 'child_process'; import * as fs from 'fs/promises'; -import { type ProofCreator, type ProofOutput } from '../interface/proof_creator.js'; +import { type AppCircuitProofOutput, type KernelProofOutput, type ProofCreator } from '../interface/proof_creator.js'; /** * Temporary implementation of ProofCreator using the native bb binary. @@ -44,9 +48,9 @@ import { type ProofCreator, type ProofOutput } from '../interface/proof_creator. const VK_FILENAME = 'vk'; const VK_FIELDS_FILENAME = 'vk_fields.json'; const PROOF_FILENAME = 'proof'; -//const PROOF_FIELDS_FILENAME = 'proof_fields.json'; +const PROOF_FIELDS_FILENAME = 'proof_fields.json'; -//const AGGREGATION_OBJECT_SIZE = 16; +const AGGREGATION_OBJECT_SIZE = 16; const CIRCUIT_SIZE_INDEX = 3; const CIRCUIT_PUBLIC_INPUTS_INDEX = 4; const CIRCUIT_RECURSIVE_INDEX = 5; @@ -452,21 +456,21 @@ export class BBNativeProofCreator implements ProofCreator { public async createProofInit( inputs: PrivateKernelInitCircuitPrivateInputs, - ): Promise> { + ): Promise> { const witnessMap = convertPrivateKernelInitInputsToWitnessMap(inputs); return await this.createSafeProof(witnessMap, 'PrivateKernelInitArtifact'); } public async createProofInner( inputs: PrivateKernelInnerCircuitPrivateInputs, - ): Promise> { + ): Promise> { const witnessMap = convertPrivateKernelInnerInputsToWitnessMap(inputs); return await this.createSafeProof(witnessMap, 'PrivateKernelInnerArtifact'); } public async createProofTail( inputs: PrivateKernelTailCircuitPrivateInputs, - ): Promise> { + ): Promise> { if (!inputs.isForPublic()) { const witnessMap = convertPrivateKernelTailInputsToWitnessMap(inputs); return await this.createSafeProof(witnessMap, 'PrivateKernelTailArtifact'); @@ -475,14 +479,25 @@ export class BBNativeProofCreator implements ProofCreator { return await this.createSafeProof(witnessMap, 'PrivateKernelTailToPublicArtifact'); } - public async createAppCircuitProof(partialWitness: Map, bytecode: Buffer): Promise { + public async createAppCircuitProof( + partialWitness: Map, + bytecode: Buffer, + ): Promise { const directory = `${this.bbWorkingDirectory}/${randomBytes(8).toString('hex')}`; await fs.mkdir(directory, { recursive: true }); this.log.debug(`Created directory: ${directory}`); try { this.log.debug(`Proving app circuit`); - const proof = await this.createProof(directory, partialWitness, bytecode, 'App'); - return new Proof(proof); + const proofOutput = await this.createProof(directory, partialWitness, bytecode, 'App'); + if (proofOutput.proof.proof.length != RECURSIVE_PROOF_LENGTH) { + throw new Error(`Incorrect proof length`); + } + const proof = proofOutput.proof as RecursiveProof; + const output: AppCircuitProofOutput = { + proof, + verificationKey: proofOutput.verificationKey, + }; + return output; } finally { await fs.rm(directory, { recursive: true, force: true }); this.log.debug(`Deleted directory: ${directory}`); @@ -494,27 +509,16 @@ export class BBNativeProofCreator implements ProofCreator { * @param circuitType - The type of circuit whose proof is to be verified * @param proof - The proof to be verified */ - public async verifyProof(circuitType: ClientProtocolArtifact, proof: Proof) { - // Create random directory to be used for temp files - const bbWorkingDirectory = `${this.bbWorkingDirectory}/${randomBytes(8).toString('hex')}`; - await fs.mkdir(bbWorkingDirectory, { recursive: true }); - - const proofFileName = `${bbWorkingDirectory}/proof`; - const verificationKeyPath = `${bbWorkingDirectory}/vk`; + public async verifyProofForProtocolCircuit(circuitType: ClientProtocolArtifact, proof: Proof) { const verificationKey = await this.getVerificationKeyDataForCircuit(circuitType); this.log.debug(`Verifying with key: ${verificationKey.hash.toString()}`); - await fs.writeFile(proofFileName, proof.buffer); - await fs.writeFile(verificationKeyPath, verificationKey.keyAsBytes); - const logFunction = (message: string) => { this.log.debug(`${circuitType} BB out - ${message}`); }; - const result = await verifyProof(this.bbBinaryPath, proofFileName, verificationKeyPath!, logFunction); - - await fs.rm(bbWorkingDirectory, { recursive: true, force: true }); + const result = await this.verifyProofFromKey(verificationKey.keyAsBytes, proof, logFunction); if (result.status === BB_RESULT.FAILURE) { const errorMessage = `Failed to verify ${circuitType} proof!`; @@ -524,6 +528,28 @@ export class BBNativeProofCreator implements ProofCreator { this.log.info(`Successfully verified ${circuitType} proof in ${result.duration} ms`); } + private async verifyProofFromKey( + verificationKey: Buffer, + proof: Proof, + logFunction: (message: string) => void = () => {}, + ) { + // Create random directory to be used for temp files + const bbWorkingDirectory = `${this.bbWorkingDirectory}/${randomBytes(8).toString('hex')}`; + await fs.mkdir(bbWorkingDirectory, { recursive: true }); + + const proofFileName = `${bbWorkingDirectory}/proof`; + const verificationKeyPath = `${bbWorkingDirectory}/vk`; + + await fs.writeFile(proofFileName, proof.buffer); + await fs.writeFile(verificationKeyPath, verificationKey); + + try { + return await verifyProof(this.bbBinaryPath, proofFileName, verificationKeyPath!, logFunction); + } finally { + await fs.rm(bbWorkingDirectory, { recursive: true, force: true }); + } + } + /** * Returns the verification key data for a circuit, will generate and cache it if not cached internally * @param circuitType - The type of circuit for which the verification key is required @@ -588,10 +614,13 @@ export class BBNativeProofCreator implements ProofCreator { this.log.debug(`Updated verification key for circuit: ${circuitType}`); this.verificationKeys.set(circuitType, promise); } - await promise; + return await promise; } - private async createSafeProof(inputs: WitnessMap, circuitType: ClientProtocolArtifact): Promise> { + private async createSafeProof( + inputs: WitnessMap, + circuitType: ClientProtocolArtifact, + ): Promise> { const directory = `${this.bbWorkingDirectory}/${randomBytes(8).toString('hex')}`; await fs.mkdir(directory, { recursive: true }); this.log.debug(`Created directory: ${directory}`); @@ -607,7 +636,7 @@ export class BBNativeProofCreator implements ProofCreator { inputs: WitnessMap, circuitType: ClientProtocolArtifact, directory: string, - ): Promise> { + ): Promise> { this.log.debug(`Generating witness for ${circuitType}`); const compiledCircuit: NoirCompiledCircuit = ClientCircuitArtifacts[circuitType]; @@ -617,18 +646,23 @@ export class BBNativeProofCreator implements ProofCreator { const publicInputs = KernelArtifactMapping[circuitType].convertOutputs(outputWitness) as T; - const proofBuffer = await this.createProof( + const proofOutput = await this.createProof( directory, outputWitness, Buffer.from(compiledCircuit.bytecode, 'base64'), circuitType, ); + if (proofOutput.proof.proof.length != NESTED_RECURSIVE_PROOF_LENGTH) { + throw new Error(`Incorrect proof length`); + } + const nestedProof = proofOutput.proof as RecursiveProof; - const proofOutput: ProofOutput = { + const kernelOutput: KernelProofOutput = { publicInputs, - proof: new Proof(proofBuffer), + proof: nestedProof, + verificationKey: proofOutput.verificationKey, }; - return proofOutput; + return kernelOutput; } private async createProof( @@ -636,7 +670,10 @@ export class BBNativeProofCreator implements ProofCreator { partialWitness: WitnessMap, bytecode: Buffer, circuitType: ClientProtocolArtifact | 'App', - ) { + ): Promise<{ + proof: RecursiveProof | RecursiveProof; + verificationKey: VerificationKeyAsFields; + }> { const compressedBincodedWitness = serializeWitness(partialWitness); const inputsWitnessFile = `${directory}/witness.gz`; @@ -659,11 +696,15 @@ export class BBNativeProofCreator implements ProofCreator { throw new Error(provingResult.reason); } - if (circuitType !== 'App') { - await this.updateVerificationKeyAfterProof(directory, circuitType); + if (circuitType === 'App') { + const vkData = await this.convertVk(directory); + const proof = await this.readProofAsFields(directory, circuitType, vkData); + return { proof, verificationKey: new VerificationKeyAsFields(vkData.keyAsFields, vkData.hash) }; } - const proofFile = `${directory}/${PROOF_FILENAME}`; - return await fs.readFile(proofFile); + + const vkData = await this.updateVerificationKeyAfterProof(directory, circuitType); + const proof = await this.readProofAsFields(directory, circuitType, vkData); + return { proof, verificationKey: new VerificationKeyAsFields(vkData.keyAsFields, vkData.hash) }; } /** @@ -672,28 +713,24 @@ export class BBNativeProofCreator implements ProofCreator { * @param circuitType - The type of circuit proven * @returns The proof */ - // private async readProofAsFields( - // filePath: string, - // circuitType: ClientProtocolArtifact, - // ): Promise> { - // const [binaryProof, proofString] = await Promise.all([ - // fs.readFile(`${filePath}/${PROOF_FILENAME}`), - // fs.readFile(`${filePath}/${PROOF_FIELDS_FILENAME}`, { encoding: 'utf-8' }), - // ]); - // const json = JSON.parse(proofString); - // const fields = json.map(Fr.fromString); - // const vkData = await this.verificationKeys.get(circuitType); - // if (!vkData) { - // throw new Error(`Invalid verification key for ${circuitType}`); - // } - // const numPublicInputs = CIRCUITS_WITHOUT_AGGREGATION.has(circuitType) - // ? vkData.numPublicInputs - // : vkData.numPublicInputs - AGGREGATION_OBJECT_SIZE; - // const fieldsWithoutPublicInputs = fields.slice(numPublicInputs); - // logger.debug( - // `Circuit type: ${circuitType}, complete proof length: ${fields.length}, without public inputs: ${fieldsWithoutPublicInputs.length}, num public inputs: ${numPublicInputs}, circuit size: ${vkData.circuitSize}, is recursive: ${vkData.isRecursive}, raw length: ${binaryProof.length}`, - // ); - // const proof = new RecursiveProof(fieldsWithoutPublicInputs, new Proof(binaryProof)); - // return proof; - // } + private async readProofAsFields( + filePath: string, + circuitType: ClientProtocolArtifact | 'App', + vkData: VerificationKeyData, + ): Promise> { + const [binaryProof, proofString] = await Promise.all([ + fs.readFile(`${filePath}/${PROOF_FILENAME}`), + fs.readFile(`${filePath}/${PROOF_FIELDS_FILENAME}`, { encoding: 'utf-8' }), + ]); + const json = JSON.parse(proofString); + const fields = json.map(Fr.fromString); + const numPublicInputs = + circuitType === 'App' ? vkData.numPublicInputs : vkData.numPublicInputs - AGGREGATION_OBJECT_SIZE; + const fieldsWithoutPublicInputs = fields.slice(numPublicInputs); + this.log.debug( + `Circuit type: ${circuitType}, complete proof length: ${fields.length}, without public inputs: ${fieldsWithoutPublicInputs.length}, num public inputs: ${numPublicInputs}, circuit size: ${vkData.circuitSize}, is recursive: ${vkData.isRecursive}, raw length: ${binaryProof.length}`, + ); + const proof = new RecursiveProof(fieldsWithoutPublicInputs, new Proof(binaryProof)); + return proof; + } } diff --git a/yarn-project/pxe/src/kernel_prover/interface/proof_creator.ts b/yarn-project/pxe/src/kernel_prover/interface/proof_creator.ts index 5e085ae3b347..5b93d6980589 100644 --- a/yarn-project/pxe/src/kernel_prover/interface/proof_creator.ts +++ b/yarn-project/pxe/src/kernel_prover/interface/proof_creator.ts @@ -1,11 +1,14 @@ import { + type NESTED_RECURSIVE_PROOF_LENGTH, type PrivateCircuitPublicInputs, type PrivateKernelCircuitPublicInputs, type PrivateKernelInitCircuitPrivateInputs, type PrivateKernelInnerCircuitPrivateInputs, type PrivateKernelTailCircuitPrivateInputs, type PrivateKernelTailCircuitPublicInputs, - type Proof, + type RECURSIVE_PROOF_LENGTH, + type RecursiveProof, + type VerificationKeyAsFields, } from '@aztec/circuits.js'; import { type Fr } from '@aztec/foundation/fields'; import { type ACVMField } from '@aztec/simulator'; @@ -14,7 +17,7 @@ import { type ACVMField } from '@aztec/simulator'; * Represents the output of the proof creation process for init and inner private kernel circuit. * Contains the public inputs required for the init and inner private kernel circuit and the generated proof. */ -export type ProofOutput = { +export type KernelProofOutput = { /** * The public inputs required for the proof generation process. */ @@ -22,7 +25,22 @@ export type ProofOutput = { /** * The zk-SNARK proof for the kernel execution. */ - proof: Proof; + proof: RecursiveProof; + + verificationKey: VerificationKeyAsFields; +}; + +/** + * Represents the output of the proof creation process for init and inner private kernel circuit. + * Contains the public inputs required for the init and inner private kernel circuit and the generated proof. + */ +export type AppCircuitProofOutput = { + /** + * The zk-SNARK proof for the kernel execution. + */ + proof: RecursiveProof; + + verificationKey: VerificationKeyAsFields; }; /** @@ -46,7 +64,7 @@ export interface ProofCreator { */ createProofInit( privateKernelInputsInit: PrivateKernelInitCircuitPrivateInputs, - ): Promise>; + ): Promise>; /** * Creates a proof output for a given previous kernel data and private call data for an inner iteration. @@ -56,7 +74,7 @@ export interface ProofCreator { */ createProofInner( privateKernelInputsInner: PrivateKernelInnerCircuitPrivateInputs, - ): Promise>; + ): Promise>; /** * Creates a proof output based on the last inner kernel iteration kernel data for the final ordering iteration. @@ -66,7 +84,7 @@ export interface ProofCreator { */ createProofTail( privateKernelInputsTail: PrivateKernelTailCircuitPrivateInputs, - ): Promise>; + ): Promise>; /** * Creates a proof for an app circuit. @@ -75,5 +93,5 @@ export interface ProofCreator { * @param bytecode - The circuit bytecode in gzipped bincode format * @returns A Promise resolving to a Proof object */ - createAppCircuitProof(partialWitness: Map, bytecode: Buffer): Promise; + createAppCircuitProof(partialWitness: Map, bytecode: Buffer): Promise; } diff --git a/yarn-project/pxe/src/kernel_prover/kernel_prover.test.ts b/yarn-project/pxe/src/kernel_prover/kernel_prover.test.ts index 58f29d4ceda2..6a52d2c7a672 100644 --- a/yarn-project/pxe/src/kernel_prover/kernel_prover.test.ts +++ b/yarn-project/pxe/src/kernel_prover/kernel_prover.test.ts @@ -5,16 +5,19 @@ import { MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NEW_NOTE_HASHES_PER_TX, MembershipWitness, + NESTED_RECURSIVE_PROOF_LENGTH, NoteHash, PrivateCallStackItem, PrivateCircuitPublicInputs, PrivateKernelCircuitPublicInputs, PrivateKernelTailCircuitPublicInputs, + RECURSIVE_PROOF_LENGTH, ScopedNoteHash, type TxRequest, VK_TREE_HEIGHT, VerificationKey, - makeEmptyProof, + VerificationKeyAsFields, + makeRecursiveProof, } from '@aztec/circuits.js'; import { makeTxRequest } from '@aztec/circuits.js/testing'; import { makeTuple } from '@aztec/foundation/array'; @@ -91,7 +94,8 @@ describe('Kernel Prover', () => { publicInputs.end.newNoteHashes = noteHashes; return { publicInputs, - proof: makeEmptyProof(), + proof: makeRecursiveProof(NESTED_RECURSIVE_PROOF_LENGTH), + verificationKey: VerificationKeyAsFields.makeEmpty(), }; }; @@ -105,7 +109,15 @@ describe('Kernel Prover', () => { return { publicInputs, - proof: makeEmptyProof(), + proof: makeRecursiveProof(NESTED_RECURSIVE_PROOF_LENGTH), + verificationKey: VerificationKeyAsFields.makeEmpty(), + }; + }; + + const createAppCircuitProofOutput = () => { + return { + proof: makeRecursiveProof(RECURSIVE_PROOF_LENGTH), + verificationKey: VerificationKeyAsFields.makeEmpty(), }; }; @@ -151,6 +163,7 @@ describe('Kernel Prover', () => { proofCreator.createProofInit.mockResolvedValue(createProofOutput([])); proofCreator.createProofInner.mockResolvedValue(createProofOutput([])); proofCreator.createProofTail.mockResolvedValue(createProofOutputFinal([])); + proofCreator.createAppCircuitProof.mockResolvedValue(createAppCircuitProofOutput()); prover = new KernelProver(oracle, proofCreator); }); diff --git a/yarn-project/pxe/src/kernel_prover/kernel_prover.ts b/yarn-project/pxe/src/kernel_prover/kernel_prover.ts index 73612e9e7513..e0f2a0fad4a9 100644 --- a/yarn-project/pxe/src/kernel_prover/kernel_prover.ts +++ b/yarn-project/pxe/src/kernel_prover/kernel_prover.ts @@ -3,6 +3,7 @@ import { Fr, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, + NESTED_RECURSIVE_PROOF_LENGTH, PrivateCallData, PrivateKernelCircuitPublicInputs, PrivateKernelData, @@ -10,11 +11,12 @@ import { PrivateKernelInnerCircuitPrivateInputs, PrivateKernelTailCircuitPrivateInputs, type PrivateKernelTailCircuitPublicInputs, - type Proof, + type RECURSIVE_PROOF_LENGTH, + type RecursiveProof, type TxRequest, VK_TREE_HEIGHT, - VerificationKey, - makeEmptyProof, + VerificationKeyAsFields, + makeRecursiveProof, } from '@aztec/circuits.js'; import { padArrayEnd } from '@aztec/foundation/collection'; import { createDebugLogger } from '@aztec/foundation/log'; @@ -22,7 +24,7 @@ import { assertLength } from '@aztec/foundation/serialize'; import { pushTestData } from '@aztec/foundation/testing'; import { type ExecutionResult, collectNoteHashLeafIndexMap, collectNullifiedNoteHashCounters } from '@aztec/simulator'; -import { type ProofCreator, type ProofOutput } from './interface/proof_creator.js'; +import { type KernelProofOutput, type ProofCreator } from './interface/proof_creator.js'; import { buildPrivateKernelInnerHints, buildPrivateKernelTailHints, @@ -54,14 +56,14 @@ export class KernelProver { async prove( txRequest: TxRequest, executionResult: ExecutionResult, - ): Promise> { + ): Promise> { const executionStack = [executionResult]; let firstIteration = true; - let previousVerificationKey = VerificationKey.makeFake(); - let output: ProofOutput = { + let output: KernelProofOutput = { publicInputs: PrivateKernelCircuitPublicInputs.empty(), - proof: makeEmptyProof(), + proof: makeRecursiveProof(NESTED_RECURSIVE_PROOF_LENGTH), + verificationKey: VerificationKeyAsFields.makeEmpty(), }; const noteHashLeafIndexMap = collectNoteHashLeafIndexMap(executionResult); @@ -76,7 +78,7 @@ export class KernelProver { ); const publicCallRequests = currentExecution.enqueuedPublicFunctionCalls.map(result => result.toCallRequest()); - const proof = await this.proofCreator.createAppCircuitProof( + const proofOutput = await this.proofCreator.createAppCircuitProof( currentExecution.partialWitness, currentExecution.acir, ); @@ -85,7 +87,8 @@ export class KernelProver { currentExecution, privateCallRequests, publicCallRequests, - proof, + proofOutput.proof, + proofOutput.verificationKey, ); const hints = buildPrivateKernelInnerHints( @@ -98,11 +101,11 @@ export class KernelProver { pushTestData('private-kernel-inputs-init', proofInput); output = await this.proofCreator.createProofInit(proofInput); } else { - const previousVkMembershipWitness = await this.oracle.getVkMembershipWitness(previousVerificationKey); + const previousVkMembershipWitness = await this.oracle.getVkMembershipWitness(output.verificationKey); const previousKernelData = new PrivateKernelData( output.publicInputs, output.proof, - previousVerificationKey, + output.verificationKey, Number(previousVkMembershipWitness.leafIndex), assertLength(previousVkMembershipWitness.siblingPath, VK_TREE_HEIGHT), ); @@ -111,14 +114,13 @@ export class KernelProver { output = await this.proofCreator.createProofInner(proofInput); } firstIteration = false; - previousVerificationKey = privateCallData.vk; } - const previousVkMembershipWitness = await this.oracle.getVkMembershipWitness(previousVerificationKey); + const previousVkMembershipWitness = await this.oracle.getVkMembershipWitness(output.verificationKey); const previousKernelData = new PrivateKernelData( output.publicInputs, output.proof, - previousVerificationKey, + output.verificationKey, Number(previousVkMembershipWitness.leafIndex), assertLength(previousVkMembershipWitness.siblingPath, VK_TREE_HEIGHT), ); @@ -138,10 +140,11 @@ export class KernelProver { } private async createPrivateCallData( - { callStackItem, vk }: ExecutionResult, + { callStackItem }: ExecutionResult, privateCallRequests: CallRequest[], publicCallRequests: CallRequest[], - proof: Proof, + proof: RecursiveProof, + vk: VerificationKeyAsFields, ) { const { contractAddress, functionData } = callStackItem; @@ -172,7 +175,7 @@ export class KernelProver { privateCallStack, publicCallStack, proof, - vk: VerificationKey.fromBuffer(vk), + vk, publicKeysHash, contractClassArtifactHash, contractClassPublicBytecodeCommitment, diff --git a/yarn-project/pxe/src/kernel_prover/proving_data_oracle.ts b/yarn-project/pxe/src/kernel_prover/proving_data_oracle.ts index ba408e4cf771..04af3cad3edc 100644 --- a/yarn-project/pxe/src/kernel_prover/proving_data_oracle.ts +++ b/yarn-project/pxe/src/kernel_prover/proving_data_oracle.ts @@ -8,7 +8,7 @@ import { type NOTE_HASH_TREE_HEIGHT, type Point, type VK_TREE_HEIGHT, - type VerificationKey, + type VerificationKeyAsFields, } from '@aztec/circuits.js'; import { type AztecAddress } from '@aztec/foundation/aztec-address'; @@ -50,7 +50,7 @@ export interface ProvingDataOracle { * @param vk - The VerificationKey for which the membership witness is needed. * @returns A Promise that resolves to the MembershipWitness instance. */ - getVkMembershipWitness(vk: VerificationKey): Promise>; + getVkMembershipWitness(vk: VerificationKeyAsFields): Promise>; /** * Get the note membership witness for a note in the note hash tree at the given leaf index. diff --git a/yarn-project/pxe/src/kernel_prover/test/test_circuit_prover.ts b/yarn-project/pxe/src/kernel_prover/test/test_circuit_prover.ts index 4880e937eebd..6b3a29e72b8e 100644 --- a/yarn-project/pxe/src/kernel_prover/test/test_circuit_prover.ts +++ b/yarn-project/pxe/src/kernel_prover/test/test_circuit_prover.ts @@ -1,20 +1,22 @@ import { type CircuitSimulationStats } from '@aztec/circuit-types/stats'; import { + NESTED_RECURSIVE_PROOF_LENGTH, type PrivateCircuitPublicInputs, type PrivateKernelCircuitPublicInputs, type PrivateKernelInitCircuitPrivateInputs, type PrivateKernelInnerCircuitPrivateInputs, type PrivateKernelTailCircuitPrivateInputs, type PrivateKernelTailCircuitPublicInputs, - Proof, - makeEmptyProof, + RECURSIVE_PROOF_LENGTH, + VerificationKeyAsFields, + makeRecursiveProof, } from '@aztec/circuits.js'; import { siloNoteHash } from '@aztec/circuits.js/hash'; import { createDebugLogger } from '@aztec/foundation/log'; import { elapsed } from '@aztec/foundation/timer'; import { executeInit, executeInner, executeTail, executeTailForPublic } from '@aztec/noir-protocol-circuits-types'; -import { type ProofCreator, type ProofOutput } from '../interface/proof_creator.js'; +import { type AppCircuitProofOutput, type KernelProofOutput, type ProofCreator } from '../interface/proof_creator.js'; /** * Test Proof Creator executes circuit simulations and provides fake proofs. @@ -32,7 +34,7 @@ export class TestProofCreator implements ProofCreator { public async createProofInit( privateInputs: PrivateKernelInitCircuitPrivateInputs, - ): Promise> { + ): Promise> { const [duration, result] = await elapsed(() => executeInit(privateInputs)); this.log.debug(`Simulated private kernel init`, { eventName: 'circuit-simulation', @@ -41,17 +43,12 @@ export class TestProofCreator implements ProofCreator { inputSize: privateInputs.toBuffer().length, outputSize: result.toBuffer().length, } satisfies CircuitSimulationStats); - const proof = makeEmptyProof(); - - return { - publicInputs: result, - proof: proof, - }; + return this.makeEmptyKernelProofOutput(result); } public async createProofInner( privateInputs: PrivateKernelInnerCircuitPrivateInputs, - ): Promise> { + ): Promise> { const [duration, result] = await elapsed(() => executeInner(privateInputs)); this.log.debug(`Simulated private kernel inner`, { eventName: 'circuit-simulation', @@ -60,17 +57,12 @@ export class TestProofCreator implements ProofCreator { inputSize: privateInputs.toBuffer().length, outputSize: result.toBuffer().length, } satisfies CircuitSimulationStats); - const proof = makeEmptyProof(); - - return { - publicInputs: result, - proof: proof, - }; + return this.makeEmptyKernelProofOutput(result); } public async createProofTail( privateInputs: PrivateKernelTailCircuitPrivateInputs, - ): Promise> { + ): Promise> { const isForPublic = privateInputs.isForPublic(); const [duration, result] = await elapsed(() => isForPublic ? executeTailForPublic(privateInputs) : executeTail(privateInputs), @@ -82,15 +74,23 @@ export class TestProofCreator implements ProofCreator { inputSize: privateInputs.toBuffer().length, outputSize: result.toBuffer().length, } satisfies CircuitSimulationStats); - const proof = makeEmptyProof(); + return this.makeEmptyKernelProofOutput(result); + } - return { - publicInputs: result, - proof: proof, + createAppCircuitProof(_1: Map, _2: Buffer): Promise { + const appCircuitProofOutput: AppCircuitProofOutput = { + proof: makeRecursiveProof(RECURSIVE_PROOF_LENGTH), + verificationKey: VerificationKeyAsFields.makeEmpty(), }; + return Promise.resolve(appCircuitProofOutput); } - createAppCircuitProof(_1: Map, _2: Buffer): Promise { - return Promise.resolve(new Proof(Buffer.alloc(0))); + private makeEmptyKernelProofOutput(publicInputs: PublicInputsType) { + const kernelProofOutput: KernelProofOutput = { + publicInputs, + proof: makeRecursiveProof(NESTED_RECURSIVE_PROOF_LENGTH), + verificationKey: VerificationKeyAsFields.makeEmpty(), + }; + return kernelProofOutput; } } diff --git a/yarn-project/pxe/src/pxe_service/pxe_service.ts b/yarn-project/pxe/src/pxe_service/pxe_service.ts index 1f0e859fa8fe..02ff03a95ee0 100644 --- a/yarn-project/pxe/src/pxe_service/pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/pxe_service.ts @@ -678,7 +678,7 @@ export class PXEService implements PXE { const tx = new Tx( publicInputs, - proof, + proof.binaryProof, encryptedLogs, unencryptedLogs, enqueuedPublicFunctions,