Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test vectors & benchmark for PCS #222

Merged
merged 14 commits into from
Jan 5, 2024
Merged
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,7 @@ Cargo.lock
**/*.rs.bk

# Configurations for VSCode
.vscode/
.vscode/

# Configuration for Jetbrains
.idea/
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ harness = false
name = "compressed-snark-supernova"
harness = false

[[bench]]
name = "pcs"
harness = false

[features]
default = []
abomonate = []
Expand Down
2 changes: 1 addition & 1 deletion benches/compressed-snark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type SS2 = arecibo::spartan::ppsnark::RelaxedR1CSSNARK<E2, EE2>;
type C1 = NonTrivialCircuit<<E1 as Engine>::Scalar>;
type C2 = TrivialCircuit<<E2 as Engine>::Scalar>;

// To run these benchmarks, first download `criterion` with `cargo install cargo install cargo-criterion`.
// To run these benchmarks, first download `criterion` with `cargo install cargo-criterion`.
// Then `cargo criterion --bench compressed-snark`. The results are located in `target/criterion/data/<name-of-benchmark>`.
// For flamegraphs, run `cargo criterion --bench compressed-snark --features flamegraph -- --profile-time <secs>`.
// The results are located in `target/criterion/profile/<name-of-benchmark>`.
Expand Down
198 changes: 198 additions & 0 deletions benches/pcs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
use arecibo::provider::{
ipa_pc::EvaluationEngine as IPAEvaluationEngine, mlkzg::EvaluationEngine as MLEvaluationEngine,
non_hiding_zeromorph::ZMPCS, Bn256EngineKZG, Bn256EngineZM, GrumpkinEngine,
};
use arecibo::spartan::polys::multilinear::MultilinearPolynomial;
use arecibo::traits::{
commitment::CommitmentEngineTrait, evaluation::EvaluationEngineTrait, Engine,
TranscriptEngineTrait,
};
use criterion::{criterion_group, criterion_main, Bencher, BenchmarkId, Criterion, SamplingMode};
use ff::Field;
use halo2curves::bn256::Bn256;
use rand::rngs::StdRng;
use rand_core::{CryptoRng, RngCore, SeedableRng};
use std::any::type_name;
use std::time::Duration;

// To run these benchmarks, first download `criterion` with `cargo install cargo-criterion`.
// Then `cargo criterion --bench pcs`.
// For flamegraphs, run `cargo criterion --bench pcs --features flamegraph -- --profile-time <secs>`.
// The results are located in `target/criterion/profile/<name-of-benchmark>`.
cfg_if::cfg_if! {
if #[cfg(feature = "flamegraph")] {
criterion_group! {
name = pcs;
config = Criterion::default().warm_up_time(Duration::from_millis(3000)).with_profiler(pprof::criterion::PProfProfiler::new(100, pprof::criterion::Output::Flamegraph(None)));
targets = bench_pcs
}
} else {
criterion_group! {
name = pcs;
config = Criterion::default().warm_up_time(Duration::from_millis(3000));
targets = bench_pcs
}
}
}

criterion_main!(pcs);

const NUM_VARS_TEST_VECTOR: [usize; 6] = [10, 12, 14, 16, 18, 20];

struct BenchAssests<E: Engine, EE: EvaluationEngineTrait<E>> {
poly: MultilinearPolynomial<<E as Engine>::Scalar>,
point: Vec<<E as Engine>::Scalar>,
eval: <E as Engine>::Scalar,
ck: <<E as Engine>::CE as CommitmentEngineTrait<E>>::CommitmentKey,
commitment: <<E as Engine>::CE as CommitmentEngineTrait<E>>::Commitment,
prover_key: <EE as EvaluationEngineTrait<E>>::ProverKey,
verifier_key: <EE as EvaluationEngineTrait<E>>::VerifierKey,
proof: Option<<EE as EvaluationEngineTrait<E>>::EvaluationArgument>,
}

/// Returns a random polynomial, a point and calculate its evaluation.
pub fn random_poly_with_eval<E: Engine, R: RngCore + CryptoRng>(
num_vars: usize,
mut rng: &mut R,
) -> (
MultilinearPolynomial<<E as Engine>::Scalar>,
Vec<<E as Engine>::Scalar>,
<E as Engine>::Scalar,
) {
// Generate random polynomial and point.
let poly = MultilinearPolynomial::random(num_vars, &mut rng);
let point = (0..num_vars)
.map(|_| <E as Engine>::Scalar::random(&mut rng))
.collect::<Vec<_>>();

// Calculation evaluation of point over polynomial.
let eval = MultilinearPolynomial::evaluate_with(poly.evaluations(), &point);

(poly, point, eval)
}

impl<E: Engine, EE: EvaluationEngineTrait<E>> BenchAssests<E, EE> {
pub(crate) fn from_num_vars<R: CryptoRng + RngCore>(num_vars: usize, rng: &mut R) -> Self {
let (poly, point, eval) = random_poly_with_eval::<E, R>(num_vars, rng);

// Mock commitment key.
let ck = E::CE::setup(b"test", 1 << num_vars);
// Commits to the provided vector using the provided generators.
let commitment = E::CE::commit(&ck, poly.evaluations());

let (prover_key, verifier_key) = EE::setup(&ck);

// Generate proof so that we can bench verification.
let proof = EE::prove(
&ck,
&prover_key,
&mut E::TE::new(b"TestEval"),
&commitment,
poly.evaluations(),
&point,
&eval,
)
.unwrap();

Self {
poly,
point,
eval,
ck,
commitment,
prover_key,
verifier_key,
proof: Some(proof),
}
}
}

// Macro to generate benchmark code for multiple evaluation engine types
macro_rules! benchmark_all_engines {
($criterion:expr, $test_vector:expr, $proving_fn:expr, $verifying_fn:expr, $( ($assets:ident, $eval_engine:ty) ),*) => {
for num_vars in $test_vector.iter() {
let mut rng = rand::rngs::StdRng::seed_from_u64(*num_vars as u64);

$(
let $assets: BenchAssests<_, $eval_engine> = BenchAssests::from_num_vars::<StdRng>(*num_vars, &mut rng);
)*

// Proving group
let mut proving_group = $criterion.benchmark_group(format!("PCS-Proving {}", num_vars));
proving_group
.sampling_mode(SamplingMode::Auto)
.sample_size(10);

$(
proving_group.bench_with_input(BenchmarkId::new(type_name::<$eval_engine>(), num_vars), &num_vars, |b, _| {
$proving_fn(b, &$assets);
});
)*

proving_group.finish();

// Verifying group
let mut verifying_group = $criterion.benchmark_group(format!("PCS-Verifying {}", num_vars));
verifying_group
.sampling_mode(SamplingMode::Auto)
.sample_size(10);

$(
verifying_group.bench_with_input(BenchmarkId::new(type_name::<$eval_engine>(), num_vars), &num_vars, |b, _| {
$verifying_fn(b, &$assets);
});
)*

verifying_group.finish();
}
};
}

fn bench_pcs(c: &mut Criterion) {
benchmark_all_engines!(
c,
NUM_VARS_TEST_VECTOR,
bench_pcs_proving_internal,
bench_pcs_verifying_internal,
(ipa_assets, IPAEvaluationEngine<GrumpkinEngine>),
(mlkzg_assets, MLEvaluationEngine<Bn256, Bn256EngineKZG>),
(zm_assets, ZMPCS<Bn256, Bn256EngineZM>)
);
}

fn bench_pcs_proving_internal<E: Engine, EE: EvaluationEngineTrait<E>>(
b: &mut Bencher<'_>,
bench_assets: &BenchAssests<E, EE>,
) {
// Bench generate proof.
b.iter(|| {
EE::prove(
&bench_assets.ck,
&bench_assets.prover_key,
&mut E::TE::new(b"TestEval"),
&bench_assets.commitment,
bench_assets.poly.evaluations(),
&bench_assets.point,
&bench_assets.eval,
)
.unwrap();
});
}

fn bench_pcs_verifying_internal<E: Engine, EE: EvaluationEngineTrait<E>>(
b: &mut Bencher<'_>,
bench_assets: &BenchAssests<E, EE>,
) {
// Bench verify proof.
b.iter(|| {
EE::verify(
&bench_assets.verifier_key,
&mut E::TE::new(b"TestEval"),
&bench_assets.commitment,
&bench_assets.point,
&bench_assets.eval,
bench_assets.proof.as_ref().unwrap(),
)
.unwrap();
});
}
2 changes: 1 addition & 1 deletion benches/recursive-snark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ type E2 = VestaEngine;
type C1 = NonTrivialCircuit<<E1 as Engine>::Scalar>;
type C2 = TrivialCircuit<<E2 as Engine>::Scalar>;

// To run these benchmarks, first download `criterion` with `cargo install cargo install cargo-criterion`.
// To run these benchmarks, first download `criterion` with `cargo install cargo-criterion`.
huitseeker marked this conversation as resolved.
Show resolved Hide resolved
// Then `cargo criterion --bench recursive-snark`. The results are located in `target/criterion/data/<name-of-benchmark>`.
// For flamegraphs, run `cargo criterion --bench recursive-snark --features flamegraph -- --profile-time <secs>`.
// The results are located in `target/criterion/profile/<name-of-benchmark>`.
Expand Down
14 changes: 14 additions & 0 deletions src/provider/ipa_pc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,3 +410,17 @@ where
}
}
}

#[cfg(test)]
mod test {
use crate::provider::ipa_pc::EvaluationEngine;
use crate::provider::util::test_utils::prove_verify_from_num_vars;
use crate::provider::GrumpkinEngine;

#[test]
fn test_multiple_polynomial_size() {
for num_vars in [4, 5, 6] {
prove_verify_from_num_vars::<_, EvaluationEngine<GrumpkinEngine>>(num_vars);
}
}
}
55 changes: 4 additions & 51 deletions src/provider/mlkzg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -429,12 +429,11 @@ where
#[cfg(test)]
mod tests {
use super::*;
use crate::provider::util::test_utils::prove_verify_from_num_vars;
use crate::{
provider::keccak::Keccak256Transcript, spartan::polys::multilinear::MultilinearPolynomial,
traits::commitment::CommitmentTrait, CommitmentKey,
provider::keccak::Keccak256Transcript, traits::commitment::CommitmentTrait, CommitmentKey,
};
use bincode::Options;
use rand::SeedableRng;

type E = halo2curves::bn256::Bn256;
type NE = crate::provider::Bn256EngineKZG;
Expand Down Expand Up @@ -558,54 +557,8 @@ mod tests {
#[test]
fn test_mlkzg_more() {
// test the mlkzg prover and verifier with random instances (derived from a seed)
for ell in [4, 5, 6] {
let mut rng = rand::rngs::StdRng::seed_from_u64(ell as u64);

let n = 1 << ell; // n = 2^ell

let poly = (0..n).map(|_| Fr::random(&mut rng)).collect::<Vec<_>>();
let point = (0..ell).map(|_| Fr::random(&mut rng)).collect::<Vec<_>>();
let eval = MultilinearPolynomial::evaluate_with(&poly, &point);

let ck: CommitmentKey<NE> =
<KZGCommitmentEngine<E> as CommitmentEngineTrait<NE>>::setup(b"test", n);
let (pk, vk): (KZGProverKey<E>, KZGVerifierKey<E>) = EvaluationEngine::<E, NE>::setup(&ck);

// make a commitment
let C = <KZGCommitmentEngine<E> as CommitmentEngineTrait<NE>>::commit(&ck, &poly);

// prove an evaluation
let mut prover_transcript = Keccak256Transcript::<NE>::new(b"TestEval");
let proof: EvaluationArgument<E> = EvaluationEngine::<E, NE>::prove(
&ck,
&pk,
&mut prover_transcript,
&C,
&poly,
&point,
&eval,
)
.unwrap();

// verify the evaluation
let mut verifier_tr = Keccak256Transcript::<NE>::new(b"TestEval");
assert!(
EvaluationEngine::<E, NE>::verify(&vk, &mut verifier_tr, &C, &point, &eval, &proof).is_ok()
);

// Change the proof and expect verification to fail
let mut bad_proof = proof.clone();
bad_proof.comms[0] = (bad_proof.comms[0] + bad_proof.comms[1]).to_affine();
let mut verifier_tr2 = Keccak256Transcript::<NE>::new(b"TestEval");
assert!(EvaluationEngine::<E, NE>::verify(
&vk,
&mut verifier_tr2,
&C,
&point,
&eval,
&bad_proof
)
.is_err());
for num_vars in [4, 5, 6] {
prove_verify_from_num_vars::<_, EvaluationEngine<E, NE>>(num_vars);
}
}
}
2 changes: 1 addition & 1 deletion src/provider/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub(crate) mod traits;
// a non-hiding variant of {kzg, zeromorph}
pub(crate) mod kzg_commitment;
pub(crate) mod non_hiding_kzg;
mod util;
pub(crate) mod util;

// crate-private modules
mod keccak;
Expand Down
Loading
Loading