diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 83241dca..bf37686f 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -236,6 +236,33 @@ jobs: - name: KZG prove and verify tests run: cargo test --release --verbose tests::kzg_prove_and_verify_ -- --test-threads 8 + fuzz-tests: + runs-on: ubuntu-latest-32-cores + needs: + [ + build, + build-wasm, + library-tests, + mock-proving-tests, + mock-proving-tests-wasi, + python-tests, + ] + steps: + - uses: actions/checkout@v3 + - uses: actions-rs/toolchain@v1 + with: + toolchain: nightly-2022-11-03 + override: true + components: rustfmt, clippy + - name: Install solc + run: (hash svm 2>/dev/null || cargo install svm-rs) && svm install 0.8.17 && solc --version + - name: Install Anvil + run: cargo install --git https://github.com/foundry-rs/foundry --profile local --locked foundry-cli anvil + - name: fuzz tests (EVM) + run: cargo test --release --verbose tests_evm::kzg_evm_fuzz_ -- --test-threads 6 + - name: fuzz tests + run: cargo test --release --verbose tests::kzg_fuzz_ -- --test-threads 6 + prove-and-verify-aggr-tests: runs-on: self-hosted needs: @@ -278,7 +305,7 @@ jobs: - name: Install solc run: (hash svm 2>/dev/null || cargo install svm-rs) && svm install 0.8.17 && solc --version - name: Install Anvil - run: cargo install --git https://github.com/foundry-rs/foundry --profile local --locked foundry-cli anvil + run: cargo install --git https://github.com/foundry-rs/foundry --profile local --locked foundry-cli anvil - name: KZG prove and verify aggr tests run: cargo test --release --verbose tests_evm::kzg_evm_aggr_prove_and_verify_ -- --include-ignored --test-threads 8 diff --git a/Cargo.lock b/Cargo.lock index 9e79501a..fa2a250b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -712,6 +712,7 @@ dependencies = [ "encode_unicode", "lazy_static", "libc", + "unicode-width", "windows-sys 0.42.0", ] @@ -1684,10 +1685,12 @@ dependencies = [ "ethereum-types", "ethers", "ethers-solc", + "gag", "getrandom", "halo2_proofs", "halo2curves", "hex", + "indicatif 0.17.4", "itertools", "lazy_static", "log", @@ -1736,6 +1739,17 @@ dependencies = [ "subtle", ] +[[package]] +name = "filedescriptor" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7199d965852c3bac31f779ef99cbb4537f80e952e2d6aa0ffeb30cce00f4f46e" +dependencies = [ + "libc", + "thiserror", + "winapi", +] + [[package]] name = "filetime" version = "0.2.20" @@ -1998,6 +2012,16 @@ dependencies = [ "byteorder", ] +[[package]] +name = "gag" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a713bee13966e9fbffdf7193af71d54a6b35a0bb34997cd6c9519ebeb5005972" +dependencies = [ + "filedescriptor", + "tempfile", +] + [[package]] name = "generic-array" version = "0.14.6" @@ -2453,6 +2477,20 @@ dependencies = [ "regex", ] +[[package]] +name = "indicatif" +version = "0.17.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db45317f37ef454e6519b6c3ed7d377e5f23346f0823f86e65ca36912d1d0ef8" +dependencies = [ + "console 0.15.5", + "instant", + "number_prefix", + "portable-atomic", + "rayon", + "unicode-width", +] + [[package]] name = "indoc" version = "1.0.9" @@ -3519,6 +3557,12 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "portable-atomic" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc59d1bcc64fc5d021d67521f818db868368028108d37f0e98d74e33f68297b5" + [[package]] name = "poseidon" version = "0.2.0" @@ -4682,7 +4726,7 @@ dependencies = [ "fs2", "hex", "home", - "indicatif", + "indicatif 0.16.2", "itertools", "once_cell", "rand 0.8.5", diff --git a/Cargo.toml b/Cargo.toml index c97d4f31..1523ac8c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,7 @@ tokio = { version = "1.26.0", features = ["macros", "rt"] } rayon = "*" bincode = "*" + # python binding related deps pyo3 = { version = "0.18.3", features = ["extension-module", "abi3-py37"], optional = true } pyo3-log = { version = "0.8.1", optional = true } @@ -48,6 +49,8 @@ pyo3-log = { version = "0.8.1", optional = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] ethers = { version = "2.0.1", features = ["ledger"] } ethers-solc = "2.0.1" +indicatif = {version = "0.17.4", features = ["rayon"]} +gag = "1.0.0" [target.'cfg(target_arch = "wasm32")'.dependencies] getrandom = { version = "0.2.8", features = ["js"] } diff --git a/src/commands.rs b/src/commands.rs index 26c0b92a..581d3e0d 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -326,6 +326,31 @@ pub enum Commands { #[clap(flatten)] args: RunArgs, }, + #[cfg(not(target_arch = "wasm32"))] + /// Loads model, data, and creates proof + #[command(arg_required_else_help = true)] + Fuzz { + /// The path to the .json data file, which should include both the network input (possibly private) and the network output (public input to the proof) + #[arg(short = 'D', long)] + data: String, + /// The path to the .onnx model file + #[arg(short = 'M', long)] + model: PathBuf, + #[arg( + long, + require_equals = true, + num_args = 0..=1, + default_value_t = TranscriptType::Blake, + value_enum + )] + transcript: TranscriptType, + /// proving arguments + #[clap(flatten)] + args: RunArgs, + /// number of fuzz iterations + #[arg(long)] + num_runs: usize, + }, /// Loads model, data, and creates proof #[command(arg_required_else_help = true)] @@ -430,7 +455,7 @@ pub enum Commands { /// Lower values optimze for deployment size while higher values optimize for execution cost. /// If not set will just use the default unoptimized SOLC configuration. #[arg(long)] - optimizer_runs: Option + optimizer_runs: Option, }, #[cfg(not(target_arch = "wasm32"))] @@ -505,7 +530,7 @@ pub enum Commands { /// Lower values optimze for deployment size while higher values optimize for execution cost. /// If not set will just use the default unoptimized SOLC configuration. #[arg(long)] - optimizer_runs: Option + optimizer_runs: Option, }, /// Print the proof in hexadecimal diff --git a/src/execute.rs b/src/execute.rs index 6fa9b1a4..31625555 100644 --- a/src/execute.rs +++ b/src/execute.rs @@ -1,6 +1,5 @@ use crate::circuit::CheckMode; use crate::commands::{Cli, Commands, RunArgs, StrategyType}; -use crate::pfsys::evm::{DeploymentCode,YulCode}; #[cfg(not(target_arch = "wasm32"))] use crate::eth::{ deploy_verifier, fix_verifier_sol, get_ledger_signing_provider, get_provider, @@ -9,15 +8,18 @@ use crate::eth::{ use crate::graph::{quantize_float, scale_to_multiplier, Model, ModelCircuit, ModelParams}; use crate::pfsys::evm::aggregation::{AggregationCircuit, PoseidonTranscript}; #[cfg(not(target_arch = "wasm32"))] -use crate::pfsys::evm::{aggregation::gen_aggregation_evm_verifier, single::gen_evm_verifier}; -#[cfg(not(target_arch = "wasm32"))] use crate::pfsys::evm::evm_verify; +#[cfg(not(target_arch = "wasm32"))] +use crate::pfsys::evm::{aggregation::gen_aggregation_evm_verifier, single::gen_evm_verifier}; +use crate::pfsys::evm::{DeploymentCode, YulCode}; use crate::pfsys::{ create_keys, load_params, load_pk, load_vk, save_params, save_pk, Snark, TranscriptType, }; use crate::pfsys::{create_proof_circuit, gen_srs, prepare_data, save_vk, verify_proof_circuit}; #[cfg(not(target_arch = "wasm32"))] use ethers::providers::Middleware; +#[cfg(not(target_arch = "wasm32"))] +use gag::Gag; use halo2_proofs::dev::VerifyFailure; use halo2_proofs::plonk::{Circuit, ProvingKey, VerifyingKey}; use halo2_proofs::poly::commitment::Params; @@ -31,12 +33,20 @@ use halo2_proofs::poly::VerificationStrategy; use halo2_proofs::transcript::{Blake2bRead, Blake2bWrite, Challenge255}; use halo2_proofs::{dev::MockProver, poly::commitment::ParamsProver}; use halo2curves::bn256::{Bn256, Fr, G1Affine}; +#[cfg(not(target_arch = "wasm32"))] +use halo2curves::ff::Field; +#[cfg(not(target_arch = "wasm32"))] +use indicatif::ParallelProgressIterator; use itertools::Itertools; #[cfg(not(target_arch = "wasm32"))] use log::warn; use log::{info, trace}; #[cfg(feature = "render")] use plotters::prelude::*; +#[cfg(not(target_arch = "wasm32"))] +use rand::Rng; +#[cfg(not(target_arch = "wasm32"))] +use rayon::prelude::IntoParallelIterator; use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; use snark_verifier::loader::evm; use snark_verifier::loader::native::NativeLoader; @@ -49,6 +59,8 @@ use std::fs::File; use std::io::Write; use std::path::PathBuf; #[cfg(not(target_arch = "wasm32"))] +use std::sync::atomic::{AtomicBool, AtomicI64, Ordering}; +#[cfg(not(target_arch = "wasm32"))] use std::sync::Arc; use std::time::Instant; use thiserror::Error; @@ -64,6 +76,14 @@ pub enum ExecutionError { /// Run an ezkl command with given args pub async fn run(cli: Cli) -> Result<(), Box> { match cli.command { + #[cfg(not(target_arch = "wasm32"))] + Commands::Fuzz { + data, + model: _, + transcript, + args, + num_runs, + } => fuzz(args.logrows, data, transcript, num_runs), #[cfg(not(target_arch = "wasm32"))] Commands::SendProofEVM { secret, @@ -79,7 +99,16 @@ pub async fn run(cli: Cli) -> Result<(), Box> { deployment_code_path, sol_code_path, optimizer_runs, - } => deploy_verifier_evm(secret, rpc_url, deployment_code_path, sol_code_path, optimizer_runs).await, + } => { + deploy_verifier_evm( + secret, + rpc_url, + deployment_code_path, + sol_code_path, + optimizer_runs, + ) + .await + } Commands::GenSrs { params_path, logrows, @@ -114,7 +143,9 @@ pub async fn run(cli: Cli) -> Result<(), Box> { params_path, deployment_code_path, sol_code_path, - } => create_evm_aggregate_verifier(vk_path, params_path, deployment_code_path, sol_code_path), + } => { + create_evm_aggregate_verifier(vk_path, params_path, deployment_code_path, sol_code_path) + } Commands::Setup { data, params_path, @@ -182,8 +213,16 @@ pub async fn run(cli: Cli) -> Result<(), Box> { proof_path, deployment_code_path, sol_code_path, - optimizer_runs - } => verify_evm(proof_path, deployment_code_path, sol_code_path, optimizer_runs).await, + optimizer_runs, + } => { + verify_evm( + proof_path, + deployment_code_path, + sol_code_path, + optimizer_runs, + ) + .await + } Commands::PrintProofHex { proof_path } => print_proof_hex(proof_path), } } @@ -334,7 +373,7 @@ async fn deploy_verifier_evm( rpc_url: String, deployment_code_path: Option, sol_code_path: Option, - runs: Option + runs: Option, ) -> Result<(), Box> { let provider = get_provider(&rpc_url)?; let chain_id = provider.get_chainid().await?; @@ -435,7 +474,7 @@ fn print_proof_hex(proof_path: PathBuf) -> Result<(), Box> { /// helper function to generate the deployment code from yul code pub fn gen_deployment_code(yul_code: YulCode) -> Result> { Ok(DeploymentCode { - code: evm::compile_yul(&yul_code) + code: evm::compile_yul(&yul_code), }) } @@ -501,18 +540,14 @@ async fn verify_evm( proof_path: PathBuf, deployment_code_path: PathBuf, sol_code_path: Option, - runs: Option + runs: Option, ) -> Result<(), Box> { let proof = Snark::load::>(&proof_path, None, None)?; let code = DeploymentCode::load(&deployment_code_path)?; evm_verify(code, proof.clone())?; if sol_code_path.is_some() { - let result = verify_proof_via_solidity( - proof, - sol_code_path.unwrap(), - runs - ).await?; + let result = verify_proof_via_solidity(proof, sol_code_path.unwrap(), runs).await?; info!("Solidity verification result: {}", result); @@ -530,8 +565,7 @@ fn create_evm_aggregate_verifier( ) -> Result<(), Box> { let params: ParamsKZG = load_params::>(params_path)?; - let agg_vk = - load_vk::, Fr, AggregationCircuit>(vk_path, ())?; + let agg_vk = load_vk::, Fr, AggregationCircuit>(vk_path, ())?; let yul_code = gen_aggregation_evm_verifier( ¶ms, @@ -641,6 +675,280 @@ fn prove( Ok(()) } +#[cfg(not(target_arch = "wasm32"))] +fn fuzz( + logrows: u32, + data: String, + transcript: TranscriptType, + num_runs: usize, +) -> Result<(), Box> { + let passed = AtomicBool::new(true); + + info!("setting up tests"); + + let _r = Gag::stdout().unwrap(); + let params = gen_srs::>(logrows); + + let data = prepare_data(data)?; + // these aren't real values so the sanity checks are mostly meaningless + let circuit = ModelCircuit::::from_arg(&data, CheckMode::UNSAFE)?; + let pk = create_keys::, Fr, ModelCircuit>(&circuit, ¶ms) + .map_err(Box::::from)?; + + let public_inputs = circuit.prepare_public_inputs(&data)?; + + let strategy = KZGSingleStrategy::new(¶ms); + std::mem::drop(_r); + + info!("starting fuzzing"); + + info!("fuzzing pk"); + + let fuzz_pk = || { + let new_params = gen_srs::>(logrows); + + let bad_pk = + create_keys::, Fr, ModelCircuit>(&circuit, &new_params) + .unwrap(); + + let bad_proof = create_proof_circuit_kzg( + circuit.clone(), + ¶ms, + public_inputs.clone(), + &bad_pk, + transcript, + strategy.clone(), + CheckMode::UNSAFE, + ) + .unwrap(); + + verify_proof_circuit_kzg( + params.verifier_params(), + bad_proof.clone(), + &pk.get_vk(), + strategy.clone(), + ) + .map_err(|_| ()) + }; + + run_fuzz_fn(num_runs, fuzz_pk, &passed); + + info!("fuzzing public inputs"); + + let fuzz_public_inputs = || { + let mut bad_inputs = vec![]; + for l in &public_inputs { + bad_inputs.push(vec![Fr::random(rand::rngs::OsRng); l.len()]); + } + + let bad_proof = create_proof_circuit_kzg( + circuit.clone(), + ¶ms, + bad_inputs.clone(), + &pk, + transcript, + strategy.clone(), + CheckMode::UNSAFE, + ) + .unwrap(); + + verify_proof_circuit_kzg( + params.verifier_params(), + bad_proof.clone(), + &pk.get_vk(), + strategy.clone(), + ) + .map_err(|_| ()) + }; + + run_fuzz_fn(num_runs, fuzz_public_inputs, &passed); + + info!("fuzzing vk"); + + let proof = create_proof_circuit_kzg( + circuit.clone(), + ¶ms, + public_inputs.clone(), + &pk, + transcript, + strategy.clone(), + CheckMode::SAFE, + )?; + + let fuzz_vk = || { + let new_params = gen_srs::>(logrows); + + let bad_pk = + create_keys::, Fr, ModelCircuit>(&circuit, &new_params) + .unwrap(); + + let bad_vk = bad_pk.get_vk(); + + verify_proof_circuit_kzg( + params.verifier_params(), + proof.clone(), + &bad_vk, + strategy.clone(), + ) + .map_err(|_| ()) + }; + + run_fuzz_fn(num_runs, fuzz_vk, &passed); + + info!("fuzzing proof bytes"); + + let fuzz_proof_bytes = || { + let mut rng = rand::thread_rng(); + + let bad_proof_bytes: Vec = (0..proof.proof.len()) + .map(|_| rng.gen_range(0..20)) + .collect(); + + let bad_proof = Snark::<_, _> { + instances: proof.instances.clone(), + proof: bad_proof_bytes, + protocol: proof.protocol.clone(), + transcript_type: transcript, + }; + + verify_proof_circuit_kzg( + params.verifier_params(), + bad_proof.clone(), + &pk.get_vk(), + strategy.clone(), + ) + .map_err(|_| ()) + }; + + run_fuzz_fn(num_runs, fuzz_proof_bytes, &passed); + + info!("fuzzing proof instances"); + + let fuzz_proof_instances = || { + let mut bad_inputs = vec![]; + for l in &proof.instances { + bad_inputs.push(vec![Fr::random(rand::rngs::OsRng); l.len()]); + } + + let bad_proof = Snark::<_, _> { + instances: bad_inputs.clone(), + proof: proof.proof.clone(), + protocol: proof.protocol.clone(), + transcript_type: transcript, + }; + + verify_proof_circuit_kzg( + params.verifier_params(), + bad_proof.clone(), + &pk.get_vk(), + strategy.clone(), + ) + .map_err(|_| ()) + }; + + run_fuzz_fn(num_runs, fuzz_proof_instances, &passed); + + if matches!(transcript, TranscriptType::EVM) { + let num_instance = circuit + .params + .instance_shapes + .iter() + .map(|x| x.iter().product()) + .collect(); + + let yul_code = gen_evm_verifier(¶ms, pk.get_vk(), num_instance)?; + let deployment_code = gen_deployment_code(yul_code.clone()).unwrap(); + + info!("fuzzing proof bytes for evm verifier"); + + let fuzz_evm_proof_bytes = || { + let mut rng = rand::thread_rng(); + + let bad_proof_bytes: Vec = (0..proof.proof.len()) + .map(|_| rng.gen_range(0..20)) + .collect(); + + let bad_proof = Snark::<_, _> { + instances: proof.instances.clone(), + proof: bad_proof_bytes, + protocol: proof.protocol.clone(), + transcript_type: transcript, + }; + + let res = evm_verify(deployment_code.clone(), bad_proof); + + match res { + Ok(b) => match b { + true => Ok(()), + false => Err(()), + }, + Err(_) => Err(()), + } + }; + + run_fuzz_fn(num_runs, fuzz_evm_proof_bytes, &passed); + + info!("fuzzing proof instances for evm verifier"); + + let fuzz_evm_instances = || { + let mut bad_inputs = vec![]; + for l in &proof.instances { + bad_inputs.push(vec![Fr::random(rand::rngs::OsRng); l.len()]); + } + + let bad_proof = Snark::<_, _> { + instances: bad_inputs.clone(), + proof: proof.proof.clone(), + protocol: proof.protocol.clone(), + transcript_type: transcript, + }; + + let res = evm_verify(deployment_code.clone(), bad_proof); + + match res { + Ok(b) => match b { + true => Ok(()), + false => Err(()), + }, + Err(_) => Err(()), + } + }; + + run_fuzz_fn(num_runs, fuzz_evm_instances, &passed); + } + + if !passed.into_inner() { + Err("fuzzing failed".into()) + } else { + Ok(()) + } +} + +#[cfg(not(target_arch = "wasm32"))] +fn run_fuzz_fn( + num_runs: usize, + f: impl Fn() -> Result<(), ()> + std::marker::Sync + std::marker::Send, + passed: &AtomicBool, +) { + let num_failures = AtomicI64::new(0); + let _r = Gag::stdout().unwrap(); + + (0..num_runs).into_par_iter().progress().for_each(|_| { + let result = f(); + if result.is_ok() { + passed.swap(false, Ordering::Relaxed); + num_failures.fetch_add(1, Ordering::Relaxed); + } + }); + + std::mem::drop(_r); + info!( + "num failures: {} out of {}", + num_failures.load(Ordering::Relaxed), + num_runs + ); +} + fn aggregate( proof_path: PathBuf, aggregation_snarks: Vec, diff --git a/src/graph/model.rs b/src/graph/model.rs index 364a61b1..6968919b 100644 --- a/src/graph/model.rs +++ b/src/graph/model.rs @@ -599,6 +599,16 @@ impl Model { visibility, ) } + #[cfg(not(target_arch = "wasm32"))] + Commands::Fuzz { model, args, .. } => { + let visibility = VarVisibility::from_args(args.clone())?; + Model::new( + &mut std::fs::File::open(model)?, + args, + Mode::Prove, + visibility, + ) + } #[cfg(feature = "render")] Commands::RenderCircuit { model, args, .. } => { let visibility = VarVisibility::from_args(args.clone())?; diff --git a/src/pfsys/evm/mod.rs b/src/pfsys/evm/mod.rs index ad8a2ad6..e8ff93f1 100644 --- a/src/pfsys/evm/mod.rs +++ b/src/pfsys/evm/mod.rs @@ -41,7 +41,7 @@ pub enum EvmVerificationError { pub type YulCode = String; /// Defines the proof generated by a model / circuit suitably for serialization/deserialization. -#[derive(Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Deserialize, Serialize)] pub struct DeploymentCode { pub(crate) code: Vec, } diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 445a9f81..46f61f57 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -258,6 +258,7 @@ mod native_tests { use crate::native_tests::mock_public_params; use crate::native_tests::forward_pass; use crate::native_tests::kzg_prove_and_verify; + use crate::native_tests::kzg_fuzz; use crate::native_tests::render_circuit; use crate::native_tests::tutorial as run_tutorial; use crate::native_tests::percentage_tolerance as run_percentage_tolerance; @@ -312,6 +313,12 @@ mod native_tests { kzg_prove_and_verify(test.to_string(), 7, 16, 17, "safe"); } + #(#[test_case(TESTS[N])])* + fn kzg_fuzz_(test: &str) { + crate::native_tests::init_binary(); + kzg_fuzz(test.to_string(), 7, 16, 17, "blake"); + } + }); @@ -342,6 +349,7 @@ mod native_tests { use test_case::test_case; use crate::native_tests::kzg_evm_prove_and_verify; use crate::native_tests::kzg_evm_aggr_prove_and_verify; + use crate::native_tests::kzg_fuzz; /// Not all models will pass VerifyEVM because their contract size exceeds the limit, so we only /// specify those that will @@ -374,6 +382,13 @@ mod native_tests { crate::native_tests::init_params_17(); kzg_evm_prove_and_verify(test.to_string(), TESTS_SOLIDITY.contains(&test)); } + + #(#[test_case(TESTS_EVM[N])])* + fn kzg_evm_fuzz_(test: &str) { + crate::native_tests::init_binary(); + kzg_fuzz(test.to_string(), 7, 16, 17, "evm"); + } + // these take a particularly long time to run #(#[test_case(TESTS_EVM[N])])* #[ignore] @@ -923,14 +938,18 @@ mod native_tests { .expect("failed to execute process"); assert!(status.success()); - let pf_arg = format!("{}/{}_evm_aggr.pf", TEST_DIR.path().to_str().unwrap(), example_name); + let pf_arg = format!( + "{}/{}_evm_aggr.pf", + TEST_DIR.path().to_str().unwrap(), + example_name + ); let mut args = vec![ "verify-evm", "--proof-path", pf_arg.as_str(), "--deployment-code-path", - code_arg.as_str() + code_arg.as_str(), ]; if with_solidity { args.push("--sol-code-path"); @@ -947,7 +966,7 @@ mod native_tests { .args(args) .status() .expect("failed to execute process"); - assert!(!status.success()); + assert!(!status.success()); } // prove-serialize-verify, the usual full path @@ -1037,6 +1056,26 @@ mod native_tests { assert!(status.success()); } + // prove-serialize-verify, the usual full path + fn kzg_fuzz(example_name: String, scale: usize, bits: usize, logrows: usize, transcript: &str) { + let status = Command::new(format!("{}/release/ezkl", *CARGO_TARGET_DIR)) + .args([ + "fuzz", + "-D", + format!("./examples/onnx/{}/input.json", example_name).as_str(), + "-M", + format!("./examples/onnx/{}/network.onnx", example_name).as_str(), + &format!("--bits={}", bits), + &format!("--logrows={}", logrows), + &format!("--scale={}", scale), + &format!("--num-runs={}", 5), + &format!("--transcript={}", transcript), + ]) + .status() + .expect("failed to execute process"); + assert!(status.success()); + } + // prove-serialize-verify, the usual full path fn kzg_evm_prove_and_verify(example_name: String, with_solidity: bool) { let status = Command::new(format!("{}/release/ezkl", *CARGO_TARGET_DIR)) @@ -1139,7 +1178,7 @@ mod native_tests { pf_arg.as_str(), "--deployment-code-path", code_arg.as_str(), - "--optimizer-runs=1" + "--optimizer-runs=1", ]; if with_solidity { args.push("--sol-code-path"); @@ -1156,7 +1195,7 @@ mod native_tests { .args(args) .status() .expect("failed to execute process"); - assert!(!status.success()); + assert!(!status.success()); } fn build_ezkl() {