Skip to content
This repository was archived by the owner on Apr 18, 2025. It is now read-only.

Commit 3dbdc4c

Browse files
a few comments on proof aggregation circuit (#558)
* a few comments inside core function for proof compression: extract_accumulators_and_proof * comments on proof compression circuit * comments on pi aggregation circuit, especially calculation of hash indexes when using Keccak circuit, which are hard-coded here so needs be very careful * comments on proof aggregation circuit * a few comments inside core function for proof compression: extract_accumulators_and_proof * comments on proof compression circuit * comments on pi aggregation circuit, especially calculation of hash indexes when using Keccak circuit, which are hard-coded here so needs be very careful * comments on proof aggregation circuit * clean up all commits from my side * clean up of all commits on my side
1 parent a6d627d commit 3dbdc4c

File tree

5 files changed

+54
-4
lines changed

5 files changed

+54
-4
lines changed

aggregator/src/core.rs

+28
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,20 @@ pub(crate) fn assign_batch_hashes<F: Field>(
5050
let num_rows = 1 << LOG_DEGREE;
5151

5252
let timer = start_timer!(|| ("multi keccak").to_string());
53+
// wenqing: preimages consists of the following parts
54+
// (1) batchPiHash preimage =
55+
// (chain_id ||
56+
// chunk[0].prev_state_root ||
57+
// chunk[k-1].post_state_root ||
58+
// chunk[k-1].withdraw_root ||
59+
// batch_data_hash)
60+
// (2) batchDataHash preimage =
61+
// (chunk[0].dataHash || ... || chunk[k-1].dataHash)
62+
// (3) chunk[i].piHash preimage =
63+
// (chain id ||
64+
// chunk[i].prevStateRoot || chunk[i].postStateRoot ||
65+
// chunk[i].withdrawRoot || chunk[i].datahash)
66+
// each part of the preimage is mapped to image by Keccak256
5367
let witness = multi_keccak(preimages, challenges, capacity(num_rows))?;
5468
end_timer!(timer);
5569

@@ -84,10 +98,12 @@ pub(crate) fn assign_batch_hashes<F: Field>(
8498
let row = config.set_row(&mut region, offset, keccak_row)?;
8599

86100
if cur_preimage_index.is_some() && *cur_preimage_index.unwrap() == offset {
101+
// wenqing: 7-th column is Keccak input in Keccak circuit
87102
current_hash_input_cells.push(row[6].clone());
88103
cur_preimage_index = preimage_indices_iter.next();
89104
}
90105
if cur_digest_index.is_some() && *cur_digest_index.unwrap() == offset {
106+
// wenqing: last column is Keccak output in Keccak circuit
91107
current_hash_output_cells.push(row.last().unwrap().clone());
92108
cur_digest_index = digest_indices_iter.next();
93109
}
@@ -126,6 +142,7 @@ pub(crate) fn assign_batch_hashes<F: Field>(
126142
for i in 0..4 {
127143
for j in 0..8 {
128144
// sanity check
145+
// wenqing: 96 + CHAIN_ID_LEN is the byte position for batch_data_hash
129146
assert_equal(
130147
&hash_input_cells[0][i * 8 + j + 96 + CHAIN_ID_LEN],
131148
&hash_output_cells[1][(3 - i) * 8 + j],
@@ -155,6 +172,10 @@ pub(crate) fn assign_batch_hashes<F: Field>(
155172
// chunk[i].postStateRoot ||
156173
// chunk[i].withdrawRoot ||
157174
// chunk[i].datahash)
175+
// wenqing: CHAIN_ID_LEN,
176+
// CHAIN_ID_LEN+32,
177+
// CHAIN_ID_LEN+64 used below are byte positions for
178+
// prev_state_root, post_state_root, withdraw_root
158179
for i in 0..32 {
159180
// 2.2.1 chunk[0].prev_state_root
160181
// sanity check
@@ -271,6 +292,8 @@ pub(crate) fn extract_accumulators_and_proof(
271292
&snark.instances,
272293
&mut transcript_read,
273294
);
295+
// wenqing: each accumulator has (lhs, rhs) based on Shplonk
296+
// lhs and rhs are EC points
274297
Shplonk::succinct_verify(&svk, &snark.protocol, &snark.instances, &proof)
275298
})
276299
.collect::<Vec<_>>();
@@ -279,6 +302,11 @@ pub(crate) fn extract_accumulators_and_proof(
279302
PoseidonTranscript::<NativeLoader, Vec<u8>>::from_spec(vec![], POSEIDON_SPEC.clone());
280303
// We always use SHPLONK for accumulation scheme when aggregating proofs
281304
let accumulator =
305+
// wenqing: core step
306+
// KzgAs does KZG accumulation scheme based on given accumulators and random number (for adding blinding)
307+
// accumulated ec_pt = ec_pt_1 * 1 + ec_pt_2 * r + ... + ec_pt_n * r^{n-1}
308+
// ec_pt can be lhs and rhs
309+
// r is the challenge squeezed from proof
282310
KzgAs::<Kzg<Bn256, Bdfg21>>::create_proof::<PoseidonTranscript<NativeLoader, Vec<u8>>, _>(
283311
&Default::default(),
284312
&accumulators,

aggregator/src/proof_aggregation/circuit.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ impl AggregationCircuit {
6868
let snark_hash_bytes = &snark.instances[0];
6969

7070
for i in 0..32 {
71+
// wenqing: for each snark,
72+
// first 12 elements are accumulator
73+
// next 32 elements are data hash (44=12+32)
74+
// next 32 elements are public_input_hash
75+
// data hash + public_input_hash = snark public input
7176
assert_eq!(
7277
Fr::from(chunk.data_hash.as_bytes()[i] as u64),
7378
snark_hash_bytes[i + 12]
@@ -83,6 +88,8 @@ impl AggregationCircuit {
8388
// extract the accumulators and proofs
8489
let svk = params.get_g()[0].into();
8590

91+
// wenqing: this aggregates MULTIPLE snarks
92+
// (instead of ONE as in proof compression)
8693
let (accumulator, as_proof) = extract_accumulators_and_proof(params, snarks, rng);
8794
let KzgAccumulator::<G1Affine, NativeLoader> { lhs, rhs } = accumulator;
8895
let acc_instances = [lhs.x, lhs.y, rhs.x, rhs.y]
@@ -164,7 +171,7 @@ impl Circuit<Fr> for AggregationCircuit {
164171
// re-export all the public input of the snarks, denoted by [snarks_instances], and the
165172
// accumulator [acc_instances]
166173
// - 2. use public input aggregation circuit to aggregate the chunks; expose the instance
167-
// dentoed by [pi_agg_instances]
174+
// denoted by [pi_agg_instances]
168175
// - 3. assert [snarks_instances] are private inputs used for public input aggregation
169176
// circuit
170177

@@ -195,7 +202,7 @@ impl Circuit<Fr> for AggregationCircuit {
195202
//
196203
// extract the assigned values for
197204
// - instances which are the public inputs of each chunk (prefixed with 12 instances
198-
// from previous accumualtors)
205+
// from previous accumulators)
199206
// - new accumulator to be verified on chain
200207
//
201208
let (assigned_aggregation_instances, acc) = aggregate::<Kzg<Bn256, Bdfg21>>(
@@ -350,6 +357,7 @@ impl Circuit<Fr> for AggregationCircuit {
350357
for i in 0..4 {
351358
for j in 0..8 {
352359
// digest in circuit has a different endianness
360+
// wenqing: 96 is the byte position for batch data hash
353361
layouter.constrain_instance(
354362
hash_output_cells[0][(3 - i) * 8 + j].cell(),
355363
config.instance,
@@ -358,6 +366,7 @@ impl Circuit<Fr> for AggregationCircuit {
358366
}
359367
}
360368
// last 8 inputs are the chain id
369+
// wenqing: chain_id is put at last here
361370
for i in 0..CHAIN_ID_LEN {
362371
layouter.constrain_instance(
363372
hash_input_cells[0][i].cell(),

aggregator/src/proof_aggregation/config.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,12 @@ pub struct AggregationConfig {
3030
/// Instance for public input; stores
3131
/// - accumulator from aggregation (12 elements)
3232
/// - aggregated public inputs (136 elements):
33-
/// chain_id ||
3433
/// chunk\[0\].prev_state_root ||
3534
/// chunk\[k-1\].post_state_root ||
3635
/// chunk\[k-1\].withdraw_root ||
37-
/// batch_data_hash
36+
/// batch_data_hash ||
37+
/// chain_id
38+
/// wenqing: chain_id is put at last here for instance
3839
pub instance: Column<Instance>,
3940
}
4041

aggregator/src/proof_compression/circuit.rs

+6
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ impl Circuit<Fr> for CompressionCircuit {
8484
)
8585
.unwrap();
8686

87+
// wenqing: circuit configuration is built from config with given num columns etc
88+
// can be wide or thin circuit
8789
Self::Config::configure(meta, params)
8890
}
8991

@@ -166,6 +168,10 @@ impl CompressionCircuit {
166168
) -> Self {
167169
let svk = params.get_g()[0].into();
168170

171+
// wenqing: for the proof compression, only ONE snark is under accumulation
172+
// it is turned into an accumulator via KzgAs accumulation scheme
173+
// in case not first time:
174+
// (old_accumulator, public inputs) -> (new_accumulator, public inputs)
169175
let (accumulator, as_proof) = extract_accumulators_and_proof(params, &[snark.clone()], rng);
170176

171177
// the instance for the outer circuit is

aggregator/src/util.rs

+6
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ pub(crate) fn get_indices(preimages: &[Vec<u8>]) -> (Vec<usize>, Vec<usize>) {
3030
let mut round_ctr = 0;
3131

3232
for preimage in preimages.iter() {
33+
// wenqing: 136 = 17 * 8 is the size in bits of each
34+
// input chunk that can be processed by Keccak circuit using absorb
35+
// each chunk of size 136 needs 300 Keccak circuit rows to prove
36+
// which consists of 12 Keccak rows for each of 24 + 1 Keccak cicuit rounds
37+
// digest only happens at the end of the last input chunk with
38+
// 4 Keccak circuit rounds, so 48 Keccak rows, and 300 - 48 = 256
3339
let num_rounds = 1 + preimage.len() / 136;
3440
let mut preimage_padded = preimage.clone();
3541
preimage_padded.resize(136 * num_rounds, 0);

0 commit comments

Comments
 (0)