You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
#711 + #713 remove num chunks from public input; relax the constraints for the dummy chunk proofs to avoid dummy chunk proofgen time (#712)
* partiall address review comments of #670
* disable disable_proof_agg by default
* fix soundness issues with data hash
* add fixed cells for chunk_is_valid
* fix typo
* well... need morning coffee
* typo in readme
* fix soundness issue in is_smaller_than
* [feat] unify u8 u16 lookup table (#694)
* add range table
* replace Range256Table of rlp_circuit_fsm
* replace u16_table of tx_circuit
* use TableColumn
* add type alias
* use type alias
* annotate lookup column
* opt min_num_rows_block in poseidon_circuit (#700)
prune debug prints and lint
* speedup ci using verify_at_rows (#703)
* speedup ci using verify_at_rows
* use verify_at_rows to speedup super circuit ci tests
* update super circuit row estimation API (#695)
* remove num_of_chunks in aggregation circuit's instance column (#704)
Co-authored-by: kunxian xia <[email protected]>
* fix: lost tx_type when doing type conversion (#710)
* fix condition (#708)
* gates for zero checks
* statement 1 is correct
* reenable statements 3,6,7
* reenable statement 4
* everything seems to work again
* update aggregation test accordingly
* update spec
* minor clean up
* Fix fmt.
* Make `ChunkHash` fields public.
* fix decompose function
* update figures
* clean up
* address comments
* add is_final checks
* update readme
* constraint hash input length
* fix clippy
---------
Co-authored-by: Akase Cho <[email protected]>
Co-authored-by: Ho <[email protected]>
Co-authored-by: Zhang Zhuo <[email protected]>
Co-authored-by: kunxian xia <[email protected]>
Co-authored-by: Steven Gu <[email protected]>
Copy file name to clipboardexpand all lines: aggregator/README.md
+26-115
Original file line number
Diff line number
Diff line change
@@ -2,64 +2,6 @@ Proof Aggregation
2
2
-----
3
3
4
4

5
-
<!--
6
-
This repo does proof aggregations for zkEVM proofs.
7
-
8
-
## zkEVM circuit
9
-
A zkEVM circuits generates a ZK proof for a chunk of blocks. It takes 64 field elements as its public input, consist of
10
-
- chunk's data hash digest: each byte is encoded in an Fr element
11
-
- chunk's public input hash digest: each byte is encoded in an Fr element
12
-
The total size for a public input is 64 bytes, encoded in 64 Fr element
13
-
14
-
For the ease of testing, this repo implements a `MockCircuit` which hash same public input APIs as a zkEVM circuit.
15
-
16
-
## First compression circuit
17
-
The first compression circuit takes in a fresh snark proof and generates a new (potentially small) snark proof.
18
-
The public inputs to the new snark proof consists of
19
-
- 12 elements from the accumulators
20
-
- an accumulator consists of 2 G1 elements, which are the left and right inputs to the pairing
21
-
- this is treated as 4 Fq elements, each decomposed into 3 limbs and encoded in Fr
22
-
- 64 elements from previous snark
23
-
- re-expose the same public inputs as the original snark
24
-
25
-
The first compression circuit is configured [wide config file](./configs/compression_wide.config).
26
-
27
-
## Second compression circuit
28
-
29
-
The second compression circuit takes in a compressed snark proof and generates a new (potentially small) snark proof.
30
-
The public inputs to the new snark proof consists of
31
-
- 12 elements from the accumulators
32
-
- an accumulator consists of 2 G1 elements, which are the left and right inputs to the pairing
33
-
- this is treated as 4 Fq elements, each decomposed into 3 limbs and encoded in Fr
34
-
- accumulator from the previous snark is accumulated into the current accumulator
35
-
- 64 elements from previous snark
36
-
- skipping the first 12 elements which are previous accumulator, as they are already accumulated
37
-
- re-expose the rest 64 field elements as the public inputs
38
-
39
-
The second compression circuit is configured [thin config file](./configs/compression_thin.config).
40
-
41
-
## Aggregation circuit
42
-
An aggregation circuit takes in a batch of `k` proofs, each for a chunk of blocks.
43
-
It generates a single proof asserting the validity of all the proofs.
44
-
45
-
It also performs public input aggregation, i.e., reducing the `64k` public elements into a fixed number of `144` elements:
46
-
- 12 elements from accumulators, which accumulates all the previous `k` accumulators from each snark
47
-
- 132 elements from the hashes
48
-
- first_chunk_prev_state_root: 32 Field elements
49
-
- last_chunk_post_state_root: 32 Field elements
50
-
- last_chunk_withdraw_root: 32 Field elements
51
-
- batch_public_input_hash: 32 Field elements
52
-
- chain_id: 8 Field elements
53
-
54
-
In addition, it attests that, for chunks indexed from `0` to `k-1`,
55
-
- batch_data_hash := keccak(chunk_0.data_hash || ... || chunk_k-1.data_hash) where chunk_i.data_hash is a public input to the i-th batch snark circuit
56
-
- chunk_pi_hash := keccak(chain_id || prev_state_root || post_state_root || withdraw_root || chunk_data_hash) where chunk_data_hash is a public input to the i-th batch snark circuit
57
-
- and the related field matches public input
58
-
59
-
See [public input aggregation](./src/proof_aggregation/public_input_aggregation.rs) for the details of public input aggregation. -->
An __empty chunk__ is a chunk that does not contain any transactions. It is used for padding.
98
-
If $k< n$, $(n-k)$ empty chunks are padded to the list. An empty chunk has the same data fields as a real chunk, and the parameters are set as
99
-
- state root before this chunk: `c_k.post_state_root`
100
-
- state root after this chunk: `c_k.post_state_root`
101
-
- the withdraw root of this chunk: `c_k.withdraw_root`
102
-
- the data hash of this chunk: `keccak("")`
38
+
## Padded chunk
39
+
A __padded chunk__ is a chunk that repeats last valid chunk. It is used for padding.
40
+
If $k< n$, $(n-k)$ padded chunks are padded to the list. A padded chunk has the same data fields as the last real chunk, and the parameters are set as
41
+
- state root before this chunk: `c_{k}.prev_state_root`
42
+
- state root after this chunk: `c_{k}.post_state_root`
43
+
- the withdraw root of this chunk: `c_{k}.withdraw_root`
44
+
- the data hash of this chunk: `c_{k}.data_hash`
103
45
104
46
## Batch
105
47
106
-
A __batch__ consists of continuous chunks of size `n`. If the input chunks' size `k` is less than `n`, we pad the input with `(n-k)`empty chunks using the above logic.
48
+
A __batch__ consists of continuous chunks of size `k`. If the input chunks' size `k` is less than `n`, we pad the input with `(n-k)` chunks identical to `chunk[k]`.
107
49
108
50
# Circuits
109
51
@@ -114,20 +56,16 @@ Circuit proving the relationship for a chunk is indeed the zkEVM circuit. It wil
114
56
- 12 from accumulators
115
57
- 32 from public input hash
116
58
117
-
## Empty chunk circuit
118
-
An empty chunk circuit also takes 44 elements as public inputs.
119
-
In our design it is curial that __a same circuit__ is used for both real chunk circuit and empty chunk circuit. In other words, an empty chunk circuit will also go through the same compressions before it is aggregated.
120
-
121
59
122
60

123
61
124
62
## Aggregation Circuit
125
63
126
-
We want to aggregate `k` snarks, each from a valid chunk. We generate `(n-k)`empty chunks, and obtain a total of `n` snarks.
64
+
We want to aggregate `k` snarks, each from a valid chunk. We generate `(n-k)`padded chunks, and obtain a total of `n` snarks.
127
65
128
-
In the above example, we have `k = 2` valid chunks, and `2`empty chunks.
66
+
In the above example, we have `k = 2` valid chunks, and `2`padded chunks.
129
67
130
-
> Interlude: we just need to generate 1 empty snark, and the rest `n-k-1` will be identical for the same batch. We cannot pre-compute it though, as the witness `c_k.post_state_root` and `c_k.withdraw_root` are batch dependent.
68
+
The padded snarks are identical the the last valid snark, so the aggregator does not need to generate snarks for padded chunks.
131
69
132
70
### Configuration
133
71
@@ -140,7 +78,6 @@ There will be three configurations for Aggregation circuit.
140
78
The public input of the aggregation circuit consists of
141
79
- 12 elements from accumulator
142
80
- 32 elements of `batch_pi_hash`
143
-
- 1 element of `k`
144
81
145
82
### Statements
146
83
For snarks $s_1,\dots,s_k,\dots, s_n$ the aggregation circuit argues the following statements.
@@ -162,9 +99,9 @@ for i in 1 ... __n__
162
99
163
100
This is done by compute the RLCs of chunk[i]'s data_hash for `i=0..k`, and then check the RLC matches the one from the keccak table.
164
101
165
-
4. chunks are continuous: they are linked via the state roots. __Static__.
102
+
4. chunks are continuous when they are not padded: they are linked via the state roots.
166
103
167
-
for i in 1 ... __n-1__
104
+
for i in 1 ... __k-1__
168
105
```
169
106
c_i.post_state_root == c_{i+1}.prev_state_root
170
107
```
@@ -175,17 +112,18 @@ for i in 1 ... __n__
175
112
batch.chain_id == chunk[i].chain_id
176
113
```
177
114
178
-
6. The last `(n-k)` chunk[i]'s prev_state_root == post_state_root when chunk[i] is padded
7. chunk[i]'s data_hash len is `0` when chunk[i] is padded
188
-
121
+
This is done via comparing the `data_rlc` of `chunk_{i-1}` and ` chunk_{i}`.
122
+
7. the hash input length are correct
123
+
- first MAX_AGG_SNARKS + 1 hashes all have 136 bytes input
124
+
- batch's data_hash length is 32 * number_of_valid_snarks
125
+
8. batch data hash is correct w.r.t. its RLCs
126
+
9. is_final_cells are set correctly
189
127
190
128
### Handling dynamic inputs
191
129
@@ -201,11 +139,13 @@ Suppose we target for `MAX_AGG_SNARK = 10`. Then, the last hash function will ta
201
139
We also know in the circuit if a chunk is an empty one or not. This is given by a flag `is_padding`.
202
140
203
141
For the input of the final data hash
204
-
- we extract `32 * MAX_AGG_SNARK` number of cells (__static__ here) from the last hash. We then compute the RLC of those `32 * MAX_AGG_SNARK` when the corresponding `is_padding` is not set. We constraint this RLC matches the `data_rlc` from the keccak table.
205
-
142
+
- we extract `32 * MAX_AGG_SNARK` number of cells (__static__ here) from the last hash. We then compute the RLC of those `32 * MAX_AGG_SNARK` when the corresponding `is_padding` is not set. We constrain this RLC matches the `data_rlc` from the keccak table.
206
143
207
144
For the output of the final data hash
208
145
- we extract all three hash digest cells from last 3 rounds. We then constraint that the actual data hash matches one of the three hash digest cells with proper flags defined as follows.
146
+
- if the num_of_valid_snarks <= 4, which only needs 1 keccak-f round. Therefore the batch's data hash (input, len, data_rlc, output_rlc) are in the first 300 keccak rows;
147
+
- else if the num_of_valid_snarks <= 8, which needs 2 keccak-f rounds. Therefore the batch's data hash (input, len, data_rlc, output_rlc) are in the 2nd 300 keccak rows;
148
+
- else the num_of_valid_snarks <= 12, which needs 3 keccak-f rounds. Therefore the batch's data hash (input, len, data_rlc, output_rlc) are in the 3rd 300 keccak rows;
209
149
210
150
|#valid snarks | offset of data hash | flags|
211
151
|---| ---| ---|
@@ -214,33 +154,4 @@ For the output of the final data hash
214
154
|9,10 | 64 | 0, 0, 1|
215
155
216
156
Additional checks for dummy chunk
217
-
- if `is_padding` for `i`-th chunk, we constrain `chunk[i].prev_state_root = chunk[i].post_state_root`
218
-
- if `is_padding` for `i`-th chunk, we constrain `chunk[i-1].withdraw_root = chunk[i].withdraw_root`
219
-
- if `is_padding` for `i`-th chunk, we constrain `chunk[i-1].data_hash.len() == 0`
220
-
221
-
<!--
222
-
1. Extact the final `data_rlc` cell from each round. There are maximum $t$ of this, denoted by $r_1,\dots r_t$
223
-
- __caveat__: will need to make sure the circuit is padded as if there are $t$ rounds, if the actual number of rounds is less than $t$. This is done by keccak table already:
224
-
all columns of keccak table are padded to `1<<LOG_DEGREE` by construction (__need to double check this is circuit dependent__)
225
-
2. Extract a challenge and then compute `rlc:= RLC(chunk_1.data_hash || ... || chunk_k.data_hash)` using a __phase 2__ column
226
-
3. assert `rlc` is valid via a lookup argument
227
-
- constrain `rlc` cell is within the "data_rlc" column of keccak table via standard lookup API
228
-
- potential optimization: avoid using lookup API. There is only $t$ elements as $rlc \in \{r_1,\dots r_t\}$ and we may check equality one by one.
229
-
-->
230
-
231
-
<!--
232
-
Circuit witnesses:
233
-
- a list of k __real__ CHUNKs, each with 44 elements of public inputs (12 from accumulators and
0 commit comments