From 4c2d9b0131e44a80aef2408afd45b735765833e9 Mon Sep 17 00:00:00 2001 From: tchataigner Date: Thu, 25 Jan 2024 17:58:13 -0500 Subject: [PATCH] Test vectors & benchmark for PCS (#222) * test(ipa): proof verified random seed test(ipa): proof verified test(ipa): switch from keccak to grumpkin transcript test(ipa): wip test IPA prove & verify chore: added Jetbrain config to gitignore * test(ipa): using generic fn over mlkzg, ipa & zm - Implemented test_fail_bad_proof that generates a test case from a seed to try and verify a non valid proof. - Implement both test_fail_bad_proof & test_from_seed for IPA over Grumpkin, MLKZG over Bn256 and ZM over Bn256 * ci(ipa): fixed xclippy * feat(ipa): wip bench pcs * feat(ipa): bench proof generation and verification - Created a benchmark for proof generation and verification for IPA over Grumpkin, MLKZG over Bn and ZM over Bn - multilinear.rs to public for benchmark purposes - Refactored generic test methods per @adr1anh comment * feat(ipa): proper polynomial sizes for test & sample size to 10 * feat(ipa): benchmark groups * ci(ipa): fix xclippy * test(ipa): added more polynomial sizes * test(ipa): renamed test method * refactor(ipa): revamp based on review * refactor(ipa): Flat -> Auto bench * refactor(ipa): random_with_eval inline * ci(ipa): fix xclippy --- Cargo.toml | 7 + benches/compressed-snark.rs | 2 +- benches/pcs.rs | 199 +++++++++++++++++++++++++++ benches/recursive-snark.rs | 2 +- src/provider/hyperkzg.rs | 55 +------- src/provider/ipa_pc.rs | 14 ++ src/provider/mod.rs | 2 +- src/provider/non_hiding_zeromorph.rs | 36 +++-- src/provider/test_utils/mod.rs | 115 ++++++++++++++++ src/provider/util/mod.rs | 124 ++++++++++++++++- src/spartan/polys/mod.rs | 3 + src/spartan/polys/multilinear.rs | 3 - 12 files changed, 490 insertions(+), 72 deletions(-) create mode 100644 benches/pcs.rs create mode 100644 src/provider/test_utils/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 99536b31..dd341810 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -73,8 +73,15 @@ harness = false name = "sha256" harness = false + +[[bench]] +name = "pcs" +harness = false +required-features = ["bench"] + [features] default = [] +bench = [] asm = ["halo2curves/asm"] # Compiles in portable mode, w/o ISA extensions => binary can be executed on all systems. portable = ["pasta-msm/portable"] diff --git a/benches/compressed-snark.rs b/benches/compressed-snark.rs index 7d7482bc..fdeb5029 100644 --- a/benches/compressed-snark.rs +++ b/benches/compressed-snark.rs @@ -28,7 +28,7 @@ type SS2 = nova_snark::spartan::ppsnark::RelaxedR1CSSNARK; type C1 = NonTrivialCircuit<::Scalar>; type C2 = TrivialCircuit<::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/`. // For flamegraphs, run `cargo criterion --bench compressed-snark --features flamegraph -- --profile-time `. // The results are located in `target/criterion/profile/`. diff --git a/benches/pcs.rs b/benches/pcs.rs new file mode 100644 index 00000000..364a1c53 --- /dev/null +++ b/benches/pcs.rs @@ -0,0 +1,199 @@ +use criterion::{criterion_group, criterion_main, Bencher, BenchmarkId, Criterion, SamplingMode}; +use ff::Field; +use halo2curves::bn256::Bn256; +use nova_snark::provider::{ + hyperkzg::EvaluationEngine as MLEvaluationEngine, + ipa_pc::EvaluationEngine as IPAEvaluationEngine, non_hiding_zeromorph::ZMPCS, Bn256Engine, + Bn256EngineKZG, Bn256EngineZM, +}; +use nova_snark::spartan::polys::multilinear::MultilinearPolynomial; +use nova_snark::traits::{ + commitment::CommitmentEngineTrait, evaluation::EvaluationEngineTrait, Engine, + TranscriptEngineTrait, +}; +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 `. +// The results are located in `target/criterion/profile/`. +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> { + poly: MultilinearPolynomial<::Scalar>, + point: Vec<::Scalar>, + eval: ::Scalar, + ck: <::CE as CommitmentEngineTrait>::CommitmentKey, + commitment: <::CE as CommitmentEngineTrait>::Commitment, + prover_key: >::ProverKey, + verifier_key: >::VerifierKey, + proof: Option<>::EvaluationArgument>, +} + +/// Returns a random polynomial, a point and calculate its evaluation. +pub fn random_poly_with_eval( + num_vars: usize, + mut rng: &mut R, +) -> ( + MultilinearPolynomial<::Scalar>, + Vec<::Scalar>, + ::Scalar, +) { + // Generate random polynomial and point. + let poly = MultilinearPolynomial::random(num_vars, &mut rng); + let point = (0..num_vars) + .map(|_| ::Scalar::random(&mut rng)) + .collect::>(); + + // Calculation evaluation of point over polynomial. + let eval = MultilinearPolynomial::evaluate_with(poly.evaluations(), &point); + + (poly, point, eval) +} + +impl> BenchAssests { + pub(crate) fn from_num_vars(num_vars: usize, rng: &mut R) -> Self { + let (poly, point, eval) = random_poly_with_eval::(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::(*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), + (mlkzg_assets, MLEvaluationEngine), + (zm_assets, ZMPCS) + ); +} + +fn bench_pcs_proving_internal>( + b: &mut Bencher<'_>, + bench_assets: &BenchAssests, +) { + // 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>( + b: &mut Bencher<'_>, + bench_assets: &BenchAssests, +) { + // 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(); + }); +} diff --git a/benches/recursive-snark.rs b/benches/recursive-snark.rs index 5b16faa1..5d489f21 100644 --- a/benches/recursive-snark.rs +++ b/benches/recursive-snark.rs @@ -20,7 +20,7 @@ type E2 = VestaEngine; type C1 = NonTrivialCircuit<::Scalar>; type C2 = TrivialCircuit<::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 recursive-snark`. The results are located in `target/criterion/data/`. // For flamegraphs, run `cargo criterion --bench recursive-snark --features flamegraph -- --profile-time `. // The results are located in `target/criterion/profile/`. diff --git a/src/provider/hyperkzg.rs b/src/provider/hyperkzg.rs index 43df5629..9dd64d74 100644 --- a/src/provider/hyperkzg.rs +++ b/src/provider/hyperkzg.rs @@ -428,12 +428,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; @@ -557,54 +556,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::>(); - let point = (0..ell).map(|_| Fr::random(&mut rng)).collect::>(); - let eval = MultilinearPolynomial::evaluate_with(&poly, &point); - - let ck: CommitmentKey = - as CommitmentEngineTrait>::setup(b"test", n); - let (pk, vk): (KZGProverKey, KZGVerifierKey) = EvaluationEngine::::setup(&ck); - - // make a commitment - let C = as CommitmentEngineTrait>::commit(&ck, &poly); - - // prove an evaluation - let mut prover_transcript = Keccak256Transcript::::new(b"TestEval"); - let proof: EvaluationArgument = EvaluationEngine::::prove( - &ck, - &pk, - &mut prover_transcript, - &C, - &poly, - &point, - &eval, - ) - .unwrap(); - - // verify the evaluation - let mut verifier_tr = Keccak256Transcript::::new(b"TestEval"); - assert!( - EvaluationEngine::::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::::new(b"TestEval"); - assert!(EvaluationEngine::::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>(num_vars); } } } diff --git a/src/provider/ipa_pc.rs b/src/provider/ipa_pc.rs index 3ac01b6d..abcd9f74 100644 --- a/src/provider/ipa_pc.rs +++ b/src/provider/ipa_pc.rs @@ -407,3 +407,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>(num_vars); + } + } +} diff --git a/src/provider/mod.rs b/src/provider/mod.rs index 86c84c9c..a337d8b0 100644 --- a/src/provider/mod.rs +++ b/src/provider/mod.rs @@ -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; diff --git a/src/provider/non_hiding_zeromorph.rs b/src/provider/non_hiding_zeromorph.rs index 71f5c401..b9561002 100644 --- a/src/provider/non_hiding_zeromorph.rs +++ b/src/provider/non_hiding_zeromorph.rs @@ -438,19 +438,19 @@ fn eval_and_quotient_scalars(y: F, x: F, z: F, point: &[F]) -> (F, (Ve // = [- (y^i * x^(2^num_vars - d_i - 1) + z * (x^(2^i) * Φ_(n-i-1)(x^(2^(i+1))) - u_i * Φ_(n-i)(x^(2^i)))), i ∈ [0, num_vars-1]] #[allow(clippy::disallowed_methods)] let q_scalars = iter::successors(Some(F::ONE), |acc| Some(*acc * y)).take(num_vars) - .zip_eq(offsets_of_x) - // length: num_vars + 1 - .zip(squares_of_x) - // length: num_vars + 1 - .zip(&vs) - .zip_eq(&vs[1..]) - .zip_eq(point.iter().rev()) // assume variables come in BE form - .map( - |(((((power_of_y, offset_of_x), square_of_x), v_i), v_j), u_i)| { - (-(power_of_y * offset_of_x), -(z * (square_of_x * v_j - *u_i * v_i))) - }, - ) - .unzip(); + .zip_eq(offsets_of_x) + // length: num_vars + 1 + .zip(squares_of_x) + // length: num_vars + 1 + .zip(&vs) + .zip_eq(&vs[1..]) + .zip_eq(point.iter().rev()) // assume variables come in BE form + .map( + |(((((power_of_y, offset_of_x), square_of_x), v_i), v_j), u_i)| { + (-(power_of_y * offset_of_x), -(z * (square_of_x * v_j - *u_i * v_i))) + }, + ) + .unzip(); // -vs[0] * z = -z * (x^(2^num_vars) - 1) / (x - 1) = -z Φ_n(x) (-vs[0] * z, q_scalars) @@ -530,7 +530,8 @@ mod test { batched_lifted_degree_quotient, eval_and_quotient_scalars, trim, ZMEvaluation, ZMPCS, }, traits::DlogGroup, - Bn256Engine, + util::test_utils::prove_verify_from_num_vars, + Bn256Engine, Bn256EngineZM, }, spartan::polys::multilinear::MultilinearPolynomial, traits::{Engine as NovaEngine, Group, TranscriptEngineTrait, TranscriptReprTrait}, @@ -593,6 +594,13 @@ mod test { commit_open_verify_with::(); } + #[test] + fn test_multiple_polynomial_size() { + for num_vars in [4, 5, 6] { + prove_verify_from_num_vars::<_, ZMPCS>(num_vars); + } + } + #[test] fn test_quotients() { // Define size parameters diff --git a/src/provider/test_utils/mod.rs b/src/provider/test_utils/mod.rs new file mode 100644 index 00000000..7377c5ea --- /dev/null +++ b/src/provider/test_utils/mod.rs @@ -0,0 +1,115 @@ +//! Utilities for provider module. +//! Contains utilities for testing and benchmarking. +use crate::spartan::polys::multilinear::MultilinearPolynomial; +use crate::traits::{commitment::CommitmentEngineTrait, evaluation::EvaluationEngineTrait, Engine}; +use ff::Field; +use rand::rngs::StdRng; +use rand_core::{CryptoRng, RngCore}; + +/// Returns a random polynomial, a point and calculate its evaluation. +fn random_poly_with_eval( + num_vars: usize, + mut rng: &mut R, +) -> ( + MultilinearPolynomial<::Scalar>, + Vec<::Scalar>, + ::Scalar, +) { + // Generate random polynomial and point. + let poly = MultilinearPolynomial::random(num_vars, &mut rng); + let point = (0..num_vars) + .map(|_| ::Scalar::random(&mut rng)) + .collect::>(); + + // Calculation evaluation of point over polynomial. + let eval = MultilinearPolynomial::evaluate_with(poly.evaluations(), &point); + + (poly, point, eval) +} + +/// Methods used to test the prove and verify flow of [`MultilinearPolynomial`] Commitment Schemes +/// (PCS). +/// +/// Generates a random polynomial and point from a seed to test a proving/verifying flow of one +/// of our [`EvaluationEngine`]. +pub(crate) fn prove_verify_from_num_vars>(num_vars: usize) { + use rand_core::SeedableRng; + + let mut rng = rand::rngs::StdRng::seed_from_u64(num_vars as u64); + + let (poly, point, eval) = random_poly_with_eval::(num_vars, &mut 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()); + + prove_verify_with::(&ck, &commitment, &poly, &point, &eval, true) +} + +fn prove_verify_with>( + ck: &<::CE as CommitmentEngineTrait>::CommitmentKey, + commitment: &<::CE as CommitmentEngineTrait>::Commitment, + poly: &MultilinearPolynomial<::Scalar>, + point: &[::Scalar], + eval: &::Scalar, + evaluate_bad_proof: bool, +) { + use crate::traits::TranscriptEngineTrait; + use std::ops::Add; + + // Generate Prover and verifier key for given commitment key. + let (prover_key, verifier_key) = EE::setup(ck); + + // Generate proof. + let mut prover_transcript = E::TE::new(b"TestEval"); + let proof = EE::prove( + ck, + &prover_key, + &mut prover_transcript, + commitment, + poly.evaluations(), + point, + eval, + ) + .unwrap(); + let pcp = prover_transcript.squeeze(b"c").unwrap(); + + // Verify proof. + let mut verifier_transcript = E::TE::new(b"TestEval"); + EE::verify( + &verifier_key, + &mut verifier_transcript, + commitment, + point, + eval, + &proof, + ) + .unwrap(); + let pcv = verifier_transcript.squeeze(b"c").unwrap(); + + // Check if the prover transcript and verifier transcript are kept in the same state. + assert_eq!(pcp, pcv); + + if evaluate_bad_proof { + // Generate another point to verify proof. Also produce eval. + let altered_verifier_point = point + .iter() + .map(|s| s.add(::Scalar::ONE)) + .collect::>(); + let altered_verifier_eval = + MultilinearPolynomial::evaluate_with(poly.evaluations(), &altered_verifier_point); + + // Verify proof, should fail. + let mut verifier_transcript = E::TE::new(b"TestEval"); + assert!(EE::verify( + &verifier_key, + &mut verifier_transcript, + commitment, + &altered_verifier_point, + &altered_verifier_eval, + &proof, + ) + .is_err()); + } +} diff --git a/src/provider/util/mod.rs b/src/provider/util/mod.rs index 535b0b41..d11fa855 100644 --- a/src/provider/util/mod.rs +++ b/src/provider/util/mod.rs @@ -1,2 +1,124 @@ -/// Utilities for provider module +//! Utilities for provider module. pub(in crate::provider) mod fb_msm; + +#[cfg(test)] +pub mod test_utils { + //! Contains utilities for testing and benchmarking. + use crate::spartan::polys::multilinear::MultilinearPolynomial; + use crate::traits::{ + commitment::CommitmentEngineTrait, evaluation::EvaluationEngineTrait, Engine, + }; + use ff::Field; + use rand::rngs::StdRng; + use rand_core::{CryptoRng, RngCore}; + + /// Returns a random polynomial, a point and calculate its evaluation. + pub fn random_poly_with_eval( + num_vars: usize, + mut rng: &mut R, + ) -> ( + MultilinearPolynomial<::Scalar>, + Vec<::Scalar>, + ::Scalar, + ) { + // Generate random polynomial and point. + let poly = MultilinearPolynomial::random(num_vars, &mut rng); + let point = (0..num_vars) + .map(|_| ::Scalar::random(&mut rng)) + .collect::>(); + + // Calculation evaluation of point over polynomial. + let eval = MultilinearPolynomial::evaluate_with(poly.evaluations(), &point); + + (poly, point, eval) + } + + /// Methods used to test the prove and verify flow of [`MultilinearPolynomial`] Commitment Schemes + /// (PCS). + /// + /// Generates a random polynomial and point from a seed to test a proving/verifying flow of one + /// of our [`EvaluationEngine`]. + pub(crate) fn prove_verify_from_num_vars>( + num_vars: usize, + ) { + use rand_core::SeedableRng; + + let mut rng = rand::rngs::StdRng::seed_from_u64(num_vars as u64); + + let (poly, point, eval) = random_poly_with_eval::(num_vars, &mut 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()); + + prove_verify_with::(&ck, &commitment, &poly, &point, &eval, true) + } + + pub(crate) fn prove_verify_with>( + ck: &<::CE as CommitmentEngineTrait>::CommitmentKey, + commitment: &<::CE as CommitmentEngineTrait>::Commitment, + poly: &MultilinearPolynomial<::Scalar>, + point: &[::Scalar], + eval: &::Scalar, + evaluate_bad_proof: bool, + ) { + use crate::traits::TranscriptEngineTrait; + use std::ops::Add; + + // Generate Prover and verifier key for given commitment key. + let (prover_key, verifier_key) = EE::setup(ck); + + // Generate proof. + let mut prover_transcript = E::TE::new(b"TestEval"); + let proof = EE::prove( + ck, + &prover_key, + &mut prover_transcript, + commitment, + poly.evaluations(), + point, + eval, + ) + .unwrap(); + let pcp = prover_transcript.squeeze(b"c").unwrap(); + + // Verify proof. + let mut verifier_transcript = E::TE::new(b"TestEval"); + EE::verify( + &verifier_key, + &mut verifier_transcript, + commitment, + point, + eval, + &proof, + ) + .unwrap(); + let pcv = verifier_transcript.squeeze(b"c").unwrap(); + + // Check if the prover transcript and verifier transcript are kept in the same state. + assert_eq!(pcp, pcv); + + if evaluate_bad_proof { + // Generate another point to verify proof. Also produce eval. + let altered_verifier_point = point + .iter() + .map(|s| s.add(::Scalar::ONE)) + .collect::>(); + let altered_verifier_eval = + MultilinearPolynomial::evaluate_with(poly.evaluations(), &altered_verifier_point); + + // Verify proof, should fail. + let mut verifier_transcript = E::TE::new(b"TestEval"); + assert!(EE::verify( + &verifier_key, + &mut verifier_transcript, + commitment, + &altered_verifier_point, + &altered_verifier_eval, + &proof, + ) + .is_err()); + } + } +} diff --git a/src/spartan/polys/mod.rs b/src/spartan/polys/mod.rs index a1a192ef..408aeb28 100644 --- a/src/spartan/polys/mod.rs +++ b/src/spartan/polys/mod.rs @@ -2,6 +2,9 @@ pub(crate) mod eq; pub(crate) mod identity; pub(crate) mod masked_eq; +#[cfg(features = "bench")] pub(crate) mod multilinear; +#[cfg(not(features = "bench"))] +pub mod multilinear; pub(crate) mod power; pub(crate) mod univariate; diff --git a/src/spartan/polys/multilinear.rs b/src/spartan/polys/multilinear.rs index fea46c27..472f1e4e 100644 --- a/src/spartan/polys/multilinear.rs +++ b/src/spartan/polys/multilinear.rs @@ -1,7 +1,6 @@ //! Main components: //! - `MultilinearPolynomial`: Dense representation of multilinear polynomials, represented by evaluations over all possible binary inputs. //! - `SparsePolynomial`: Efficient representation of sparse multilinear polynomials, storing only non-zero evaluations. - use std::ops::{Add, Index}; use ff::PrimeField; @@ -60,9 +59,7 @@ impl MultilinearPolynomial { self.Z.len() } - /// Binds the polynomial's top variable using the given scalar. /// Returns a random polynomial - /// pub fn random(num_vars: usize, mut rng: &mut R) -> Self { MultilinearPolynomial::new( std::iter::from_fn(|| Some(Scalar::random(&mut rng)))