Skip to content

Commit 056e553

Browse files
authored
docs(yellowpaper): private kernel circuits (AztecProtocol#3559)
We're still hashing out a bunch of stuff and things might change pretty soon. So the content avoid delving into details. It only provides an overview of data flow and a general sense of the structures. Things to be added (need discussions): - Reset gadget circuits. - Keys (protocol functions). - Squashing logs. - VM circuit reverts. # Checklist: Remove the checklist to signal you've completed it. Enable auto-merge if the PR is ready to merge. - [ ] If the pull request requires a cryptography review (e.g. cryptographic algorithm implementations) I have added the 'crypto' tag. - [ ] I have reviewed my diff in github, line by line and removed unexpected formatting changes, testing logs, or commented-out code. - [ ] Every change is related to the PR description. - [ ] I have [linked](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) this pull request to relevant issues (if any exist).
1 parent 18edb98 commit 056e553

8 files changed

+1569
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"label": "Circuits",
3+
"position": 2,
4+
"link": {
5+
"type": "generated-index",
6+
"description": "circuits..."
7+
}
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Private Function Circuit
2+
3+
:::info Disclaimer
4+
This is a draft. These requirements need to be considered by the wider team, and might change significantly before a mainnet release.
5+
:::
6+
7+
## Requirements
8+
9+
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.
10+
11+
The logic of this circuit is flexible, yet its public inputs must adhere to a specific format.
12+
13+
## Private Inputs
14+
15+
The private inputs of a private function circuit are customizable.
16+
17+
## Public Inputs
18+
19+
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.
20+
21+
It must adhere to the following format:
22+
23+
| Field | Type | Description |
24+
| ---------------------------------- | -------------------------- | ---------------------------------------------------------------------- |
25+
| _call_context_ | _CallContext_ | Context of the call corresponding to this function execution. |
26+
| _args_hash_ | _field_ | Hash of the function arguments. |
27+
| _return_values_ | [_field_; C] | Return values of this function call. |
28+
| _read_requests_ | [_ReadRequest_; C] | Requests to read a note in the note hash tree. |
29+
| _note_hash_contexts_ | [_NoteHashContext_; C] | New note hashes created in this function call. |
30+
| _nullifier_contexts_ | [_NullifierContext_; C] | New nullifiers created in this function call. |
31+
| _l2_to_l1_msg_contexts_ | [_L2L1MessageContext; C] | New L2 to L1 messages created in this function call. |
32+
| _new_contract_contexts_ | [_ContractDataContext_; C] | Data of contracts deployed in this function call. |
33+
| _encrypted_logs_hash_ | [_field_; N] | Hash of the encrypted logs emitted in this function call. |
34+
| _unencrypted_logs_hash_ | [_field_; N] | Hash of the unencrypted logs emitted in this function call. |
35+
| _encrypted_log_preimages_length_ | [_field_; N] | Length of the encrypted log preimages emitted in this function call. |
36+
| _unencrypted_log_preimages_length_ | [_field_; N] | Length of the unencrypted log preimages emitted in this function call. |
37+
| _private_call_stack_hashes_ | [_field_; C] | Hashes of the private function calls initiated by this function. |
38+
| _public_call_stack_hashes_ | [_field_; C] | Hashes of the public function calls initiated by this function. |
39+
| _block_header_ | _BlockHeader_ | Information about the trees used for the transaction. |
40+
| _chain_id_ | _field_ | Chain ID of the transaction. |
41+
| _version_ | _field_ | Version of the transaction. |
42+
43+
> The above **C**s represent constants defined by the protocol. Each **C** might have a different value from the others.
44+
45+
> The above **N**s represent the number of _field_ of a hash. Its value depends on the hash function chosen by the protocol.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
# Private Kernel Circuit - Initial
2+
3+
:::info Disclaimer
4+
This is a draft. These requirements need to be considered by the wider team, and might change significantly before a mainnet release.
5+
:::
6+
7+
## Requirements
8+
9+
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.
10+
11+
### Key Responsibilities Specific to this Circuit
12+
13+
#### Validating the correspondence of function call with caller's intent.
14+
15+
This entails ensuring that the following data from the private call aligns with the specifications in the transaction request:
16+
17+
- Contract address.
18+
- [Function data](#function_data).
19+
- Function arguments.
20+
21+
> 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.
22+
23+
#### Verifying the legitimacy of the function as the entrypoint.
24+
25+
- It must be a private function.
26+
- It must not be an internal function.
27+
28+
#### Ensuring the function call is the first call.
29+
30+
- It must not be a delegate call.
31+
- It must not be a static call.
32+
33+
#### Ensuring transaction uniqueness.
34+
35+
- It must emit the hash of the transaction request as the **first** nullifier.
36+
37+
This nullifier serves multiple purposes:
38+
39+
- Identifying a transaction.
40+
- Preventing the signature of a transaction request from being reused in another transaction.
41+
- 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.
42+
43+
> 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.
44+
45+
### Processing Private Function Call
46+
47+
#### Ensuring the contract instance being called is deployed.
48+
49+
It proves that the nullifier representing the contract exists in the contract tree.
50+
51+
This nullifier is the contract address siloed with the address of a precompiled deployment contract.
52+
53+
#### Ensuring the function being called exists in the contract.
54+
55+
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.
56+
57+
Each leaf of the function tree is a hash representing a function. The preimage includes:
58+
59+
- Function data.
60+
- Hash of the verification key.
61+
- Hash of the function bytecode.
62+
63+
To ensure the function's existence, the circuit executes the following steps:
64+
65+
1. Computes the hash of the verification key.
66+
2. Calculates the function leaf: `hash(...function_data, vk_hash, bytecode_hash)`
67+
3. Derives the function tree root with the leaf and the specified sibling path.
68+
4. Computes the contract class ID using the function tree root and additional information.
69+
5. Generates the contract address using the contract class ID and other relevant details.
70+
6. Validates that the contract address matches the address specified in the private call data.
71+
72+
#### Verifying the private function proof.
73+
74+
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.
75+
76+
#### Verifying the public inputs of the private function circuit.
77+
78+
It ensures the private function circuit's intention by checking the following:
79+
80+
- The contract address for each non-empty item in the following arrays must equal the current contract address:
81+
- Note hash contexts.
82+
- Nullifier contexts.
83+
- L2-to-L1 message contexts.
84+
- Read requests.
85+
- The portal contract address for each non-empty L2-to-L1 message context must equal the current portal contract address.
86+
- If the new contract contexts array is not empty, the contract address must equal the precompiled deployment contract address.
87+
- The historical data must match the one in the constant data.
88+
89+
> 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.
90+
91+
#### Verifying the call requests.
92+
93+
For both private and public call requests initiated in the current function call, it ensures that for each request at index _i_:
94+
95+
- Its hash equals the value at index _i_ within the call request hashes array in private function circuit's public inputs.
96+
- Its caller context is either empty or aligns with the call context of the current function call, including:
97+
- _msg_sender_
98+
- Storage contract address.
99+
100+
> 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.
101+
102+
#### Verifying the counters.
103+
104+
It verifies that each relevant value is associated with a legitimate counter.
105+
106+
1. For the current call:
107+
108+
- The _counter_start_ must be 0.
109+
- The _counter_end_ must be greater than the _counter_start_.
110+
111+
2. For private call requests:
112+
113+
- The _counter_end_ of each request must be greater than its _counter_start_.
114+
- The _counter_start_ of the first request must be greater than the _counter_start_ of the current call.
115+
- The _counter_start_ of the second and subsequent requests must be greater than the _counter_end_ of the previous request.
116+
- The _counter_end_ of the last request must be less than the _counter_end_ of the current call.
117+
118+
3. For items in each ordered array created in the current call:
119+
120+
- The counter of the first item much be greater than the _counter_start_ of the current call.
121+
- The counter of each subsequent item much be greater than the counter of the previous item.
122+
- The counter of the last item much be less than the _counter_end_ of the current call.
123+
124+
The ordered arrays include:
125+
126+
- Note hash contexts.
127+
- Nullifier contexts.
128+
- New contract contexts.
129+
- Read requests.
130+
- Public call requests.
131+
132+
> 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.
133+
134+
### Validating Public Inputs
135+
136+
#### Verifying the accumulated data.
137+
138+
It verifies that the following values align with those in the private call data:
139+
140+
- Log hashes.
141+
- Log lengths.
142+
143+
#### Verifying the transient accumulated data.
144+
145+
1. It ensures that the following arrays match those in the private call data:
146+
147+
- Note hash contexts.
148+
- Nullifier contexts.
149+
- L2-to-L1 message contexts.
150+
- New contract contexts.
151+
- Read requests.
152+
- Public call requests.
153+
154+
2. It checks that the following aligns with the array in the private call data, with items arranged in **reverse** order:
155+
156+
- Private call requests.
157+
158+
> 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.
159+
160+
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:
161+
162+
- Zero: if the note is not nullified in the same transaction.
163+
- Greater than zero: if the note is nullified in the same transaction.
164+
- This value must be greater than the counter of the note hash.
165+
166+
> 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.
167+
168+
> 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.
169+
170+
#### Verifying the constant data.
171+
172+
It verifies that:
173+
174+
- The transaction context matches the one in the transaction request.
175+
176+
> 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).
177+
178+
## Private Inputs
179+
180+
### Transaction Request
181+
182+
A transaction request represents the caller's intent. It contains:
183+
184+
- Sender's address.
185+
- <a name="function_data">Function data</a>:
186+
187+
- Function selector.
188+
- Function type (private/public/unconstrained).
189+
- A flag indicating whether the function is an internal function.
190+
191+
- Hash of the function arguments.
192+
- Transaction context
193+
- A flag indicating whether it is a fee paying transaction.
194+
- A flag indicating whether it is a fee rebate transaction.
195+
- Chain ID.
196+
- Version of the transaction.
197+
198+
### Private Call Data
199+
200+
The private call data holds details about the current private function call:
201+
202+
- Contract address.
203+
- Function data.
204+
- Private call requests.
205+
- Public call requests.
206+
- Private function circuit public inputs.
207+
- Proof of the private function circuit.
208+
- Verification key of the private function circuit.
209+
- Hash of the function bytecode.
210+
211+
### Hints
212+
213+
Data that aids in the verifications carried out in this circuit or later iterations:
214+
215+
- Membership witness for the function leaf.
216+
- Membership witness for the contract leaf.
217+
- Transient note nullifier counters.
218+
219+
## Public Inputs
220+
221+
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).
222+
223+
### Constant Data
224+
225+
These are constants that remain the same throughout the entire transaction:
226+
227+
- Historical data - representing the states of the block at which the transaction is constructed, including:
228+
- Hash of the global variables.
229+
- Roots of the trees:
230+
- Note hash tree.
231+
- Nullifier tree.
232+
- Contract tree.
233+
- L1-to-l2 message tree.
234+
- Public data tree.
235+
- Transaction context
236+
- A flag indicating whether it is a fee paying transaction.
237+
- A flag indicating whether it is a fee rebate transaction.
238+
- Chain ID.
239+
- Version of the transaction.
240+
241+
### Accumulated Data
242+
243+
It contains the result from the current function call:
244+
245+
- Log hashes.
246+
- Log lengths.
247+
248+
### Transient Accumulated Data
249+
250+
It includes transient data accumulated during the execution of the transaction up to this point:
251+
252+
- Note hash contexts.
253+
- Nullifier contexts.
254+
- L2-to-L1 message contexts.
255+
- New contract contexts.
256+
- Read requests.
257+
- Private call requests.
258+
- Public call requests.

0 commit comments

Comments
 (0)