Skip to content

Commit ae95e3b

Browse files
authored
Merge branch 'develop' into feat/rlc
2 parents 23851aa + 7fd6b6d commit ae95e3b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+2441
-1286
lines changed

Cargo.lock

+116-52
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

aggregator/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ num-bigint.workspace = true
3838

3939
# da-compression
4040
bitstream-io = "2.2.0"
41-
zstd-encoder = { package = "encoder", git = "https://github.com/scroll-tech/da-codec.git", tag = "v0.1.0" }
41+
zstd-encoder = { package = "encoder", git = "https://github.com/scroll-tech/da-codec.git", tag = "v0.1.2" }
4242

4343
[dev-dependencies]
4444

aggregator/src/aggregation.rs

+39
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,42 @@ pub(crate) use rlc::{RlcConfig, POWS_OF_256};
1919

2020
pub use circuit::BatchCircuit;
2121
pub use config::BatchCircuitConfig;
22+
use halo2_base::halo2_proofs::halo2curves::bn256::{Fr, G1Affine};
23+
use snark_verifier::Protocol;
24+
25+
/// Alias for a list of G1 points.
26+
pub type PreprocessedPolyCommits = Vec<G1Affine>;
27+
/// Alias for the transcript's initial state.
28+
pub type TranscriptInitState = Fr;
29+
30+
/// Alias for the fixed part of the protocol which consists of the commitments to the preprocessed
31+
/// polynomials and the initial state of the transcript.
32+
#[derive(Clone)]
33+
pub struct FixedProtocol {
34+
/// The commitments to the preprocessed polynomials.
35+
pub preprocessed: PreprocessedPolyCommits,
36+
/// The initial state of the transcript.
37+
pub init_state: TranscriptInitState,
38+
}
39+
40+
impl From<Protocol<G1Affine>> for FixedProtocol {
41+
fn from(protocol: Protocol<G1Affine>) -> Self {
42+
Self {
43+
preprocessed: protocol.preprocessed,
44+
init_state: protocol
45+
.transcript_initial_state
46+
.expect("protocol transcript init state None"),
47+
}
48+
}
49+
}
50+
51+
impl From<&Protocol<G1Affine>> for FixedProtocol {
52+
fn from(protocol: &Protocol<G1Affine>) -> Self {
53+
Self {
54+
preprocessed: protocol.preprocessed.clone(),
55+
init_state: protocol
56+
.transcript_initial_state
57+
.expect("protocol transcript init state None"),
58+
}
59+
}
60+
}

aggregator/src/aggregation/circuit.rs

