diff --git a/Makefile b/Makefile index 5eb57cb9c..15d3119f9 100644 --- a/Makefile +++ b/Makefile @@ -41,9 +41,6 @@ test-inner-prove: test-chunk-prove: @cargo test --features prove_verify --release test_chunk_prove_verify -test-comp-prove: - @cargo test --features prove_verify --release test_comp_prove_verify - test-agg-prove: @cargo test --features prove_verify --release test_agg_prove_verify diff --git a/README.md b/README.md index 052e4ca0e..6993fcfcb 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ make download-setup -e degree=DEGREE params_dir=PARAMS_DIR `make test-chunk-prove` is the main testing entry point for the multi-level circuit constraint system of scroll-zkevm. Developers could understand how the system works by reading the codes of this test. -Besides it, `make test-inner-prove` could be used to test the first-level circuit, and `make-comp-prove` could be used to test two-layers compression circuits. +Besides it, `make test-inner-prove` could be used to test the first-level circuit. ### Binaries diff --git a/bin/src/prove.rs b/bin/src/prove.rs index f5d32422b..32dca7ca6 100644 --- a/bin/src/prove.rs +++ b/bin/src/prove.rs @@ -47,7 +47,7 @@ fn main() { let now = Instant::now(); let chunk_proof = prover - .gen_chunk_proof(traces.as_slice()) + .gen_chunk_proof(traces, None) .expect("cannot generate chunk proof"); info!( "finish generating chunk proof, elapsed: {:?}", diff --git a/bin/src/verify.rs b/bin/src/verify.rs index 159879371..d842ca332 100644 --- a/bin/src/verify.rs +++ b/bin/src/verify.rs @@ -20,12 +20,12 @@ fn main() { let args = Args::parse(); let chunk_vk = read_from_file(&args.vk_path); - let v = Verifier::from_params_dir(&args.params_path, Some(chunk_vk)); + let v = Verifier::from_params_dir(&args.params_path, &chunk_vk); let proof_path = PathBuf::from("proof_data").join("chunk_full_proof.json"); let proof_vec = read_from_file(&proof_path.to_string_lossy()); let proof = serde_json::from_slice::(proof_vec.as_slice()).unwrap(); - let verified = v.verify_chunk_proof(proof).is_ok(); + let verified = v.verify_chunk_proof(proof); info!("verify agg proof: {}", verified) } diff --git a/ffi/src/prove.rs b/ffi/src/prove.rs index 3f8a5819b..71a321e1c 100644 --- a/ffi/src/prove.rs +++ b/ffi/src/prove.rs @@ -21,7 +21,11 @@ pub unsafe extern "C" fn init_prover(params_path: *const c_char, _seed_path: *co pub unsafe extern "C" fn create_block_proof(trace_char: *const c_char) -> *const c_char { let trace_vec = c_char_to_vec(trace_char); let trace = serde_json::from_slice::(&trace_vec).unwrap(); - let proof = PROVER.get_mut().unwrap().gen_chunk_proof(&[trace]).unwrap(); + let proof = PROVER + .get_mut() + .unwrap() + .gen_chunk_proof(vec![trace], None) + .unwrap(); let proof_bytes = serde_json::to_vec(&proof).unwrap(); vec_to_c_char(proof_bytes) } @@ -34,7 +38,7 @@ pub unsafe extern "C" fn create_chunk_proof(trace_char: *const c_char) -> *const let proof = PROVER .get_mut() .unwrap() - .gen_chunk_proof(traces.as_slice()) + .gen_chunk_proof(traces, None) .unwrap(); let proof_bytes = serde_json::to_vec(&proof).unwrap(); vec_to_c_char(proof_bytes) diff --git a/ffi/src/verify.rs b/ffi/src/verify.rs index 30b3f149b..a8fa3284d 100644 --- a/ffi/src/verify.rs +++ b/ffi/src/verify.rs @@ -16,7 +16,7 @@ pub unsafe extern "C" fn init_verifier(params_path: *const c_char, agg_vk_path: let mut agg_vk = vec![]; f.read_to_end(&mut agg_vk).unwrap(); - let v = Box::new(zkevm::Verifier::from_params_dir(params_path, Some(agg_vk))); + let v = Box::new(zkevm::Verifier::from_params_dir(params_path, &agg_vk)); VERIFIER = Some(Box::leak(v)) } @@ -25,6 +25,6 @@ pub unsafe extern "C" fn init_verifier(params_path: *const c_char, agg_vk_path: pub unsafe extern "C" fn verify_chunk_proof(proof: *const c_char) -> c_char { let proof_vec = c_char_to_vec(proof); let chunk_proof = serde_json::from_slice::(proof_vec.as_slice()).unwrap(); - let verified = VERIFIER.unwrap().verify_chunk_proof(chunk_proof).is_ok(); + let verified = VERIFIER.unwrap().verify_chunk_proof(chunk_proof); verified as c_char } diff --git a/prover/configs/agg_layer1.config b/prover/configs/layer1.config similarity index 100% rename from prover/configs/agg_layer1.config rename to prover/configs/layer1.config diff --git a/prover/configs/agg_layer2.config b/prover/configs/layer2.config similarity index 100% rename from prover/configs/agg_layer2.config rename to prover/configs/layer2.config diff --git a/prover/configs/agg_layer3.config b/prover/configs/layer3.config similarity index 100% rename from prover/configs/agg_layer3.config rename to prover/configs/layer3.config diff --git a/prover/configs/agg_layer4.config b/prover/configs/layer4.config similarity index 96% rename from prover/configs/agg_layer4.config rename to prover/configs/layer4.config index 83e53fe41..59864d22b 100644 --- a/prover/configs/agg_layer4.config +++ b/prover/configs/layer4.config @@ -2,7 +2,7 @@ "strategy": "Simple", "degree": 25, "num_advice": [ - 1 + 2 ], "num_lookup_advice": [ 1 diff --git a/prover/src/aggregator/prover/chunk.rs b/prover/src/aggregator/prover/chunk.rs deleted file mode 100644 index cd7715700..000000000 --- a/prover/src/aggregator/prover/chunk.rs +++ /dev/null @@ -1,31 +0,0 @@ -use super::Prover; -use crate::{ - utils::{gen_rng, metric_of_witness_block}, - zkevm::circuit::TargetCircuit, -}; -use anyhow::Result; -use halo2_proofs::halo2curves::bn256::Fr; -use snark_verifier_sdk::{gen_snark_shplonk, Snark}; -use zkevm_circuits::evm_circuit::witness::Block; - -impl Prover { - pub fn gen_chunk_snark( - &mut self, - witness_block: &Block, - ) -> Result { - log::info!( - "Proving the chunk: {:?}", - metric_of_witness_block(witness_block) - ); - - let (circuit, _instance) = C::from_witness_block(witness_block)?; - log::info!("Create {} proof", C::name()); - - let (params, pk) = self.inner_params_and_pk::(&C::dummy_inner_circuit())?; - - // Generate the SNARK proof for inner circuit. - let snark = gen_snark_shplonk(params, pk, circuit, &mut gen_rng(), None::); - - Ok(snark) - } -} diff --git a/prover/src/aggregator/prover/common.rs b/prover/src/aggregator/prover/common.rs deleted file mode 100644 index 139a2ae85..000000000 --- a/prover/src/aggregator/prover/common.rs +++ /dev/null @@ -1,106 +0,0 @@ -use super::Prover; -use crate::{config::INNER_DEGREE, utils::tick, zkevm::circuit::TargetCircuit, Proof}; -use anyhow::Result; -use halo2_proofs::{ - halo2curves::bn256::{Bn256, Fr, G1Affine}, - plonk::{keygen_pk2, Circuit, ProvingKey}, - poly::{commitment::Params, kzg::commitment::ParamsKZG}, -}; -use rand::Rng; -use snark_verifier_sdk::{gen_evm_proof_shplonk, gen_pk, gen_snark_shplonk, CircuitExt, Snark}; - -impl Prover { - pub fn gen_snark>( - &mut self, - id: &str, - degree: u32, - rng: &mut (impl Rng + Send), - circuit: C, - ) -> Snark { - let (params, pk) = self.outer_params_and_pk(id, &circuit, degree); - - gen_snark_shplonk(params, pk, circuit, rng, None::<&str>) - } - - pub fn gen_evm_proof>( - &mut self, - id: &str, - degree: u32, - rng: &mut (impl Rng + Send), - circuit: C, - ) -> Result { - let (params, pk) = self.outer_params_and_pk(id, &circuit, degree); - - let instances = circuit.instances(); - let num_instance = circuit.num_instance(); - let proof = gen_evm_proof_shplonk(params, pk, circuit, instances.clone(), rng); - - Proof::new(pk, proof, &instances, Some(num_instance)) - } - - // TODO: test if it could use `outer_params_and_pk`. - pub fn inner_params_and_pk( - &mut self, - circuit: &::Inner, - ) -> Result<(&ParamsKZG, &ProvingKey)> { - let id = C::name(); - - // Reuse pk. - if !self.pk_map.contains_key(&id) { - tick(&format!("Before generate inner pk of {}", &id)); - let pk = keygen_pk2(self.params(*INNER_DEGREE), circuit)?; - tick(&format!("After generate inner pk of {}", &id)); - - self.pk_map.insert(id.clone(), pk); - } - assert!(self.params_map.contains_key(&*INNER_DEGREE)); - - Ok((&self.params_map[&*INNER_DEGREE], &self.pk_map[&id])) - } - - pub fn params(&mut self, degree: u32) -> &ParamsKZG { - if self.params_map.contains_key(°ree) { - return &self.params_map[°ree]; - } - - log::warn!("Optimization: download params{degree} to params dir"); - - tick(&format!("Before generate params of {degree}")); - let mut new_params = self - .params_map - .range(degree..) - .next() - .unwrap_or_else(|| panic!("Must have params of degree-{degree}")) - .1 - .clone(); - new_params.downsize(degree); - tick(&format!("After generate params of {degree}")); - - self.params_map.insert(degree, new_params); - &self.params_map[°ree] - } - - pub fn pk(&self, id: &str) -> Option<&ProvingKey> { - self.pk_map.get(id) - } - - pub fn outer_params_and_pk>( - &mut self, - id: &str, - circuit: &C, - degree: u32, - ) -> (&ParamsKZG, &ProvingKey) { - // Reuse pk. - if self.pk_map.contains_key(id) { - return (&self.params_map[°ree], &self.pk_map[id]); - } - - tick(&format!("Before generate outer pk of {}", &id)); - let pk = gen_pk(self.params(degree), circuit, None); - tick(&format!("After generate outer pk of {}", &id)); - - self.pk_map.insert(id.to_string(), pk); - - (&self.params_map[°ree], &self.pk_map[id]) - } -} diff --git a/prover/src/aggregator/prover/compression.rs b/prover/src/aggregator/prover/compression.rs deleted file mode 100644 index 868475634..000000000 --- a/prover/src/aggregator/prover/compression.rs +++ /dev/null @@ -1,36 +0,0 @@ -use super::Prover; -use crate::Proof; -use aggregator::CompressionCircuit; -use anyhow::{anyhow, Result}; -use rand::Rng; -use snark_verifier_sdk::Snark; - -impl Prover { - pub fn gen_comp_snark( - &mut self, - id: &str, - is_fresh: bool, - degree: u32, - mut rng: impl Rng + Send, - prev_snark: Snark, - ) -> Result { - let circuit = CompressionCircuit::new(self.params(degree), prev_snark, is_fresh, &mut rng) - .map_err(|err| anyhow!("Failed to construct compression circuit: {err:?}"))?; - - Ok(self.gen_snark(id, degree, &mut rng, circuit)) - } - - pub fn gen_comp_evm_proof( - &mut self, - id: &str, - is_fresh: bool, - degree: u32, - mut rng: impl Rng + Send, - prev_snark: Snark, - ) -> Result { - let circuit = CompressionCircuit::new(self.params(degree), prev_snark, is_fresh, &mut rng) - .map_err(|err| anyhow!("Failed to construct compression circuit: {err:?}"))?; - - self.gen_evm_proof(id, degree, &mut rng, circuit) - } -} diff --git a/prover/src/aggregator/verifier.rs b/prover/src/aggregator/verifier.rs deleted file mode 100644 index 34b522355..000000000 --- a/prover/src/aggregator/verifier.rs +++ /dev/null @@ -1,74 +0,0 @@ -use crate::{utils::load_params, Proof}; -use aggregator::CompressionCircuit; -use anyhow::Result; -use halo2_proofs::{ - halo2curves::bn256::{Bn256, Fr, G1Affine}, - plonk::VerifyingKey, - poly::kzg::commitment::ParamsKZG, - SerdeFormat, -}; -use snark_verifier::pcs::kzg::{Bdfg21, Kzg}; -use snark_verifier_sdk::{evm_verify, gen_evm_verifier, verify_snark_shplonk, CircuitExt}; -use std::{io::Cursor, path::Path}; - -#[derive(Debug)] -pub struct Verifier { - params: ParamsKZG, - vk: Option>, -} - -impl Verifier { - pub fn new(params: ParamsKZG, vk: Option>) -> Self { - Self { params, vk } - } - - pub fn from_params(params: ParamsKZG, raw_vk: Option>) -> Self { - let vk = raw_vk.as_ref().map(|k| { - VerifyingKey::::read::<_, CompressionCircuit>( - &mut Cursor::new(&k), - SerdeFormat::Processed, - ) - .unwrap() - }); - - Self { params, vk } - } - - pub fn from_params_dir(params_dir: &str, degree: u32, vk: Option>) -> Self { - let params = load_params(params_dir, degree, None).unwrap(); - - Self::from_params(params, vk) - } - - pub fn verify_agg_proof(&self, proof: Proof) -> Result { - let vk = match &self.vk { - Some(vk) => vk, - None => panic!("Aggregation verification key is missing"), - }; - - Ok(verify_snark_shplonk::( - &self.params, - proof.to_snark(), - vk, - )) - } - - // Should panic if failed to verify. - pub fn evm_verify>(&self, proof: &Proof, yul_file_path: Option<&Path>) { - let vk = match &self.vk { - Some(vk) => vk, - None => panic!("Aggregation verification key is missing"), - }; - - let num_instance = proof.num_instance().expect("Not a EVM proof").clone(); - - let deployment_code = gen_evm_verifier::>( - &self.params, - vk, - num_instance, - yul_file_path, - ); - - evm_verify(deployment_code, proof.instances(), proof.proof().to_vec()); - } -} diff --git a/prover/src/aggregator.rs b/prover/src/common.rs similarity index 71% rename from prover/src/aggregator.rs rename to prover/src/common.rs index ac0279ed5..ca8b5acb1 100644 --- a/prover/src/aggregator.rs +++ b/prover/src/common.rs @@ -2,3 +2,4 @@ mod prover; mod verifier; pub use self::{prover::Prover, verifier::Verifier}; +pub use aggregator::ChunkHash; diff --git a/prover/src/aggregator/prover.rs b/prover/src/common/prover.rs similarity index 97% rename from prover/src/aggregator/prover.rs rename to prover/src/common/prover.rs index 023e5c0f4..9dde26236 100644 --- a/prover/src/aggregator/prover.rs +++ b/prover/src/common/prover.rs @@ -6,9 +6,11 @@ use halo2_proofs::{ }; use std::collections::{BTreeMap, BTreeSet, HashMap}; -mod chunk; -mod common; mod compression; +mod evm; +mod inner; +mod mock; +mod utils; #[derive(Debug)] pub struct Prover { diff --git a/prover/src/common/prover/compression.rs b/prover/src/common/prover/compression.rs new file mode 100644 index 000000000..e1ef764af --- /dev/null +++ b/prover/src/common/prover/compression.rs @@ -0,0 +1,57 @@ +use super::Prover; +use crate::{ + io::{load_snark, write_snark}, + utils::gen_rng, +}; +use aggregator::CompressionCircuit; +use anyhow::{anyhow, Result}; +use rand::Rng; +use snark_verifier_sdk::Snark; +use std::env::set_var; + +impl Prover { + pub fn gen_comp_snark( + &mut self, + id: &str, + is_fresh: bool, + degree: u32, + mut rng: impl Rng + Send, + prev_snark: Snark, + ) -> Result { + let circuit = CompressionCircuit::new(self.params(degree), prev_snark, is_fresh, &mut rng) + .map_err(|err| anyhow!("Failed to construct compression circuit: {err:?}"))?; + + self.gen_snark(id, degree, &mut rng, circuit) + } + + pub fn load_or_gen_comp_snark( + &mut self, + name: &str, + id: &str, + is_fresh: bool, + degree: u32, + prev_snark: Snark, + output_dir: Option<&str>, + ) -> Result { + let file_path = format!( + "{}/compression_snark_{}.json", + output_dir.unwrap_or_default(), + name + ); + + match output_dir.and_then(|_| load_snark(&file_path).ok().flatten()) { + Some(snark) => Ok(snark), + None => { + set_var("COMPRESSION_CONFIG", format!("./configs/{id}.config")); + + let rng = gen_rng(); + let result = self.gen_comp_snark(id, is_fresh, degree, rng, prev_snark); + if let (Some(_), Ok(snark)) = (output_dir, &result) { + write_snark(&file_path, snark); + } + + result + } + } + } +} diff --git a/prover/src/common/prover/evm.rs b/prover/src/common/prover/evm.rs new file mode 100644 index 000000000..90f911fb7 --- /dev/null +++ b/prover/src/common/prover/evm.rs @@ -0,0 +1,52 @@ +use super::Prover; +use crate::{utils::gen_rng, Proof}; +use aggregator::CompressionCircuit; +use anyhow::{anyhow, Result}; +use halo2_proofs::halo2curves::bn256::Fr; +use rand::Rng; +use snark_verifier_sdk::{gen_evm_proof_shplonk, CircuitExt, Snark}; +use std::{env::set_var, path::PathBuf}; + +impl Prover { + pub fn gen_comp_evm_proof( + &mut self, + name: &str, + id: &str, + is_fresh: bool, + degree: u32, + prev_snark: Snark, + output_dir: Option<&str>, + ) -> Result { + set_var("COMPRESSION_CONFIG", format!("./configs/{id}.config")); + + let mut rng = gen_rng(); + let circuit = CompressionCircuit::new(self.params(degree), prev_snark, is_fresh, &mut rng) + .map_err(|err| anyhow!("Failed to construct compression circuit: {err:?}"))?; + + let result = self.gen_evm_proof(id, degree, &mut rng, circuit); + + if let (Some(output_dir), Ok(proof)) = (output_dir, &result) { + proof.dump(&mut PathBuf::from(output_dir), name)?; + } + + result + } + + fn gen_evm_proof>( + &mut self, + id: &str, + degree: u32, + rng: &mut (impl Rng + Send), + circuit: C, + ) -> Result { + Self::assert_if_mock_prover(id, degree, &circuit); + + let (params, pk) = self.params_and_pk(id, &circuit, degree)?; + + let instances = circuit.instances(); + let num_instance = circuit.num_instance(); + let proof = gen_evm_proof_shplonk(params, pk, circuit, instances.clone(), rng); + + Proof::new(pk, proof, &instances, Some(num_instance)) + } +} diff --git a/prover/src/common/prover/inner.rs b/prover/src/common/prover/inner.rs new file mode 100644 index 000000000..6dc5b38ea --- /dev/null +++ b/prover/src/common/prover/inner.rs @@ -0,0 +1,63 @@ +use super::Prover; +use crate::{ + config::INNER_DEGREE, + io::{load_snark, write_snark}, + utils::{gen_rng, metric_of_witness_block}, + zkevm::circuit::{SuperCircuit, TargetCircuit}, +}; +use anyhow::Result; +use halo2_proofs::halo2curves::bn256::Fr; +use rand::Rng; +use snark_verifier_sdk::{gen_snark_shplonk, Snark}; +use zkevm_circuits::evm_circuit::witness::Block; + +impl Prover { + pub fn gen_inner_snark( + &mut self, + mut rng: impl Rng + Send, + witness_block: &Block, + ) -> Result { + log::info!( + "Proving the chunk: {:?}", + metric_of_witness_block(witness_block) + ); + + let id = C::name(); + let degree = *INNER_DEGREE; + + let (circuit, _instance) = C::from_witness_block(witness_block)?; + + Self::assert_if_mock_prover(&id, degree, &circuit); + + let (params, pk) = self.params_and_pk(&id, &C::dummy_inner_circuit(), degree)?; + let snark = gen_snark_shplonk(params, pk, circuit, &mut rng, None::); + + Ok(snark) + } + + pub fn load_or_gen_inner_snark( + &mut self, + name: &str, + witness_block: Block, + output_dir: Option<&str>, + ) -> Result { + let file_path = format!( + "{}/inner_snark_{}.json", + output_dir.unwrap_or_default(), + name + ); + + match output_dir.and_then(|_| load_snark(&file_path).ok().flatten()) { + Some(snark) => Ok(snark), + None => { + let rng = gen_rng(); + let result = self.gen_inner_snark::(rng, &witness_block); + if let (Some(_), Ok(snark)) = (output_dir, &result) { + write_snark(&file_path, snark); + } + + result + } + } + } +} diff --git a/prover/src/common/prover/mock.rs b/prover/src/common/prover/mock.rs new file mode 100644 index 000000000..e6beab5fb --- /dev/null +++ b/prover/src/common/prover/mock.rs @@ -0,0 +1,23 @@ +use super::Prover; +use crate::utils::read_env_var; +use halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; +use once_cell::sync::Lazy; +use snark_verifier_sdk::CircuitExt; + +pub static MOCK_PROVE: Lazy = Lazy::new(|| read_env_var("MOCK_PROVE", false)); + +impl Prover { + pub fn assert_if_mock_prover>(id: &str, degree: u32, circuit: &C) { + if !*MOCK_PROVE { + return; + } + + log::info!("Mock prove for {id} - BEGIN"); + + let instances = circuit.instances(); + let mock_prover = MockProver::::run(degree, circuit, instances).unwrap(); + mock_prover.assert_satisfied_par(); + + log::info!("Mock prove for {id} - END"); + } +} diff --git a/prover/src/common/prover/utils.rs b/prover/src/common/prover/utils.rs new file mode 100644 index 000000000..37125138c --- /dev/null +++ b/prover/src/common/prover/utils.rs @@ -0,0 +1,71 @@ +use super::Prover; +use anyhow::Result; +use halo2_proofs::{ + halo2curves::bn256::{Bn256, Fr, G1Affine}, + plonk::{keygen_pk2, Circuit, ProvingKey}, + poly::{commitment::Params, kzg::commitment::ParamsKZG}, +}; +use rand::Rng; +use snark_verifier_sdk::{gen_snark_shplonk, CircuitExt, Snark}; + +impl Prover { + pub fn gen_snark>( + &mut self, + id: &str, + degree: u32, + rng: &mut (impl Rng + Send), + circuit: C, + ) -> Result { + Self::assert_if_mock_prover(id, degree, &circuit); + + let (params, pk) = self.params_and_pk(id, &circuit, degree)?; + + Ok(gen_snark_shplonk(params, pk, circuit, rng, None::)) + } + + pub fn params(&mut self, degree: u32) -> &ParamsKZG { + if self.params_map.contains_key(°ree) { + return &self.params_map[°ree]; + } + + log::warn!("Optimization: download params{degree} to params dir"); + + log::info!("Before generate params of {degree}"); + let mut new_params = self + .params_map + .range(degree..) + .next() + .unwrap_or_else(|| panic!("Must have params of degree-{degree}")) + .1 + .clone(); + new_params.downsize(degree); + log::info!("After generate params of {degree}"); + + self.params_map.insert(degree, new_params); + &self.params_map[°ree] + } + + pub fn pk(&self, id: &str) -> Option<&ProvingKey> { + self.pk_map.get(id) + } + + pub fn params_and_pk>( + &mut self, + id: &str, + circuit: &C, + degree: u32, + ) -> Result<(&ParamsKZG, &ProvingKey)> { + // Reuse pk. + if self.pk_map.contains_key(id) { + return Ok((&self.params_map[°ree], &self.pk_map[id])); + } + + log::info!("Before generate pk of {}", &id); + let pk = keygen_pk2(self.params(degree), circuit)?; + log::info!("After generate pk of {}", &id); + + self.pk_map.insert(id.to_string(), pk); + + Ok((&self.params_map[°ree], &self.pk_map[id])) + } +} diff --git a/prover/src/common/verifier.rs b/prover/src/common/verifier.rs new file mode 100644 index 000000000..65dbadd8b --- /dev/null +++ b/prover/src/common/verifier.rs @@ -0,0 +1,45 @@ +use crate::{utils::load_params, Proof}; +use aggregator::CompressionCircuit; +use halo2_proofs::{ + halo2curves::bn256::{Bn256, Fr, G1Affine}, + plonk::VerifyingKey, + poly::kzg::commitment::ParamsKZG, + SerdeFormat, +}; +use snark_verifier_sdk::{verify_snark_shplonk, CircuitExt}; +use std::io::Cursor; + +mod evm; +mod utils; + +#[derive(Debug)] +pub struct Verifier { + params: ParamsKZG, + vk: VerifyingKey, +} + +impl Verifier { + pub fn new(params: ParamsKZG, vk: VerifyingKey) -> Self { + Self { params, vk } + } + + pub fn from_params(params: ParamsKZG, raw_vk: &[u8]) -> Self { + let vk = VerifyingKey::::read::<_, CompressionCircuit>( + &mut Cursor::new(raw_vk), + SerdeFormat::Processed, + ) + .unwrap(); + + Self { params, vk } + } + + pub fn from_params_dir(params_dir: &str, degree: u32, vk: &[u8]) -> Self { + let params = load_params(params_dir, degree, None).unwrap(); + + Self::from_params(params, vk) + } + + pub fn verify_proof>(&self, proof: Proof) -> bool { + verify_snark_shplonk::(&self.params, proof.to_snark(), &self.vk) + } +} diff --git a/prover/src/common/verifier/evm.rs b/prover/src/common/verifier/evm.rs new file mode 100644 index 000000000..18dbba1ca --- /dev/null +++ b/prover/src/common/verifier/evm.rs @@ -0,0 +1,47 @@ +use super::Verifier; +use crate::{io::write_file, Proof}; +use halo2_proofs::halo2curves::bn256::{Bn256, Fr}; +use itertools::Itertools; +use snark_verifier::{ + pcs::kzg::{Bdfg21, Kzg}, + util::arithmetic::PrimeField, +}; +use snark_verifier_sdk::{evm_verify, gen_evm_verifier, CircuitExt}; +use std::{path::PathBuf, str::FromStr}; + +impl Verifier { + // Should panic if failed to verify. + pub fn evm_verify>(&self, proof: &Proof, output_dir: &str) { + let num_instance = proof.num_instance().expect("Not a EVM proof").clone(); + + let mut yul_file_path = PathBuf::from_str(output_dir).unwrap(); + yul_file_path.push("evm_verifier.yul"); + + // Generate deployment code and dump YUL file. + let deployment_code = gen_evm_verifier::>( + &self.params, + &self.vk, + num_instance, + Some(yul_file_path.as_path()), + ); + + // Dump bytecode. + let mut output_dir = PathBuf::from_str(output_dir).unwrap(); + write_file(&mut output_dir, "evm_verifier.bin", &deployment_code); + + // Dump public input data. + let pi_data: Vec<_> = proof + .instances() + .iter() + .flatten() + .flat_map(|value| value.to_repr().as_ref().iter().rev().cloned().collect_vec()) + .collect(); + write_file(&mut output_dir, "evm_pi_data.data", &pi_data); + + // Dump proof. + let proof_data = proof.proof().to_vec(); + write_file(&mut output_dir, "evm_proof.data", &proof_data); + + evm_verify(deployment_code, proof.instances(), proof_data); + } +} diff --git a/prover/src/common/verifier/utils.rs b/prover/src/common/verifier/utils.rs new file mode 100644 index 000000000..60dfa75f4 --- /dev/null +++ b/prover/src/common/verifier/utils.rs @@ -0,0 +1,16 @@ +use super::Verifier; +use halo2_proofs::{ + halo2curves::bn256::{Bn256, G1Affine}, + plonk::VerifyingKey, + poly::kzg::commitment::ParamsKZG, +}; + +impl Verifier { + pub fn params(&self) -> &ParamsKZG { + &self.params + } + + pub fn vk(&self) -> &VerifyingKey { + &self.vk + } +} diff --git a/prover/src/config.rs b/prover/src/config.rs index 2b26fbe7c..b891ed2fe 100644 --- a/prover/src/config.rs +++ b/prover/src/config.rs @@ -3,20 +3,25 @@ use once_cell::sync::Lazy; use std::collections::HashSet; pub static INNER_DEGREE: Lazy = Lazy::new(|| read_env_var("INNER_DEGREE", 20)); -pub static CHUNK_DEGREE: Lazy = Lazy::new(|| read_env_var("CHUNK_DEGREE", 25)); +pub static LAYER1_DEGREE: Lazy = Lazy::new(|| read_env_var("LAYER1_DEGREE", 25)); +pub static LAYER2_DEGREE: Lazy = Lazy::new(|| read_env_var("LAYER2_DEGREE", 25)); +pub static LAYER3_DEGREE: Lazy = Lazy::new(|| read_env_var("LAYER3_DEGREE", 25)); +pub static LAYER4_DEGREE: Lazy = Lazy::new(|| read_env_var("LAYER4_DEGREE", 25)); -pub static AGG_LAYER1_DEGREE: Lazy = Lazy::new(|| read_env_var("AGG_LAYER1_DEGREE", 25)); -pub static AGG_LAYER2_DEGREE: Lazy = Lazy::new(|| read_env_var("AGG_LAYER2_DEGREE", 25)); -pub static AGG_LAYER3_DEGREE: Lazy = Lazy::new(|| read_env_var("AGG_LAYER3_DEGREE", 25)); -pub static AGG_LAYER4_DEGREE: Lazy = Lazy::new(|| read_env_var("AGG_LAYER4_DEGREE", 25)); - -pub static ALL_AGG_DEGREES: Lazy> = Lazy::new(|| { +pub static ZKEVM_DEGREES: Lazy> = Lazy::new(|| { Vec::from_iter(HashSet::from([ *INNER_DEGREE, - *CHUNK_DEGREE, - *AGG_LAYER1_DEGREE, - *AGG_LAYER2_DEGREE, - *AGG_LAYER3_DEGREE, - *AGG_LAYER4_DEGREE, + *LAYER1_DEGREE, + *LAYER2_DEGREE, + ])) +}); + +pub static AGG_DEGREES: Lazy> = Lazy::new(|| { + Vec::from_iter(HashSet::from([ + // TODO: optimize to decrease degree for padding. + *LAYER1_DEGREE, // For layer-1 padding snark generation + *LAYER2_DEGREE, // For layer-2 padding snark generation + *LAYER3_DEGREE, + *LAYER4_DEGREE, ])) }); diff --git a/prover/src/lib.rs b/prover/src/lib.rs index 7c1191499..870d2023e 100644 --- a/prover/src/lib.rs +++ b/prover/src/lib.rs @@ -1,4 +1,4 @@ -pub mod aggregator; +pub mod common; pub mod config; mod evm_verifier; pub mod io; @@ -7,6 +7,7 @@ pub mod test_util; pub mod utils; pub mod zkevm; +pub use common::ChunkHash; pub use evm_verifier::EvmVerifier; pub use proof::Proof; diff --git a/prover/src/proof.rs b/prover/src/proof.rs index 5ef39567f..bffb670dc 100644 --- a/prover/src/proof.rs +++ b/prover/src/proof.rs @@ -2,7 +2,7 @@ use crate::io::{deserialize_fr_matrix, serialize_fr_matrix, serialize_vk, write_ use anyhow::Result; use halo2_proofs::{ halo2curves::bn256::{Fr, G1Affine}, - plonk::ProvingKey, + plonk::{Circuit, ProvingKey, VerifyingKey}, SerdeFormat, }; use serde_derive::{Deserialize, Serialize}; @@ -16,6 +16,7 @@ use snark_verifier::{ use snark_verifier_sdk::Snark; use std::{ fs::File, + io::Cursor, path::{Path, PathBuf}, }; use types::base64; @@ -104,6 +105,11 @@ impl Proof { &self.proof } + pub fn vk>(&self) -> VerifyingKey { + VerifyingKey::::read::<_, C>(&mut Cursor::new(&self.vk), SerdeFormat::Processed) + .unwrap() + } + pub fn instances(&self) -> Vec> { let buf: Vec>> = serde_json::from_reader(self.instances.as_slice()).unwrap(); diff --git a/prover/src/test_util.rs b/prover/src/test_util.rs index 8656269a1..d85bbc47a 100644 --- a/prover/src/test_util.rs +++ b/prover/src/test_util.rs @@ -2,7 +2,6 @@ use crate::utils::{get_block_trace_from_file, read_env_var}; use glob::glob; use types::eth::BlockTrace; -pub mod aggregator; pub mod mock_plonk; pub const PARAMS_DIR: &str = "./test_params"; diff --git a/prover/src/test_util/aggregator.rs b/prover/src/test_util/aggregator.rs deleted file mode 100644 index 8f58b7588..000000000 --- a/prover/src/test_util/aggregator.rs +++ /dev/null @@ -1,70 +0,0 @@ -use crate::{ - aggregator::Prover, - io::{load_snark, write_snark}, - utils::gen_rng, - zkevm::circuit::SuperCircuit, - Proof, -}; -use halo2_proofs::halo2curves::bn256::Fr; -use snark_verifier_sdk::Snark; -use std::{env::set_var, path::PathBuf}; -use zkevm_circuits::evm_circuit::witness::Block; - -pub fn gen_comp_evm_proof( - output_dir: &str, - id: &str, - is_fresh: bool, - degree: u32, - prover: &mut Prover, - prev_snark: Snark, -) -> Proof { - set_var("COMPRESSION_CONFIG", format!("./configs/{id}.config")); - - let rng = gen_rng(); - let proof = prover - .gen_comp_evm_proof(id, is_fresh, degree, rng, prev_snark) - .unwrap(); - proof.dump(&mut PathBuf::from(output_dir), id).unwrap(); - - proof -} - -pub fn load_or_gen_chunk_snark( - output_dir: &str, - id: &str, - prover: &mut Prover, - witness_block: Block, -) -> Snark { - let file_path = format!("{output_dir}/{id}_chunk_snark.json"); - - load_snark(&file_path).unwrap().unwrap_or_else(|| { - let snark = prover - .gen_chunk_snark::(&witness_block) - .unwrap(); - write_snark(&file_path, &snark); - - snark - }) -} - -pub fn load_or_gen_comp_snark( - output_dir: &str, - id: &str, - is_fresh: bool, - degree: u32, - prover: &mut Prover, - prev_snark: Snark, -) -> Snark { - set_var("COMPRESSION_CONFIG", format!("./configs/{id}.config")); - let file_path = format!("{output_dir}/{id}_snark.json"); - - load_snark(&file_path).unwrap().unwrap_or_else(|| { - let rng = gen_rng(); - let snark = prover - .gen_comp_snark(id, is_fresh, degree, rng, prev_snark) - .unwrap(); - write_snark(&file_path, &snark); - - snark - }) -} diff --git a/prover/src/zkevm/prover.rs b/prover/src/zkevm/prover.rs index d0ac82e7a..ef9809040 100644 --- a/prover/src/zkevm/prover.rs +++ b/prover/src/zkevm/prover.rs @@ -1,236 +1,82 @@ -use super::circuit::{ - block_traces_to_witness_block, check_batch_capacity, SuperCircuit, TargetCircuit, -}; use crate::{ - config::{CHUNK_DEGREE, INNER_DEGREE}, - utils::{load_params, metric_of_witness_block, read_env_var, tick}, + common, + config::{LAYER1_DEGREE, LAYER2_DEGREE, ZKEVM_DEGREES}, + utils::chunk_trace_to_witness_block, Proof, }; -use anyhow::{bail, Result}; -use halo2_proofs::poly::{ - commitment::{Params, ParamsProver}, - kzg::commitment::ParamsVerifierKZG, -}; -use log::info; -use once_cell::sync::Lazy; -use rand::SeedableRng; -use rand_xorshift::XorShiftRng; -use std::collections::HashMap; +use anyhow::Result; +use halo2_proofs::{halo2curves::bn256::Bn256, poly::kzg::commitment::ParamsKZG}; +use std::collections::BTreeMap; use types::eth::BlockTrace; -use halo2_proofs::{ - dev::MockProver, - halo2curves::bn256::{Bn256, Fr, G1Affine}, - plonk::{keygen_pk2, ProvingKey}, - poly::kzg::commitment::ParamsKZG, -}; -use snark_verifier_sdk::{ - gen_evm_proof_shplonk, gen_pk, gen_snark_shplonk, AggregationCircuit, CircuitExt, Snark, -}; - -mod evm; mod mock; -#[cfg(target_os = "linux")] -extern crate procfs; - -#[allow(dead_code)] -pub static OPT_MEM: Lazy = Lazy::new(|| read_env_var("OPT_MEM", false)); -pub static MOCK_PROVE: Lazy = Lazy::new(|| read_env_var("MOCK_PROVE", false)); - #[derive(Debug)] -// This is the aggregation prover that takes in a list of traces, produces -// a proof that can be verified on chain. pub struct Prover { - pub inner_params: ParamsKZG, - pub chunk_params: ParamsKZG, - /// We may have a list of public keys for different inner circuits. - /// Those keys are stored as a hash map, and keyed by a `name` String. - pub inner_pks: HashMap>, - pub chunk_pk: Option>, + inner: common::Prover, } -impl Prover { - pub fn from_params(inner_params: ParamsKZG, chunk_params: ParamsKZG) -> Self { - assert!(inner_params.k() == *INNER_DEGREE); - assert!(chunk_params.k() == *CHUNK_DEGREE); - - // notice that `inner_k < chunk`_k which is not necessary the case in practice - log::info!( - "loaded parameters for degrees {} and {}", - *INNER_DEGREE, - *CHUNK_DEGREE - ); - - // this check can be skipped since the `params` is downsized? - { - let target_params_verifier: &ParamsVerifierKZG = inner_params.verifier_params(); - let agg_params_verifier: &ParamsVerifierKZG = chunk_params.verifier_params(); - log::info!( - "params g2 {:?} s_g2 {:?}", - target_params_verifier.g2(), - target_params_verifier.s_g2() - ); - debug_assert_eq!(target_params_verifier.s_g2(), agg_params_verifier.s_g2()); - debug_assert_eq!(target_params_verifier.g2(), agg_params_verifier.g2()); - } - - Self { - inner_params, - chunk_params, - inner_pks: Default::default(), - chunk_pk: None, - } - } - - pub fn from_params_dir(params_dir: &str) -> Self { - let chunk_params = load_params(params_dir, *CHUNK_DEGREE, None).unwrap(); - let inner_params = load_params(params_dir, *INNER_DEGREE, None).unwrap_or_else(|_| { - assert!(*CHUNK_DEGREE >= *INNER_DEGREE); - log::warn!( - "Optimization: download params{} to params dir", - *INNER_DEGREE - ); - - let mut new_params = chunk_params.clone(); - new_params.downsize(*INNER_DEGREE); - new_params - }); - - Self::from_params(inner_params, chunk_params) +impl From for Prover { + fn from(inner: common::Prover) -> Self { + Self { inner } } +} - // Generate the chunk proof given the chunk trace using Poseidon hash for challenges. - // The returned proof is expected to be verified by only rust verifier not solidity verifier. - pub fn gen_chunk_proof(&mut self, chunk_trace: &[BlockTrace]) -> Result { - let inner_snark = self.gen_inner_snark::(chunk_trace)?; - // Compress the inner snark using the aggregation proof. - self.gen_agg_proof(vec![inner_snark]) +impl Prover { + pub fn from_params(params_map: BTreeMap>) -> Self { + common::Prover::from_params(params_map).into() } - // Generate the chunk proof given the chunk trace using Keccak hash for challenges. - // The returned proof can be efficiently verified by solidity verifier. - pub fn gen_chunk_evm_proof(&mut self, chunk_trace: &[BlockTrace]) -> Result { - let inner_snark = self.gen_inner_snark::(chunk_trace)?; - // Compress the inner snark using the aggregation proof. - self.gen_agg_evm_proof(vec![inner_snark]) + pub fn from_params_dir(params_dir: &str) -> Self { + common::Prover::from_params_dir(params_dir, &ZKEVM_DEGREES).into() } - // Generate the snark of the inner circuit - pub fn gen_inner_snark( + pub fn gen_chunk_proof( &mut self, - chunk_trace: &[BlockTrace], - ) -> Result { - if chunk_trace.is_empty() { - bail!("Empty chunk trace"); - } - - let mut block_traces = chunk_trace.to_vec(); - - let (circuit, instance) = { - // will return early if the check finds out the trace exceeds the circuit capacity - check_batch_capacity(&mut block_traces)?; - - let witness_block = block_traces_to_witness_block(&block_traces)?; - log::info!( - "proving the chunk: {:?}", - metric_of_witness_block(&witness_block) - ); - - C::from_witness_block(&witness_block)? - }; - - // generate the proof for the inner circuit - info!( - "Create {} proof of block {} ... block {}, batch len {}", - C::name(), - chunk_trace.first().unwrap().header.hash.unwrap(), - chunk_trace.last().unwrap().header.hash.unwrap(), - chunk_trace.len() - ); - - let seed = [0u8; 16]; - let mut rng = XorShiftRng::from_seed(seed); - - if *MOCK_PROVE { - log::info!("mock prove {} start", C::name()); - let prover = MockProver::::run(*INNER_DEGREE, &circuit, instance)?; - if let Err(errs) = prover.verify_par() { - log::error!("err num: {}", errs.len()); - for err in &errs { - log::error!("{}", err); - } - bail!("{:#?}", errs); - } - log::info!("mock prove {} done", C::name()); - } - - if !self.inner_pks.contains_key(&C::name()) { - self.gen_inner_pk::(&C::dummy_inner_circuit()); - } - let pk = &self.inner_pks[&C::name()]; - - // Generate the SNARK proof for the inner circuit - let snark_proof = - gen_snark_shplonk(&self.inner_params, pk, circuit, &mut rng, None::); - Ok(snark_proof) - } - - // Generate the aggregation proof given the proofs of inner circuit - pub fn gen_agg_proof(&mut self, snarks: Vec) -> Result { - // build the aggregation circuit inputs from the inner circuit outputs - let seed = [0u8; 16]; - let mut rng = XorShiftRng::from_seed(seed); - - let agg_circuit = AggregationCircuit::new(&self.chunk_params, snarks, &mut rng); - let chunk_pk = self - .chunk_pk - .get_or_insert_with(|| gen_pk(&self.chunk_params, &agg_circuit, None)); - - let agg_proof = gen_snark_shplonk( - &self.chunk_params, - chunk_pk, - agg_circuit, - &mut rng, - None::, - ); - - Proof::from_snark(chunk_pk, &agg_proof) - } - - // Generate the aggregation evm proof given the proofs of inner circuit - pub fn gen_agg_evm_proof(&mut self, snarks: Vec) -> Result { - // build the aggregation circuit inputs from the inner circuit outputs - let seed = [0u8; 16]; - let mut rng = XorShiftRng::from_seed(seed); - - let agg_circuit = AggregationCircuit::new(&self.chunk_params, snarks, &mut rng); - let chunk_pk = self - .chunk_pk - .get_or_insert_with(|| gen_pk(&self.chunk_params, &agg_circuit, None)); - - let agg_proof = gen_evm_proof_shplonk( - &self.chunk_params, - chunk_pk, - agg_circuit.clone(), - agg_circuit.instances(), - &mut rng, - ); - - Proof::new( - chunk_pk, - agg_proof, - &agg_circuit.instances(), - Some(agg_circuit.num_instance()), - ) - } - - // Initiates the public key for a given inner circuit. - pub(crate) fn gen_inner_pk(&mut self, circuit: &::Inner) { - tick(&format!("before init pk of {}", C::name())); - let pk = keygen_pk2(&self.inner_params, circuit) - .unwrap_or_else(|e| panic!("failed to generate {} pk: {:?}", C::name(), e)); - self.inner_pks.insert(C::name(), pk); - tick(&format!("after init pk of {}", C::name())); + chunk_trace: Vec, + output_dir: Option<&str>, + ) -> Result { + assert!(!chunk_trace.is_empty()); + + let witness_block = chunk_trace_to_witness_block(chunk_trace)?; + log::info!("Got witness block"); + + let name = witness_block + .context + .first_or_default() + .number + .low_u64() + .to_string(); + + // Load or generate inner snark. + let inner_snark = self + .inner + .load_or_gen_inner_snark(&name, witness_block, output_dir)?; + log::info!("Got inner snark: {name}"); + + // Load or generate compression wide snark (layer-1). + let layer1_snark = self.inner.load_or_gen_comp_snark( + &name, + "layer1", + true, + *LAYER1_DEGREE, + inner_snark, + output_dir, + )?; + log::info!("Got compression wide snark (layer-1): {name}"); + + // Load or generate compression thin snark (layer-2). + let layer2_snark = self.inner.load_or_gen_comp_snark( + &name, + "layer2", + false, + *LAYER2_DEGREE, + layer1_snark, + output_dir, + )?; + log::info!("Got compression thin snark (layer-2): {name}"); + + let pk = self.inner.pk("layer2").unwrap(); + Proof::from_snark(pk, &layer2_snark) } } diff --git a/prover/src/zkevm/prover/evm.rs b/prover/src/zkevm/prover/evm.rs deleted file mode 100644 index 1ec64d6a3..000000000 --- a/prover/src/zkevm/prover/evm.rs +++ /dev/null @@ -1,21 +0,0 @@ -use super::Prover; -use halo2_proofs::{halo2curves::bn256::G1Affine, plonk::VerifyingKey}; -use snark_verifier_sdk::{gen_evm_verifier_shplonk, AggregationCircuit, CircuitExt}; -use std::path::Path; - -impl Prover { - /// Generate the EVM bytecode for plonk verifier. - pub fn create_evm_verifier_bytecode( - &self, - agg_circuit: &AggregationCircuit, - agg_vk: &VerifyingKey, - path: Option<&Path>, - ) -> Vec { - gen_evm_verifier_shplonk::( - &self.chunk_params, - agg_vk, - agg_circuit.num_instance(), - path, - ) - } -} diff --git a/prover/src/zkevm/verifier.rs b/prover/src/zkevm/verifier.rs index a49e9cc7f..036339eae 100644 --- a/prover/src/zkevm/verifier.rs +++ b/prover/src/zkevm/verifier.rs @@ -1,119 +1,52 @@ -use super::circuit::TargetCircuit; -use crate::{ - config::{CHUNK_DEGREE, INNER_DEGREE}, - utils::load_params, - Proof, -}; -use anyhow::{bail, Result}; +use crate::{common, config::LAYER2_DEGREE, Proof}; +use aggregator::CompressionCircuit; use halo2_proofs::{ halo2curves::bn256::{Bn256, G1Affine}, - plonk::{keygen_vk, verify_proof, VerifyingKey}, - poly::{ - commitment::{Params, ParamsProver}, - kzg::{commitment::ParamsKZG, multiopen::VerifierSHPLONK, strategy::AccumulatorStrategy}, - VerificationStrategy, - }, - transcript::TranscriptReadBuffer, - SerdeFormat, + plonk::VerifyingKey, + poly::kzg::commitment::ParamsKZG, }; -use itertools::Itertools; -use snark_verifier::system::halo2::transcript::evm::EvmTranscript; -use snark_verifier_sdk::{verify_snark_shplonk, AggregationCircuit, Snark}; -use std::{collections::HashMap, io::Cursor}; +#[derive(Debug)] pub struct Verifier { - inner_params: ParamsKZG, - chunk_params: ParamsKZG, - chunk_vk: Option>, - inner_vks: HashMap>, + inner: common::Verifier, } -impl Verifier { - pub fn from_params( - inner_params: ParamsKZG, - chunk_params: ParamsKZG, - raw_chunk_vk: Option>, - ) -> Self { - let chunk_vk = raw_chunk_vk.as_ref().map(|k| { - VerifyingKey::::read::<_, AggregationCircuit>( - &mut Cursor::new(&k), - SerdeFormat::Processed, - ) - .unwrap() - }); - - Self { - inner_params, - chunk_params, - chunk_vk, - inner_vks: Default::default(), - } +impl From for Verifier { + fn from(inner: common::Verifier) -> Self { + Self { inner } } +} - pub fn from_params_dir(params_dir: &str, chunk_vk: Option>) -> Self { - let chunk_params = load_params(params_dir, *CHUNK_DEGREE, None).unwrap(); - let inner_params = load_params(params_dir, *INNER_DEGREE, None).unwrap_or_else(|_| { - assert!(*CHUNK_DEGREE >= *INNER_DEGREE); - log::warn!( - "Optimization: download params{} to params dir", - *INNER_DEGREE - ); - - let mut new_params = chunk_params.clone(); - new_params.downsize(*INNER_DEGREE); - new_params - }); - - Self::from_params(inner_params, chunk_params, chunk_vk) +impl Verifier { + pub fn new(params: ParamsKZG, vk: VerifyingKey) -> Self { + common::Verifier::new(params, vk).into() } - pub fn verify_chunk_proof(&self, proof: Proof) -> Result { - let chunk_vk = match &self.chunk_vk { - Some(vk) => vk, - None => panic!("Chunk verification key is missing"), - }; - - Ok(verify_snark_shplonk::( - &self.chunk_params, - proof.to_snark(), - chunk_vk, - )) + pub fn from_params(params: ParamsKZG, raw_vk: &[u8]) -> Self { + common::Verifier::from_params(params, raw_vk).into() } - pub fn verify_chunk_evm_proof(&self, proof: Proof) -> Result { - let chunk_vk = match &self.chunk_vk { - Some(vk) => vk, - None => panic!("Chunk verification key is missing"), - }; - - let mut transcript = TranscriptReadBuffer::<_, G1Affine, _>::init(proof.proof()); - - // Deserialize instances - let instances = proof.instances(); - let instances = instances.iter().map(|ins| ins.as_slice()).collect_vec(); + pub fn from_params_dir(params_dir: &str, vk: &[u8]) -> Self { + common::Verifier::from_params_dir(params_dir, *LAYER2_DEGREE, vk).into() + } - Ok(VerificationStrategy::<_, VerifierSHPLONK>::finalize( - verify_proof::<_, VerifierSHPLONK, _, EvmTranscript<_, _, _, _>, _>( - &self.chunk_params, - chunk_vk, - AccumulatorStrategy::new(&self.inner_params), - &[instances.as_slice()], - &mut transcript, - )?, - )) + pub fn verify_chunk_proof(&self, proof: Proof) -> bool { + self.inner.verify_proof::(proof) } - pub fn verify_inner_proof(&mut self, snark: &Snark) -> Result<()> { - let verifier_params = self.inner_params.verifier_params(); - let vk = self.inner_vks.entry(C::name()).or_insert_with(|| { - let circuit = C::dummy_inner_circuit(); - keygen_vk(&self.inner_params, &circuit) - .unwrap_or_else(|_| panic!("Failed to generate {} vk", C::name())) - }); - if verify_snark_shplonk::(verifier_params, snark.clone(), vk) { - Ok(()) - } else { - bail!("Snark verification failed".to_string()) + /* TODO: verify inner proof. + pub fn verify_inner_proof(&mut self, snark: &Snark) -> Result<()> { + let verifier_params = self.inner_params.verifier_params(); + let vk = self.inner_vks.entry(C::name()).or_insert_with(|| { + let circuit = C::dummy_inner_circuit(); + keygen_vk(&self.inner_params, &circuit) + .unwrap_or_else(|_| panic!("Failed to generate {} vk", C::name())) + }); + if verify_snark_shplonk::(verifier_params, snark.clone(), vk) { + Ok(()) + } else { + bail!("Snark verification failed".to_string()) + } } - } + */ } diff --git a/prover/tests/chunk_tests.rs b/prover/tests/chunk_tests.rs index 952e0f6c4..58e74ae7c 100644 --- a/prover/tests/chunk_tests.rs +++ b/prover/tests/chunk_tests.rs @@ -1,98 +1,64 @@ +use aggregator::CompressionCircuit; use prover::{ - io::{load_snark, write_file, write_snark}, + common::{Prover, Verifier}, + config::{LAYER1_DEGREE, LAYER2_DEGREE, ZKEVM_DEGREES}, test_util::{load_block_traces_for_test, PARAMS_DIR}, - utils::init_env_and_log, - zkevm::{ - circuit::{SuperCircuit, TargetCircuit}, - Prover, - }, - EvmVerifier, -}; -use rand::SeedableRng; -use rand_xorshift::XorShiftRng; -use snark_verifier_sdk::{AggregationCircuit, CircuitExt}; -use std::{ - path::{Path, PathBuf}, - str::FromStr, + utils::{chunk_trace_to_witness_block, init_env_and_log}, }; #[cfg(feature = "prove_verify")] #[test] fn test_chunk_prove_verify() { - std::env::set_var("VERIFY_CONFIG", "./configs/verify_circuit.config"); - - let output_dir = init_env_and_log("chunk_tests"); - let mut output_path = PathBuf::from_str(&output_dir).unwrap(); - log::info!("Inited ENV and created output-dir {output_dir}"); - - let block_traces = load_block_traces_for_test().1; - log::info!("Loaded block-traces"); - - // ==================================================== - // A whole aggregation procedure takes the following steps - // 1. instantiation the parameters and the prover - // 2. read inner circuit proofs (a.k.a. SNARKs) from previous dumped file or - // convert block traces into - // 3. build an aggregation circuit proof - // 4. generate bytecode for evm to verify aggregation circuit proof - // 5. validate the proof with evm bytecode - // ==================================================== - // - // 1. instantiation the parameters and the prover - // - - let mut prover = Prover::from_params_dir(PARAMS_DIR); - log::info!("build prover"); - - // - // 2. read inner circuit proofs (a.k.a. SNARKs) from previous dumped file or - // convert block traces into - // - let inner_snark_file_path = format!("{}/{}_snark.json", output_dir, SuperCircuit::name()); - let inner_snark = load_snark(&inner_snark_file_path) - .unwrap() - .unwrap_or_else(|| { - let snark = prover - .gen_inner_snark::(block_traces.as_slice()) - .unwrap(); - - // Dump inner circuit proof. - write_snark(&inner_snark_file_path, &snark); - - snark - }); - log::info!("got super circuit proof"); - - // sanity check: the inner proof is correct - - // 3. build an aggregation circuit proof - let agg_circuit = AggregationCircuit::new( - &prover.chunk_params, - vec![inner_snark.clone()], - XorShiftRng::from_seed([0u8; 16]), - ); - - let chunk_proof = prover.gen_agg_evm_proof(vec![inner_snark]).unwrap(); - - // Dump aggregation proof, vk and instance. - chunk_proof.dump(&mut output_path, &"chunk").unwrap(); - - log::info!("finished aggregation generation"); - - // 4. generate bytecode for evm to verify aggregation circuit proof - let agg_vk = prover.chunk_pk.as_ref().unwrap().get_vk(); - - // Create bytecode and dump yul-code. - let yul_file_path = format!("{}/verifier.yul", output_dir); - let deployment_code = - prover.create_evm_verifier_bytecode(&agg_circuit, agg_vk, Some(Path::new(&yul_file_path))); - - // Dump bytecode. - write_file(&mut output_path, "verifier.bin", &deployment_code); - - log::info!("finished byte code generation"); - - // 5. validate the proof with evm bytecode - EvmVerifier::new(deployment_code).verify(agg_circuit.instances(), chunk_proof.proof().to_vec()); - log::info!("end to end test completed"); + // Init, load block traces and construct prover. + + let output_dir = init_env_and_log("comp_tests"); + log::info!("Initialized ENV and created output-dir {output_dir}"); + + let chunk_trace = load_block_traces_for_test().1; + log::info!("Loaded chunk-trace"); + + let witness_block = chunk_trace_to_witness_block(chunk_trace).unwrap(); + log::info!("Got witness-block"); + + let mut prover = Prover::from_params_dir(PARAMS_DIR, &*ZKEVM_DEGREES); + log::info!("Constructed prover"); + + // Load or generate inner snark. + let inner_snark = prover + .load_or_gen_inner_snark("layer0", witness_block, Some(&output_dir)) + .unwrap(); + log::info!("Got inner-snark"); + + // Load or generate compression wide snark (layer-1). + let layer1_snark = prover + .load_or_gen_comp_snark( + "layer1_0", + "layer1", + true, + *LAYER1_DEGREE, + inner_snark, + Some(&output_dir), + ) + .unwrap(); + log::info!("Got compression-wide-snark (layer-1)"); + + // Load or generate compression EVM proof (layer-2). + let proof = prover + .gen_comp_evm_proof( + "layer2_0", + "layer2", + false, + *LAYER2_DEGREE, + layer1_snark, + Some(&output_dir), + ) + .unwrap(); + log::info!("Got compression-EVM-proof (layer-2)"); + + // Construct verifier and EVM verify. + let params = prover.params(*LAYER2_DEGREE).clone(); + let vk = proof.vk::(); + let verifier = Verifier::new(params, vk); + verifier.evm_verify::(&proof, &output_dir); + log::info!("Finish EVM verify"); } diff --git a/prover/tests/compression_tests.rs b/prover/tests/compression_tests.rs deleted file mode 100644 index 6258e616a..000000000 --- a/prover/tests/compression_tests.rs +++ /dev/null @@ -1,66 +0,0 @@ -use aggregator::CompressionCircuit; -use prover::{ - aggregator::{Prover, Verifier}, - config::{AGG_LAYER1_DEGREE, AGG_LAYER2_DEGREE, INNER_DEGREE}, - test_util::{ - aggregator::{gen_comp_evm_proof, load_or_gen_chunk_snark, load_or_gen_comp_snark}, - load_block_traces_for_test, PARAMS_DIR, - }, - utils::{chunk_trace_to_witness_block, init_env_and_log}, -}; -use std::path::Path; - -#[cfg(feature = "prove_verify")] -#[test] -fn test_comp_prove_verify() { - // Init, load block traces and construct prover. - - let output_dir = init_env_and_log("comp_tests"); - log::info!("Initialized ENV and created output-dir {output_dir}"); - - let chunk_trace = load_block_traces_for_test().1; - log::info!("Loaded chunk-trace"); - - let witness_block = chunk_trace_to_witness_block(chunk_trace).unwrap(); - log::info!("Got witness-block"); - - let mut prover = Prover::from_params_dir( - PARAMS_DIR, - &[*INNER_DEGREE, *AGG_LAYER1_DEGREE, *AGG_LAYER2_DEGREE], - ); - log::info!("Constructed prover"); - - // Load or generate chunk snark. - let chunk_snark = load_or_gen_chunk_snark(&output_dir, "comp", &mut prover, witness_block); - log::info!("Got chunk-snark"); - - // Load or generate compression wide snark (layer-1). - let layer1_snark = load_or_gen_comp_snark( - &output_dir, - "agg_layer1", - true, - *AGG_LAYER1_DEGREE, - &mut prover, - chunk_snark, - ); - log::info!("Got compression wide snark (layer-1)"); - - // Load or generate compression EVM proof (layer-2). - let proof = gen_comp_evm_proof( - &output_dir, - "agg_layer2", - false, - *AGG_LAYER2_DEGREE, - &mut prover, - layer1_snark, - ); - log::info!("Got compression EVM proof (layer-2)"); - - // Construct verifier and EVM verify. - let params = prover.params(*AGG_LAYER2_DEGREE).clone(); - let vk = prover.pk("agg_layer2").unwrap().get_vk().clone(); - let verifier = Verifier::new(params, Some(vk)); - let yul_file_path = format!("{output_dir}/comp_verifier.yul"); - verifier.evm_verify::(&proof, Some(Path::new(&yul_file_path))); - log::info!("Finish EVM verify"); -} diff --git a/prover/tests/integration.rs b/prover/tests/integration.rs index 6c311f7b6..0cabe0028 100644 --- a/prover/tests/integration.rs +++ b/prover/tests/integration.rs @@ -1,4 +1,3 @@ -use chrono::Utc; use halo2_proofs::{plonk::keygen_vk, SerdeFormat}; use prover::{ config::INNER_DEGREE, @@ -7,7 +6,7 @@ use prover::{ utils::{get_block_trace_from_file, init_env_and_log, load_params}, zkevm::{ circuit::{SuperCircuit, TargetCircuit}, - CircuitCapacityChecker, Prover, Verifier, + CircuitCapacityChecker, Prover, }, }; @@ -203,33 +202,35 @@ fn test_vk_same() { } fn test_target_circuit_prove_verify() { - use std::time::Instant; - - init_env_and_log("integration"); - - let (_, block_traces) = load_block_traces_for_test(); - - log::info!("start generating {} snark", C::name()); - let now = Instant::now(); - let mut prover = Prover::from_params_dir(PARAMS_DIR); - log::info!("build prover"); - let snark = prover - .gen_inner_snark::(block_traces.as_slice()) - .unwrap(); - log::info!("finish generating snark, elapsed: {:?}", now.elapsed()); - - let output_file = format!( - "/tmp/{}_{}.json", - C::name(), - Utc::now().format("%Y%m%d_%H%M%S") - ); - let mut fd = std::fs::File::create(&output_file).unwrap(); - serde_json::to_writer_pretty(&mut fd, &snark).unwrap(); - log::info!("write snark to {}", output_file); - - log::info!("start verifying snark"); - let now = Instant::now(); - let mut verifier = Verifier::from_params_dir(PARAMS_DIR, None); - assert!(verifier.verify_inner_proof::(&snark).is_ok()); - log::info!("finish verifying snark, elapsed: {:?}", now.elapsed()); + /* TODO: verify inner proof. + use std::time::Instant; + + init_env_and_log("integration"); + + let (_, block_traces) = load_block_traces_for_test(); + + log::info!("start generating {} snark", C::name()); + let now = Instant::now(); + let mut prover = Prover::from_params_dir(PARAMS_DIR); + log::info!("build prover"); + let snark = prover + .gen_inner_snark::(block_traces.as_slice()) + .unwrap(); + log::info!("finish generating snark, elapsed: {:?}", now.elapsed()); + + let output_file = format!( + "/tmp/{}_{}.json", + C::name(), + Utc::now().format("%Y%m%d_%H%M%S") + ); + let mut fd = std::fs::File::create(&output_file).unwrap(); + serde_json::to_writer_pretty(&mut fd, &snark).unwrap(); + log::info!("write snark to {}", output_file); + + log::info!("start verifying snark"); + let now = Instant::now(); + let mut verifier = Verifier::from_params_dir(PARAMS_DIR, None); + assert!(verifier.verify_inner_proof::(&snark).is_ok()); + log::info!("finish verifying snark, elapsed: {:?}", now.elapsed()); + */ }