diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml index 6fd804592..1959fb5b5 100644 --- a/primitives/Cargo.toml +++ b/primitives/Cargo.toml @@ -74,6 +74,11 @@ harness = false name = "pcs" harness = false +[[bench]] +name = "pcs-size" +path = "benches/pcs_size.rs" +harness = false + [[bench]] name = "reed-solomon" path = "benches/reed_solomon.rs" diff --git a/primitives/benches/pcs.rs b/primitives/benches/pcs.rs index ad5f1d484..74416d465 100644 --- a/primitives/benches/pcs.rs +++ b/primitives/benches/pcs.rs @@ -4,100 +4,160 @@ // You should have received a copy of the MIT License // along with the Jellyfish library. If not, see . -#[cfg(not(feature = "test-srs"))] -fn main() { - panic!("We need features=['bench'] to run this benchmark."); +#![cfg(feature = "test-srs")] + +use std::time::{Duration, Instant}; + +use ark_bls12_381::Bls12_381; +use ark_bn254::Bn254; +use ark_ec::pairing::Pairing; +use ark_ff::UniformRand; +use ark_poly::{DenseMultilinearExtension, MultilinearExtension}; +use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; +use jf_primitives::pcs::{ + prelude::{MultilinearKzgPCS, PolynomialCommitmentScheme, MLE}, + StructuredReferenceString, +}; +use jf_utils::test_rng; + +const MIN_NUM_VARS: usize = 10; +const MAX_NUM_VARS: usize = 20; + +/// Measure the time cost of {commit/open/verify} across a range of num_vars +pub fn bench_pcs_method( + c: &mut Criterion, + range: impl Iterator, + msg: &str, + method: impl Fn(& as PolynomialCommitmentScheme>::SRS, usize) -> Duration, +) { + let mut group = c.benchmark_group(msg); + + let mut rng = &mut test_rng(); + + for num_vars in range { + let pp = MultilinearKzgPCS::::gen_srs_for_testing(&mut rng, num_vars).unwrap(); + + group.bench_with_input( + BenchmarkId::from_parameter(num_vars), + &num_vars, + |b, num_vars| { + b.iter(|| method(&pp, *num_vars)); + }, + ); + } + + group.finish(); } -#[cfg(feature = "test-srs")] -fn main() -> Result<(), jf_primitives::pcs::prelude::PCSError> { - bench::bench_pcs() +/// Report the time cost of a commitment +pub fn commit( + pp: & as PolynomialCommitmentScheme>::SRS, + num_vars: usize, +) -> Duration { + let rng = &mut test_rng(); + + let (ml_ck, _ml_vk) = pp.0.trim(num_vars).unwrap(); + let (uni_ck, _uni_vk) = pp.1.trim(num_vars).unwrap(); + let ck = (ml_ck, uni_ck); + + let poly = MLE::from(DenseMultilinearExtension::rand(num_vars, rng)); + + let start = Instant::now(); + let _ = MultilinearKzgPCS::commit(&ck, &poly).unwrap(); + start.elapsed() } -#[cfg(feature = "test-srs")] -mod bench { - use ark_bls12_381::{Bls12_381, Fr}; - use ark_ff::UniformRand; - use ark_poly::{DenseMultilinearExtension, MultilinearExtension}; - use jf_primitives::pcs::{ - prelude::{MultilinearKzgPCS, PCSError, PolynomialCommitmentScheme, MLE}, - StructuredReferenceString, - }; - use jf_utils::test_rng; - use std::time::Instant; - - pub(crate) fn bench_pcs() -> Result<(), PCSError> { - let mut rng = test_rng(); - - // normal polynomials - let uni_params = MultilinearKzgPCS::::gen_srs_for_testing(&mut rng, 18)?; - - for nv in 4..19 { - let repetition = if nv < 10 { - 100 - } else if nv < 20 { - 50 - } else { - 10 - }; - - let poly = MLE::from(DenseMultilinearExtension::rand(nv, &mut rng)); - let (ml_ck, ml_vk) = uni_params.0.trim(nv)?; - let (uni_ck, uni_vk) = uni_params.1.trim(nv)?; - let ck = (ml_ck, uni_ck); - let vk = (ml_vk, uni_vk); - - let point: Vec<_> = (0..nv).map(|_| Fr::rand(&mut rng)).collect(); - - // commit - let com = { - let start = Instant::now(); - for _ in 0..repetition { - let _commit = MultilinearKzgPCS::commit(&ck, &poly)?; - } - - println!( - "KZG commit for {} variables: {} ns", - nv, - start.elapsed().as_nanos() / repetition as u128 - ); - - MultilinearKzgPCS::commit(&ck, &poly)? - }; - - // open - let (proof, value) = { - let start = Instant::now(); - for _ in 0..repetition { - let _open = MultilinearKzgPCS::open(&ck, &poly, &point)?; - } - - println!( - "KZG open for {} variables: {} ns", - nv, - start.elapsed().as_nanos() / repetition as u128 - ); - MultilinearKzgPCS::open(&ck, &poly, &point)? - }; - - // verify - { - let start = Instant::now(); - for _ in 0..repetition { - assert!(MultilinearKzgPCS::verify( - &vk, &com, &point, &value, &proof - )?); - } - println!( - "KZG verify for {} variables: {} ns", - nv, - start.elapsed().as_nanos() / repetition as u128 - ); - } - - println!("===================================="); - } - - Ok(()) - } +/// Report the time cost of an opening +pub fn open( + pp: & as PolynomialCommitmentScheme>::SRS, + num_vars: usize, +) -> Duration { + let rng = &mut test_rng(); + + let (ml_ck, _ml_vk) = pp.0.trim(num_vars).unwrap(); + let (uni_ck, _uni_vk) = pp.1.trim(num_vars).unwrap(); + let ck = (ml_ck, uni_ck); + + let poly = MLE::from(DenseMultilinearExtension::rand(num_vars, rng)); + let point: Vec<_> = (0..num_vars).map(|_| E::ScalarField::rand(rng)).collect(); + + let start = Instant::now(); + let _ = MultilinearKzgPCS::open(&ck, &poly, &point).unwrap(); + start.elapsed() } + +/// Report the time cost of a verification +pub fn verify( + pp: & as PolynomialCommitmentScheme>::SRS, + num_vars: usize, +) -> Duration { + let rng = &mut test_rng(); + + let (ml_ck, ml_vk) = pp.0.trim(num_vars).unwrap(); + let (uni_ck, uni_vk) = pp.1.trim(num_vars).unwrap(); + let ck = (ml_ck, uni_ck); + let vk = (ml_vk, uni_vk); + + let poly = MLE::from(DenseMultilinearExtension::rand(num_vars, rng)); + let point: Vec<_> = (0..num_vars).map(|_| E::ScalarField::rand(rng)).collect(); + + let commitment = MultilinearKzgPCS::commit(&ck, &poly).unwrap(); + + let (proof, value) = MultilinearKzgPCS::open(&ck, &poly, &point).unwrap(); + + let start = Instant::now(); + assert!(MultilinearKzgPCS::verify(&vk, &commitment, &point, &value, &proof).unwrap()); + start.elapsed() +} + +fn kzg_254(c: &mut Criterion) { + bench_pcs_method::( + c, + (MIN_NUM_VARS..MAX_NUM_VARS).step_by(2), + "commit_kzg_range_BN_254", + commit::, + ); + bench_pcs_method::( + c, + (MIN_NUM_VARS..MAX_NUM_VARS).step_by(2), + "open_kzg_range_BN_254", + open::, + ); + bench_pcs_method::( + c, + (MIN_NUM_VARS..MAX_NUM_VARS).step_by(2), + "verify_kzg_range_BN_254", + verify::, + ); +} + +fn kzg_381(c: &mut Criterion) { + bench_pcs_method::( + c, + (MIN_NUM_VARS..MAX_NUM_VARS).step_by(2), + "commit_kzg_range_BLS_381", + commit::, + ); + bench_pcs_method::( + c, + (MIN_NUM_VARS..MAX_NUM_VARS).step_by(2), + "open_kzg_range_BLS_381", + open::, + ); + bench_pcs_method::( + c, + (MIN_NUM_VARS..MAX_NUM_VARS).step_by(2), + "verify_kzg_range_BLS_381", + verify::, + ); +} + +criterion_group! { + name = pcs_benches; + config = Criterion::default(); + targets = + kzg_254, + kzg_381 +} + +criterion_main!(pcs_benches); diff --git a/primitives/benches/pcs_size.rs b/primitives/benches/pcs_size.rs new file mode 100644 index 000000000..873192658 --- /dev/null +++ b/primitives/benches/pcs_size.rs @@ -0,0 +1,86 @@ +#![cfg(feature = "test-srs")] + +use ark_bls12_381::Bls12_381; +use ark_bn254::Bn254; +use ark_ec::pairing::Pairing; +use ark_ff::UniformRand; +use ark_poly::{DenseMultilinearExtension, MultilinearExtension}; +use ark_serialize::CanonicalSerialize; +use jf_primitives::pcs::{ + prelude::{MultilinearKzgPCS, PolynomialCommitmentScheme, MLE}, + StructuredReferenceString, +}; +use jf_utils::test_rng; + +const MIN_NUM_VARS: usize = 10; +const MAX_NUM_VARS: usize = 20; + +/// Report the size of a commitment +pub fn commitment_size(num_vars: usize) -> usize { + let rng = &mut test_rng(); + let pp = MultilinearKzgPCS::::gen_srs_for_testing(rng, num_vars).unwrap(); + + let (ml_ck, _ml_vk) = pp.0.trim(num_vars).unwrap(); + let (uni_ck, _uni_vk) = pp.1.trim(num_vars).unwrap(); + let ck = (ml_ck, uni_ck); + + let poly = MLE::from(DenseMultilinearExtension::rand(num_vars, rng)); + + let commitment = MultilinearKzgPCS::commit(&ck, &poly).unwrap(); + commitment.serialized_size(ark_serialize::Compress::No) +} + +/// Report the size of a proof +pub fn proof_size(num_vars: usize) -> usize { + let rng = &mut test_rng(); + let pp = MultilinearKzgPCS::::gen_srs_for_testing(rng, num_vars).unwrap(); + + let (ml_ck, _ml_vk) = pp.0.trim(num_vars).unwrap(); + let (uni_ck, _uni_vk) = pp.1.trim(num_vars).unwrap(); + let ck = (ml_ck, uni_ck); + + let poly = MLE::from(DenseMultilinearExtension::rand(num_vars, rng)); + let point: Vec<_> = (0..num_vars).map(|_| E::ScalarField::rand(rng)).collect(); + + let (proof, _) = MultilinearKzgPCS::open(&ck, &poly, &point).unwrap(); + + proof.serialized_size(ark_serialize::Compress::No) +} + +fn main() { + println!("\nKZG on BN-254: Commitment size"); + for num_vars in (MIN_NUM_VARS..MAX_NUM_VARS).step_by(2) { + println!( + "\tnum_vars: {}, size: {} B", + num_vars, + commitment_size::(num_vars) + ); + } + + println!("\nKZG on BN-254: Proof size"); + for num_vars in (MIN_NUM_VARS..MAX_NUM_VARS).step_by(2) { + println!( + "\tnum_vars: {}, size: {} B", + num_vars, + proof_size::(num_vars) + ); + } + + println!("\nKZG on BLS-381: Commitment size"); + for num_vars in (MIN_NUM_VARS..MAX_NUM_VARS).step_by(2) { + println!( + "\tnum_vars: {}, size: {} B", + num_vars, + commitment_size::(num_vars) + ); + } + + println!("\nKZG on BLS-381: Proof size"); + for num_vars in (MIN_NUM_VARS..MAX_NUM_VARS).step_by(2) { + println!( + "\tnum_vars: {}, size: {} B", + num_vars, + proof_size::(num_vars) + ); + } +}