Private Kernel Circuit - Inner
Requirements
Each inner kernel iteration processes a private function call and the results of a previous kernel iteration.
Verification of the Previous Iteration
Verifying the previous kernel proof.
It verifies that the previous iteration was executed successfully with the provided proof data, verification key, and public inputs, sourced from private_inputs
.previous_kernel
.
The preceding proof can be:
- Initial private kernel proof.
- Inner private kernel proof.
- Reset private kernel proof.
The previous proof and the proof for the current function call are verified using recursion.
Processing Private Function Call
Ensuring the function being called exists in the contract.
This section follows the same process as outlined in the initial private kernel circuit.
Ensuring the current call matches the call request.
The top item in the private_call_request_stack
of the previous_kernel
must pertain to the current function call.
This circuit will:
Pop the call request from the stack:
call_request = previous_kernel.public_inputs.transient_accumulated_data.private_call_request_stack.pop()
Compare the hash with that of the current function call:
call_request.call_stack_item_hash == private_call.call_stack_item.hash()
- The hash of the
call_stack_item
is computed as:hash(contract_address, function_data.hash(), public_inputs.hash())
- Where
function_data.hash()
andpublic_inputs.hash()
are the hashes of the serialized field elements.
Ensuring this function is called with the correct context.
For the call_context
in the public_inputs
of the private_call
.call_stack_item
and the call_request
popped in the previous step, this circuit checks that:
If it is a standard call:
call_context.is_delegate_call == false
- The
msg_sender
of the current iteration must be the same as the caller'scontract_address
:call_context.msg_sender == call_request.caller_contract_address
- The
storage_contract_address
of the current iteration must be the same as itscontract_address
:call_context.storage_contract_address == call_stack_item.contract_address
- The
If it is a delegate call:
call_context.is_delegate_call == true
- The
caller_context
in thecall_request
must not be empty. Specifically, the following values of the caller must not be zeros:msg_sender
storage_contract_address
- The
msg_sender
of the current iteration must equal the caller'smsg_sender
:call_context.msg_sender == caller_context.msg_sender
- The
storage_contract_address
of the current iteration must equal the caller'sstorage_contract_address
:call_context.storage_contract_address == caller_context.storage_contract_address
- The
storage_contract_address
of the current iteration must not equal thecontract_address
:call_context.storage_contract_address != call_stack_item.contract_address
- The
If it is NOT a static call:
call_context.is_static_call == false
- The previous iteration must not be a static call:
caller_context.is_static_call == false
- The previous iteration must not be a static call:
Verifying the private function proof.
It verifies that the private function was executed successfully with the provided proof data, verification key, and the public inputs, sourced from private_inputs
.private_call
.
This circuit verifies this proof and the proof of the previous kernel iteration using recursion, and generates a single proof. This consolidation of multiple proofs into one is what allows the private kernel circuits to gradually merge private function proofs into a single proof of execution that represents the entire private section of a transaction.
Verifying the public inputs of the private function circuit.
It ensures the private function circuit's intention by checking the following in private_call
.call_stack_item
.public_inputs
:
- The
block_header
must match the one in the constant_data. - If it is a static call (
public_inputs.call_context.is_static_call == true
), it ensures that the function does not induce any state changes by verifying that the following arrays are empty:note_hashes
nullifiers
l2_to_l1_messages
unencrypted_log_hashes
encrypted_log_hashes
encrypted_note_preimage_hashes
Verifying the counters.
This section follows the same process as outlined in the initial private kernel circuit.
Additionally, it verifies that for the call_stack_item
, the counter_start
and counter_end
must match those in the call_request
popped from the private_call_request_stack
in a previous step.
Validating Public Inputs
Verifying the transient accumulated data.
The transient_accumulated_data
in this circuit's public_inputs
includes values from both the previous iterations and the private_call
.
For each array in the transient_accumulated_data
, this circuit verifies that:
It is populated with the values from the previous iterations, specifically:
public_inputs.transient_accumulated_data.ARRAY[0..N] == private_inputs.previous_kernel.public_inputs.transient_accumulated_data.ARRAY[0..N]
It's important to note that the top item in the
private_call_request_stack
from theprevious_kernel
won't be included, as it has been removed in a previous step.As for the subsequent items appended after the values from the previous iterations, they constitute the values from the
private_call
, and each must undergo the same verification as outlined in the initial private kernel circuit.
Verifying other data.
It verifies that the constant_data
and the min_revertible_side_effect_counter
in the public_inputs
align with the corresponding values in private_inputs
.previous_kernel
.public_inputs
.
Private Inputs
PreviousKernel
Data of the previous kernel iteration.
Field | Type | Description |
---|---|---|
public_inputs | InitialPrivateKernelPublicInputs | Public inputs of the proof. |
proof | Proof | Proof of the kernel circuit. |
vk | VerificationKey | Verification key of the kernel circuit. |
membership_witness | MembershipWitness | Membership witness for the verification key. |
PrivateCall
The format aligns with the PrivateCall
of the initial private kernel circuit.
PublicInputs
The format aligns with the Public Inputs
of the initial private kernel circuit.