Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
717243e
Private kernels.
LeilaWang Dec 4, 2023
1a0413d
Small update.
LeilaWang Dec 5, 2023
4713371
Small updates.
LeilaWang Dec 5, 2023
06cb05a
Small updates.
LeilaWang Dec 5, 2023
1f832af
Some changes.
LeilaWang Dec 6, 2023
a9e9deb
Some changes.
LeilaWang Dec 8, 2023
da44d7a
Some changes.
LeilaWang Dec 10, 2023
8cfc361
Public kernels.
LeilaWang Dec 11, 2023
b5560f5
Adjust public inputs.
LeilaWang Dec 11, 2023
c38737f
Merge remote-tracking branch 'origin/master' into lw/yp_private_kernels
LeilaWang Dec 12, 2023
678b0fc
Add private function circuit.
LeilaWang Dec 12, 2023
1c15d7c
Update variable names.
LeilaWang Dec 12, 2023
5408e56
Rename files.
LeilaWang Dec 12, 2023
399db5a
Some changes.
LeilaWang Dec 12, 2023
9a8b1e9
More changes.
LeilaWang Dec 12, 2023
e09c54d
Update links.
LeilaWang Dec 14, 2023
1ee48fd
Ordering after siloing.
LeilaWang Dec 18, 2023
bd12445
Remove old value in update request.
LeilaWang Dec 19, 2023
14bdf69
Allow to call new contract.
LeilaWang Dec 20, 2023
106a823
Execute calls in chronological order.
LeilaWang Dec 20, 2023
930e51d
Add footnote.
LeilaWang Dec 20, 2023
2456d09
Shorter titles.
LeilaWang Dec 20, 2023
d0d6b8b
Formatting.
LeilaWang Dec 20, 2023
4435220
Some changes.
LeilaWang Dec 20, 2023
f142758
Rename.
LeilaWang Dec 20, 2023
95a956b
Rename.
LeilaWang Dec 20, 2023
8e720ad
Recalibrate public call request counters.
LeilaWang Dec 21, 2023
766a5d9
Recalibrate new contract contexts.
LeilaWang Dec 22, 2023
b837091
Merge remote-tracking branch 'origin/master' into lw/yp_private_kernels
LeilaWang Dec 22, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions yellow-paper/docs/circuits/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"label": "Circuits",
"position": 2,
"link": {
"type": "generated-index",
"description": "circuits..."
}
}
45 changes: 45 additions & 0 deletions yellow-paper/docs/circuits/private-function.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Private Function Circuit
Comment thread
LeilaWang marked this conversation as resolved.

:::info Disclaimer
This is a draft. These requirements need to be considered by the wider team, and might change significantly before a mainnet release.
:::

## Requirements

A private function circuit is a custom circuit tailored to the needs of a specific application. This circuit should be designed to handle private data processing while generating public inputs that safeguard the application and account's intentions without compromising sensitive information.
Comment thread
LeilaWang marked this conversation as resolved.

The logic of this circuit is flexible, yet its public inputs must adhere to a specific format.

## Private Inputs

The private inputs of a private function circuit are customizable.

## Public Inputs

The public inputs of a private function circuit will be incorporated into the private inputs of a private kernel circuit. Private kernel circuits leverage these public inputs, coupled with proof data and verification key from a private function circuit, to prove the correct execution of a private function.

It must adhere to the following format:
Comment thread
LeilaWang marked this conversation as resolved.

| Field | Type | Description |
| ---------------------------------- | -------------------------- | ---------------------------------------------------------------------- |
| _call_context_ | _CallContext_ | Context of the call corresponding to this function execution. |
Comment thread
LeilaWang marked this conversation as resolved.
| _args_hash_ | _field_ | Hash of the function arguments. |
| _return_values_ | [_field_; C] | Return values of this function call. |
| _read_requests_ | [_ReadRequest_; C] | Requests to read a note in the note hash tree. |
| _note_hash_contexts_ | [_NoteHashContext_; C] | New note hashes created in this function call. |
| _nullifier_contexts_ | [_NullifierContext_; C] | New nullifiers created in this function call. |
| _l2_to_l1_msg_contexts_ | [_L2L1MessageContext; C] | New L2 to L1 messages created in this function call. |
| _new_contract_contexts_ | [_ContractDataContext_; C] | Data of contracts deployed in this function call. |
| _encrypted_logs_hash_ | [_field_; N] | Hash of the encrypted logs emitted in this function call. |
| _unencrypted_logs_hash_ | [_field_; N] | Hash of the unencrypted logs emitted in this function call. |
| _encrypted_log_preimages_length_ | [_field_; N] | Length of the encrypted log preimages emitted in this function call. |
| _unencrypted_log_preimages_length_ | [_field_; N] | Length of the unencrypted log preimages emitted in this function call. |
| _private_call_stack_hashes_ | [_field_; C] | Hashes of the private function calls initiated by this function. |
| _public_call_stack_hashes_ | [_field_; C] | Hashes of the public function calls initiated by this function. |
| _block_header_ | _BlockHeader_ | Information about the trees used for the transaction. |
| _chain_id_ | _field_ | Chain ID of the transaction. |
| _version_ | _field_ | Version of the transaction. |