+133-18
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use ark_std::{end_timer, start_timer};
22
use halo2_proofs::{
3+
arithmetic::Field,
34
circuit::{Layouter, SimpleFloorPlanner, Value},
45
halo2curves::bn256::{Bn256, Fr, G1Affine},
56
plonk::{Circuit, ConstraintSystem, Error, Selector},
@@ -11,14 +12,20 @@ use snark_verifier::{
1112
loader::halo2::{
1213
halo2_ecc::{
1314
ecc::EccChip,
14-
fields::fp::FpConfig,
15-
halo2_base::{AssignedValue, Context, ContextParams},
15+
fields::{fp::FpConfig, FieldChip},
16+
halo2_base::{
17+
gates::{GateInstructions, RangeInstructions},
18+
AssignedValue, Context, ContextParams,
19+
QuantumCell::Existing,
20+
},
1621
},
17-
Halo2Loader,
22+
Halo2Loader, IntegerInstructions,
1823
},
1924
pcs::kzg::{Bdfg21, Kzg, KzgSuccinctVerifyingKey},
2025
};
21-
use snark_verifier_sdk::{aggregate, flatten_accumulator, CircuitExt, Snark, SnarkWitness};
26+
use snark_verifier_sdk::{
27+
aggregate_as_witness, flatten_accumulator, CircuitExt, Snark, SnarkWitness,
28+
};
2229
use std::{env, fs::File, rc::Rc};
2330
use zkevm_circuits::util::Challenges;
2431

@@ -30,8 +37,8 @@ use crate::{
3037
core::{assign_batch_hashes, extract_proof_and_instances_with_pairing_check},
3138
util::parse_hash_digest_cells,
3239
witgen::{zstd_encode, MultiBlockProcessResult},
33-
ConfigParams, LOG_DEGREE, PI_CHAIN_ID, PI_CURRENT_BATCH_HASH, PI_CURRENT_STATE_ROOT,
34-
PI_CURRENT_WITHDRAW_ROOT, PI_PARENT_BATCH_HASH, PI_PARENT_STATE_ROOT,
40+
ConfigParams, FixedProtocol, LOG_DEGREE, PI_CHAIN_ID, PI_CURRENT_BATCH_HASH,
41+
PI_CURRENT_STATE_ROOT, PI_CURRENT_WITHDRAW_ROOT, PI_PARENT_BATCH_HASH, PI_PARENT_STATE_ROOT,
3542
};
3643

3744
/// Batch circuit, the chunk aggregation routine below recursion circuit
@@ -55,14 +62,21 @@ pub struct BatchCircuit<const N_SNARKS: usize> {
5562
// batch hash circuit for which the snarks are generated
5663
// the chunks in this batch are also padded already
5764
pub batch_hash: BatchHash<N_SNARKS>,
65+
66+
/// The SNARK protocol from the halo2-based inner circuit route.
67+
pub halo2_protocol: FixedProtocol,
68+
/// The SNARK protocol from the sp1-based inner circuit route.
69+
pub sp1_protocol: FixedProtocol,
5870
}
5971

6072
impl<const N_SNARKS: usize> BatchCircuit<N_SNARKS> {
61-
pub fn new(
73+
pub fn new<P: Into<FixedProtocol>>(
6274
params: &ParamsKZG<Bn256>,
6375
snarks_with_padding: &[Snark],
6476
rng: impl Rng + Send,
6577
batch_hash: BatchHash<N_SNARKS>,
78+
halo2_protocol: P,
79+
sp1_protocol: P,
6680
) -> Result<Self, snark_verifier::Error> {
6781
let timer = start_timer!(|| "generate aggregation circuit");
6882

@@ -120,6 +134,8 @@ impl<const N_SNARKS: usize> BatchCircuit<N_SNARKS> {
120134
flattened_instances,
121135
as_proof: Value::known(as_proof),
122136
batch_hash,
137+
halo2_protocol: halo2_protocol.into(),
138+
sp1_protocol: sp1_protocol.into(),
123139
})
124140
}
125141

@@ -209,22 +225,21 @@ impl<const N_SNARKS: usize> Circuit<Fr> for BatchCircuit<N_SNARKS> {
209225
let loader: Rc<Halo2Loader<G1Affine, EccChip<Fr, FpConfig<Fr, Fq>>>> =
210226
Halo2Loader::new(ecc_chip, ctx);
211227

212-
//
213228
// extract the assigned values for
214229
// - instances which are the public inputs of each chunk (prefixed with 12
215230
// instances from previous accumulators)
216231
// - new accumulator
217-
//
218-
log::debug!("aggregation: chunk aggregation");
219-
let (assigned_aggregation_instances, acc) = aggregate::<Kzg<Bn256, Bdfg21>>(
232+
let (
233+
assigned_aggregation_instances,
234+
acc,
235+
preprocessed_poly_sets,
236+
transcript_init_states,
237+
) = aggregate_as_witness::<Kzg<Bn256, Bdfg21>>(
220238
&self.svk,
221239
&loader,
222240
&self.snarks_with_padding,
223241
self.as_proof(),
224242
);
225-
for (i, e) in assigned_aggregation_instances[0].iter().enumerate() {
226-
log::trace!("{}-th instance: {:?}", i, e.value)
227-
}
228243

229244
// extract the following cells for later constraints
230245
// - the accumulators
@@ -238,13 +253,113 @@ impl<const N_SNARKS: usize> Circuit<Fr> for BatchCircuit<N_SNARKS> {
238253
.iter()
239254
.flat_map(|instance_column| instance_column.iter().skip(ACC_LEN)),
240255
);
256+
for (i, e) in assigned_aggregation_instances[0].iter().enumerate() {
257+
log::trace!("{}-th instance: {:?}", i, e.value)
258+
}
241259

242-
loader
243-
.ctx_mut()
244-
.print_stats(&["snark aggregation [chunks -> batch]"]);
260+
loader.ctx_mut().print_stats(&["snark aggregation"]);
245261

246262
let mut ctx = Rc::into_inner(loader).unwrap().into_ctx();
247-
log::debug!("batching: assigning barycentric");
263+
264+
// We must ensure that the commitments to preprocessed polynomial and initial
265+
// state of transcripts for every SNARK that is being aggregated belongs to the
266+
// fixed set of values expected.
267+
//
268+
// First we load the constants.
269+
log::info!("populating constants");
270+
let mut preprocessed_polys_halo2 = Vec::with_capacity(7);
271+
let mut preprocessed_polys_sp1 = Vec::with_capacity(7);
272+
for &preprocessed_poly in self.halo2_protocol.preprocessed.iter() {
273+
preprocessed_polys_halo2.push(
274+
config
275+
.ecc_chip()
276+
.assign_constant_point(&mut ctx, preprocessed_poly),
277+
);
278+
}
279+
for &preprocessed_poly in self.sp1_protocol.preprocessed.iter() {
280+
preprocessed_polys_sp1.push(
281+
config
282+
.ecc_chip()
283+
.assign_constant_point(&mut ctx, preprocessed_poly),
284+
);
285+
}
286+
let transcript_init_state_halo2 = config
287+
.ecc_chip()
288+
.field_chip()
289+
.range()
290+
.gate()
291+
.assign_constant(&mut ctx, self.halo2_protocol.init_state)
292+
.expect("IntegerInstructions::assign_constant infallible");
293+
let transcript_init_state_sp1 = config
294+
.ecc_chip()
295+
.field_chip()
296+
.range()
297+
.gate()
298+
.assign_constant(&mut ctx, self.sp1_protocol.init_state)
299+
.expect("IntegerInstructions::assign_constant infallible");
300+
301+
// Commitments to the preprocessed polynomials.
302+
for preprocessed_polys in preprocessed_poly_sets.iter() {
303+
let mut preprocessed_check_1 =
304+
config.flex_gate().load_constant(&mut ctx, Fr::ONE);
305+
let mut preprocessed_check_2 =
306+
config.flex_gate().load_constant(&mut ctx, Fr::ONE);
307+
for ((commitment, comm_halo2), comm_sp1) in preprocessed_polys
308+
.iter()
309+
.zip_eq(preprocessed_polys_halo2.iter())
310+
.zip_eq(preprocessed_polys_sp1.iter())
311+
{
312+
let check_1 =
313+
config.ecc_chip().is_equal(&mut ctx, commitment, comm_halo2);
314+
let check_2 =
315+
config.ecc_chip().is_equal(&mut ctx, commitment, comm_sp1);
316+
preprocessed_check_1 = config.flex_gate().and(
317+
&mut ctx,
318+
Existing(preprocessed_check_1),
319+
Existing(check_1),
320+
);
321+
preprocessed_check_2 = config.flex_gate().and(
322+
&mut ctx,
323+
Existing(preprocessed_check_2),
324+
Existing(check_2),
325+
);
326+
}
327+
let preprocessed_check = config.flex_gate().or(
328+
&mut ctx,
329+
Existing(preprocessed_check_1),
330+
Existing(preprocessed_check_2),
331+
);
332+
config
333+
.flex_gate()
334+
.assert_is_const(&mut ctx, &preprocessed_check, Fr::ONE);
335+
}
336+
337+
// Transcript initial state.
338+
for transcript_init_state in transcript_init_states {
339+
let transcript_init_state = transcript_init_state
340+
.expect("SNARK should have an initial state for transcript");
341+
let transcript_check_1 = config.flex_gate().is_equal(
342+
&mut ctx,
343+
Existing(transcript_init_state),
344+
Existing(transcript_init_state_halo2),
345+
);
346+
let transcript_check_2 = config.flex_gate().is_equal(
347+
&mut ctx,
348+
Existing(transcript_init_state),
349+
Existing(transcript_init_state_sp1),
350+
);
351+
let transcript_check = config.flex_gate().or(
352+
&mut ctx,
353+
Existing(transcript_check_1),
354+
Existing(transcript_check_2),
355+
);
356+
config
357+
.flex_gate()
358+
.assert_is_const(&mut ctx, &transcript_check, Fr::ONE);
359+
}
360+
361+
ctx.print_stats(&["protocol check"]);
362+
248363
let barycentric = config.blob_consistency_config.assign_barycentric(
249364
&mut ctx,
250365
&self.batch_hash.blob_bytes,

aggregator/src/blob_consistency.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ mod eip4844;
1919
cfg_if! {
2020
if #[cfg(feature = "da-avail")] {
2121
// const DATA_AVAILABILITY: DataAvailability = DataAvailability::Avail;
22-
pub use avail::{BlobConsistencyConfig, BlobConsistencyWitness, BLOB_WIDTH};
22+
pub use avail::{BlobConsistencyConfig, BlobConsistencyWitness, BLOB_WIDTH, get_blob_bytes};
2323
} else {
2424
// const DATA_AVAILABILITY: DatayAvailability = DataAvailability::Eip4844;
25-
pub use eip4844::{BlobConsistencyConfig, BlobConsistencyWitness, BLOB_WIDTH};
25+
pub use eip4844::{BlobConsistencyConfig, BlobConsistencyWitness, BLOB_WIDTH, get_blob_bytes};
2626
}
2727
}

aggregator/src/blob_consistency/avail.rs

+4
Original file line numberDiff line numberDiff line change
@@ -107,4 +107,8 @@ impl AssignedBarycentricEvaluationConfig {
107107
pub fn challenge_digest(&self) -> &CRTInteger<Fr> {
108108
&self.barycentric_assignments[BLOB_WIDTH]
109109
}
110+
111+
/// Get the blob data bytes that will be populated in BlobDataConfig.
112+
pub fn get_blob_bytes(_batch_bytes: &[u8]) -> Vec<u8> {
113+
unimplemented!("trick for linting");
110114
}

aggregator/src/blob_consistency/eip4844.rs

-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ fn kzg_to_versioned_hash(commitment: &c_kzg::KzgCommitment) -> H256 {
8484
H256::from_slice(&res[..])
8585
}
8686

87-
#[cfg(test)]
8887
/// Get the blob data bytes that will be populated in BlobDataConfig.
8988
pub fn get_blob_bytes(batch_bytes: &[u8]) -> Vec<u8> {
9089
let mut blob_bytes = crate::witgen::zstd_encode(batch_bytes);

aggregator/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ mod tests;
2727
pub use self::core::extract_proof_and_instances_with_pairing_check;
2828
pub use aggregation::*;
2929
pub use batch::{BatchHash, BatchHeader};
30+
pub use blob_consistency::get_blob_bytes;
3031
pub use chunk::ChunkInfo;
3132
pub use compression::*;
3233
pub use constants::MAX_AGG_SNARKS;

aggregator/src/tests/aggregation.rs

+9
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use crate::{
1717
};
1818

1919
#[test]
20+
#[ignore = "dbg: insufficient number of advice columns"]
2021
fn batch_circuit_raw() {
2122
let k = 21;
2223
let circuit: BatchCircuit<MAX_AGG_SNARKS> = build_batch_circuit_skip_encoding();
@@ -26,6 +27,7 @@ fn batch_circuit_raw() {
2627
}
2728

2829
#[test]
30+
#[ignore = "dbg: insufficient number of advice columns"]
2931
fn batch_circuit_encode() {
3032
let k = 21;
3133
let circuit: BatchCircuit<MAX_AGG_SNARKS> = build_new_batch_circuit(2, k);
@@ -209,6 +211,7 @@ fn build_new_batch_circuit<const N_SNARKS: usize>(
209211
})
210212
.collect_vec()
211213
};
214+
let snark_protocol = real_snarks[0].protocol.clone();
212215

213216
// ==========================
214217
// padded chunks
@@ -225,6 +228,8 @@ fn build_new_batch_circuit<const N_SNARKS: usize>(
225228
[real_snarks, padded_snarks].concat().as_ref(),
226229
rng,
227230
batch_hash,
231+
&snark_protocol,
232+
&snark_protocol,
228233
)
229234
.unwrap()
230235
}
@@ -293,6 +298,8 @@ fn build_batch_circuit_skip_encoding<const N_SNARKS: usize>() -> BatchCircuit<N_
293298
})
294299
.collect_vec()
295300
};
301+
let snark_protocol = real_snarks[0].protocol.clone();
302+
296303
// ==========================
297304
// padded chunks
298305
// ==========================
@@ -302,6 +309,8 @@ fn build_batch_circuit_skip_encoding<const N_SNARKS: usize>() -> BatchCircuit<N_
302309
[real_snarks, padded_snarks].concat().as_ref(),
303310
rng,
304311
batch_hash,
312+
&snark_protocol,
313+
&snark_protocol,
305314
)
306315
.unwrap()
307316
}

prover/Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,13 @@ serde.workspace = true
3434
serde_derive = "1.0"
3535
serde_json = { workspace = true, features = ["unbounded_depth"] }
3636
serde_stacker.workspace = true
37+
thiserror = "1.0"
3738
sha2 ="0.10.2"
3839
revm = { version = "17.1.0", default-features = false, features = ["std"] }
3940

41+
[dev-dependencies]
42+
tempdir = "0.3"
43+
4044
[features]
4145
default = ["scroll"]
4246
parallel_syn = ["halo2_proofs/parallel_syn", "zkevm-circuits/parallel_syn"]

prover/src/aggregator.rs

-6
This file was deleted.

0 commit comments

Comments
 (0)