Skip to content

Commit

Permalink
feat: Reproducible KZG benches (#390)
Browse files Browse the repository at this point in the history
* Use criterion for consistent benches

* adapted poly-commit benchmarks

* added the file...

* fixed incorrect call to open instead of verify

* fmt the bench

* add copyright

* remove old pcs bench

* rename hcs -> pcs

* remove extra comments

* Added size benches

Co-authored-by: Antonio Mejías Gil <[email protected]>

* fixed build action by formatting

* added KZG tests with the curve Bls12_381

* added KZG commitment/proof size benchmarks with the curve Bls12_381

* changed the range argument from a vector to an interator

---------

Co-authored-by: Antonio Mejías Gil <[email protected]>
  • Loading branch information
tessico and Antonio95 authored Nov 6, 2023
1 parent b7704dc commit 9bd4d63
Show file tree
Hide file tree
Showing 3 changed files with 243 additions and 92 deletions.
5 changes: 5 additions & 0 deletions primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
244 changes: 152 additions & 92 deletions primitives/benches/pcs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,100 +4,160 @@
// You should have received a copy of the MIT License
// along with the Jellyfish library. If not, see <https://mit-license.org/>.

#[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<E: Pairing>(
c: &mut Criterion,
range: impl Iterator<Item = usize>,
msg: &str,
method: impl Fn(&<MultilinearKzgPCS<E> 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::<E>::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<E: Pairing>(
pp: &<MultilinearKzgPCS<E> 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::<Bls12_381>::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<E: Pairing>(
pp: &<MultilinearKzgPCS<E> 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<E: Pairing>(
pp: &<MultilinearKzgPCS<E> 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::<Bn254>(
c,
(MIN_NUM_VARS..MAX_NUM_VARS).step_by(2),
"commit_kzg_range_BN_254",
commit::<Bn254>,
);
bench_pcs_method::<Bn254>(
c,
(MIN_NUM_VARS..MAX_NUM_VARS).step_by(2),
"open_kzg_range_BN_254",
open::<Bn254>,
);
bench_pcs_method::<Bn254>(
c,
(MIN_NUM_VARS..MAX_NUM_VARS).step_by(2),
"verify_kzg_range_BN_254",
verify::<Bn254>,
);
}

fn kzg_381(c: &mut Criterion) {
bench_pcs_method::<Bls12_381>(
c,
(MIN_NUM_VARS..MAX_NUM_VARS).step_by(2),
"commit_kzg_range_BLS_381",
commit::<Bls12_381>,
);
bench_pcs_method::<Bls12_381>(
c,
(MIN_NUM_VARS..MAX_NUM_VARS).step_by(2),
"open_kzg_range_BLS_381",
open::<Bls12_381>,
);
bench_pcs_method::<Bls12_381>(
c,
(MIN_NUM_VARS..MAX_NUM_VARS).step_by(2),
"verify_kzg_range_BLS_381",
verify::<Bls12_381>,
);
}

criterion_group! {
name = pcs_benches;
config = Criterion::default();
targets =
kzg_254,
kzg_381
}

criterion_main!(pcs_benches);
86 changes: 86 additions & 0 deletions primitives/benches/pcs_size.rs
Original file line number Diff line number Diff line change
@@ -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<E: Pairing>(num_vars: usize) -> usize {
let rng = &mut test_rng();
let pp = MultilinearKzgPCS::<E>::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<E: Pairing>(num_vars: usize) -> usize {
let rng = &mut test_rng();
let pp = MultilinearKzgPCS::<E>::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::<Bn254>(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::<Bn254>(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::<Bls12_381>(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::<Bls12_381>(num_vars)
);
}
}

0 comments on commit 9bd4d63

Please sign in to comment.