mirror of
https://github.com/zkonduit/ezkl.git
synced 2026-01-10 06:48:01 -05:00
feat: fuzz testing command (#259)
This commit is contained in:
29
.github/workflows/rust.yml
vendored
29
.github/workflows/rust.yml
vendored
@@ -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
|
||||
|
||||
|
||||
46
Cargo.lock
generated
46
Cargo.lock
generated
@@ -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",
|
||||
|
||||
@@ -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"] }
|
||||
|
||||
@@ -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<usize>
|
||||
optimizer_runs: Option<usize>,
|
||||
},
|
||||
|
||||
#[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<usize>
|
||||
optimizer_runs: Option<usize>,
|
||||
},
|
||||
|
||||
/// Print the proof in hexadecimal
|
||||
|
||||
342
src/execute.rs
342
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<dyn Error>> {
|
||||
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<dyn Error>> {
|
||||
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<dyn Error>> {
|
||||
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<dyn Error>> {
|
||||
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<PathBuf>,
|
||||
sol_code_path: Option<PathBuf>,
|
||||
runs: Option<usize>
|
||||
runs: Option<usize>,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
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<dyn Error>> {
|
||||
/// helper function to generate the deployment code from yul code
|
||||
pub fn gen_deployment_code(yul_code: YulCode) -> Result<DeploymentCode, Box<dyn Error>> {
|
||||
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<PathBuf>,
|
||||
runs: Option<usize>
|
||||
runs: Option<usize>,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let proof = Snark::load::<KZGCommitmentScheme<Bn256>>(&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<dyn Error>> {
|
||||
let params: ParamsKZG<Bn256> = load_params::<KZGCommitmentScheme<Bn256>>(params_path)?;
|
||||
|
||||
let agg_vk =
|
||||
load_vk::<KZGCommitmentScheme<Bn256>, Fr, AggregationCircuit>(vk_path, ())?;
|
||||
let agg_vk = load_vk::<KZGCommitmentScheme<Bn256>, 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<dyn Error>> {
|
||||
let passed = AtomicBool::new(true);
|
||||
|
||||
info!("setting up tests");
|
||||
|
||||
let _r = Gag::stdout().unwrap();
|
||||
let params = gen_srs::<KZGCommitmentScheme<Bn256>>(logrows);
|
||||
|
||||
let data = prepare_data(data)?;
|
||||
// these aren't real values so the sanity checks are mostly meaningless
|
||||
let circuit = ModelCircuit::<Fr>::from_arg(&data, CheckMode::UNSAFE)?;
|
||||
let pk = create_keys::<KZGCommitmentScheme<Bn256>, Fr, ModelCircuit<Fr>>(&circuit, ¶ms)
|
||||
.map_err(Box::<dyn Error>::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::<KZGCommitmentScheme<Bn256>>(logrows);
|
||||
|
||||
let bad_pk =
|
||||
create_keys::<KZGCommitmentScheme<Bn256>, Fr, ModelCircuit<Fr>>(&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::<KZGCommitmentScheme<Bn256>>(logrows);
|
||||
|
||||
let bad_pk =
|
||||
create_keys::<KZGCommitmentScheme<Bn256>, Fr, ModelCircuit<Fr>>(&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<u8> = (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<u8> = (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<PathBuf>,
|
||||
|
||||
@@ -599,6 +599,16 @@ impl<F: PrimeField + TensorType + PartialOrd> Model<F> {
|
||||
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())?;
|
||||
|
||||
@@ -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<u8>,
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user