> The above **C**s represent constants defined by the protocol. Each **C** might have a different value from the others.

> The above **N**s represent the number of _field_ of a hash. Its value depends on the hash function chosen by the protocol.
258 changes: 258 additions & 0 deletions yellow-paper/docs/circuits/private-kernel-initial.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
# Private Kernel Circuit - Initial

:::info Disclaimer
This is a draft. These requirements need to be considered by the wider team, and might change significantly before a mainnet release.
:::

## Requirements

In the **initial** kernel iteration, the process involves taking a transaction request and private call data, verifying their integrity, and preparing the necessary data for subsequent circuits to operate. This step is particularly beneficial due to its separation from the [inner private kernel circuit](./private-kernel-inner.md), as the first call lacks a "previous kernel" to process. Additionally, it executes tasks that are pertinent to a transaction and need only occur once.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need a section that describes at a high level how the initial, inner, reset, tail circuits relate to one another


### Key Responsibilities Specific to this Circuit

#### Validating the correspondence of function call with caller's intent.

This entails ensuring that the following data from the private call aligns with the specifications in the transaction request:
Comment thread
LeilaWang marked this conversation as resolved.

- Contract address.
- [Function data](#function_data).
- Function arguments.

> Although it's not enforced in the protocol, it is customary to provide a signature signed over the transaction request and verify it in the first function call. This practice guarantees that only the party possessing the key(s) can authorize a transaction with the exact transaction request.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is msg.sender set to when executing the first function call? Do we define this anywhere?

I would assume that it is set to some kind of null address, but do we actually support that?


#### Verifying the legitimacy of the function as the entrypoint.

- It must be a private function.
- It must not be an internal function.
Comment thread
LeilaWang marked this conversation as resolved.

#### Ensuring the function call is the first call.
Comment thread
LeilaWang marked this conversation as resolved.

- It must not be a delegate call.
- It must not be a static call.

#### Ensuring transaction uniqueness.

- It must emit the hash of the transaction request as the **first** nullifier.

This nullifier serves multiple purposes:

- Identifying a transaction.
- Preventing the signature of a transaction request from being reused in another transaction.
Comment thread
LeilaWang marked this conversation as resolved.
- Generating values that should be maintained within the transaction's scope. For example, it is utilized to compute the nonces for all the note hashes in a transaction.

> Note that the final transaction data is not deterministic for a given transaction request. The production of new notes, the destruction of notes, and various other values are likely to change based on the time and conditions when a transaction is being composed. However, the intricacies of implementation should not be a concern for the entity initiating the transaction.

### Processing Private Function Call

#### Ensuring the contract instance being called is deployed.

It proves that the nullifier representing the contract exists in the contract tree.

This nullifier is the contract address siloed with the address of a precompiled deployment contract.
Comment thread
LeilaWang marked this conversation as resolved.

#### Ensuring the function being called exists in the contract.

The contract address contains the contract class ID, which is a hash of the root of its function tree and additional values. This circuit leverages these characteristics to establish the validity of the function's association with the contract address.
Comment thread
LeilaWang marked this conversation as resolved.

Each leaf of the function tree is a hash representing a function. The preimage includes:
Comment thread
LeilaWang marked this conversation as resolved.

- Function data.
- Hash of the verification key.
- Hash of the function bytecode.

To ensure the function's existence, the circuit executes the following steps:

1. Computes the hash of the verification key.
2. Calculates the function leaf: `hash(...function_data, vk_hash, bytecode_hash)`
3. Derives the function tree root with the leaf and the specified sibling path.
4. Computes the contract class ID using the function tree root and additional information.
5. Generates the contract address using the contract class ID and other relevant details.
6. Validates that the contract address matches the address specified in the private call data.

#### 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 of the private function circuit.

#### Verifying the public inputs of the private function circuit.

It ensures the private function circuit's intention by checking the following:

- The contract address for each non-empty item in the following arrays must equal the current contract address:
- Note hash contexts.
- Nullifier contexts.
- L2-to-L1 message contexts.
- Read requests.
- The portal contract address for each non-empty L2-to-L1 message context must equal the current portal contract address.
- If the new contract contexts array is not empty, the contract address must equal the precompiled deployment contract address.
- The historical data must match the one in the constant data.

> Ensuring the alignment of the contract addresses is crucial, as it is later used to silo the value and to establish associations with values within the same contract.
Comment thread
LeilaWang marked this conversation as resolved.

#### Verifying the call requests.

For both private and public call requests initiated in the current function call, it ensures that for each request at index _i_:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be useful to define the request index i

e.g. the request index is a unique identifier assigned to public and private call requests. The first call request Index value is 0. The index value increases by 1 for each subsequent call


- Its hash equals the value at index _i_ within the call request hashes array in private function circuit's public inputs.
- Its caller context is either empty or aligns with the call context of the current function call, including:
- _msg_sender_
- Storage contract address.

> It is important to note that the caller context in a call request may be empty for standard calls. This precaution is crucial to prevent information leakage, particularly as revealing the _msg_sender_ to the public could pose security risks when calling a public function.

#### Verifying the counters.

It verifies that each relevant value is associated with a legitimate counter.

1. For the current call:

- The _counter_start_ must be 0.
- The _counter_end_ must be greater than the _counter_start_.

2. For private call requests:

- The _counter_end_ of each request must be greater than its _counter_start_.
- The _counter_start_ of the first request must be greater than the _counter_start_ of the current call.
- The _counter_start_ of the second and subsequent requests must be greater than the _counter_end_ of the previous request.
- The _counter_end_ of the last request must be less than the _counter_end_ of the current call.

3. For items in each ordered array created in the current call:

- The counter of the first item much be greater than the _counter_start_ of the current call.
- The counter of each subsequent item much be greater than the counter of the previous item.
- The counter of the last item much be less than the _counter_end_ of the current call.

The ordered arrays include:

- Note hash contexts.
- Nullifier contexts.
- New contract contexts.
- Read requests.
- Public call requests.

> Note that _counter_start_ is used in the above steps for public call requests to ensure their correct ordering. At this point, the _counter_end_ of public call request is unknown. Both counters will be [recalibrated](./private-kernel-tail.md#recalibrating-counters) in the tail circuit following the simulation of all public function calls.

### Validating Public Inputs

#### Verifying the accumulated data.

It verifies that the following values align with those in the private call data:

- Log hashes.
- Log lengths.

#### Verifying the transient accumulated data.

1. It ensures that the following arrays match those in the private call data:

- Note hash contexts.
- Nullifier contexts.
- L2-to-L1 message contexts.
- New contract contexts.
- Read requests.
- Public call requests.

2. It checks that the following aligns with the array in the private call data, with items arranged in **reverse** order:

- Private call requests.

> It's important that the call requests are arranged in reverse order to ensure they are executed in chronological order. This becomes particularly crucial when calling a contract deployed earlier within the same transaction.

3. For the note hash contexts, it also verifies that each is associated with a nullifier counter, which is provided as a hint via the private inputs. The nullifier counter can be:

- Zero: if the note is not nullified in the same transaction.
- Greater than zero: if the note is nullified in the same transaction.
- This value must be greater than the counter of the note hash.

> Nullifier counters are used in the [reset private kernel circuit](./private-kernel-reset.md#verifying-read-requests) to ensure a read happens **before** a transient note is nullified.

> Zero can be used to indicate a non-existing transient nullifier, as this value can never serve as the counter of a nullifier. It corresponds to the _counter_start_ of the first function call.

#### Verifying the constant data.

It verifies that:

- The transaction context matches the one in the transaction request.

> The historical data must align with the data used in the private function circuit, as verified [earlier](#verifying-the-public-inputs-of-the-private-function-circuit).

## Private Inputs

### Transaction Request

A transaction request represents the caller's intent. It contains:

- Sender's address.
- <a name="function_data">Function data</a>:

- Function selector.
- Function type (private/public/unconstrained).
- A flag indicating whether the function is an internal function.

- Hash of the function arguments.
- Transaction context
- A flag indicating whether it is a fee paying transaction.
- A flag indicating whether it is a fee rebate transaction.
- Chain ID.
- Version of the transaction.

### Private Call Data

The private call data holds details about the current private function call:

- Contract address.
- Function data.
Comment thread
LeilaWang marked this conversation as resolved.
- Private call requests.
- Public call requests.
- Private function circuit public inputs.
- Proof of the private function circuit.
- Verification key of the private function circuit.
- Hash of the function bytecode.

### Hints

Data that aids in the verifications carried out in this circuit or later iterations:

- Membership witness for the function leaf.
- Membership witness for the contract leaf.
- Transient note nullifier counters.

## Public Inputs

The structure of this public inputs aligns with that of the [inner private kernel circuit](./private-kernel-inner.md) and the [reset private kernel circuit](./private-kernel-reset.md).

### Constant Data

These are constants that remain the same throughout the entire transaction:

- Historical data - representing the states of the block at which the transaction is constructed, including:
- Hash of the global variables.
- Roots of the trees:
- Note hash tree.
- Nullifier tree.
- Contract tree.
- L1-to-l2 message tree.
- Public data tree.
- Transaction context
- A flag indicating whether it is a fee paying transaction.
- A flag indicating whether it is a fee rebate transaction.
- Chain ID.
- Version of the transaction.

### Accumulated Data

It contains the result from the current function call:

- Log hashes.
- Log lengths.

### Transient Accumulated Data

It includes transient data accumulated during the execution of the transaction up to this point:

- Note hash contexts.
- Nullifier contexts.
- L2-to-L1 message contexts.
- New contract contexts.
- Read requests.
- Private call requests.
- Public call requests.
Loading