From a2ab8a65970ee773593f890a24aa5232de882914 Mon Sep 17 00:00:00 2001 From: Rohit Narurkar Date: Thu, 17 Oct 2024 14:12:48 +0100 Subject: [PATCH 01/11] initial work | to be tested --- Cargo.lock | 4 +- aggregator/src/aggregation/circuit.rs | 127 ++++++++++++-- aggregator/src/constants.rs | 241 ++++++++++++++++++++++++++ 3 files changed, 357 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6155537ce5..7506201fcf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4594,7 +4594,7 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "snark-verifier" version = "0.1.0" -source = "git+https://github.com/scroll-tech/snark-verifier?branch=develop#572ef69d1595fca82213d3b05e859eaf355a5fa1" +source = "git+https://github.com/scroll-tech/snark-verifier?branch=develop#948671cac73f11e66187a15483e38ab3626dc2a3" dependencies = [ "bytes", "ethereum-types", @@ -4617,7 +4617,7 @@ dependencies = [ [[package]] name = "snark-verifier-sdk" version = "0.0.1" -source = "git+https://github.com/scroll-tech/snark-verifier?branch=develop#572ef69d1595fca82213d3b05e859eaf355a5fa1" +source = "git+https://github.com/scroll-tech/snark-verifier?branch=develop#948671cac73f11e66187a15483e38ab3626dc2a3" dependencies = [ "bincode", "ethereum-types", diff --git a/aggregator/src/aggregation/circuit.rs b/aggregator/src/aggregation/circuit.rs index b9a3cc7c79..3901894645 100644 --- a/aggregator/src/aggregation/circuit.rs +++ b/aggregator/src/aggregation/circuit.rs @@ -1,5 +1,6 @@ use ark_std::{end_timer, start_timer}; use halo2_proofs::{ + arithmetic::Field, circuit::{Layouter, SimpleFloorPlanner, Value}, halo2curves::bn256::{Bn256, Fr, G1Affine}, plonk::{Circuit, ConstraintSystem, Error, Selector}, @@ -8,17 +9,25 @@ use halo2_proofs::{ use itertools::Itertools; use rand::Rng; use snark_verifier::{ - loader::halo2::{ - halo2_ecc::{ - ecc::EccChip, - fields::fp::FpConfig, - halo2_base::{AssignedValue, Context, ContextParams}, + loader::{ + halo2::{ + halo2_ecc::{ + ecc::EccChip, + fields::fp::FpConfig, + halo2_base::{ + gates::GateInstructions, AssignedValue, Context, ContextParams, + QuantumCell::Existing, + }, + }, + Halo2Loader, }, - Halo2Loader, + EcPointLoader, ScalarLoader, }, pcs::kzg::{Bdfg21, Kzg, KzgSuccinctVerifyingKey}, }; -use snark_verifier_sdk::{aggregate, flatten_accumulator, CircuitExt, Snark, SnarkWitness}; +use snark_verifier_sdk::{ + aggregate_as_witness, flatten_accumulator, CircuitExt, Snark, SnarkWitness, +}; use std::{env, fs::File, rc::Rc}; use zkevm_circuits::util::Challenges; @@ -26,7 +35,10 @@ use crate::{ aggregation::{decoder::WORKED_EXAMPLE, witgen::process, BatchCircuitConfig, BatchData}, batch::BatchHash, blob_consistency::BlobConsistencyConfig, - constants::{ACC_LEN, DIGEST_LEN}, + constants::{ + ACC_LEN, DIGEST_LEN, PREPROCESSED_POLYS_HALO2, PREPROCESSED_POLYS_SP1, + TRANSCRIPT_INIT_STATE_HALO2, TRANSCRIPT_INIT_STATE_SP1, + }, core::{assign_batch_hashes, extract_proof_and_instances_with_pairing_check}, util::parse_hash_digest_cells, witgen::{zstd_encode, MultiBlockProcessResult}, @@ -216,7 +228,12 @@ impl Circuit for BatchCircuit { // - new accumulator // log::debug!("aggregation: chunk aggregation"); - let (assigned_aggregation_instances, acc) = aggregate::>( + let ( + assigned_aggregation_instances, + acc, + preprocessed_poly_sets, + transcript_init_states, + ) = aggregate_as_witness::>( &self.svk, &loader, &self.snarks_with_padding, @@ -226,6 +243,93 @@ impl Circuit for BatchCircuit { log::trace!("{}-th instance: {:?}", i, e.value) } + // We must ensure that the commitments to preprocessed polynomial and initial + // state of transcripts for every SNARK that is being aggregated belongs to the + // fixed set of values expected. + // + // Commitments to the preprocessed polynomials. + let mut ctx = loader.ctx_mut(); + let mut preprocessed_polys_halo2 = Vec::with_capacity(7); + let mut preprocessed_polys_sp1 = Vec::with_capacity(7); + for preprocessed_poly in PREPROCESSED_POLYS_HALO2.iter() { + preprocessed_polys_halo2.push( + loader + .ec_point_load_const(preprocessed_poly) + .into_assigned(), + ); + } + for preprocessed_poly in PREPROCESSED_POLYS_SP1.iter() { + preprocessed_polys_sp1.push( + loader + .ec_point_load_const(preprocessed_poly) + .into_assigned(), + ); + } + for preprocessed_polys in preprocessed_poly_sets.iter() { + let mut preprocessed_check_1 = + config.flex_gate().load_constant(&mut ctx, Fr::ONE); + let mut preprocessed_check_2 = + config.flex_gate().load_constant(&mut ctx, Fr::ONE); + for ((commitment, comm_halo2), comm_sp1) in preprocessed_polys + .iter() + .zip_eq(preprocessed_polys_halo2.iter()) + .zip_eq(preprocessed_polys_sp1.iter()) + { + let check_1 = + config.ecc_chip().is_equal(&mut ctx, commitment, comm_halo2); + let check_2 = + config.ecc_chip().is_equal(&mut ctx, commitment, comm_sp1); + preprocessed_check_1 = config.flex_gate().and( + &mut ctx, + Existing(preprocessed_check_1), + Existing(check_1), + ); + preprocessed_check_2 = config.flex_gate().and( + &mut ctx, + Existing(preprocessed_check_2), + Existing(check_2), + ); + } + let preprocessed_check = config.flex_gate().or( + &mut ctx, + Existing(preprocessed_check_1), + Existing(preprocessed_check_2), + ); + config + .flex_gate() + .assert_is_const(&mut ctx, &preprocessed_check, Fr::ONE); + } + + // Transcript initial state. + let transcript_init_state_halo2 = loader + .load_const(&TRANSCRIPT_INIT_STATE_HALO2) + .into_assigned(); + let transcript_init_state_sp1 = loader + .load_const(&TRANSCRIPT_INIT_STATE_SP1) + .into_assigned(); + for transcript_init_state in transcript_init_states { + let transcript_init_state = transcript_init_state + .expect("SNARK should have an initial state for transcript"); + let transcript_check_1 = config.flex_gate().is_equal( + &mut ctx, + Existing(transcript_init_state), + Existing(transcript_init_state_halo2), + ); + let transcript_check_2 = config.flex_gate().is_equal( + &mut ctx, + Existing(transcript_init_state), + Existing(transcript_init_state_sp1), + ); + let transcript_check = config.flex_gate().or( + &mut ctx, + Existing(transcript_check_1), + Existing(transcript_check_2), + ); + config + .flex_gate() + .assert_is_const(&mut ctx, &transcript_check, Fr::ONE); + } + // extract the following cells for later constraints // - the accumulators // - the public inputs from each snark @@ -239,11 +343,8 @@ impl Circuit for BatchCircuit { .flat_map(|instance_column| instance_column.iter().skip(ACC_LEN)), ); - loader - .ctx_mut() - .print_stats(&["snark aggregation [chunks -> batch]"]); + ctx.print_stats(&["snark aggregation [chunks -> batch]"]); - let mut ctx = Rc::into_inner(loader).unwrap().into_ctx(); log::debug!("batching: assigning barycentric"); let barycentric = config.blob_consistency_config.assign_barycentric( &mut ctx, diff --git a/aggregator/src/constants.rs b/aggregator/src/constants.rs index 7d5d633172..3fa61b9c63 100644 --- a/aggregator/src/constants.rs +++ b/aggregator/src/constants.rs @@ -1,3 +1,6 @@ +use halo2_proofs::halo2curves::bn256::{Fq, Fr, G1Affine}; +use std::sync::LazyLock; + // A chain_id is u64 and uses 8 bytes pub(crate) const CHAIN_ID_LEN: usize = 8; @@ -88,3 +91,241 @@ pub const MAX_AGG_SNARKS: usize = 45; // Number of bytes in a u256. pub const N_BYTES_U256: usize = 32; + +/// The [`Batch Circuit`] supports aggregation of up to [`MAX_AGG_SNARKS`] SNARKs, where either +/// SNARK is of 2 kinds, namely: +/// +/// 1. halo2-based [`SuperCircuit`] -> [`CompressionCircuit`] (wide) -> `CompressionCircuit` (thin) +/// 2. sp1-based STARK -> halo2-based backend -> `CompressionCircuit` (thin) +/// +/// For each SNARK witness provided for aggregation, we require that the commitments to the +/// preprocessed polynomials and the transcript's initial state belong to a fixed set, one +/// belonging to each of the above SNARK kinds. +/// +/// Represents the fixed commitments to the preprocessed polynomials for [`ChunkKind::Halo2`]. +pub static PREPROCESSED_POLYS_HALO2: LazyLock> = LazyLock::new(|| { + vec![ + G1Affine { + x: Fq::from_raw([ + 4541478842587617678, + 7188475718571567728, + 239378696823010373, + 179342154257362491, + ]), + y: Fq::from_raw([ + 2102960765482384605, + 18163083796572731063, + 17943480866217266774, + 85103875006328896, + ]), + }, + G1Affine { + x: Fq::from_raw([ + 4093061539863783111, + 194291308596025748, + 11369022891089479442, + 1463255879024205618, + ]), + y: Fq::from_raw([ + 16700532425791245072, + 7378851796565816368, + 17346566642486298786, + 970075911594951367, + ]), + }, + G1Affine { + x: Fq::from_raw([ + 6315321914675870134, + 1582860689439567350, + 15739400164232855740, + 1223439486676386684, + ]), + y: Fq::from_raw([ + 13096458462745381806, + 11924041770036958177, + 12977682459629830027, + 1912305792904139855, + ]), + }, + G1Affine { + x: Fq::from_raw([ + 408389462232057354, + 10888945426883186814, + 9738219244958428216, + 3343776552242400005, + ]), + y: Fq::from_raw([ + 2204271371398632469, + 3229396059398198493, + 15594587291868236687, + 1533897200726072018, + ]), + }, + G1Affine { + x: Fq::from_raw([ + 14778744839025706557, + 7305439111399726684, + 14617960481571289161, + 2468165792866445337, + ]), + y: Fq::from_raw([ + 15298503060320124348, + 16948478742631860463, + 10983004142833888255, + 70418435200471011, + ]), + }, + G1Affine { + x: Fq::from_raw([ + 10682202061899776328, + 12746133157404224107, + 10194303803070492548, + 3314924930376820519, + ]), + y: Fq::from_raw([ + 10891118471780302094, + 7166241992404117528, + 6263062724619736264, + 340188705380829494, + ]), + }, + G1Affine { + x: Fq::from_raw([ + 9240035288364311447, + 16941312289372401027, + 15915874119483357666, + 2647144763697367565, + ]), + y: Fq::from_raw([ + 11086173928117658245, + 3518116464318723439, + 13832518766777794466, + 2351978436917361063, + ]), + }, + ] +}); + +/// Represents the fixed commitments to the preprocessed polynomials for [`ChunkKind::Sp1`]. +pub static PREPROCESSED_POLYS_SP1: LazyLock> = LazyLock::new(|| { + vec![ + G1Affine { + x: Fq::from_raw([ + 4541478842587617678, + 7188475718571567728, + 239378696823010373, + 179342154257362491, + ]), + y: Fq::from_raw([ + 2102960765482384605, + 18163083796572731063, + 17943480866217266774, + 85103875006328896, + ]), + }, + G1Affine { + x: Fq::from_raw([ + 14482602916982982999, + 2357100016965177442, + 18431616353722806990, + 1632384859399911320, + ]), + y: Fq::from_raw([ + 9341870623509249436, + 10625117674485803345, + 11602556742997327241, + 588490870283709105, + ]), + }, + G1Affine { + x: Fq::from_raw([ + 1695984461415246698, + 16627531726212442277, + 7436715082446168910, + 1334937499741146447, + ]), + y: Fq::from_raw([ + 10378694966954049300, + 14869436676005235944, + 8183056858201575129, + 2775754316985040075, + ]), + }, + G1Affine { + x: Fq::from_raw([ + 10696015357775661092, + 16365831078551355495, + 6432053641301558040, + 3332063291233986333, + ]), + y: Fq::from_raw([ + 15981342105615776301, + 12342977772828558934, + 12118653449154188133, + 528988368198712851, + ]), + }, + G1Affine { + x: Fq::from_raw([ + 4303830904018986544, + 12892574281015932006, + 12553056811812850723, + 3211210156168296116, + ]), + y: Fq::from_raw([ + 4036545931324298107, + 7599907392816691312, + 15293245440448741876, + 212143551489911410, + ]), + }, + G1Affine { + x: Fq::from_raw([ + 10931155675221794876, + 4312691987032924781, + 9804797475001633245, + 3451890802936893314, + ]), + y: Fq::from_raw([ + 11180962733343570413, + 10484712170183330434, + 14444948151863902680, + 2123487521383807780, + ]), + }, + G1Affine { + x: Fq::from_raw([ + 1814367689437931729, + 8489483461414090990, + 10000388380055359653, + 1286074470617787276, + ]), + y: Fq::from_raw([ + 7726546312100213647, + 1034780786427294399, + 6531068821869198065, + 517274402271116562, + ]), + }, + ] +}); + +/// Represents the initial state of the transcript for [`ChunkKind::Halo2`]. +pub static TRANSCRIPT_INIT_STATE_HALO2: LazyLock = LazyLock::new(|| { + Fr::from_raw([ + 3505826241380660566, + 11473746322117040456, + 14075887197298535585, + 1737617936020314372, + ]) +}); + +/// Represents the initial state of the transcript for [`ChunkKind::Sp1`]. +pub static TRANSCRIPT_INIT_STATE_SP1: LazyLock = LazyLock::new(|| { + Fr::from_raw([ + 1678899198020618715, + 10231258143962228858, + 12365017456265435574, + 841984517048583699, + ]) +}); From 2f257442232e0e4daa26dd8106a679fe663b2728 Mon Sep 17 00:00:00 2001 From: Rohit Narurkar Date: Thu, 17 Oct 2024 15:56:24 +0100 Subject: [PATCH 02/11] fix: borrow ctx from loader only once --- aggregator/src/aggregation/circuit.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/aggregator/src/aggregation/circuit.rs b/aggregator/src/aggregation/circuit.rs index 3901894645..184215a154 100644 --- a/aggregator/src/aggregation/circuit.rs +++ b/aggregator/src/aggregation/circuit.rs @@ -247,8 +247,8 @@ impl Circuit for BatchCircuit { // state of transcripts for every SNARK that is being aggregated belongs to the // fixed set of values expected. // - // Commitments to the preprocessed polynomials. - let mut ctx = loader.ctx_mut(); + // First we load the constants. + log::info!("populating constants"); let mut preprocessed_polys_halo2 = Vec::with_capacity(7); let mut preprocessed_polys_sp1 = Vec::with_capacity(7); for preprocessed_poly in PREPROCESSED_POLYS_HALO2.iter() { @@ -265,6 +265,16 @@ impl Circuit for BatchCircuit { .into_assigned(), ); } + let transcript_init_state_halo2 = loader + .load_const(&TRANSCRIPT_INIT_STATE_HALO2) + .into_assigned(); + let transcript_init_state_sp1 = loader + .load_const(&TRANSCRIPT_INIT_STATE_SP1) + .into_assigned(); + log::info!("populating constants OK"); + + // Commitments to the preprocessed polynomials. + let mut ctx = Rc::into_inner(loader).unwrap().into_ctx(); for preprocessed_polys in preprocessed_poly_sets.iter() { let mut preprocessed_check_1 = config.flex_gate().load_constant(&mut ctx, Fr::ONE); @@ -301,12 +311,6 @@ impl Circuit for BatchCircuit { } // Transcript initial state. - let transcript_init_state_halo2 = loader - .load_const(&TRANSCRIPT_INIT_STATE_HALO2) - .into_assigned(); - let transcript_init_state_sp1 = loader - .load_const(&TRANSCRIPT_INIT_STATE_SP1) - .into_assigned(); for transcript_init_state in transcript_init_states { let transcript_init_state = transcript_init_state .expect("SNARK should have an initial state for transcript"); From 590056d34196e1dd3cc94e0f7fe0b36b2274d21a Mon Sep 17 00:00:00 2001 From: Rohit Narurkar Date: Thu, 17 Oct 2024 17:29:15 +0100 Subject: [PATCH 03/11] more logs --- aggregator/src/aggregation/circuit.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/aggregator/src/aggregation/circuit.rs b/aggregator/src/aggregation/circuit.rs index 184215a154..9a895f5423 100644 --- a/aggregator/src/aggregation/circuit.rs +++ b/aggregator/src/aggregation/circuit.rs @@ -251,23 +251,28 @@ impl Circuit for BatchCircuit { log::info!("populating constants"); let mut preprocessed_polys_halo2 = Vec::with_capacity(7); let mut preprocessed_polys_sp1 = Vec::with_capacity(7); - for preprocessed_poly in PREPROCESSED_POLYS_HALO2.iter() { + for (i, preprocessed_poly) in PREPROCESSED_POLYS_HALO2.iter().enumerate() { + log::debug!("load const {i}"); preprocessed_polys_halo2.push( loader .ec_point_load_const(preprocessed_poly) .into_assigned(), ); + log::debug!("load const {i} OK"); } - for preprocessed_poly in PREPROCESSED_POLYS_SP1.iter() { + for (i, preprocessed_poly) in PREPROCESSED_POLYS_SP1.iter().enumerate() { + log::debug!("load const (sp1) {i}"); preprocessed_polys_sp1.push( loader .ec_point_load_const(preprocessed_poly) .into_assigned(), ); + log::debug!("load const (sp1) {i} OK"); } let transcript_init_state_halo2 = loader .load_const(&TRANSCRIPT_INIT_STATE_HALO2) .into_assigned(); + log::debug!("load transcript OK"); let transcript_init_state_sp1 = loader .load_const(&TRANSCRIPT_INIT_STATE_SP1) .into_assigned(); From 572f2fffae823f50accb7fc0bf686416c58f880d Mon Sep 17 00:00:00 2001 From: Rohit Narurkar Date: Fri, 18 Oct 2024 11:12:01 +0100 Subject: [PATCH 04/11] read from protocol json files --- aggregator/src/aggregation/circuit.rs | 18 ++++++++------- aggregator/src/constants.rs | 33 +++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/aggregator/src/aggregation/circuit.rs b/aggregator/src/aggregation/circuit.rs index 9a895f5423..e0260efbf1 100644 --- a/aggregator/src/aggregation/circuit.rs +++ b/aggregator/src/aggregation/circuit.rs @@ -35,10 +35,7 @@ use crate::{ aggregation::{decoder::WORKED_EXAMPLE, witgen::process, BatchCircuitConfig, BatchData}, batch::BatchHash, blob_consistency::BlobConsistencyConfig, - constants::{ - ACC_LEN, DIGEST_LEN, PREPROCESSED_POLYS_HALO2, PREPROCESSED_POLYS_SP1, - TRANSCRIPT_INIT_STATE_HALO2, TRANSCRIPT_INIT_STATE_SP1, - }, + constants::{ACC_LEN, DIGEST_LEN, FIXED_PROTOCOL_HALO2, FIXED_PROTOCOL_SP1}, core::{assign_batch_hashes, extract_proof_and_instances_with_pairing_check}, util::parse_hash_digest_cells, witgen::{zstd_encode, MultiBlockProcessResult}, @@ -251,7 +248,12 @@ impl Circuit for BatchCircuit { log::info!("populating constants"); let mut preprocessed_polys_halo2 = Vec::with_capacity(7); let mut preprocessed_polys_sp1 = Vec::with_capacity(7); - for (i, preprocessed_poly) in PREPROCESSED_POLYS_HALO2.iter().enumerate() { + let (fixed_preprocessed_polys_halo2, fixed_transcript_init_state_halo2) = + FIXED_PROTOCOL_HALO2.clone(); + let (fixed_preprocessed_polys_sp1, fixed_transcript_init_state_sp1) = + FIXED_PROTOCOL_SP1.clone(); + for (i, preprocessed_poly) in fixed_preprocessed_polys_halo2.iter().enumerate() + { log::debug!("load const {i}"); preprocessed_polys_halo2.push( loader @@ -260,7 +262,7 @@ impl Circuit for BatchCircuit { ); log::debug!("load const {i} OK"); } - for (i, preprocessed_poly) in PREPROCESSED_POLYS_SP1.iter().enumerate() { + for (i, preprocessed_poly) in fixed_preprocessed_polys_sp1.iter().enumerate() { log::debug!("load const (sp1) {i}"); preprocessed_polys_sp1.push( loader @@ -270,11 +272,11 @@ impl Circuit for BatchCircuit { log::debug!("load const (sp1) {i} OK"); } let transcript_init_state_halo2 = loader - .load_const(&TRANSCRIPT_INIT_STATE_HALO2) + .load_const(&fixed_transcript_init_state_halo2) .into_assigned(); log::debug!("load transcript OK"); let transcript_init_state_sp1 = loader - .load_const(&TRANSCRIPT_INIT_STATE_SP1) + .load_const(&fixed_transcript_init_state_sp1) .into_assigned(); log::info!("populating constants OK"); diff --git a/aggregator/src/constants.rs b/aggregator/src/constants.rs index 3fa61b9c63..b64473421c 100644 --- a/aggregator/src/constants.rs +++ b/aggregator/src/constants.rs @@ -103,6 +103,39 @@ pub const N_BYTES_U256: usize = 32; /// belonging to each of the above SNARK kinds. /// /// Represents the fixed commitments to the preprocessed polynomials for [`ChunkKind::Halo2`]. +pub type PreprocessedPolyCommits = Vec; +pub type TranscriptInitState = Fr; +pub type FixedProtocol = (PreprocessedPolyCommits, TranscriptInitState); + +pub static FIXED_PROTOCOL_HALO2: LazyLock = LazyLock::new(|| { + let path = + std::env::var("HALO2_CHUNK_PROTOCOL").unwrap_or("chunk_chunk_halo2.protocol".to_string()); + let file = std::fs::File::open(&path).expect("could not open file"); + let reader = std::io::BufReader::new(file); + let protocol: snark_verifier::Protocol = + serde_json::from_reader(reader).expect("could not deserialise protocol"); + ( + protocol.preprocessed, + protocol + .transcript_initial_state + .expect("transcript initial state is None"), + ) +}); +pub static FIXED_PROTOCOL_SP1: LazyLock = LazyLock::new(|| { + let path = + std::env::var("SP1_CHUNK_PROTOCOL").unwrap_or("chunk_chunk_sp1.protocol".to_string()); + let file = std::fs::File::open(&path).expect("could not open file"); + let reader = std::io::BufReader::new(file); + let protocol: snark_verifier::Protocol = + serde_json::from_reader(reader).expect("could not deserialise protocol"); + ( + protocol.preprocessed, + protocol + .transcript_initial_state + .expect("transcript initial state is None"), + ) +}); + pub static PREPROCESSED_POLYS_HALO2: LazyLock> = LazyLock::new(|| { vec![ G1Affine { From 43fc4d29b7512a90b8988c2dc9e5ea4c80b7c080 Mon Sep 17 00:00:00 2001 From: Rohit Narurkar Date: Fri, 18 Oct 2024 13:47:47 +0100 Subject: [PATCH 05/11] dir + name --- aggregator/src/constants.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/aggregator/src/constants.rs b/aggregator/src/constants.rs index b64473421c..2011313aef 100644 --- a/aggregator/src/constants.rs +++ b/aggregator/src/constants.rs @@ -108,8 +108,11 @@ pub type TranscriptInitState = Fr; pub type FixedProtocol = (PreprocessedPolyCommits, TranscriptInitState); pub static FIXED_PROTOCOL_HALO2: LazyLock = LazyLock::new(|| { - let path = + let name = std::env::var("HALO2_CHUNK_PROTOCOL").unwrap_or("chunk_chunk_halo2.protocol".to_string()); + let dir = + std::env::var("SCROLL_PROVER_ASSETS_DIR").unwrap_or("./tests/test_assets".to_string()); + let path = std::path::Path::new(&dir).join(name); let file = std::fs::File::open(&path).expect("could not open file"); let reader = std::io::BufReader::new(file); let protocol: snark_verifier::Protocol = @@ -122,8 +125,11 @@ pub static FIXED_PROTOCOL_HALO2: LazyLock = LazyLock::new(|| { ) }); pub static FIXED_PROTOCOL_SP1: LazyLock = LazyLock::new(|| { - let path = + let name = std::env::var("SP1_CHUNK_PROTOCOL").unwrap_or("chunk_chunk_sp1.protocol".to_string()); + let dir = + std::env::var("SCROLL_PROVER_ASSETS_DIR").unwrap_or("./tests/test_assets".to_string()); + let path = std::path::Path::new(&dir).join(name); let file = std::fs::File::open(&path).expect("could not open file"); let reader = std::io::BufReader::new(file); let protocol: snark_verifier::Protocol = From b293965771cf62ae57575c63d7b0f14ae7f7ec1f Mon Sep 17 00:00:00 2001 From: Rohit Narurkar Date: Fri, 18 Oct 2024 14:33:35 +0100 Subject: [PATCH 06/11] reference already duplicated somewhere in --- aggregator/src/aggregation/circuit.rs | 53 ++++++++++++++------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/aggregator/src/aggregation/circuit.rs b/aggregator/src/aggregation/circuit.rs index e0260efbf1..e052f458bd 100644 --- a/aggregator/src/aggregation/circuit.rs +++ b/aggregator/src/aggregation/circuit.rs @@ -9,19 +9,16 @@ use halo2_proofs::{ use itertools::Itertools; use rand::Rng; use snark_verifier::{ - loader::{ - halo2::{ - halo2_ecc::{ - ecc::EccChip, - fields::fp::FpConfig, - halo2_base::{ - gates::GateInstructions, AssignedValue, Context, ContextParams, - QuantumCell::Existing, - }, + loader::halo2::{ + halo2_ecc::{ + ecc::EccChip, + fields::{fp::FpConfig, FieldChip}, + halo2_base::{ + gates::GateInstructions, utils::fe_to_biguint, AssignedValue, Context, + ContextParams, QuantumCell::Existing, }, - Halo2Loader, }, - EcPointLoader, ScalarLoader, + Halo2Loader, }, pcs::kzg::{Bdfg21, Kzg, KzgSuccinctVerifyingKey}, }; @@ -236,6 +233,7 @@ impl Circuit for BatchCircuit { &self.snarks_with_padding, self.as_proof(), ); + let mut ctx = Rc::into_inner(loader).unwrap().into_ctx(); for (i, e) in assigned_aggregation_instances[0].iter().enumerate() { log::trace!("{}-th instance: {:?}", i, e.value) } @@ -252,36 +250,37 @@ impl Circuit for BatchCircuit { FIXED_PROTOCOL_HALO2.clone(); let (fixed_preprocessed_polys_sp1, fixed_transcript_init_state_sp1) = FIXED_PROTOCOL_SP1.clone(); - for (i, preprocessed_poly) in fixed_preprocessed_polys_halo2.iter().enumerate() + for (i, &preprocessed_poly) in fixed_preprocessed_polys_halo2.iter().enumerate() { log::debug!("load const {i}"); preprocessed_polys_halo2.push( - loader - .ec_point_load_const(preprocessed_poly) - .into_assigned(), + config + .ecc_chip() + .assign_constant_point(&mut ctx, preprocessed_poly), ); log::debug!("load const {i} OK"); } - for (i, preprocessed_poly) in fixed_preprocessed_polys_sp1.iter().enumerate() { + for (i, &preprocessed_poly) in fixed_preprocessed_polys_sp1.iter().enumerate() { log::debug!("load const (sp1) {i}"); preprocessed_polys_sp1.push( - loader - .ec_point_load_const(preprocessed_poly) - .into_assigned(), + config + .ecc_chip() + .assign_constant_point(&mut ctx, preprocessed_poly), ); log::debug!("load const (sp1) {i} OK"); } - let transcript_init_state_halo2 = loader - .load_const(&fixed_transcript_init_state_halo2) - .into_assigned(); + let transcript_init_state_halo2 = config + .ecc_chip() + .field_chip() + .load_constant(&mut ctx, fe_to_biguint(&fixed_transcript_init_state_halo2)); log::debug!("load transcript OK"); - let transcript_init_state_sp1 = loader - .load_const(&fixed_transcript_init_state_sp1) - .into_assigned(); + let transcript_init_state_sp1 = config + .ecc_chip() + .field_chip() + .load_constant(&mut ctx, fe_to_biguint(&fixed_transcript_init_state_sp1)); log::info!("populating constants OK"); // Commitments to the preprocessed polynomials. - let mut ctx = Rc::into_inner(loader).unwrap().into_ctx(); for preprocessed_polys in preprocessed_poly_sets.iter() { let mut preprocessed_check_1 = config.flex_gate().load_constant(&mut ctx, Fr::ONE); @@ -318,6 +317,7 @@ impl Circuit for BatchCircuit { } // Transcript initial state. + /* for transcript_init_state in transcript_init_states { let transcript_init_state = transcript_init_state .expect("SNARK should have an initial state for transcript"); @@ -340,6 +340,7 @@ impl Circuit for BatchCircuit { .flex_gate() .assert_is_const(&mut ctx, &transcript_check, Fr::ONE); } + */ // extract the following cells for later constraints // - the accumulators From 9ffe8742b69f9a6f308a2bab037cd7f958eb4c17 Mon Sep 17 00:00:00 2001 From: Rohit Narurkar Date: Fri, 18 Oct 2024 15:04:16 +0100 Subject: [PATCH 07/11] minor updates, bump snark-verifier --- aggregator/src/aggregation/circuit.rs | 20 ++- aggregator/src/constants.rs | 247 ++------------------------ 2 files changed, 27 insertions(+), 240 deletions(-) diff --git a/aggregator/src/aggregation/circuit.rs b/aggregator/src/aggregation/circuit.rs index e052f458bd..46d04352d8 100644 --- a/aggregator/src/aggregation/circuit.rs +++ b/aggregator/src/aggregation/circuit.rs @@ -14,11 +14,13 @@ use snark_verifier::{ ecc::EccChip, fields::{fp::FpConfig, FieldChip}, halo2_base::{ - gates::GateInstructions, utils::fe_to_biguint, AssignedValue, Context, - ContextParams, QuantumCell::Existing, + gates::{GateInstructions, RangeInstructions}, + utils::fe_to_biguint, + AssignedValue, Context, ContextParams, + QuantumCell::Existing, }, }, - Halo2Loader, + Halo2Loader, IntegerInstructions, }, pcs::kzg::{Bdfg21, Kzg, KzgSuccinctVerifyingKey}, }; @@ -272,12 +274,18 @@ impl Circuit for BatchCircuit { let transcript_init_state_halo2 = config .ecc_chip() .field_chip() - .load_constant(&mut ctx, fe_to_biguint(&fixed_transcript_init_state_halo2)); + .range() + .gate() + .assign_constant(&mut ctx, fixed_transcript_init_state_halo2) + .expect("IntegerInstructions::assign_constant infallible"); log::debug!("load transcript OK"); let transcript_init_state_sp1 = config .ecc_chip() .field_chip() - .load_constant(&mut ctx, fe_to_biguint(&fixed_transcript_init_state_sp1)); + .range() + .gate() + .assign_constant(&mut ctx, fixed_transcript_init_state_sp1) + .expect("IntegerInstructions::assign_constant infallible"); log::info!("populating constants OK"); // Commitments to the preprocessed polynomials. @@ -317,7 +325,6 @@ impl Circuit for BatchCircuit { } // Transcript initial state. - /* for transcript_init_state in transcript_init_states { let transcript_init_state = transcript_init_state .expect("SNARK should have an initial state for transcript"); @@ -340,7 +347,6 @@ impl Circuit for BatchCircuit { .flex_gate() .assert_is_const(&mut ctx, &transcript_check, Fr::ONE); } - */ // extract the following cells for later constraints // - the accumulators diff --git a/aggregator/src/constants.rs b/aggregator/src/constants.rs index 2011313aef..9637ec0226 100644 --- a/aggregator/src/constants.rs +++ b/aggregator/src/constants.rs @@ -1,4 +1,4 @@ -use halo2_proofs::halo2curves::bn256::{Fq, Fr, G1Affine}; +use halo2_proofs::halo2curves::bn256::{Fr, G1Affine}; use std::sync::LazyLock; // A chain_id is u64 and uses 8 bytes @@ -92,6 +92,14 @@ pub const MAX_AGG_SNARKS: usize = 45; // Number of bytes in a u256. pub const N_BYTES_U256: usize = 32; +/// Alias for a list of G1 points. +type PreprocessedPolyCommits = Vec; +/// Alias for the transcript's initial state. +type TranscriptInitState = Fr; +/// Alias for the fixed part of the protocol which consists of the commitments to the preprocessed +/// polynomials and the initial state of the transcript. +type FixedProtocol = (PreprocessedPolyCommits, TranscriptInitState); + /// The [`Batch Circuit`] supports aggregation of up to [`MAX_AGG_SNARKS`] SNARKs, where either /// SNARK is of 2 kinds, namely: /// @@ -102,11 +110,8 @@ pub const N_BYTES_U256: usize = 32; /// preprocessed polynomials and the transcript's initial state belong to a fixed set, one /// belonging to each of the above SNARK kinds. /// -/// Represents the fixed commitments to the preprocessed polynomials for [`ChunkKind::Halo2`]. -pub type PreprocessedPolyCommits = Vec; -pub type TranscriptInitState = Fr; -pub type FixedProtocol = (PreprocessedPolyCommits, TranscriptInitState); - +/// Represents the fixed commitments to the preprocessed polynomials and the initial state of the +/// transcript for [`ChunkKind::Halo2`]. pub static FIXED_PROTOCOL_HALO2: LazyLock = LazyLock::new(|| { let name = std::env::var("HALO2_CHUNK_PROTOCOL").unwrap_or("chunk_chunk_halo2.protocol".to_string()); @@ -124,6 +129,9 @@ pub static FIXED_PROTOCOL_HALO2: LazyLock = LazyLock::new(|| { .expect("transcript initial state is None"), ) }); + +/// Represents the fixed commitments to the preprocessed polynomials and the initial state of the +/// transcript for [`ChunkKind::Sp1`]. pub static FIXED_PROTOCOL_SP1: LazyLock = LazyLock::new(|| { let name = std::env::var("SP1_CHUNK_PROTOCOL").unwrap_or("chunk_chunk_sp1.protocol".to_string()); @@ -141,230 +149,3 @@ pub static FIXED_PROTOCOL_SP1: LazyLock = LazyLock::new(|| { .expect("transcript initial state is None"), ) }); - -pub static PREPROCESSED_POLYS_HALO2: LazyLock> = LazyLock::new(|| { - vec![ - G1Affine { - x: Fq::from_raw([ - 4541478842587617678, - 7188475718571567728, - 239378696823010373, - 179342154257362491, - ]), - y: Fq::from_raw([ - 2102960765482384605, - 18163083796572731063, - 17943480866217266774, - 85103875006328896, - ]), - }, - G1Affine { - x: Fq::from_raw([ - 4093061539863783111, - 194291308596025748, - 11369022891089479442, - 1463255879024205618, - ]), - y: Fq::from_raw([ - 16700532425791245072, - 7378851796565816368, - 17346566642486298786, - 970075911594951367, - ]), - }, - G1Affine { - x: Fq::from_raw([ - 6315321914675870134, - 1582860689439567350, - 15739400164232855740, - 1223439486676386684, - ]), - y: Fq::from_raw([ - 13096458462745381806, - 11924041770036958177, - 12977682459629830027, - 1912305792904139855, - ]), - }, - G1Affine { - x: Fq::from_raw([ - 408389462232057354, - 10888945426883186814, - 9738219244958428216, - 3343776552242400005, - ]), - y: Fq::from_raw([ - 2204271371398632469, - 3229396059398198493, - 15594587291868236687, - 1533897200726072018, - ]), - }, - G1Affine { - x: Fq::from_raw([ - 14778744839025706557, - 7305439111399726684, - 14617960481571289161, - 2468165792866445337, - ]), - y: Fq::from_raw([ - 15298503060320124348, - 16948478742631860463, - 10983004142833888255, - 70418435200471011, - ]), - }, - G1Affine { - x: Fq::from_raw([ - 10682202061899776328, - 12746133157404224107, - 10194303803070492548, - 3314924930376820519, - ]), - y: Fq::from_raw([ - 10891118471780302094, - 7166241992404117528, - 6263062724619736264, - 340188705380829494, - ]), - }, - G1Affine { - x: Fq::from_raw([ - 9240035288364311447, - 16941312289372401027, - 15915874119483357666, - 2647144763697367565, - ]), - y: Fq::from_raw([ - 11086173928117658245, - 3518116464318723439, - 13832518766777794466, - 2351978436917361063, - ]), - }, - ] -}); - -/// Represents the fixed commitments to the preprocessed polynomials for [`ChunkKind::Sp1`]. -pub static PREPROCESSED_POLYS_SP1: LazyLock> = LazyLock::new(|| { - vec![ - G1Affine { - x: Fq::from_raw([ - 4541478842587617678, - 7188475718571567728, - 239378696823010373, - 179342154257362491, - ]), - y: Fq::from_raw([ - 2102960765482384605, - 18163083796572731063, - 17943480866217266774, - 85103875006328896, - ]), - }, - G1Affine { - x: Fq::from_raw([ - 14482602916982982999, - 2357100016965177442, - 18431616353722806990, - 1632384859399911320, - ]), - y: Fq::from_raw([ - 9341870623509249436, - 10625117674485803345, - 11602556742997327241, - 588490870283709105, - ]), - }, - G1Affine { - x: Fq::from_raw([ - 1695984461415246698, - 16627531726212442277, - 7436715082446168910, - 1334937499741146447, - ]), - y: Fq::from_raw([ - 10378694966954049300, - 14869436676005235944, - 8183056858201575129, - 2775754316985040075, - ]), - }, - G1Affine { - x: Fq::from_raw([ - 10696015357775661092, - 16365831078551355495, - 6432053641301558040, - 3332063291233986333, - ]), - y: Fq::from_raw([ - 15981342105615776301, - 12342977772828558934, - 12118653449154188133, - 528988368198712851, - ]), - }, - G1Affine { - x: Fq::from_raw([ - 4303830904018986544, - 12892574281015932006, - 12553056811812850723, - 3211210156168296116, - ]), - y: Fq::from_raw([ - 4036545931324298107, - 7599907392816691312, - 15293245440448741876, - 212143551489911410, - ]), - }, - G1Affine { - x: Fq::from_raw([ - 10931155675221794876, - 4312691987032924781, - 9804797475001633245, - 3451890802936893314, - ]), - y: Fq::from_raw([ - 11180962733343570413, - 10484712170183330434, - 14444948151863902680, - 2123487521383807780, - ]), - }, - G1Affine { - x: Fq::from_raw([ - 1814367689437931729, - 8489483461414090990, - 10000388380055359653, - 1286074470617787276, - ]), - y: Fq::from_raw([ - 7726546312100213647, - 1034780786427294399, - 6531068821869198065, - 517274402271116562, - ]), - }, - ] -}); - -/// Represents the initial state of the transcript for [`ChunkKind::Halo2`]. -pub static TRANSCRIPT_INIT_STATE_HALO2: LazyLock = LazyLock::new(|| { - Fr::from_raw([ - 3505826241380660566, - 11473746322117040456, - 14075887197298535585, - 1737617936020314372, - ]) -}); - -/// Represents the initial state of the transcript for [`ChunkKind::Sp1`]. -pub static TRANSCRIPT_INIT_STATE_SP1: LazyLock = LazyLock::new(|| { - Fr::from_raw([ - 1678899198020618715, - 10231258143962228858, - 12365017456265435574, - 841984517048583699, - ]) -}); From f9d59f241aabf0c78aac18a3d31eaf0932e59826 Mon Sep 17 00:00:00 2001 From: Rohit Narurkar Date: Fri, 18 Oct 2024 15:17:14 +0100 Subject: [PATCH 08/11] refactor --- aggregator/src/aggregation/circuit.rs | 35 +++++++++++++++------------ 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/aggregator/src/aggregation/circuit.rs b/aggregator/src/aggregation/circuit.rs index 46d04352d8..2566c1e6b9 100644 --- a/aggregator/src/aggregation/circuit.rs +++ b/aggregator/src/aggregation/circuit.rs @@ -235,11 +235,29 @@ impl Circuit for BatchCircuit { &self.snarks_with_padding, self.as_proof(), ); - let mut ctx = Rc::into_inner(loader).unwrap().into_ctx(); + + // extract the following cells for later constraints + // - the accumulators + // - the public inputs from each snark + accumulator_instances.extend(flatten_accumulator(acc).iter().copied()); + // the snark is not a fresh one, assigned_instances already contains an + // accumulator so we want to skip the first 12 elements from the public + // input + snark_inputs.extend( + assigned_aggregation_instances + .iter() + .flat_map(|instance_column| instance_column.iter().skip(ACC_LEN)), + ); for (i, e) in assigned_aggregation_instances[0].iter().enumerate() { log::trace!("{}-th instance: {:?}", i, e.value) } + loader + .ctx_mut() + .print_stats(&["snark aggregation"]); + + let mut ctx = Rc::into_inner(loader).unwrap().into_ctx(); + // We must ensure that the commitments to preprocessed polynomial and initial // state of transcripts for every SNARK that is being aggregated belongs to the // fixed set of values expected. @@ -348,20 +366,7 @@ impl Circuit for BatchCircuit { .assert_is_const(&mut ctx, &transcript_check, Fr::ONE); } - // extract the following cells for later constraints - // - the accumulators - // - the public inputs from each snark - accumulator_instances.extend(flatten_accumulator(acc).iter().copied()); - // the snark is not a fresh one, assigned_instances already contains an - // accumulator so we want to skip the first 12 elements from the public - // input - snark_inputs.extend( - assigned_aggregation_instances - .iter() - .flat_map(|instance_column| instance_column.iter().skip(ACC_LEN)), - ); - - ctx.print_stats(&["snark aggregation [chunks -> batch]"]); + ctx.print_stats(&["protocol check"]); log::debug!("batching: assigning barycentric"); let barycentric = config.blob_consistency_config.assign_barycentric( From f33998431479affaa5040c2ee4d6e7d4c5825a70 Mon Sep 17 00:00:00 2001 From: Rohit Narurkar Date: Tue, 22 Oct 2024 17:32:17 +0100 Subject: [PATCH 09/11] clean up + refactor --- aggregator/src/aggregation.rs | 40 ++++++++++++++++ aggregator/src/aggregation/circuit.rs | 36 ++++++++------- aggregator/src/constants.rs | 61 ------------------------- aggregator/src/tests/aggregation.rs | 7 +++ prover/src/aggregator/prover.rs | 2 + prover/src/common/prover/aggregation.rs | 32 +++++++++++-- prover/src/consts.rs | 20 +++++++- 7 files changed, 115 insertions(+), 83 deletions(-) diff --git a/aggregator/src/aggregation.rs b/aggregator/src/aggregation.rs index bb067bfb0c..501c2fb591 100644 --- a/aggregator/src/aggregation.rs +++ b/aggregator/src/aggregation.rs @@ -19,3 +19,43 @@ pub(crate) use rlc::{RlcConfig, POWS_OF_256}; pub use circuit::BatchCircuit; pub use config::BatchCircuitConfig; +use halo2_base::halo2_proofs::halo2curves::bn256::{Fr, G1Affine}; +use snark_verifier::Protocol; + +/// Alias for a list of G1 points. +pub type PreprocessedPolyCommits = Vec; +/// Alias for the transcript's initial state. +pub type TranscriptInitState = Fr; + +/// Alias for the fixed part of the protocol which consists of the commitments to the preprocessed +/// polynomials and the initial state of the transcript. +#[derive(Clone)] +pub struct FixedProtocol { + /// The commitments to the preprocessed polynomials. + pub preprocessed: PreprocessedPolyCommits, + /// The initial state of the transcript. + pub init_state: TranscriptInitState, +} + +impl From> for FixedProtocol { + fn from(protocol: Protocol) -> Self { + Self { + preprocessed: protocol.preprocessed, + init_state: protocol + .transcript_initial_state + .expect("protocol transcript init state None"), + } + } +} + +impl From<&Protocol> for FixedProtocol { + fn from(protocol: &Protocol) -> Self { + Self { + preprocessed: protocol.preprocessed.clone(), + init_state: protocol + .transcript_initial_state + .clone() + .expect("protocol transcript init state None"), + } + } +} diff --git a/aggregator/src/aggregation/circuit.rs b/aggregator/src/aggregation/circuit.rs index 2566c1e6b9..4ef74b977d 100644 --- a/aggregator/src/aggregation/circuit.rs +++ b/aggregator/src/aggregation/circuit.rs @@ -15,7 +15,6 @@ use snark_verifier::{ fields::{fp::FpConfig, FieldChip}, halo2_base::{ gates::{GateInstructions, RangeInstructions}, - utils::fe_to_biguint, AssignedValue, Context, ContextParams, QuantumCell::Existing, }, @@ -34,12 +33,12 @@ use crate::{ aggregation::{decoder::WORKED_EXAMPLE, witgen::process, BatchCircuitConfig, BatchData}, batch::BatchHash, blob_consistency::BlobConsistencyConfig, - constants::{ACC_LEN, DIGEST_LEN, FIXED_PROTOCOL_HALO2, FIXED_PROTOCOL_SP1}, + constants::{ACC_LEN, DIGEST_LEN}, core::{assign_batch_hashes, extract_proof_and_instances_with_pairing_check}, util::parse_hash_digest_cells, witgen::{zstd_encode, MultiBlockProcessResult}, - ConfigParams, LOG_DEGREE, PI_CHAIN_ID, PI_CURRENT_BATCH_HASH, PI_CURRENT_STATE_ROOT, - PI_CURRENT_WITHDRAW_ROOT, PI_PARENT_BATCH_HASH, PI_PARENT_STATE_ROOT, + ConfigParams, FixedProtocol, LOG_DEGREE, PI_CHAIN_ID, PI_CURRENT_BATCH_HASH, + PI_CURRENT_STATE_ROOT, PI_CURRENT_WITHDRAW_ROOT, PI_PARENT_BATCH_HASH, PI_PARENT_STATE_ROOT, }; /// Batch circuit, the chunk aggregation routine below recursion circuit @@ -63,14 +62,21 @@ pub struct BatchCircuit { // batch hash circuit for which the snarks are generated // the chunks in this batch are also padded already pub batch_hash: BatchHash, + + /// The SNARK protocol from the halo2-based inner circuit route. + pub halo2_protocol: FixedProtocol, + /// The SNARK protocol from the sp1-based inner circuit route. + pub sp1_protocol: FixedProtocol, } impl BatchCircuit { - pub fn new( + pub fn new>( params: &ParamsKZG, snarks_with_padding: &[Snark], rng: impl Rng + Send, batch_hash: BatchHash, + halo2_protocol: P, + sp1_protocol: P, ) -> Result { let timer = start_timer!(|| "generate aggregation circuit"); @@ -128,6 +134,8 @@ impl BatchCircuit { flattened_instances, as_proof: Value::known(as_proof), batch_hash, + halo2_protocol: halo2_protocol.into(), + sp1_protocol: sp1_protocol.into(), }) } @@ -252,9 +260,7 @@ impl Circuit for BatchCircuit { log::trace!("{}-th instance: {:?}", i, e.value) } - loader - .ctx_mut() - .print_stats(&["snark aggregation"]); + loader.ctx_mut().print_stats(&["snark aggregation"]); let mut ctx = Rc::into_inner(loader).unwrap().into_ctx(); @@ -266,11 +272,8 @@ impl Circuit for BatchCircuit { log::info!("populating constants"); let mut preprocessed_polys_halo2 = Vec::with_capacity(7); let mut preprocessed_polys_sp1 = Vec::with_capacity(7); - let (fixed_preprocessed_polys_halo2, fixed_transcript_init_state_halo2) = - FIXED_PROTOCOL_HALO2.clone(); - let (fixed_preprocessed_polys_sp1, fixed_transcript_init_state_sp1) = - FIXED_PROTOCOL_SP1.clone(); - for (i, &preprocessed_poly) in fixed_preprocessed_polys_halo2.iter().enumerate() + for (i, &preprocessed_poly) in + self.halo2_protocol.preprocessed.iter().enumerate() { log::debug!("load const {i}"); preprocessed_polys_halo2.push( @@ -280,7 +283,8 @@ impl Circuit for BatchCircuit { ); log::debug!("load const {i} OK"); } - for (i, &preprocessed_poly) in fixed_preprocessed_polys_sp1.iter().enumerate() { + for (i, &preprocessed_poly) in self.sp1_protocol.preprocessed.iter().enumerate() + { log::debug!("load const (sp1) {i}"); preprocessed_polys_sp1.push( config @@ -294,7 +298,7 @@ impl Circuit for BatchCircuit { .field_chip() .range() .gate() - .assign_constant(&mut ctx, fixed_transcript_init_state_halo2) + .assign_constant(&mut ctx, self.halo2_protocol.init_state) .expect("IntegerInstructions::assign_constant infallible"); log::debug!("load transcript OK"); let transcript_init_state_sp1 = config @@ -302,7 +306,7 @@ impl Circuit for BatchCircuit { .field_chip() .range() .gate() - .assign_constant(&mut ctx, fixed_transcript_init_state_sp1) + .assign_constant(&mut ctx, self.sp1_protocol.init_state) .expect("IntegerInstructions::assign_constant infallible"); log::info!("populating constants OK"); diff --git a/aggregator/src/constants.rs b/aggregator/src/constants.rs index 9637ec0226..7d5d633172 100644 --- a/aggregator/src/constants.rs +++ b/aggregator/src/constants.rs @@ -1,6 +1,3 @@ -use halo2_proofs::halo2curves::bn256::{Fr, G1Affine}; -use std::sync::LazyLock; - // A chain_id is u64 and uses 8 bytes pub(crate) const CHAIN_ID_LEN: usize = 8; @@ -91,61 +88,3 @@ pub const MAX_AGG_SNARKS: usize = 45; // Number of bytes in a u256. pub const N_BYTES_U256: usize = 32; - -/// Alias for a list of G1 points. -type PreprocessedPolyCommits = Vec; -/// Alias for the transcript's initial state. -type TranscriptInitState = Fr; -/// Alias for the fixed part of the protocol which consists of the commitments to the preprocessed -/// polynomials and the initial state of the transcript. -type FixedProtocol = (PreprocessedPolyCommits, TranscriptInitState); - -/// The [`Batch Circuit`] supports aggregation of up to [`MAX_AGG_SNARKS`] SNARKs, where either -/// SNARK is of 2 kinds, namely: -/// -/// 1. halo2-based [`SuperCircuit`] -> [`CompressionCircuit`] (wide) -> `CompressionCircuit` (thin) -/// 2. sp1-based STARK -> halo2-based backend -> `CompressionCircuit` (thin) -/// -/// For each SNARK witness provided for aggregation, we require that the commitments to the -/// preprocessed polynomials and the transcript's initial state belong to a fixed set, one -/// belonging to each of the above SNARK kinds. -/// -/// Represents the fixed commitments to the preprocessed polynomials and the initial state of the -/// transcript for [`ChunkKind::Halo2`]. -pub static FIXED_PROTOCOL_HALO2: LazyLock = LazyLock::new(|| { - let name = - std::env::var("HALO2_CHUNK_PROTOCOL").unwrap_or("chunk_chunk_halo2.protocol".to_string()); - let dir = - std::env::var("SCROLL_PROVER_ASSETS_DIR").unwrap_or("./tests/test_assets".to_string()); - let path = std::path::Path::new(&dir).join(name); - let file = std::fs::File::open(&path).expect("could not open file"); - let reader = std::io::BufReader::new(file); - let protocol: snark_verifier::Protocol = - serde_json::from_reader(reader).expect("could not deserialise protocol"); - ( - protocol.preprocessed, - protocol - .transcript_initial_state - .expect("transcript initial state is None"), - ) -}); - -/// Represents the fixed commitments to the preprocessed polynomials and the initial state of the -/// transcript for [`ChunkKind::Sp1`]. -pub static FIXED_PROTOCOL_SP1: LazyLock = LazyLock::new(|| { - let name = - std::env::var("SP1_CHUNK_PROTOCOL").unwrap_or("chunk_chunk_sp1.protocol".to_string()); - let dir = - std::env::var("SCROLL_PROVER_ASSETS_DIR").unwrap_or("./tests/test_assets".to_string()); - let path = std::path::Path::new(&dir).join(name); - let file = std::fs::File::open(&path).expect("could not open file"); - let reader = std::io::BufReader::new(file); - let protocol: snark_verifier::Protocol = - serde_json::from_reader(reader).expect("could not deserialise protocol"); - ( - protocol.preprocessed, - protocol - .transcript_initial_state - .expect("transcript initial state is None"), - ) -}); diff --git a/aggregator/src/tests/aggregation.rs b/aggregator/src/tests/aggregation.rs index ec374c420b..96c5034464 100644 --- a/aggregator/src/tests/aggregation.rs +++ b/aggregator/src/tests/aggregation.rs @@ -209,6 +209,7 @@ fn build_new_batch_circuit( }) .collect_vec() }; + let snark_protocol = real_snarks[0].protocol.clone(); // ========================== // padded chunks @@ -225,6 +226,8 @@ fn build_new_batch_circuit( [real_snarks, padded_snarks].concat().as_ref(), rng, batch_hash, + &snark_protocol, + &snark_protocol, ) .unwrap() } @@ -293,6 +296,8 @@ fn build_batch_circuit_skip_encoding() -> BatchCircuit() -> BatchCircuit Prover<'params> { LayerId::Layer3.id(), LayerId::Layer3.degree(), batch_info, + &self.halo2_protocol, + &self.sp1_protocol, &layer2_snarks, output_dir, )?; diff --git a/prover/src/common/prover/aggregation.rs b/prover/src/common/prover/aggregation.rs index 4d4ca2bc1b..cca60d5443 100644 --- a/prover/src/common/prover/aggregation.rs +++ b/prover/src/common/prover/aggregation.rs @@ -6,6 +6,7 @@ use crate::{ }; use aggregator::{BatchCircuit, BatchHash}; use anyhow::{anyhow, Result}; +use halo2_proofs::halo2curves::bn256::G1Affine; use rand::Rng; use snark_verifier_sdk::Snark; use std::env; @@ -17,13 +18,26 @@ impl<'params> Prover<'params> { degree: u32, mut rng: impl Rng + Send, batch_info: BatchHash, + halo2_protocol: &[u8], + sp1_protocol: &[u8], previous_snarks: &[Snark], ) -> Result { env::set_var("AGGREGATION_CONFIG", layer_config_path(id)); - let circuit: BatchCircuit = - BatchCircuit::new(self.params(degree), previous_snarks, &mut rng, batch_info) - .map_err(|err| anyhow!("Failed to construct aggregation circuit: {err:?}"))?; + let halo2_protocol = + serde_json::from_slice::>(halo2_protocol)?; + let sp1_protocol = + serde_json::from_slice::>(sp1_protocol)?; + + let circuit: BatchCircuit = BatchCircuit::new( + self.params(degree), + previous_snarks, + &mut rng, + batch_info, + halo2_protocol, + sp1_protocol, + ) + .map_err(|err| anyhow!("Failed to construct aggregation circuit: {err:?}"))?; self.gen_snark(id, degree, &mut rng, circuit, "gen_agg_snark") } @@ -34,6 +48,8 @@ impl<'params> Prover<'params> { id: &str, degree: u32, batch_info: BatchHash, + halo2_protocol: &[u8], + sp1_protocol: &[u8], previous_snarks: &[Snark], output_dir: Option<&str>, ) -> Result { @@ -48,7 +64,15 @@ impl<'params> Prover<'params> { Some(snark) => Ok(snark), None => { let rng = gen_rng(); - let result = self.gen_agg_snark(id, degree, rng, batch_info, previous_snarks); + let result = self.gen_agg_snark( + id, + degree, + rng, + batch_info, + halo2_protocol, + sp1_protocol, + previous_snarks, + ); if let (Some(_), Ok(snark)) = (output_dir, &result) { write_snark(&file_path, snark); } diff --git a/prover/src/consts.rs b/prover/src/consts.rs index 978594092d..19b1800ddb 100644 --- a/prover/src/consts.rs +++ b/prover/src/consts.rs @@ -13,8 +13,24 @@ pub fn chunk_vk_filename() -> String { read_env_var("CHUNK_VK_FILENAME", "vk_chunk.vkey".to_string()) } -pub static CHUNK_PROTOCOL_FILENAME: LazyLock = - LazyLock::new(|| read_env_var("CHUNK_PROTOCOL_FILENAME", "chunk.protocol".to_string())); +/// The file descriptor for the JSON serialised SNARK [`protocol`][protocol] that +/// defines the [`CompressionCircuit`][compr_circuit] SNARK that uses halo2-based +/// [`SuperCircuit`][super_circuit]. +/// +/// [protocol]: snark_verifier::Protocol +/// [compr_circuit]: aggregator::CompressionCircuit +/// [super_circuit]: zkevm_circuits::super_circuit::SuperCircuit +pub static FD_HALO2_CHUNK_PROTOCOL: LazyLock = + LazyLock::new(|| read_env_var("HALO2_CHUNK_PROTOCOL", "chunk_halo2.protocol".to_string())); + +/// The file descriptor for the JSON serialised SNARK [`protocol`][protocol] that +/// defines the [`CompressionCircuit`][compr_circuit] SNARK that uses sp1-based +/// STARK that is SNARKified using a halo2-backend. +/// +/// [protocol]: snark_verifier::Protocol +/// [compr_circuit]: aggregator::CompressionCircuit +pub static FD_SP1_CHUNK_PROTOCOL: LazyLock = + LazyLock::new(|| read_env_var("SP1_CHUNK_PROTOCOL", "chunk_sp1.protocol".to_string())); pub static CHUNK_VK_FILENAME: LazyLock = LazyLock::new(chunk_vk_filename); pub static BATCH_VK_FILENAME: LazyLock = LazyLock::new(batch_vk_filename); From dd10d9a464f17f33a7f159387af4a09204f08b50 Mon Sep 17 00:00:00 2001 From: Rohit Narurkar Date: Mon, 4 Nov 2024 11:56:16 +0000 Subject: [PATCH 10/11] fix(soundness): init_state depends on halo2/sp1 route --- aggregator/src/aggregation/circuit.rs | 32 ++++++++++++++++----------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/aggregator/src/aggregation/circuit.rs b/aggregator/src/aggregation/circuit.rs index 4ef74b977d..f2f914086d 100644 --- a/aggregator/src/aggregation/circuit.rs +++ b/aggregator/src/aggregation/circuit.rs @@ -311,6 +311,12 @@ impl Circuit for BatchCircuit { log::info!("populating constants OK"); // Commitments to the preprocessed polynomials. + // + // check_1: halo2-route + // check_2: sp1-route + // + // OR(check_1, check_2) == 1 + let mut route_check = Vec::with_capacity(N_SNARKS); for preprocessed_polys in preprocessed_poly_sets.iter() { let mut preprocessed_check_1 = config.flex_gate().load_constant(&mut ctx, Fr::ONE); @@ -336,6 +342,7 @@ impl Circuit for BatchCircuit { Existing(check_2), ); } + route_check.push(preprocessed_check_1); let preprocessed_check = config.flex_gate().or( &mut ctx, Existing(preprocessed_check_1), @@ -347,27 +354,26 @@ impl Circuit for BatchCircuit { } // Transcript initial state. - for transcript_init_state in transcript_init_states { + // + // If the SNARK belongs to halo2-route, the initial state is the halo2-initial + // state. Otherwise sp1-initial state. + for (transcript_init_state, &route) in + transcript_init_states.iter().zip_eq(route_check.iter()) + { let transcript_init_state = transcript_init_state .expect("SNARK should have an initial state for transcript"); - let transcript_check_1 = config.flex_gate().is_equal( + let init_state_expected = config.flex_gate().select( &mut ctx, - Existing(transcript_init_state), Existing(transcript_init_state_halo2), - ); - let transcript_check_2 = config.flex_gate().is_equal( - &mut ctx, - Existing(transcript_init_state), Existing(transcript_init_state_sp1), + Existing(route), ); - let transcript_check = config.flex_gate().or( + GateInstructions::assert_equal( + config.flex_gate(), &mut ctx, - Existing(transcript_check_1), - Existing(transcript_check_2), + Existing(transcript_init_state), + Existing(init_state_expected), ); - config - .flex_gate() - .assert_is_const(&mut ctx, &transcript_check, Fr::ONE); } ctx.print_stats(&["protocol check"]); From 7b9e296751127dbdc228a6a649e5e7c8d8644bae Mon Sep 17 00:00:00 2001 From: Rohit Narurkar Date: Tue, 5 Nov 2024 10:54:48 +0000 Subject: [PATCH 11/11] chore: clippy OK --- aggregator/src/aggregation.rs | 1 - aggregator/src/aggregation/circuit.rs | 18 ++---------------- prover/src/common/prover/aggregation.rs | 2 ++ testool/src/statetest/executor.rs | 2 +- 4 files changed, 5 insertions(+), 18 deletions(-) diff --git a/aggregator/src/aggregation.rs b/aggregator/src/aggregation.rs index 501c2fb591..a616965750 100644 --- a/aggregator/src/aggregation.rs +++ b/aggregator/src/aggregation.rs @@ -54,7 +54,6 @@ impl From<&Protocol> for FixedProtocol { preprocessed: protocol.preprocessed.clone(), init_state: protocol .transcript_initial_state - .clone() .expect("protocol transcript init state None"), } } diff --git a/aggregator/src/aggregation/circuit.rs b/aggregator/src/aggregation/circuit.rs index f2f914086d..06cb53c9b0 100644 --- a/aggregator/src/aggregation/circuit.rs +++ b/aggregator/src/aggregation/circuit.rs @@ -225,13 +225,10 @@ impl Circuit for BatchCircuit { let loader: Rc>>> = Halo2Loader::new(ecc_chip, ctx); - // // extract the assigned values for // - instances which are the public inputs of each chunk (prefixed with 12 // instances from previous accumulators) // - new accumulator - // - log::debug!("aggregation: chunk aggregation"); let ( assigned_aggregation_instances, acc, @@ -269,29 +266,21 @@ impl Circuit for BatchCircuit { // fixed set of values expected. // // First we load the constants. - log::info!("populating constants"); let mut preprocessed_polys_halo2 = Vec::with_capacity(7); let mut preprocessed_polys_sp1 = Vec::with_capacity(7); - for (i, &preprocessed_poly) in - self.halo2_protocol.preprocessed.iter().enumerate() - { - log::debug!("load const {i}"); + for &preprocessed_poly in self.halo2_protocol.preprocessed.iter() { preprocessed_polys_halo2.push( config .ecc_chip() .assign_constant_point(&mut ctx, preprocessed_poly), ); - log::debug!("load const {i} OK"); } - for (i, &preprocessed_poly) in self.sp1_protocol.preprocessed.iter().enumerate() - { - log::debug!("load const (sp1) {i}"); + for &preprocessed_poly in self.sp1_protocol.preprocessed.iter() { preprocessed_polys_sp1.push( config .ecc_chip() .assign_constant_point(&mut ctx, preprocessed_poly), ); - log::debug!("load const (sp1) {i} OK"); } let transcript_init_state_halo2 = config .ecc_chip() @@ -300,7 +289,6 @@ impl Circuit for BatchCircuit { .gate() .assign_constant(&mut ctx, self.halo2_protocol.init_state) .expect("IntegerInstructions::assign_constant infallible"); - log::debug!("load transcript OK"); let transcript_init_state_sp1 = config .ecc_chip() .field_chip() @@ -308,7 +296,6 @@ impl Circuit for BatchCircuit { .gate() .assign_constant(&mut ctx, self.sp1_protocol.init_state) .expect("IntegerInstructions::assign_constant infallible"); - log::info!("populating constants OK"); // Commitments to the preprocessed polynomials. // @@ -378,7 +365,6 @@ impl Circuit for BatchCircuit { ctx.print_stats(&["protocol check"]); - log::debug!("batching: assigning barycentric"); let barycentric = config.blob_consistency_config.assign_barycentric( &mut ctx, &self.batch_hash.blob_bytes, diff --git a/prover/src/common/prover/aggregation.rs b/prover/src/common/prover/aggregation.rs index cca60d5443..d17e838a94 100644 --- a/prover/src/common/prover/aggregation.rs +++ b/prover/src/common/prover/aggregation.rs @@ -12,6 +12,7 @@ use snark_verifier_sdk::Snark; use std::env; impl<'params> Prover<'params> { + #[allow(clippy::too_many_arguments)] pub fn gen_agg_snark( &mut self, id: &str, @@ -42,6 +43,7 @@ impl<'params> Prover<'params> { self.gen_snark(id, degree, &mut rng, circuit, "gen_agg_snark") } + #[allow(clippy::too_many_arguments)] pub fn load_or_gen_agg_snark( &mut self, name: &str, diff --git a/testool/src/statetest/executor.rs b/testool/src/statetest/executor.rs index 2dcecc8d4c..34dbbc4485 100644 --- a/testool/src/statetest/executor.rs +++ b/testool/src/statetest/executor.rs @@ -644,7 +644,7 @@ pub fn run_test( eth_types::constants::set_env_coinbase(&st.env.current_coinbase); prover::test::chunk_prove( &test_id, - prover::ChunkProvingTask::from(vec![_scroll_trace]), + prover::ChunkProvingTask::new(vec![_scroll_trace], prover::ChunkKind::Halo2), ); }