diff --git a/Cargo.lock b/Cargo.lock index a1a29333db..335a833adf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3988,6 +3988,7 @@ version = "0.1.0" dependencies = [ "aggregator", "anyhow", + "ark-std 0.4.0", "base64 0.13.1", "blake2", "bus-mapping", @@ -4005,7 +4006,9 @@ dependencies = [ "num-bigint", "once_cell", "rand", + "rand_chacha", "rand_xorshift", + "rayon", "serde", "serde_derive", "serde_json", diff --git a/aggregator/src/aggregation.rs b/aggregator/src/aggregation.rs index 4af10408c1..9401fd7bd3 100644 --- a/aggregator/src/aggregation.rs +++ b/aggregator/src/aggregation.rs @@ -7,4 +7,4 @@ mod rlc; pub use circuit::AggregationCircuit; pub use config::AggregationConfig; -pub(crate) use rlc::RlcConfig; +pub use rlc::RlcConfig; diff --git a/aggregator/src/aggregation/rlc.rs b/aggregator/src/aggregation/rlc.rs index e89a4d31c9..790ca36f2c 100644 --- a/aggregator/src/aggregation/rlc.rs +++ b/aggregator/src/aggregation/rlc.rs @@ -1,4 +1,4 @@ mod config; mod gates; -pub(crate) use config::RlcConfig; +pub use config::RlcConfig; diff --git a/aggregator/src/aggregation/rlc/config.rs b/aggregator/src/aggregation/rlc/config.rs index a5fd32f073..48dafd1f40 100644 --- a/aggregator/src/aggregation/rlc/config.rs +++ b/aggregator/src/aggregation/rlc/config.rs @@ -22,7 +22,7 @@ pub struct RlcConfig { } impl RlcConfig { - pub(crate) fn configure(meta: &mut ConstraintSystem, challenge: Challenges) -> Self { + pub fn configure(meta: &mut ConstraintSystem, challenge: Challenges) -> Self { let selector = meta.complex_selector(); let enable_challenge = meta.complex_selector(); let challenge_expr = challenge.exprs(meta); diff --git a/aggregator/src/aggregation/rlc/gates.rs b/aggregator/src/aggregation/rlc/gates.rs index b302a5e937..1c1149030f 100644 --- a/aggregator/src/aggregation/rlc/gates.rs +++ b/aggregator/src/aggregation/rlc/gates.rs @@ -12,7 +12,7 @@ use super::RlcConfig; impl RlcConfig { /// initialize the chip with fixed cells - pub(crate) fn init(&self, region: &mut Region) -> Result<(), Error> { + pub fn init(&self, region: &mut Region) -> Result<(), Error> { region.assign_fixed(|| "const zero", self.fixed, 0, || Value::known(Fr::zero()))?; region.assign_fixed(|| "const one", self.fixed, 1, || Value::known(Fr::one()))?; region.assign_fixed(|| "const two", self.fixed, 2, || Value::known(Fr::from(2)))?; @@ -115,7 +115,7 @@ impl RlcConfig { } } - pub(crate) fn load_private( + pub fn load_private( &self, region: &mut Region, f: &Fr, @@ -171,8 +171,7 @@ impl RlcConfig { } /// Enforce res = a + b - #[allow(dead_code)] - pub(crate) fn add( + pub fn add( &self, region: &mut Region, a: &AssignedCell, diff --git a/prover/Cargo.toml b/prover/Cargo.toml index f451efa415..e3eb84ce64 100644 --- a/prover/Cargo.toml +++ b/prover/Cargo.toml @@ -15,6 +15,7 @@ zkevm-circuits = { path = "../zkevm-circuits", default-features = false } snark-verifier = { git = "https://github.com/scroll-tech/snark-verifier", tag = "v0.1.5" } snark-verifier-sdk = { git = "https://github.com/scroll-tech/snark-verifier", tag = "v0.1.5", default-features=false, features = ["loader_halo2", "loader_evm", "halo2-pse"] } +ark-std = "0.4.0" anyhow = "1.0" base64 = "0.13.0" blake2 = "0.10.3" @@ -29,7 +30,9 @@ log4rs = { version = "1.2.0", default_features = false, features = ["console_app num-bigint = "0.4.3" once_cell = "1.8.0" rand = "0.8" +rand_chacha = "0.3.1" rand_xorshift = "0.3" +rayon = "1.5.1" serde = "1.0" serde_derive = "1.0" serde_json = { version = "1.0.66", features = ["unbounded_depth"] } @@ -37,7 +40,9 @@ serde_stacker = "0.1" sha2 ="0.10.2" [features] -default = [] +default = [ "unrandomized_srs" ] parallel_syn = ["halo2_proofs/parallel_syn", "zkevm-circuits/parallel_syn"] scroll = ["bus-mapping/scroll", "eth-types/scroll", "zkevm-circuits/scroll"] shanghai = ["bus-mapping/shanghai", "eth-types/shanghai", "zkevm-circuits/shanghai"] +# todo: remove once srs is randomized and finalized +unrandomized_srs = [] \ No newline at end of file diff --git a/prover/src/utils.rs b/prover/src/utils.rs index bef28a9f3f..e24ae86b56 100644 --- a/prover/src/utils.rs +++ b/prover/src/utils.rs @@ -7,7 +7,11 @@ use chrono::Utc; use eth_types::{l2_types::BlockTrace, Address}; use git_version::git_version; use halo2_proofs::{ - halo2curves::bn256::{Bn256, Fr}, + arithmetic::{g_to_lagrange, parallelize, Field}, + halo2curves::{ + bn256::{Bn256, Fr, G1Affine, G1}, + group::Curve, + }, poly::kzg::commitment::ParamsKZG, SerdeFormat, }; @@ -20,7 +24,9 @@ use log4rs::{ config::{Appender, Config, Root}, }; use rand::{Rng, SeedableRng}; +use rand_chacha::ChaCha20Rng; use rand_xorshift::XorShiftRng; +use rayon::prelude::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; use std::{ fs::{self, metadata, File}, io::{BufReader, Read}, @@ -35,6 +41,8 @@ pub static LOGGER: Once = Once::new(); pub const DEFAULT_SERDE_FORMAT: SerdeFormat = SerdeFormat::RawBytesUnchecked; pub const GIT_VERSION: &str = git_version!(args = ["--abbrev=7", "--always"]); +// FIXME: update me once the the srs is re-randomized +#[cfg(feature = "unrandomized_srs")] pub const PARAMS_G2_SECRET_POWER: &str = "(Fq2 { c0: 0x17944351223333f260ddc3b4af45191b856689eda9eab5cbcddbbe570ce860d2, c1: 0x186282957db913abd99f91db59fe69922e95040603ef44c0bd7aa3adeef8f5ac }, Fq2 { c0: 0x297772d34bc9aa8ae56162486363ffe417b02dc7e8c207fc2cc20203e67a02ad, c1: 0x298adc7396bd3865cbf6d6df91bae406694e6d2215baa893bdeadb63052895f4 })"; /// Load setup params from a file. @@ -77,6 +85,8 @@ pub fn load_params( } let p = ParamsKZG::::read_custom::<_>(&mut BufReader::new(f), serde_fmt)?; + + #[cfg(feature = "unrandomized_srs")] if format!("{:?}", p.s_g2()) != PARAMS_G2_SECRET_POWER { bail!("Wrong params file of degree {}", degree); } @@ -85,6 +95,44 @@ pub fn load_params( Ok(p) } +pub fn re_randomize_srs(param: &mut ParamsKZG, seed: &[u8; 32]) { + log::info!("start re-randomization"); + let mut rng = ChaCha20Rng::from_seed(*seed); + let secret = Fr::random(&mut rng); + let num_threads = rayon::current_num_threads(); + let chunk_size = param.n as usize / num_threads; + // Old g = [G1, [s] G1, [s^2] G1, ..., [s^(n-1)] G1] + // we multiply each g by secret^i + // and the new secret becomes s*secret + log::info!("generating new seed"); + let mut powers = vec![Fr::one(), secret]; + for _ in 0..param.n - 2 { + powers.push(secret * powers.last().unwrap()) + } + log::info!("build new params"); + let new_g_proj = param + .g + .par_iter() + .zip(powers.par_iter()) + .chunks(chunk_size) + .flat_map_iter(|pair| pair.iter().map(|(g, s)| *g * *s).collect::>()) + .collect::>(); + + log::info!("normalizing new params"); + param.g = { + let mut g = vec![G1Affine::default(); param.n as usize]; + parallelize(&mut g, |g, starts| { + G1::batch_normalize(&new_g_proj[starts..(starts + g.len())], g); + }); + g + }; + log::info!("converting to lagrange basis"); + param.g_lagrange = g_to_lagrange(new_g_proj, param.k); + param.s_g2 = (param.s_g2 * secret).into(); + + log::info!("finished re-randomization"); +} + /// get a block-result from file pub fn get_block_trace_from_file>(path: P) -> BlockTrace { let mut buffer = Vec::new(); @@ -240,3 +288,117 @@ pub fn short_git_version() -> String { commit_version[1..8].to_string() } } +#[cfg(test)] +mod tests { + + use aggregator::RlcConfig; + use ark_std::test_rng; + use halo2_proofs::{ + circuit::*, + halo2curves::bn256::{Bn256, Fr}, + plonk::*, + poly::kzg::commitment::ParamsKZG, + }; + use snark_verifier_sdk::{ + evm_verify, gen_evm_proof_shplonk, gen_evm_verifier_shplonk, gen_pk, CircuitExt, + }; + use zkevm_circuits::util::Challenges; + + use crate::utils::re_randomize_srs; + + #[derive(Clone, Default)] + struct MyCircuit { + f1: Fr, + f2: Fr, + f3: Fr, + } + + impl Circuit for MyCircuit { + type Config = RlcConfig; + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + Self::default() + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + let challenges = Challenges::construct(meta); + RlcConfig::configure(meta, challenges) + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + let mut first_pass = true; + layouter.assign_region( + || "test field circuit", + |mut region| -> Result<(), Error> { + if first_pass { + first_pass = false; + return Ok(()); + } + + config.init(&mut region)?; + + let mut offset = 0; + + let f1 = config.load_private(&mut region, &self.f1, &mut offset)?; + let f2 = config.load_private(&mut region, &self.f2, &mut offset)?; + let f3 = config.load_private(&mut region, &self.f3, &mut offset)?; + { + let f3_rec = config.add(&mut region, &f1, &f2, &mut offset)?; + region.constrain_equal(f3.cell(), f3_rec.cell())?; + } + + Ok(()) + }, + )?; + Ok(()) + } + } + + impl CircuitExt for MyCircuit { + fn num_instance(&self) -> Vec { + vec![] + } + + fn instances(&self) -> Vec> { + vec![] + } + + fn accumulator_indices() -> Option> { + None + } + + fn selectors(_config: &Self::Config) -> Vec { + vec![] + } + } + + #[test] + fn test_srs_rerandomization() { + let k = 5; + let mut rng = test_rng(); + let mut param = ParamsKZG::::unsafe_setup(k); + re_randomize_srs(&mut param, &[0; 32]); + + let circuit = MyCircuit { + f1: Fr::from(10), + f2: Fr::from(15), + f3: Fr::from(25), + }; + + let pk = gen_pk(¶m, &circuit, None); + let proof = + gen_evm_proof_shplonk(¶m, &pk, circuit.clone(), circuit.instances(), &mut rng); + let deployment_code = gen_evm_verifier_shplonk::( + ¶m, + pk.get_vk(), + circuit.num_instance(), + None, + ); + evm_verify(deployment_code, circuit.instances(), proof.clone()); + } +}