diff --git a/Cargo.lock b/Cargo.lock index 0e09daba8..6a787aca3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2932,6 +2932,12 @@ dependencies = [ "rustix 0.35.13", ] +[[package]] +name = "project-root" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bccbff07d5ed689c4087d20d7307a52ab6141edeedf487c3876a55b86cf63df" + [[package]] name = "prover" version = "0.4.0" @@ -2956,6 +2962,7 @@ dependencies = [ "num-bigint", "once_cell", "procfs", + "project-root", "rand", "rand_xorshift", "serde", diff --git a/Makefile b/Makefile index b1a0ceba6..e0bf0369e 100644 --- a/Makefile +++ b/Makefile @@ -24,9 +24,9 @@ test: ## Run tests for all the workspace members bridge-test: cargo build --release - ./target/release/prove --params=./test_params --seed=./test_seed --trace=prover/tests/traces/bridge --agg=true + ./target/release/prove --params=./test_params --trace=prover/tests/traces/bridge -test-super-trace: ## test super circuit with real trace +test-inner-prove: ## Test inner circuit with real trace cargo test --features prove_verify --release test_prove_verify mock: @@ -38,7 +38,7 @@ mock-debug: mock-testnet: @cargo run --bin mock_testnet --release -test-agg: +test-chunk-prove: @cargo test --features prove_verify --release test_aggregation_api rows: diff --git a/README.md b/README.md index 4f4cf5ddc..d29b1eb26 100644 --- a/README.md +++ b/README.md @@ -4,39 +4,60 @@ ## Usage +### Prerequisite + +Fetch git-submodule of test traces +```shell +git submodule init +git submodule update --checkout +``` + +Download setup params +```shell +make download-setup +``` +Or specify degree and target directory to download +```shell +# As default `degree=25` and `params_dir=./prover/test_params`. +make download-setup -e degree=DEGREE params_dir=PARAMS_DIR +``` ### Testing -`make test-agg` is the main testing entry point for the multi-level circuit constraint system of scroll-zkevm. Developers can understand how the system works by reading the codes of this test. +`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, `make test-super-trace` can be used to test the first-level circuit. +Besides it, `make test-inner-prove` could be used to test the first-level circuit. ### Binaries This repository is designed to be used as a Rust crate, rather than a standalone running process. However, you can still use the following command to run binaries locally. -Setup -```shell -cargo build --release --bin setup - -./target/release/setup --params -``` - -If you run into linking issues during setup you may need to run +If you run into linking issues you may need to run ```shell cp `find ./target/release/ | grep libzktrie.so` /usr/local/lib/ ``` -to move the zktrielib into a path where your linker can locate it +To move the zktrielib into a path where your linker could locate it. -Prove +Run prover ```shell cargo build --release --bin prove ./target/release/prove --help ``` -Or you can use it like the following: +Could specify arguments as +```shell +cargo run --release --bin prove -- --params=./prover/test_params --trace=./prover/tests/traces/erc20/10_transfer.json +``` + +Run verifier +```shell +cargo build --release --bin verify + +./target/release/verify --help +``` +Could specify arguments as ```shell -cargo run --release --bin prove -- --params=./params --trace=./test.json +cargo run --release --bin verify -- --params=./prover/test_params --vk=./proof_data/chunk.vkey ``` ## License diff --git a/bin/Cargo.toml b/bin/Cargo.toml index 2294f3a94..568c0c48d 100644 --- a/bin/Cargo.toml +++ b/bin/Cargo.toml @@ -23,10 +23,6 @@ tokio = { version = "1", features = ["full"] } types = { path = "../types" } prover = { path = "../prover" } -[[bin]] -name = "setup" -path = "src/setup.rs" - [[bin]] name = "prove" path = "src/prove.rs" diff --git a/bin/src/mock_testnet.rs b/bin/src/mock_testnet.rs index e0e5d25c0..dfd4c6596 100644 --- a/bin/src/mock_testnet.rs +++ b/bin/src/mock_testnet.rs @@ -1,12 +1,16 @@ use anyhow::Result; use ethers_providers::{Http, Provider}; use itertools::Itertools; -use prover::utils::init_env_and_log; -use prover::zkevm::circuit::{ - block_traces_to_witness_block, calculate_row_usage_of_witness_block, SuperCircuit, - SUB_CIRCUIT_NAMES, +use prover::{ + utils::init_env_and_log, + zkevm::{ + circuit::{ + block_traces_to_witness_block, calculate_row_usage_of_witness_block, SuperCircuit, + SUB_CIRCUIT_NAMES, + }, + Prover, + }, }; -use prover::zkevm::Prover; use reqwest::Url; use serde::Deserialize; use std::env; @@ -97,7 +101,8 @@ async fn get_traces_by_batch_api( )) } -/// Request block traces by API `scroll_getBlockTraceByNumberOrHash`. Return None for no more batches. +/// Request block traces by API `scroll_getBlockTraceByNumberOrHash`. Return None for no more +/// batches. async fn get_traces_by_block_api( provider: &Provider, setting: &Setting, diff --git a/bin/src/prove.rs b/bin/src/prove.rs index d15e9d1ac..5b5cd2d7a 100644 --- a/bin/src/prove.rs +++ b/bin/src/prove.rs @@ -1,34 +1,38 @@ use clap::Parser; use log::info; -use prover::utils::{get_block_trace_from_file, init_env_and_log, load_or_create_params}; -use prover::zkevm::{circuit::AGG_DEGREE, Prover}; -use std::fs; -use std::path::PathBuf; -use std::time::Instant; +use prover::{ + utils::{get_block_trace_from_file, init_env_and_log, load_or_download_params}, + zkevm::{circuit::AGG_DEGREE, Prover}, +}; +use std::{fs, path::PathBuf, time::Instant}; #[derive(Parser, Debug)] #[clap(author, version, about, long_about = None)] struct Args { /// Get params and write into file. - #[clap(short, long = "params")] - params_path: Option, + #[clap(short, long = "params", default_value = "prover/test_params")] + params_path: String, /// Get BlockTrace from file or dir. - #[clap(short, long = "trace")] - trace_path: Option, + #[clap( + short, + long = "trace", + default_value = "prover/tests/traces/empty.json" + )] + trace_path: String, } fn main() { init_env_and_log("prove"); - std::env::set_var("VERIFY_CONFIG", "./zkevm/configs/verify_circuit.config"); + std::env::set_var("VERIFY_CONFIG", "./prover/configs/verify_circuit.config"); let args = Args::parse(); - let agg_params = load_or_create_params(&args.params_path.unwrap(), *AGG_DEGREE) + let agg_params = load_or_download_params(&args.params_path, *AGG_DEGREE) .expect("failed to load or create params"); let mut prover = Prover::from_params(agg_params); let mut traces = Vec::new(); - let trace_path = PathBuf::from(&args.trace_path.unwrap()); + let trace_path = PathBuf::from(&args.trace_path); if trace_path.is_dir() { for entry in fs::read_dir(trace_path).unwrap() { let path = entry.unwrap().path(); @@ -42,14 +46,17 @@ fn main() { traces.push(block_trace); } - let mut proof_path = PathBuf::from("agg.proof"); + let mut proof_dir = PathBuf::from("proof_data"); let now = Instant::now(); - let agg_proof = prover - .create_agg_circuit_proof_batch(traces.as_slice()) - .expect("cannot generate agg_proof"); - info!("finish generating agg proof, elapsed: {:?}", now.elapsed()); - - fs::create_dir_all(&proof_path).unwrap(); - agg_proof.dump(&mut proof_path).unwrap(); + let chunk_proof = prover + .gen_chunk_proof(traces.as_slice()) + .expect("cannot generate chunk proof"); + info!( + "finish generating chunk proof, elapsed: {:?}", + now.elapsed() + ); + + fs::create_dir_all(&proof_dir).unwrap(); + chunk_proof.dump(&mut proof_dir, "chunk").unwrap(); } diff --git a/bin/src/setup.rs b/bin/src/setup.rs deleted file mode 100644 index 18e2831e0..000000000 --- a/bin/src/setup.rs +++ /dev/null @@ -1,20 +0,0 @@ -use clap::Parser; -use prover::utils::{init_env_and_log, load_or_create_params}; -use prover::zkevm::circuit::DEGREE; - -#[derive(Parser, Debug)] -#[clap(author, version, about, long_about = None)] -struct Args { - /// generate params and write into file - #[clap(short, long = "params")] - params_path: Option, -} - -fn main() { - init_env_and_log("setup"); - - let args = Args::parse(); - if let Some(path) = args.params_path { - load_or_create_params(&path, *DEGREE).expect("failed to load or create params"); - } -} diff --git a/bin/src/verify.rs b/bin/src/verify.rs index b7f510a48..78f6a0583 100644 --- a/bin/src/verify.rs +++ b/bin/src/verify.rs @@ -1,38 +1,43 @@ use clap::Parser; use log::info; -use prover::utils::{init_env_and_log, load_or_create_params}; -use prover::zkevm::circuit::{AGG_DEGREE, DEGREE}; -use prover::zkevm::{AggCircuitProof, Verifier}; -use std::fs::File; -use std::io::Read; +use prover::{ + utils::{init_env_and_log, load_or_download_params}, + zkevm::{ + circuit::{AGG_DEGREE, DEGREE}, + Verifier, + }, + Proof, +}; +use std::{fs::File, io::Read, path::PathBuf}; #[derive(Parser, Debug)] #[clap(author, version, about, long_about = None)] struct Args { /// Get params from the file. - #[clap(short, long = "params")] - params_path: Option, + #[clap(short, long = "params", default_value = "prover/test_params")] + params_path: String, /// Get vk from the file. - #[clap(long = "vk")] - vk_path: Option, + #[clap(long = "vk", default_value = "proof_data/chunk.vkey")] + vk_path: String, } fn main() { init_env_and_log("verify"); - std::env::set_var("VERIFY_CONFIG", "./zkevm/configs/verify_circuit.config"); + std::env::set_var("VERIFY_CONFIG", "./prover/configs/verify_circuit.config"); let args = Args::parse(); - let params = load_or_create_params(&args.params_path.clone().unwrap(), *DEGREE) + let params = load_or_download_params(&args.params_path, *DEGREE) .expect("failed to load or create params"); - let agg_params = load_or_create_params(&args.params_path.unwrap(), *AGG_DEGREE) + let agg_params = load_or_download_params(&args.params_path, *AGG_DEGREE) .expect("failed to load or create params"); - let agg_vk = read_from_file(&args.vk_path.unwrap()); + let agg_vk = read_from_file(&args.vk_path); let v = Verifier::from_params(params, agg_params, Some(agg_vk)); - let proof_vec = read_from_file("agg.proof"); - let proof = serde_json::from_slice::(proof_vec.as_slice()).unwrap(); - let verified = v.verify_agg_circuit_proof(proof).is_ok(); + 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(); info!("verify agg proof: {}", verified) } diff --git a/ffi/src/lib.rs b/ffi/src/lib.rs index 8abc2ec9d..c9a0070ad 100644 --- a/ffi/src/lib.rs +++ b/ffi/src/lib.rs @@ -4,8 +4,10 @@ pub mod prove; pub mod verify; pub(crate) mod utils { - use std::ffi::{CStr, CString}; - use std::os::raw::c_char; + use std::{ + ffi::{CStr, CString}, + os::raw::c_char, + }; pub(crate) fn c_char_to_str(c: *const c_char) -> &'static str { let cstr = unsafe { CStr::from_ptr(c) }; diff --git a/ffi/src/prove.rs b/ffi/src/prove.rs index 41fd83c17..495740648 100644 --- a/ffi/src/prove.rs +++ b/ffi/src/prove.rs @@ -1,7 +1,6 @@ use crate::utils::{c_char_to_str, c_char_to_vec, vec_to_c_char}; use libc::c_char; -use prover::utils::init_env_and_log; -use prover::zkevm; +use prover::{utils::init_env_and_log, zkevm}; use std::cell::OnceCell; use types::eth::BlockTrace; @@ -19,27 +18,23 @@ pub unsafe extern "C" fn init_prover(params_path: *const c_char, _seed_path: *co /// # Safety #[no_mangle] -pub unsafe extern "C" fn create_agg_proof(trace_char: *const c_char) -> *const c_char { +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() - .create_agg_circuit_proof(&trace) - .unwrap(); + let proof = PROVER.get_mut().unwrap().gen_chunk_proof(&[trace]).unwrap(); let proof_bytes = serde_json::to_vec(&proof).unwrap(); vec_to_c_char(proof_bytes) } /// # Safety #[no_mangle] -pub unsafe extern "C" fn create_agg_proof_multi(trace_char: *const c_char) -> *const c_char { +pub unsafe extern "C" fn create_chunk_proof(trace_char: *const c_char) -> *const c_char { let trace_vec = c_char_to_vec(trace_char); let traces = serde_json::from_slice::>(&trace_vec).unwrap(); let proof = PROVER .get_mut() .unwrap() - .create_agg_circuit_proof_batch(traces.as_slice()) + .gen_chunk_proof(traces.as_slice()) .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 3609525a7..83522f23c 100644 --- a/ffi/src/verify.rs +++ b/ffi/src/verify.rs @@ -1,9 +1,7 @@ use crate::utils::{c_char_to_str, c_char_to_vec}; use libc::c_char; -use prover::utils::init_env_and_log; -use prover::zkevm; -use std::fs::File; -use std::io::Read; +use prover::{utils::init_env_and_log, zkevm, Proof}; +use std::{fs::File, io::Read}; static mut VERIFIER: Option<&zkevm::Verifier> = None; @@ -24,12 +22,9 @@ pub unsafe extern "C" fn init_verifier(params_path: *const c_char, agg_vk_path: /// # Safety #[no_mangle] -pub unsafe extern "C" fn verify_agg_proof(proof: *const c_char) -> c_char { +pub unsafe extern "C" fn verify_chunk_proof(proof: *const c_char) -> c_char { let proof_vec = c_char_to_vec(proof); - let agg_proof = serde_json::from_slice::(proof_vec.as_slice()).unwrap(); - let verified = VERIFIER - .unwrap() - .verify_agg_circuit_proof(agg_proof) - .is_ok(); + let chunk_proof = serde_json::from_slice::(proof_vec.as_slice()).unwrap(); + let verified = VERIFIER.unwrap().verify_chunk_proof(chunk_proof).is_ok(); verified as c_char } diff --git a/prover/Cargo.toml b/prover/Cargo.toml index 1891b1959..dd246692b 100644 --- a/prover/Cargo.toml +++ b/prover/Cargo.toml @@ -17,30 +17,31 @@ mock = { git = "https://github.com/scroll-tech/zkevm-circuits", branch = "develo snark-verifier = { git = "https://github.com/scroll-tech/snark-verifier", branch = "develop" } snark-verifier-sdk = { git = "https://github.com/scroll-tech/snark-verifier", branch = "develop" } -rand = "0.8" -rand_xorshift = "0.3" -is-even = "1.0.0" +anyhow = "1.0" +blake2 = "0.10.3" +chrono = "0.4.19" +dotenv = "0.15.0" ethers-core = "0.17.0" -sha2 ="0.10.2" +git-version = "0.3.5" +glob = "0.3.0" hex = "0.4.3" -serde = "1.0" -serde_derive = "1.0" -serde_stacker = "0.1" -serde_json = { version = "1.0.66", features = ["unbounded_depth"] } -types = { path = "../types", features = ["test"] } +is-even = "1.0.0" +itertools = "0.10.5" log = "0.4" log4rs = { version = "1.2.0", default_features = false, features = ["console_appender", "file_appender"] } -anyhow = "1.0" num-bigint = "0.4.3" -blake2 = "0.10.3" -dotenv = "0.15.0" +once_cell = "1.8.0" +project-root = "0.2.2" +rand = "0.8" +rand_xorshift = "0.3" +serde = "1.0" +serde_derive = "1.0" +serde_json = { version = "1.0.66", features = ["unbounded_depth"] } +serde_stacker = "0.1" +sha2 ="0.10.2" strum = "0.24" strum_macros = "0.24" -once_cell = "1.8.0" -chrono = "0.4.19" -itertools = "0.10.5" -git-version = "0.3.5" -glob = "0.3.0" +types = { path = "../types", features = ["test"] } [target.'cfg(target_os = "linux")'.dependencies] procfs = "0.13.0" diff --git a/prover/src/evm_verifier.rs b/prover/src/evm_verifier.rs new file mode 100644 index 000000000..d93723f8a --- /dev/null +++ b/prover/src/evm_verifier.rs @@ -0,0 +1,24 @@ +use super::Proof; +use halo2_proofs::halo2curves::bn256::Fr; +use snark_verifier_sdk::evm_verify; + +pub struct EvmVerifier { + bytecode: Vec, +} + +impl EvmVerifier { + pub fn new(bytecode: Vec) -> Self { + Self { bytecode } + } + + /// Verifies the proof with EVM byte code. Panics if verification fails. + pub fn verify(&self, instances: Vec>, proof: Vec) { + evm_verify(self.bytecode.clone(), instances, proof) + } + + /// Verifies the proof with EVM byte code. Panics if verification fails. + pub fn verify_proof(&self, proof: Proof) { + let instances = proof.deserialize_instance(); + evm_verify(self.bytecode.clone(), instances, proof.proof) + } +} diff --git a/prover/src/io.rs b/prover/src/io.rs index 8540bb56c..5c57ca214 100644 --- a/prover/src/io.rs +++ b/prover/src/io.rs @@ -1,6 +1,9 @@ +use anyhow; +use num_bigint::BigUint; use std::{ + fs::File, io::{Cursor, Read, Write}, - path::PathBuf, + path::{Path, PathBuf}, }; use halo2_proofs::{ @@ -9,8 +12,8 @@ use halo2_proofs::{ poly::{commitment::Params, kzg::commitment::ParamsKZG}, SerdeFormat, }; -use num_bigint::BigUint; use snark_verifier::util::arithmetic::PrimeField; +use snark_verifier_sdk::Snark; pub fn serialize_fr(f: &Fr) -> Vec { f.to_bytes().to_vec() @@ -197,6 +200,24 @@ pub fn write_verify_circuit_solidity(folder: &mut PathBuf, buf: &[u8]) { write_file(folder, "verifier.sol", buf) } +pub fn write_snark(file_path: &str, snark: &Snark) { + let mut fd = std::fs::File::create(file_path).unwrap(); + serde_json::to_writer_pretty(&mut fd, snark).unwrap() +} + +pub fn load_snark(file_path: &str) -> anyhow::Result> { + if !Path::new(file_path).exists() { + return Ok(None); + } + + let fd = File::open(file_path)?; + let mut deserializer = serde_json::Deserializer::from_reader(fd); + deserializer.disable_recursion_limit(); + let deserializer = serde_stacker::Deserializer::new(&mut deserializer); + let snark = serde::Deserialize::deserialize(deserializer)?; + Ok(Some(snark)) +} + pub fn load_instances(buf: &[u8]) -> Vec>> { let instances: Vec>>> = serde_json::from_reader(buf).unwrap(); instances diff --git a/prover/src/lib.rs b/prover/src/lib.rs index 9a0ec3687..3e7318416 100644 --- a/prover/src/lib.rs +++ b/prover/src/lib.rs @@ -1,18 +1,25 @@ pub mod aggregator; +mod evm_verifier; pub mod io; +pub mod proof; pub mod test_util; pub mod utils; pub mod zkevm; +pub use evm_verifier::EvmVerifier; +pub use proof::Proof; + // Terminology used throughout this library. // // - Inner Circuit / Target Circuit / Super Circuit: they all mean the same thing. -// The first circuit. It takes inputs from block traces, and produces proofs pi_1 that are NOT verified on chain. +// The first circuit. It takes inputs from block traces, and produces proofs pi_1 that are NOT +// verified on chain. // // - Target Circuit proof: proof for the Inner circuit. // // - Aggregation Circuit. -// The second circuit. It takes pi_1 from previous section, and produces proofs pi_2 that are verified on chain. +// The second circuit. It takes pi_1 from previous section, and produces proofs pi_2 that are +// verified on chain. // // - AggCircuitProof: proof for the aggregation circuit. // @@ -20,13 +27,13 @@ pub mod zkevm; // I.e., aggregation prover that takes in a list of traces, produces // a proof that can be verified on chain -pub mod proof { - use crate::zkevm::AggCircuitProof; - use serde_derive::{Deserialize, Serialize}; +// pub mod proof { +// use crate::zkevm::AggCircuitProof; +// use serde_derive::{Deserialize, Serialize}; - #[derive(Serialize, Deserialize, Debug)] - pub struct ZkProof { - pub id: u64, - pub agg_proof: AggCircuitProof, - } -} +// #[derive(Serialize, Deserialize, Debug)] +// pub struct ZkProof { +// pub id: u64, +// pub agg_proof: AggCircuitProof, +// } +// } diff --git a/prover/src/proof.rs b/prover/src/proof.rs new file mode 100644 index 000000000..85be42ff3 --- /dev/null +++ b/prover/src/proof.rs @@ -0,0 +1,114 @@ +use crate::io::{deserialize_fr_matrix, serialize_fr_matrix, serialize_vk, write_file}; +use anyhow::Result; +use halo2_proofs::{ + halo2curves::bn256::{Fr, G1Affine}, + plonk::ProvingKey, +}; +use serde_derive::{Deserialize, Serialize}; +use snark_verifier::{ + util::{ + arithmetic::Domain, + protocol::{Expression, QuotientPolynomial}, + }, + Protocol, +}; +use snark_verifier_sdk::Snark; +use std::{ + fs::File, + path::{Path, PathBuf}, +}; +use types::base64; + +#[derive(Deserialize, Serialize, Debug, Default)] +pub struct Proof { + #[serde(with = "base64")] + pub proof: Vec, + #[serde(with = "base64")] + pub instance: Vec, + #[serde(with = "base64")] + pub vk: Vec, +} + +impl Proof { + pub fn from_snark(pk: &ProvingKey, snark: &Snark) -> anyhow::Result { + // Serialize instances + let instances = serialize_fr_matrix(snark.instances.as_slice()); + let instance_bytes = serde_json::to_vec(&instances)?; + + // Serialize vk + let vk_bytes = serialize_vk(pk.get_vk()); + + Ok(Proof { + proof: snark.proof.clone(), + instance: instance_bytes, + vk: vk_bytes, + }) + } + + pub fn to_snark(&self) -> Snark { + let instances = self.deserialize_instance(); + Snark { + protocol: dummy_protocol(), + instances, + proof: self.proof.clone(), + } + } + + pub fn deserialize_instance(&self) -> Vec> { + let l3_buf: Vec>> = serde_json::from_reader(self.instance.as_slice()).unwrap(); + deserialize_fr_matrix(l3_buf) + } + + pub fn dump(&self, dir: &mut PathBuf, name: &str) -> Result<()> { + write_file(dir, &format!("{name}_instance.data"), &self.instance); + write_file(dir, &format!("{name}_proof.data"), &self.proof); + write_file(dir, &format!("{name}.vkey"), &self.proof); + + dir.push("{}_full_proof.json"); + let mut fd = std::fs::File::create(dir.as_path())?; + dir.pop(); + serde_json::to_writer_pretty(&mut fd, &self)?; + + Ok(()) + } + + pub fn load_from_json(file_path: &str) -> Result> { + if !Path::new(file_path).exists() { + return Ok(None); + } + + let fd = File::open(file_path)?; + let mut deserializer = serde_json::Deserializer::from_reader(fd); + deserializer.disable_recursion_limit(); + let deserializer = serde_stacker::Deserializer::new(&mut deserializer); + let proof = serde::Deserialize::deserialize(deserializer)?; + Ok(Some(proof)) + } +} + +fn dummy_protocol() -> Protocol { + Protocol { + domain: Domain { + k: 0, + n: 0, + n_inv: Fr::zero(), + gen: Fr::zero(), + gen_inv: Fr::zero(), + }, + preprocessed: vec![], + num_instance: vec![], + num_witness: vec![], + num_challenge: vec![], + evaluations: vec![], + queries: vec![], + quotient: QuotientPolynomial { + chunk_degree: 0, + numerator: Expression::Challenge(1), + }, + //Default::default(), + transcript_initial_state: None, + instance_committing_key: None, + linearization: None, + accumulator_indices: Default::default(), + } +} diff --git a/prover/src/test_util.rs b/prover/src/test_util.rs index bbc59828b..5420caf11 100644 --- a/prover/src/test_util.rs +++ b/prover/src/test_util.rs @@ -1,5 +1,4 @@ -use crate::utils::get_block_trace_from_file; -use crate::utils::read_env_var; +use crate::utils::{get_block_trace_from_file, read_env_var}; use glob::glob; use types::eth::BlockTrace; @@ -7,34 +6,6 @@ pub mod mock_plonk; pub const PARAMS_DIR: &str = "./test_params"; -pub fn load_batch_traces(batch_dir: &str) -> (Vec, Vec) { - let file_names: Vec = glob(&format!("{batch_dir}/**/*.json")) - .unwrap() - .map(|p| p.unwrap().to_str().unwrap().to_string()) - .collect(); - log::info!("test batch with {:?}", file_names); - let mut names_and_traces = file_names - .into_iter() - .map(|trace_path| { - let trace: BlockTrace = get_block_trace_from_file(trace_path.clone()); - ( - trace_path, - trace.clone(), - trace.header.number.unwrap().as_u64(), - ) - }) - .collect::>(); - names_and_traces.sort_by(|a, b| a.2.cmp(&b.2)); - log::info!( - "sorted: {:?}", - names_and_traces - .iter() - .map(|(f, _, _)| f.clone()) - .collect::>() - ); - names_and_traces.into_iter().map(|(f, t, _)| (f, t)).unzip() -} - pub fn parse_trace_path_from_mode(mode: &str) -> &'static str { let trace_path = match mode { "empty" => "./tests/traces/empty.json", @@ -72,3 +43,31 @@ pub fn load_block_traces_for_test() -> (Vec, Vec) { let traces: Vec<_> = paths.iter().map(get_block_trace_from_file).collect(); (paths, traces) } + +fn load_batch_traces(batch_dir: &str) -> (Vec, Vec) { + let file_names: Vec = glob(&format!("{batch_dir}/**/*.json")) + .unwrap() + .map(|p| p.unwrap().to_str().unwrap().to_string()) + .collect(); + log::info!("test batch with {:?}", file_names); + let mut names_and_traces = file_names + .into_iter() + .map(|trace_path| { + let trace: BlockTrace = get_block_trace_from_file(trace_path.clone()); + ( + trace_path, + trace.clone(), + trace.header.number.unwrap().as_u64(), + ) + }) + .collect::>(); + names_and_traces.sort_by(|a, b| a.2.cmp(&b.2)); + log::info!( + "sorted: {:?}", + names_and_traces + .iter() + .map(|(f, _, _)| f.clone()) + .collect::>() + ); + names_and_traces.into_iter().map(|(f, t, _)| (f, t)).unzip() +} diff --git a/prover/src/test_util/mock_plonk.rs b/prover/src/test_util/mock_plonk.rs index 37ce043a1..20024e0a2 100644 --- a/prover/src/test_util/mock_plonk.rs +++ b/prover/src/test_util/mock_plonk.rs @@ -1,9 +1,8 @@ //! A module for Mock Plonk circuit. -//! use crate::zkevm::circuit::TargetCircuit; -use halo2_proofs::halo2curves::bn256::Fr; use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner, Value}, + halo2curves::bn256::Fr, plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Fixed, Instance}, poly::Rotation, }; diff --git a/prover/src/utils.rs b/prover/src/utils.rs index 6d014f1d6..0cc087832 100644 --- a/prover/src/utils.rs +++ b/prover/src/utils.rs @@ -1,39 +1,36 @@ use anyhow::Result; use chrono::Utc; use git_version::git_version; -use halo2_proofs::arithmetic::Field; -use halo2_proofs::halo2curves::bn256::{Bn256, Fr}; -use halo2_proofs::halo2curves::FieldExt; -use halo2_proofs::poly::kzg::commitment::ParamsKZG; -use halo2_proofs::SerdeFormat; +use halo2_proofs::{ + halo2curves::bn256::{Bn256, Fr}, + poly::kzg::commitment::ParamsKZG, + SerdeFormat, +}; use log::LevelFilter; -use log4rs::append::console::{ConsoleAppender, Target}; -use log4rs::append::file::FileAppender; -use log4rs::config::{Appender, Config, Root}; -use rand::rngs::OsRng; -use std::fs::{self, metadata, File}; -use std::io::{BufReader, Read, Write}; -use std::path::{Path, PathBuf}; -use std::str::FromStr; -use std::sync::Once; +use log4rs::{ + append::{ + console::{ConsoleAppender, Target}, + file::FileAppender, + }, + config::{Appender, Config, Root}, +}; +use std::{ + fs::{self, metadata, File}, + io::{BufReader, Read}, + path::{Path, PathBuf}, + process::{Command, Stdio}, + str::FromStr, + sync::Once, +}; use types::eth::{BlockTrace, BlockTraceJsonRpcResult}; use zkevm_circuits::witness; pub const DEFAULT_SERDE_FORMAT: SerdeFormat = SerdeFormat::RawBytesUnchecked; - pub const GIT_VERSION: &str = git_version!(); - pub static LOGGER: Once = Once::new(); -fn param_path_for_degree(params_dir: &str, degree: usize) -> String { - //format!("{params_dir}/kzg_bn254_{degree}.srs") - format!("{params_dir}/params{degree}") -} - -/// return setup params by reading from file or generate new one -pub fn load_or_create_params(params_dir: &str, degree: usize) -> Result> { - let _path = PathBuf::from(params_dir); - +/// Get setup params by reading from a file or downloading a new one. +pub fn load_or_download_params(params_dir: &str, degree: usize) -> Result> { match metadata(params_dir) { Ok(md) => { if md.is_file() { @@ -41,25 +38,30 @@ pub fn load_or_create_params(params_dir: &str, degree: usize) -> Result { - // not exist + // Not exist fs::create_dir_all(params_dir)?; } }; let params_path = param_path_for_degree(params_dir, degree); - log::info!("load_or_create_params {}", params_path); + log::info!("load_or_download_params {}", params_path); + if Path::new(¶ms_path).exists() { match load_params(¶ms_path, degree, DEFAULT_SERDE_FORMAT) { Ok(r) => return Ok(r), Err(e) => { - log::error!("load params err: {}. Recreating...", e) + log::error!( + "An error occurred when loading setup params: {}. Re-downloading ...", + e + ) } } } - create_params(¶ms_path, degree) + + download_params(params_dir, degree) } -/// load params from file +/// Load setup params from a file. pub fn load_params( params_dir: &str, degree: usize, @@ -98,31 +100,6 @@ pub fn load_params( Ok(p) } -/// create params and write it into file -pub fn create_params(params_path: &str, degree: usize) -> Result> { - log::info!("start creating params with degree {}", degree); - // The params used for production need to be generated from a trusted setup ceremony. - // Here we use a deterministic seed to generate params. This method is unsafe for production usage. - let seed_str = read_env_var("PARAM_SEED", "bb4b94a1bbef58c4b5fcda6c900629b5".to_string()); - let seed_fr = if seed_str.is_empty() { - log::info!("use OsRng to create params"); - Fr::random(OsRng) - } else { - let bytes = &mut [0u8; 64]; - bytes[..32].clone_from_slice(&seed_str.as_bytes()[..32]); - Fr::from_bytes_wide(bytes) - }; - let params: ParamsKZG = ParamsKZG::::unsafe_setup_with_s(degree as u32, seed_fr); - let mut params_buf = Vec::new(); - params.write_custom(&mut params_buf, DEFAULT_SERDE_FORMAT)?; - - let mut params_file = File::create(params_path)?; - params_file.write_all(¶ms_buf[..])?; - log::info!("create params successfully!"); - - Ok(params) -} - /// get a block-result from file pub fn get_block_trace_from_file>(path: P) -> BlockTrace { let mut buffer = Vec::new(); @@ -219,3 +196,36 @@ fn create_output_dir(id: &str) -> String { output } + +// Download setup params and write it into a file. +fn download_params(params_dir: &str, degree: usize) -> Result> { + log::warn!("Would be better to run `make download-setup` before any bins or tests"); + + log::info!("Start to download setup params"); + + let download_script_path = project_root::get_project_root()?.join("download_setup.sh"); + + Command::new("sh") + .stdout(Stdio::null()) + .args([ + download_script_path.to_string_lossy().as_ref(), + °ree.to_string(), + params_dir, + ]) + .status() + .unwrap_or_else(|e| { + panic!("Failed to download setup params with {degree} and {params_dir}: {e}") + }); + + log::info!("Finish downloading setup params"); + + load_params( + ¶m_path_for_degree(params_dir, degree), + degree, + DEFAULT_SERDE_FORMAT, + ) +} + +fn param_path_for_degree(params_dir: &str, degree: usize) -> String { + format!("{params_dir}/params{degree}") +} diff --git a/prover/src/zkevm.rs b/prover/src/zkevm.rs index 49c850c37..90ddf0720 100644 --- a/prover/src/zkevm.rs +++ b/prover/src/zkevm.rs @@ -3,6 +3,6 @@ pub mod circuit; mod prover; mod verifier; -pub use self::prover::{AggCircuitProof, Prover, TargetCircuitProof}; +pub use self::prover::Prover; pub use capacity_checker::CircuitCapacityChecker; -pub use verifier::{EvmVerifier, Verifier}; +pub use verifier::Verifier; diff --git a/prover/src/zkevm/capacity_checker.rs b/prover/src/zkevm/capacity_checker.rs index 3cf0731b5..1d2edc0e3 100644 --- a/prover/src/zkevm/capacity_checker.rs +++ b/prover/src/zkevm/capacity_checker.rs @@ -59,15 +59,16 @@ impl RowUsage { #[derive(Debug, Clone)] pub struct CircuitCapacityChecker { - /// When "light_mode" enabled, we skip zktrie subcircuit in row estimation to avoid the heavy poseidon cost. + /// When "light_mode" enabled, we skip zktrie subcircuit in row estimation to avoid the heavy + /// poseidon cost. pub light_mode: bool, pub acc_row_usage: RowUsage, pub row_usages: Vec, pub state: Option, } -// Currently TxTrace is same as BlockTrace, with "transactions" and "executionResults" should be of len 1, -// "storageProofs" should contain "slot touched" during when executing this tx. +// Currently TxTrace is same as BlockTrace, with "transactions" and "executionResults" should be of +// len 1, "storageProofs" should contain "slot touched" during when executing this tx. pub type TxTrace = BlockTrace; impl Default for CircuitCapacityChecker { diff --git a/prover/src/zkevm/circuit/builder.rs b/prover/src/zkevm/circuit/builder.rs index 3cc03d12c..705e7b3a8 100644 --- a/prover/src/zkevm/circuit/builder.rs +++ b/prover/src/zkevm/circuit/builder.rs @@ -3,21 +3,22 @@ use super::{ MAX_INNER_BLOCKS, MAX_KECCAK_ROWS, MAX_MPT_ROWS, MAX_RWS, MAX_TXS, }; use anyhow::bail; -use bus_mapping::circuit_input_builder::{self, BlockHead, CircuitInputBuilder, CircuitsParams}; -use bus_mapping::state_db::{Account, CodeDB, StateDB}; -use eth_types::evm_types::OpcodeId; -use eth_types::ToAddress; +use bus_mapping::{ + circuit_input_builder::{self, BlockHead, CircuitInputBuilder, CircuitsParams}, + state_db::{Account, CodeDB, StateDB}, +}; +use eth_types::{evm_types::OpcodeId, ToAddress}; use ethers_core::types::{Bytes, U256}; use halo2_proofs::halo2curves::bn256::Fr; use is_even::IsEven; use itertools::Itertools; use mpt_zktrie::state::ZktrieState; -use std::collections::hash_map::Entry; -use std::time::Instant; +use std::{collections::hash_map::Entry, time::Instant}; use types::eth::{BlockTrace, EthBlock, ExecStep}; -use zkevm_circuits::evm_circuit::witness::block_apply_mpt_state; -use zkevm_circuits::evm_circuit::witness::{block_convert, Block}; -use zkevm_circuits::util::SubCircuit; +use zkevm_circuits::{ + evm_circuit::witness::{block_apply_mpt_state, block_convert, Block}, + util::SubCircuit, +}; pub const SUB_CIRCUIT_NAMES: [&str; 11] = [ "evm", "state", "bytecode", "copy", "keccak", "tx", "rlp", "exp", "pi", "poseidon", "mpt", @@ -53,7 +54,6 @@ pub fn calculate_row_usage_of_witness_block( // FIXME: we need better API name for this. // This function also mutates the block trace. -/// ... pub fn check_batch_capacity(block_traces: &mut Vec) -> Result<(), anyhow::Error> { let block_traces_len = block_traces.len(); let total_tx_count = block_traces diff --git a/prover/src/zkevm/circuit/super_circuit.rs b/prover/src/zkevm/circuit/super_circuit.rs index 7ee80d957..ef0a4a728 100644 --- a/prover/src/zkevm/circuit/super_circuit.rs +++ b/prover/src/zkevm/circuit/super_circuit.rs @@ -3,8 +3,7 @@ use super::{TargetCircuit, DEGREE}; use super::{MAX_CALLDATA, MAX_INNER_BLOCKS, MAX_TXS}; use anyhow::bail; use halo2_proofs::halo2curves::bn256::Fr; -use zkevm_circuits::util::SubCircuit; -use zkevm_circuits::{super_circuit::SuperCircuit as SuperCircuitTpl, witness}; +use zkevm_circuits::{super_circuit::SuperCircuit as SuperCircuitTpl, util::SubCircuit, witness}; type SuperCircuitImpl = SuperCircuitTpl; diff --git a/prover/src/zkevm/prover.rs b/prover/src/zkevm/prover.rs index 4dcc9115f..dd309dd27 100644 --- a/prover/src/zkevm/prover.rs +++ b/prover/src/zkevm/prover.rs @@ -1,21 +1,34 @@ -use crate::utils::read_env_var; -use halo2_proofs::halo2curves::bn256::{Bn256, G1Affine}; -use halo2_proofs::plonk::ProvingKey; -use halo2_proofs::poly::kzg::commitment::ParamsKZG; +use anyhow::bail; +use log::info; use once_cell::sync::Lazy; +use rand::SeedableRng; +use rand_xorshift::XorShiftRng; use std::collections::HashMap; +use types::eth::BlockTrace; + +use super::circuit::{ + block_traces_to_witness_block, check_batch_capacity, SuperCircuit, TargetCircuit, DEGREE, +}; +use crate::{ + io::{serialize_fr_matrix, serialize_vk}, + proof::Proof, + utils::{metric_of_witness_block, read_env_var}, +}; + +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 inner_circuit; -mod inner_proof; mod mock; -mod outer_circuit; -mod outer_proof; mod util; -pub use inner_proof::TargetCircuitProof; -pub use outer_proof::AggCircuitProof; - #[cfg(target_os = "linux")] extern crate procfs; @@ -24,13 +37,161 @@ 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. +// 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 params: ParamsKZG, + pub zkevm_params: ParamsKZG, pub agg_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 target_circuit_pks: HashMap>, pub agg_pk: Option>, } + +impl Prover { + // Build a new Prover from parameters. + pub fn new(zkevm_params: ParamsKZG, agg_params: ParamsKZG) -> Self { + Self { + zkevm_params, + agg_params, + target_circuit_pks: Default::default(), + agg_pk: None, + } + } + + // 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]) -> anyhow::Result { + let inner_proof = self.gen_inner_proof::(chunk_trace)?; + // compress the inner proof using the aggregation proof + self.gen_agg_proof(vec![inner_proof]) + } + + // 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]) -> anyhow::Result { + let inner_proof = self.gen_inner_proof::(chunk_trace)?; + // compress the inner proof using the aggregation proof + self.gen_agg_evm_proof(vec![inner_proof]) + } + + // Generate the proof of the inner circuit + pub fn gen_inner_proof( + &mut self, + chunk_trace: &[BlockTrace], + ) -> anyhow::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(*DEGREE as u32, &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.target_circuit_pks.contains_key(&C::name()) { + self.gen_inner_pk::(&C::dummy_inner_circuit()); + } + let pk = &self.target_circuit_pks[&C::name()]; + + // Generate the SNARK proof for the inner circuit + let snark_proof = + gen_snark_shplonk(&self.zkevm_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) -> anyhow::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.agg_params, snarks, &mut rng); + let agg_pk = self + .agg_pk + .get_or_insert_with(|| gen_pk(&self.agg_params, &agg_circuit, None)); + + let agg_proof = gen_snark_shplonk( + &self.agg_params, + agg_pk, + agg_circuit, + &mut rng, + None::, + ); + + Proof::from_snark(agg_pk, &agg_proof) + } + + // Generate the aggregation evm proof given the proofs of inner circuit + pub fn gen_agg_evm_proof(&mut self, snarks: Vec) -> anyhow::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.agg_params, snarks, &mut rng); + let agg_pk = self + .agg_pk + .get_or_insert_with(|| gen_pk(&self.agg_params, &agg_circuit, None)); + + let agg_proof = gen_evm_proof_shplonk( + &self.agg_params, + agg_pk, + agg_circuit.clone(), + agg_circuit.instances(), + &mut rng, + ); + + let instances = serialize_fr_matrix(agg_circuit.instances().as_slice()); + let instance_bytes = serde_json::to_vec(&instances)?; + + Ok(Proof { + proof: agg_proof, + instance: instance_bytes, + vk: serialize_vk(agg_pk.get_vk()), + }) + } + + // Initiates the public key for a given inner circuit. + pub(crate) fn gen_inner_pk(&mut self, circuit: &::Inner) { + Self::tick(&format!("before init pk of {}", C::name())); + let pk = keygen_pk2(&self.zkevm_params, circuit) + .unwrap_or_else(|e| panic!("failed to generate {} pk: {:?}", C::name(), e)); + self.target_circuit_pks.insert(C::name(), pk); + Self::tick(&format!("after init pk of {}", C::name())); + } +} diff --git a/prover/src/zkevm/prover/evm.rs b/prover/src/zkevm/prover/evm.rs index c2820855c..cb7720274 100644 --- a/prover/src/zkevm/prover/evm.rs +++ b/prover/src/zkevm/prover/evm.rs @@ -1,6 +1,5 @@ use super::Prover; -use halo2_proofs::halo2curves::bn256::G1Affine; -use halo2_proofs::plonk::VerifyingKey; +use halo2_proofs::{halo2curves::bn256::G1Affine, plonk::VerifyingKey}; use snark_verifier_sdk::{gen_evm_verifier_shplonk, AggregationCircuit, CircuitExt}; use std::path::Path; diff --git a/prover/src/zkevm/prover/inner_circuit.rs b/prover/src/zkevm/prover/inner_circuit.rs deleted file mode 100644 index d61ab5d67..000000000 --- a/prover/src/zkevm/prover/inner_circuit.rs +++ /dev/null @@ -1,134 +0,0 @@ -//! Inner circuit related APIs - -use super::super::circuit::{ - block_traces_to_witness_block, check_batch_capacity, TargetCircuit, DEGREE, -}; -use super::{Prover, TargetCircuitProof, MOCK_PROVE}; -use crate::io::{serialize_instance, serialize_vk}; -use crate::utils::metric_of_witness_block; -use anyhow::{bail, Error}; -use halo2_proofs::dev::MockProver; -use halo2_proofs::halo2curves::bn256::Fr; -use log::info; -use rand::{Rng, SeedableRng}; -use rand_xorshift::XorShiftRng; -use snark_verifier_sdk::gen_snark_shplonk; -use types::eth::BlockTrace; - -impl Prover { - /// Input a list of traces, generate an instance for the outer circuit. - /// - pub fn prove_inner_circuit( - &mut self, - block_traces: &[BlockTrace], - ) -> anyhow::Result { - self.create_target_circuit_proof_batch::(block_traces) - } - - /// Input a trace, generate a proof for the outer circuit. - /// - pub fn create_target_circuit_proof( - &mut self, - block_trace: &BlockTrace, - ) -> anyhow::Result { - self.create_target_circuit_proof_batch::(&[block_trace.clone()]) - } - - /// Create a target circuit proof for a list of block traces - pub fn create_target_circuit_proof_batch( - &mut self, - block_traces: &[BlockTrace], - ) -> anyhow::Result { - let total_num_of_blocks = block_traces.len(); - - // - // Process the traces and prepare the witnesses and inputs to the inner circuits - // - let ((circuit, instance), num_of_proved_blocks) = { - let mut block_traces = block_traces.to_vec(); - check_batch_capacity(&mut block_traces)?; - let witness_block = block_traces_to_witness_block(&block_traces)?; - log::info!( - "proving batch of len {}, batch metric {:?}", - total_num_of_blocks, - metric_of_witness_block(&witness_block) - ); - ( - C::from_witness_block(&witness_block)?, - witness_block.context.ctxs.len(), - ) - }; - - // - // generate the proof for the inner circuit - // - info!( - "Create {} proof of block {} ... block {}, batch len {}", - C::name(), - block_traces[0].header.hash.unwrap(), - block_traces[block_traces.len() - 1].header.hash.unwrap(), - block_traces.len() - ); - - let seed = [0u8; 16]; - let mut rng = XorShiftRng::from_seed(seed); - self.create_target_circuit_proof_from_circuit::( - circuit, - instance, - &mut rng, - total_num_of_blocks, - num_of_proved_blocks, - ) - } - - /// - /// generate the proof for the inner circuit - /// - pub fn create_target_circuit_proof_from_circuit( - &mut self, - circuit: C::Inner, - instance: Vec>, - rng: &mut (impl Rng + Send), - total_num_of_blocks: usize, - num_of_proved_blocks: usize, - ) -> anyhow::Result { - if *MOCK_PROVE { - log::info!("mock prove {} start", C::name()); - let prover = MockProver::::run(*DEGREE as u32, &circuit, instance.clone())?; - 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.target_circuit_pks.contains_key(&C::name()) { - self.init_pk::(&C::dummy_inner_circuit()); - } - let pk = &self.target_circuit_pks[&C::name()]; - - // Generate the SNARK proof for the inner circuit - let snark_proof = gen_snark_shplonk(&self.params, pk, circuit, rng, None::); - - let instance_bytes = serialize_instance(&instance); - let name = C::name(); - log::debug!( - "{} circuit: proof {:?}, instance len {}", - name, - &snark_proof.proof[0..15], - instance_bytes.len() - ); - let target_proof = TargetCircuitProof { - name, - snark: snark_proof, - vk: serialize_vk(pk.get_vk()), - total_num_of_blocks, - num_of_proved_blocks, - }; - - Ok(target_proof) - } -} diff --git a/prover/src/zkevm/prover/inner_proof.rs b/prover/src/zkevm/prover/inner_proof.rs deleted file mode 100644 index c835f72b5..000000000 --- a/prover/src/zkevm/prover/inner_proof.rs +++ /dev/null @@ -1,41 +0,0 @@ -use anyhow::Result; -use serde_derive::{Deserialize, Serialize}; -use snark_verifier_sdk::Snark; -use std::fs::File; -use std::path::Path; -use types::base64; - -#[derive(Debug, Deserialize, Serialize)] -pub struct TargetCircuitProof { - pub name: String, - pub snark: Snark, - #[serde(with = "base64", default)] - pub vk: Vec, - pub num_of_proved_blocks: usize, - pub total_num_of_blocks: usize, -} - -impl TargetCircuitProof { - pub fn dump_to_file(&self, file_path: &str) -> Result<()> { - let mut fd = File::create(file_path)?; - serde_json::to_writer_pretty(&mut fd, self)?; - - Ok(()) - } - - /// Return the proof if file exists, otherwise return None. - pub fn restore_from_file(file_path: &str) -> Result> { - if !Path::new(file_path).exists() { - return Ok(None); - } - - let fd = File::open(file_path)?; - - let mut deserializer = serde_json::Deserializer::from_reader(fd); - deserializer.disable_recursion_limit(); - let deserializer = serde_stacker::Deserializer::new(&mut deserializer); - let proof = serde::Deserialize::deserialize(deserializer)?; - - Ok(Some(proof)) - } -} diff --git a/prover/src/zkevm/prover/mock.rs b/prover/src/zkevm/prover/mock.rs index 00bcbfdef..ce153b9ce 100644 --- a/prover/src/zkevm/prover/mock.rs +++ b/prover/src/zkevm/prover/mock.rs @@ -1,11 +1,10 @@ -use super::super::circuit::{ - block_traces_to_witness_block, check_batch_capacity, TargetCircuit, DEGREE, +use super::{ + super::circuit::{block_traces_to_witness_block, check_batch_capacity, TargetCircuit, DEGREE}, + Prover, }; -use super::Prover; use crate::utils::metric_of_witness_block; use anyhow::bail; -use halo2_proofs::dev::MockProver; -use halo2_proofs::halo2curves::bn256::Fr; +use halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; use types::eth::BlockTrace; impl Prover { diff --git a/prover/src/zkevm/prover/outer_circuit.rs b/prover/src/zkevm/prover/outer_circuit.rs deleted file mode 100644 index 7a86a909f..000000000 --- a/prover/src/zkevm/prover/outer_circuit.rs +++ /dev/null @@ -1,101 +0,0 @@ -//! This module implements outer circuit related APIs for Prover. - -use super::super::circuit::SuperCircuit; -use super::{AggCircuitProof, Prover, TargetCircuitProof}; -use crate::io::{serialize_fr_tensor, serialize_vk}; -use rand::SeedableRng; -use rand_xorshift::XorShiftRng; -use snark_verifier_sdk::{gen_evm_proof_shplonk, gen_pk, AggregationCircuit, CircuitExt}; -use types::eth::BlockTrace; - -impl Prover { - /// Input a block trace, generate a proof for the aggregation circuit. - /// This proof is verifiable by the evm. - pub fn create_agg_circuit_proof( - &mut self, - block_trace: &BlockTrace, - ) -> anyhow::Result { - self.create_agg_circuit_proof_batch(&[block_trace.clone()]) - } - - /// Input a list of block traces, generate a proof for the aggregation circuit. - /// This proof is verifiable by the evm. - pub fn create_agg_circuit_proof_batch( - &mut self, - block_traces: &[BlockTrace], - ) -> anyhow::Result { - let circuit_results: Vec = - vec![self.prove_inner_circuit::(block_traces)?]; - self.create_agg_proof_by_inner_proofs(circuit_results.as_ref()) - } - - /// Input the inner circuit proofs, output the aggregation proof. - pub fn create_agg_proof_by_inner_proofs( - &mut self, - inner_circuit_results: &[TargetCircuitProof], - ) -> anyhow::Result { - // build the aggregation circuit inputs from the inner circuit outputs - let agg_circuit = AggregationCircuit::new( - &self.agg_params, - inner_circuit_results.iter().map(|p| p.snark.clone()), - XorShiftRng::from_seed([0u8; 16]), - ); - - // total number of blocks proved - let total_proved_block_count = inner_circuit_results - .iter() - .map(|x| x.num_of_proved_blocks) - .sum(); - let total_block_count: usize = inner_circuit_results - .iter() - .map(|x| x.total_num_of_blocks) - .sum(); - - log::info!( - "create agg proof done, block proved {}/{}", - total_proved_block_count, - total_block_count - ); - - self.create_agg_proof_by_agg_circuit(&agg_circuit, total_proved_block_count) - } - - /// Input an aggregation circuit, output the aggregation proof. - /// - /// The actual work for the outer circuit prover. - /// - pub fn create_agg_proof_by_agg_circuit( - &mut self, - agg_circuit: &AggregationCircuit, - total_proved_block_count: usize, - ) -> anyhow::Result { - let seed = [0u8; 16]; - let mut rng = XorShiftRng::from_seed(seed); - let agg_pk = gen_pk(&self.agg_params, agg_circuit, None); - - let agg_proof = gen_evm_proof_shplonk( - &self.agg_params, - &agg_pk, - agg_circuit.clone(), - agg_circuit.instances(), - &mut rng, - ); - - // Serialize instances. - let instances_for_serde = serialize_fr_tensor(&[agg_circuit.instances()]); - let instance_bytes = serde_json::to_vec(&instances_for_serde)?; - - // Serialize vk. - let vk_bytes = serialize_vk(agg_pk.get_vk()); - - // Set the aggregation pk. - self.agg_pk = Some(agg_pk); - - Ok(AggCircuitProof { - proof: agg_proof, - instance: instance_bytes, - vk: vk_bytes, - total_proved_block_count, - }) - } -} diff --git a/prover/src/zkevm/prover/outer_proof.rs b/prover/src/zkevm/prover/outer_proof.rs deleted file mode 100644 index 9f2f7fb4e..000000000 --- a/prover/src/zkevm/prover/outer_proof.rs +++ /dev/null @@ -1,33 +0,0 @@ -use crate::io::{ - write_verify_circuit_instance, write_verify_circuit_proof, write_verify_circuit_vk, -}; -use anyhow::Result; -use serde_derive::{Deserialize, Serialize}; -use std::path::PathBuf; -use types::base64; - -#[derive(Deserialize, Serialize, Debug, Default)] -pub struct AggCircuitProof { - #[serde(with = "base64")] - pub proof: Vec, - #[serde(with = "base64")] - pub instance: Vec, - #[serde(with = "base64")] - pub vk: Vec, - pub total_proved_block_count: usize, -} - -impl AggCircuitProof { - pub fn dump(&self, dir: &mut PathBuf) -> Result<()> { - write_verify_circuit_instance(dir, &self.instance); - write_verify_circuit_proof(dir, &self.proof); - write_verify_circuit_vk(dir, &self.vk); - - dir.push("full_proof.data"); - let mut fd = std::fs::File::create(dir.as_path())?; - dir.pop(); - serde_json::to_writer_pretty(&mut fd, &self)?; - - Ok(()) - } -} diff --git a/prover/src/zkevm/prover/util.rs b/prover/src/zkevm/prover/util.rs index ab7b585e1..50b687238 100644 --- a/prover/src/zkevm/prover/util.rs +++ b/prover/src/zkevm/prover/util.rs @@ -1,24 +1,18 @@ //! Initialization and utility APIs for Prover. -//! -use super::super::circuit::{TargetCircuit, AGG_DEGREE, DEGREE}; -use super::Prover; +use super::{ + super::circuit::{AGG_DEGREE, DEGREE}, + Prover, +}; use crate::utils::{load_params, DEFAULT_SERDE_FORMAT}; -use halo2_proofs::halo2curves::bn256::Bn256; -use halo2_proofs::plonk::keygen_pk2; -use halo2_proofs::poly::commitment::{Params, ParamsProver}; -use halo2_proofs::poly::kzg::commitment::{ParamsKZG, ParamsVerifierKZG}; +use halo2_proofs::{ + halo2curves::bn256::Bn256, + poly::{ + commitment::{Params, ParamsProver}, + kzg::commitment::{ParamsKZG, ParamsVerifierKZG}, + }, +}; impl Prover { - /// Build a new Prover from parameters. - pub fn new(params: ParamsKZG, agg_params: ParamsKZG) -> Self { - Self { - params, - agg_params, - target_circuit_pks: Default::default(), - agg_pk: None, - } - } - /// Memory usage tracker. pub(crate) fn tick(desc: &str) { #[cfg(target_os = "linux")] @@ -35,15 +29,6 @@ impl Prover { ); } - /// Initiates the public key for a given inner circuit. - pub(crate) fn init_pk(&mut self, circuit: &::Inner) { - Self::tick(&format!("before init pk of {}", C::name())); - let pk = keygen_pk2(&self.params, circuit) - .unwrap_or_else(|e| panic!("failed to generate {} pk: {:?}", C::name(), e)); - self.target_circuit_pks.insert(C::name(), pk); - Self::tick(&format!("after init pk of {}", C::name())); - } - pub fn from_params(agg_params: ParamsKZG) -> Self { assert!(agg_params.k() == *AGG_DEGREE as u32); let mut params = agg_params.clone(); diff --git a/prover/src/zkevm/verifier.rs b/prover/src/zkevm/verifier.rs index 2415ea34e..2efd6ab47 100644 --- a/prover/src/zkevm/verifier.rs +++ b/prover/src/zkevm/verifier.rs @@ -1,27 +1,28 @@ -use std::collections::HashMap; -use std::io::Cursor; +use anyhow::anyhow; +use itertools::Itertools; +use std::{collections::HashMap, io::Cursor}; use super::circuit::{TargetCircuit, AGG_DEGREE, DEGREE}; -use super::prover::{AggCircuitProof, TargetCircuitProof}; -use crate::io::load_instances; -use crate::utils::{load_params, DEFAULT_SERDE_FORMAT}; -use anyhow::anyhow; -use halo2_proofs::halo2curves::bn256::{Bn256, Fr, G1Affine}; -use halo2_proofs::plonk::VerifyingKey; -use halo2_proofs::plonk::{keygen_vk, verify_proof}; -use halo2_proofs::poly::commitment::ParamsProver; -use halo2_proofs::poly::kzg::commitment::ParamsKZG; -use halo2_proofs::poly::kzg::multiopen::VerifierSHPLONK; -use halo2_proofs::poly::kzg::strategy::AccumulatorStrategy; -use halo2_proofs::poly::VerificationStrategy; -use halo2_proofs::transcript::TranscriptReadBuffer; +use crate::{ + proof::Proof, + utils::{load_params, DEFAULT_SERDE_FORMAT}, +}; + +use halo2_proofs::{ + halo2curves::bn256::{Bn256, G1Affine}, + plonk::{keygen_vk, verify_proof, VerifyingKey}, + poly::{ + commitment::ParamsProver, + kzg::{commitment::ParamsKZG, multiopen::VerifierSHPLONK, strategy::AccumulatorStrategy}, + VerificationStrategy, + }, + transcript::TranscriptReadBuffer, +}; use snark_verifier::system::halo2::transcript::evm::EvmTranscript; -use snark_verifier_sdk::evm_verify; -use snark_verifier_sdk::verify_snark_shplonk; -use snark_verifier_sdk::AggregationCircuit; +use snark_verifier_sdk::{verify_snark_shplonk, AggregationCircuit, Snark}; pub struct Verifier { - params: ParamsKZG, + zkevm_params: ParamsKZG, agg_params: ParamsKZG, agg_vk: Option>, target_circuit_vks: HashMap>, @@ -29,7 +30,7 @@ pub struct Verifier { impl Verifier { pub fn new( - params: ParamsKZG, + zkevm_params: ParamsKZG, agg_params: ParamsKZG, raw_agg_vk: Option>, ) -> Self { @@ -42,7 +43,7 @@ impl Verifier { }); Self { - params, + zkevm_params, agg_params, agg_vk, target_circuit_vks: Default::default(), @@ -65,66 +66,53 @@ impl Verifier { Self::from_params(params, agg_params, agg_vk) } - pub fn verify_agg_circuit_proof(&self, proof: AggCircuitProof) -> anyhow::Result { - let mut transcript = TranscriptReadBuffer::<_, G1Affine, _>::init(proof.proof.as_slice()); + pub fn verify_chunk_proof(&self, proof: Proof) -> anyhow::Result { + let vk = match self.agg_vk.clone() { + Some(k) => k, + None => panic!("aggregation verification key is missing"), + }; + + Ok(verify_snark_shplonk::( + &self.agg_params, + proof.to_snark(), + &vk, + )) + } + pub fn verify_chunk_evm_proof(&self, proof: Proof) -> anyhow::Result { let vk = match self.agg_vk.clone() { - Some(p) => p, - None => panic!("aggregation verification key is not found"), + Some(k) => k, + None => panic!("aggregation verification key is missing"), }; + let mut transcript = TranscriptReadBuffer::<_, G1Affine, _>::init(proof.proof.as_slice()); + // deserialize instances - let verify_circuit_instance: Vec>> = { - let instance = proof.instance; - load_instances(&instance) - }; - let verify_circuit_instance1: Vec> = verify_circuit_instance - .iter() - .map(|x| x.iter().map(|y| &y[..]).collect()) - .collect(); - let verify_circuit_instance2: Vec<&[&[Fr]]> = - verify_circuit_instance1.iter().map(|x| &x[..]).collect(); + let instances = proof.deserialize_instance(); + let instances = instances.iter().map(|ins| ins.as_slice()).collect_vec(); Ok(VerificationStrategy::<_, VerifierSHPLONK>::finalize( verify_proof::<_, VerifierSHPLONK, _, EvmTranscript<_, _, _, _>, _>( &self.agg_params, &vk, - AccumulatorStrategy::new(&self.params), - &verify_circuit_instance2, + AccumulatorStrategy::new(&self.zkevm_params), + &[instances.as_slice()], &mut transcript, )?, )) } - pub fn verify_target_circuit_proof( - &mut self, - proof: &TargetCircuitProof, - ) -> anyhow::Result<()> { - let verifier_params = self.params.verifier_params(); + pub fn verify_inner_proof(&mut self, snark: &Snark) -> anyhow::Result<()> { + let verifier_params = self.zkevm_params.verifier_params(); let vk = self.target_circuit_vks.entry(C::name()).or_insert_with(|| { let circuit = C::dummy_inner_circuit(); - keygen_vk(&self.params, &circuit) + keygen_vk(&self.zkevm_params, &circuit) .unwrap_or_else(|_| panic!("failed to generate {} vk", C::name())) }); - if verify_snark_shplonk::(verifier_params, proof.snark.clone(), vk) { + if verify_snark_shplonk::(verifier_params, snark.clone(), vk) { Ok(()) } else { Err(anyhow!("snark verification failed".to_string())) } } } - -pub struct EvmVerifier { - bytecode: Vec, -} - -impl EvmVerifier { - pub fn new(bytecode: Vec) -> Self { - Self { bytecode } - } - - /// Verifies the proof with EVM byte code. Panics if verification fails. - pub fn verify(&self, instances: Vec>, proof: Vec) { - evm_verify(self.bytecode.clone(), instances, proof) - } -} diff --git a/prover/tests/aggregation_tests.rs b/prover/tests/aggregation_tests.rs index 9967ab4a9..b5ed199be 100644 --- a/prover/tests/aggregation_tests.rs +++ b/prover/tests/aggregation_tests.rs @@ -1,14 +1,20 @@ -use prover::io::write_file; -use prover::test_util::{load_block_traces_for_test, PARAMS_DIR}; -use prover::utils::{init_env_and_log, load_or_create_params}; -use prover::zkevm::circuit::{SuperCircuit, TargetCircuit, AGG_DEGREE}; -use prover::zkevm::{EvmVerifier, Prover, TargetCircuitProof}; +use prover::{ + io::{load_snark, write_file, write_snark}, + test_util::{load_block_traces_for_test, PARAMS_DIR}, + utils::{init_env_and_log, load_or_download_params}, + zkevm::{ + circuit::{SuperCircuit, TargetCircuit, AGG_DEGREE}, + Prover, + }, + EvmVerifier, +}; use rand::SeedableRng; use rand_xorshift::XorShiftRng; -use snark_verifier_sdk::AggregationCircuit; -use snark_verifier_sdk::CircuitExt; -use std::path::{Path, PathBuf}; -use std::str::FromStr; +use snark_verifier_sdk::{AggregationCircuit, CircuitExt}; +use std::{ + path::{Path, PathBuf}, + str::FromStr, +}; // An end to end integration test. // The inner snark proofs are generated from a mock circuit @@ -39,7 +45,7 @@ fn test_aggregation_api() { // 1. instantiation the parameters and the prover // - let params = load_or_create_params(PARAMS_DIR, *AGG_DEGREE).unwrap(); + let params = load_or_download_params(PARAMS_DIR, *AGG_DEGREE).unwrap(); let mut prover = Prover::from_params(params); log::info!("build prover"); @@ -47,18 +53,18 @@ fn test_aggregation_api() { // 2. read inner circuit proofs (a.k.a. SNARKs) from previous dumped file or // convert block traces into // - let inner_proof_file_path = format!("{}/{}_proof.json", output_dir, SuperCircuit::name()); - let inner_proof = TargetCircuitProof::restore_from_file(&inner_proof_file_path) + let inner_proof_file_path = format!("{}/{}_snark.json", output_dir, SuperCircuit::name()); + let inner_proof = load_snark(&inner_proof_file_path) .unwrap() .unwrap_or_else(|| { - let proof = prover - .create_target_circuit_proof_batch::(block_traces.as_ref()) + let snark = prover + .gen_inner_proof::(block_traces.as_slice()) .unwrap(); // Dump inner circuit proof. - proof.dump_to_file(&inner_proof_file_path).unwrap(); + write_snark(&inner_proof_file_path, &snark); - proof + snark }); log::info!("got super circuit proof"); @@ -67,17 +73,14 @@ fn test_aggregation_api() { // 3. build an aggregation circuit proof let agg_circuit = AggregationCircuit::new( &prover.agg_params, - [inner_proof.snark.clone()], + vec![inner_proof.clone()], XorShiftRng::from_seed([0u8; 16]), ); - let proved_block_count = inner_proof.num_of_proved_blocks; - let outer_proof = prover - .create_agg_proof_by_agg_circuit(&agg_circuit, proved_block_count) - .unwrap(); + let chunk_proof = prover.gen_agg_evm_proof(vec![inner_proof]).unwrap(); // Dump aggregation proof, vk and instance. - outer_proof.dump(&mut output_path).unwrap(); + chunk_proof.dump(&mut output_path, &"chunk").unwrap(); log::info!("finished aggregation generation"); @@ -95,6 +98,6 @@ fn test_aggregation_api() { log::info!("finished byte code generation"); // 5. validate the proof with evm bytecode - EvmVerifier::new(deployment_code).verify(agg_circuit.instances(), outer_proof.proof); + EvmVerifier::new(deployment_code).verify(agg_circuit.instances(), chunk_proof.proof); log::info!("end to end test completed"); } diff --git a/prover/tests/integration.rs b/prover/tests/integration.rs index eb54ed9be..4e3752bb8 100644 --- a/prover/tests/integration.rs +++ b/prover/tests/integration.rs @@ -1,12 +1,14 @@ use chrono::Utc; use halo2_proofs::{plonk::keygen_vk, SerdeFormat}; -use prover::io::serialize_vk; -use prover::test_util::{load_block_traces_for_test, PARAMS_DIR}; -use prover::utils::{ - get_block_trace_from_file, init_env_and_log, load_or_create_params, load_params, +use prover::{ + io::serialize_vk, + test_util::{load_block_traces_for_test, PARAMS_DIR}, + utils::{get_block_trace_from_file, init_env_and_log, load_or_download_params, load_params}, + zkevm::{ + circuit::{SuperCircuit, TargetCircuit, DEGREE}, + CircuitCapacityChecker, Prover, Verifier, + }, }; -use prover::zkevm::circuit::{SuperCircuit, TargetCircuit, DEGREE}; -use prover::zkevm::{CircuitCapacityChecker, Prover, Verifier}; use zkevm_circuits::util::SubCircuit; @@ -56,10 +58,11 @@ fn test_capacity_checker() { // the capacity_checker is expected to be used inside sequencer, where we don't have the // traces of blocks, instead we only have traces of tx. // For the "TxTrace": - // transactions: the tx itself. For compatibility reasons, transactions is a vector of len 1 now. - // execution_results: tx execution trace. Similar with above, it is also of len 1 vevtor. - // storage_trace: - // storage_trace is prestate + siblings(or proofs) of touched storage_slots and accounts of this tx. + // transactions: the tx itself. For compatibility reasons, transactions is a vector of + // len 1 now. execution_results: tx execution trace. Similar with above, + // it is also of len 1 vevtor. storage_trace: + // storage_trace is prestate + siblings(or proofs) of touched storage_slots and + // accounts of this tx. let mut tx_trace = block.clone(); tx_trace.transactions = vec![tx_trace.transactions[i].clone()]; tx_trace.execution_results = vec![tx_trace.execution_results[i].clone()]; @@ -138,7 +141,7 @@ fn test_vk_same() { init_env_and_log("integration"); type C = SuperCircuit; let block_trace = load_block_traces_for_test().1; - let params = load_or_create_params(PARAMS_DIR, *DEGREE).unwrap(); + let params = load_or_download_params(PARAMS_DIR, *DEGREE).unwrap(); let dummy_circuit = C::dummy_inner_circuit(); let real_circuit = C::from_block_traces(&block_trace).unwrap().0; @@ -211,7 +214,7 @@ fn test_target_circuit_prove_verify() { let now = Instant::now(); let mut prover = Prover::from_param_dir(PARAMS_DIR); let proof = prover - .create_target_circuit_proof_batch::(&block_traces) + .gen_inner_proof::(block_traces.as_slice()) .unwrap(); log::info!("finish generating proof, elapsed: {:?}", now.elapsed()); @@ -227,6 +230,6 @@ fn test_target_circuit_prove_verify() { log::info!("start verifying proof"); let now = Instant::now(); let mut verifier = Verifier::from_fpath(PARAMS_DIR, None); - assert!(verifier.verify_target_circuit_proof::(&proof).is_ok()); + assert!(verifier.verify_inner_proof::(&proof).is_ok()); log::info!("finish verifying proof, elapsed: {:?}", now.elapsed()); } diff --git a/prover/tests/snark_verifier_api.rs b/prover/tests/snark_verifier_api.rs index 91ae92b0b..1dffb758c 100644 --- a/prover/tests/snark_verifier_api.rs +++ b/prover/tests/snark_verifier_api.rs @@ -1,22 +1,24 @@ use halo2_proofs::poly::commitment::Params; -use mock_plonk::MockPlonkCircuit; -use mock_plonk::StandardPlonk; -use prover::test_util; -use prover::utils::init_env_and_log; -use prover::zkevm::{EvmVerifier, Prover, Verifier}; +use mock_plonk::{MockPlonkCircuit, StandardPlonk}; +use prover::{ + test_util, + utils::init_env_and_log, + zkevm::{Prover, Verifier}, + EvmVerifier, +}; use rand::SeedableRng; use rand_xorshift::XorShiftRng; -use snark_verifier_sdk::AggregationCircuit; -use snark_verifier_sdk::CircuitExt; -use snark_verifier_sdk::{evm_verify, gen_evm_proof_shplonk, gen_evm_verifier_shplonk}; -use snark_verifier_sdk::{gen_pk, gen_snark_shplonk}; +use snark_verifier_sdk::{ + evm_verify, gen_evm_proof_shplonk, gen_evm_verifier_shplonk, gen_pk, gen_snark_shplonk, + AggregationCircuit, CircuitExt, +}; use test_util::mock_plonk; // This is essentially a same test as snark-verifier/evm-verifier #[cfg(feature = "prove_verify")] #[test] fn test_snark_verifier_sdk_api() { - use prover::utils::load_or_create_params; + use prover::utils::load_or_download_params; use crate::test_util::PARAMS_DIR; @@ -29,7 +31,7 @@ fn test_snark_verifier_sdk_api() { let mut rng = XorShiftRng::from_seed([0u8; 16]); let circuit = StandardPlonk::rand(&mut rng); - let params_outer = load_or_create_params(PARAMS_DIR, k_agg).unwrap(); + let params_outer = load_or_download_params(PARAMS_DIR, k_agg).unwrap(); let params_inner = { let mut params = params_outer.clone(); params.downsize(k); @@ -73,101 +75,101 @@ fn test_snark_verifier_sdk_api() { evm_verify(deployment_code, instances, proof) } -// A partial integration test. -// The inner snark proofs are generated from a mock circuit -// instead of the trace files. -#[cfg(feature = "prove_verify")] -#[test] -fn test_partial_aggregation_api() { - use prover::utils::load_or_create_params; - - use crate::test_util::PARAMS_DIR; - - std::env::set_var("VERIFY_CONFIG", "./configs/verify_circuit.config"); - - init_env_and_log("snark_verifier_api"); - let num_snarks = 3; - - // ==================================================== - // A whole aggregation procedure takes the following steps - // 1. instantiation the parameters and the prover - // 2. convert block traces into inner circuit proofs, a.k.a. SNARKs - // 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 k = 8; - let k_agg = 23; - let seed = [0u8; 16]; - let mut rng = XorShiftRng::from_seed(seed); - - // notice that k < k_agg which is not necessary the case in practice - let params_outer = load_or_create_params(PARAMS_DIR, k_agg).unwrap(); - let params_inner = { - let mut params = params_outer.clone(); - params.downsize(k); - params - }; - log::info!("loaded parameters for degrees {} and {}", k, k_agg); - let circuit = StandardPlonk::rand(&mut rng); - let mut prover = Prover::from_params(params_outer.clone()); - // - // 2. convert block traces into inner circuit proofs, a.k.a. SNARKs - // - // Note: - // we do not have traces for testing so here we simply assume that we have already - // obtained 3 inner circuits proofs for some dummy circuit - let target_circuit_proof = (0..num_snarks) - .map(|_| { - prover - .create_target_circuit_proof_from_circuit::( - circuit, - circuit.instances(), - &mut rng, - 0, - 0, - ) - .unwrap() - }) - .collect::>(); - log::info!("finished inner circuit snark generation"); - - // sanity check: the inner proof is correct - let mut verifier = Verifier::new(params_inner, params_outer.clone(), None); - for i in 0..num_snarks { - verifier - .verify_target_circuit_proof::(&target_circuit_proof[i]) - .unwrap(); - } - log::info!("sanity check: inner circuit snark are correct"); - - // 3. build an aggregation circuit proof - let snarks = target_circuit_proof - .iter() - .map(|p| p.snark.clone()) - .collect::>(); - let agg_circuit = AggregationCircuit::new(¶ms_outer, snarks, &mut rng); - let pk_outer = gen_pk(¶ms_outer, &agg_circuit, None); - - let instances = agg_circuit.instances(); - let proof = gen_evm_proof_shplonk( - ¶ms_outer, - &pk_outer, - agg_circuit.clone(), - instances.clone(), - &mut rng, - ); - log::info!("finished aggregation generation"); - - // 4. generate bytecode for evm to verify aggregation circuit proof - let deployment_code = - prover.create_evm_verifier_bytecode(&agg_circuit, pk_outer.get_vk(), None); - log::info!("finished byte code generation"); - - // 5. validate the proof with evm bytecode - EvmVerifier::new(deployment_code).verify(instances, proof); - log::info!("end to end test completed"); -} +// // A partial integration test. +// // The inner snark proofs are generated from a mock circuit +// // instead of the trace files. +// #[cfg(feature = "prove_verify")] +// #[test] +// fn test_partial_aggregation_api() { +// use prover::utils::load_or_download_params; + +// use crate::test_util::PARAMS_DIR; + +// std::env::set_var("VERIFY_CONFIG", "./configs/verify_circuit.config"); + +// init_env_and_log("snark_verifier_api"); +// let num_snarks = 3; + +// // ==================================================== +// // A whole aggregation procedure takes the following steps +// // 1. instantiation the parameters and the prover +// // 2. convert block traces into inner circuit proofs, a.k.a. SNARKs +// // 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 k = 8; +// let k_agg = 23; +// let seed = [0u8; 16]; +// let mut rng = XorShiftRng::from_seed(seed); + +// // notice that k < k_agg which is not necessary the case in practice +// let params_outer = load_or_download_params(PARAMS_DIR, k_agg).unwrap(); +// let params_inner = { +// let mut params = params_outer.clone(); +// params.downsize(k); +// params +// }; +// log::info!("loaded parameters for degrees {} and {}", k, k_agg); +// let circuit = StandardPlonk::rand(&mut rng); +// let mut prover = Prover::from_params(params_outer.clone()); +// // +// // 2. convert block traces into inner circuit proofs, a.k.a. SNARKs +// // +// // Note: +// // we do not have traces for testing so here we simply assume that we have already +// // obtained 3 inner circuits proofs for some dummy circuit +// let target_circuit_proof = (0..num_snarks) +// .map(|_| { +// prover +// .gen_inner_proof::( +// circuit, +// circuit.instances(), +// &mut rng, +// 0, +// 0, +// ) +// .unwrap() +// }) +// .collect::>(); +// log::info!("finished inner circuit snark generation"); + +// // sanity check: the inner proof is correct +// let mut verifier = Verifier::new(params_inner, params_outer.clone(), None); +// for i in 0..num_snarks { +// verifier +// .verify_target_circuit_proof::(&target_circuit_proof[i]) +// .unwrap(); +// } +// log::info!("sanity check: inner circuit snark are correct"); + +// // 3. build an aggregation circuit proof +// let snarks = target_circuit_proof +// .iter() +// .map(|p| p.snark.clone()) +// .collect::>(); +// let agg_circuit = AggregationCircuit::new(¶ms_outer, snarks, &mut rng); +// let pk_outer = gen_pk(¶ms_outer, &agg_circuit, None); + +// let instances = agg_circuit.instances(); +// let proof = gen_evm_proof_shplonk( +// ¶ms_outer, +// &pk_outer, +// agg_circuit.clone(), +// instances.clone(), +// &mut rng, +// ); +// log::info!("finished aggregation generation"); + +// // 4. generate bytecode for evm to verify aggregation circuit proof +// let deployment_code = +// prover.create_evm_verifier_bytecode(&agg_circuit, pk_outer.get_vk(), None); +// log::info!("finished byte code generation"); + +// // 5. validate the proof with evm bytecode +// EvmVerifier::new(deployment_code).verify(instances, proof); +// log::info!("end to end test completed"); +// } diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 000000000..b7a601326 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,9 @@ +edition = "2021" + +comment_width = 100 +imports_granularity = "Crate" +max_width = 100 +newline_style = "Unix" +# normalize_comments = true +reorder_imports = true +wrap_comments = true diff --git a/types/src/eth.rs b/types/src/eth.rs index 210e5bd33..4e745bde1 100644 --- a/types/src/eth.rs +++ b/types/src/eth.rs @@ -1,5 +1,7 @@ -use eth_types::evm_types::{Gas, GasCost, OpcodeId, ProgramCounter, Stack, Storage}; -use eth_types::{Block, GethExecStep, GethExecTrace, Hash, Transaction, Word, H256}; +use eth_types::{ + evm_types::{Gas, GasCost, OpcodeId, ProgramCounter, Stack, Storage}, + Block, GethExecStep, GethExecTrace, Hash, Transaction, Word, H256, +}; use ethers_core::types::{Address, Bytes, U256, U64}; use serde::{Deserialize, Deserializer, Serialize}; use std::collections::HashMap;