diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 10ee7ce..998d272 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -73,6 +73,9 @@ jobs: - name: Test run: cargo test -- --test-threads=1 + + - name: Bench + run: cargo bench docs: name: Docs diff --git a/benches/perf.rs b/benches/perf.rs index 62fedc8..4bf4418 100644 --- a/benches/perf.rs +++ b/benches/perf.rs @@ -13,6 +13,8 @@ use ark_std::UniformRand; use core::iter; use core::time::Duration; use criterion::*; +use curdleproofs::whisk::g1_generator; +use curdleproofs::whisk::rand_scalar; use curdleproofs::curdleproofs::{generate_crs, CurdleproofsProof}; use curdleproofs::util::{generate_blinders, get_permutation, msm}; @@ -27,99 +29,117 @@ fn apply_permutation_group(vec_a: Vec, permutation: &Vec) -> Vec< fn benchmark_shuffle(c: &mut Criterion) { let mut rng = StdRng::seed_from_u64(0u64); - let N = 512; + let N_VALUES = [16, 32, 64, 128]; let N_BLINDERS = 4; - let ell = N - N_BLINDERS; - - // Construct the CRS - let crs = generate_crs(ell); - - // Get witnesses: the permutation, the randomizer, and a bunch of blinders - let mut permutation: Vec = (0..ell as u32).collect(); - permutation.shuffle(&mut rng); - let k = Fr::rand(&mut rng); - let vec_r_m = generate_blinders(&mut rng, N_BLINDERS); - - // Get shuffle inputs - let vec_R: Vec = iter::repeat_with(|| G1Projective::rand(&mut rng).into_affine()) - .take(ell) - .collect(); - let vec_S: Vec = iter::repeat_with(|| G1Projective::rand(&mut rng).into_affine()) - .take(ell) - .collect(); - - // Derive shuffled outputs - c.bench_function("shuffling", |b| { - b.iter(|| { - let mut vec_T: Vec = vec_R - .iter() - .map(|R| R.mul(k.into_repr()).into_affine()) - .collect(); - let mut vec_U: Vec = vec_S - .iter() - .map(|S| S.mul(k.into_repr()).into_affine()) - .collect(); - vec_T = apply_permutation_group(vec_T, &permutation); - vec_U = apply_permutation_group(vec_U, &permutation); - }) - }); - - let mut vec_T: Vec = vec_R - .iter() - .map(|R| R.mul(k.into_repr()).into_affine()) - .collect(); - let mut vec_U: Vec = vec_S - .iter() - .map(|S| S.mul(k.into_repr()).into_affine()) - .collect(); - vec_T = apply_permutation_group(vec_T, &permutation); - vec_U = apply_permutation_group(vec_U, &permutation); - - let range_as_fr: Vec = (0..ell as u32).into_iter().map(|s| Fr::from(s)).collect(); - let sigma_ell = get_permutation(&range_as_fr, &permutation); - let M = msm(&crs.vec_G, &sigma_ell) + msm(&crs.vec_H, &vec_r_m); - - c.bench_function("prover", |b| { - b.iter(|| { - CurdleproofsProof::new( - &crs, - vec_R.clone(), - vec_S.clone(), - vec_T.clone(), - vec_U.clone(), - M, - permutation.clone(), - k, - vec_r_m.clone(), - &mut rng, - ); - }) - }); - - let shuffle_proof = CurdleproofsProof::new( - &crs, - vec_R.clone(), - vec_S.clone(), - vec_T.clone(), - vec_U.clone(), - M, - permutation, - k, - vec_r_m, - &mut rng, - ); - - c.bench_function("verifier", |b| { - b.iter(|| { - assert!(shuffle_proof - .verify(&crs, &vec_R, &vec_S, &vec_T, &vec_U, &M, &mut rng) - .is_ok()); - }) - }); + + for N in N_VALUES { + let ell = N - N_BLINDERS; + + // Construct the CRS + let crs = generate_crs(ell); + + // Get witnesses: the permutation, the randomizer, and a bunch of blinders + let mut permutation: Vec = (0..ell as u32).collect(); + permutation.shuffle(&mut rng); + let k = Fr::rand(&mut rng); + let vec_r_m = generate_blinders(&mut rng, N_BLINDERS); + + // Get shuffle inputs + let vec_R: Vec = iter::repeat_with(|| G1Projective::rand(&mut rng).into_affine()) + .take(ell) + .collect(); + let vec_S: Vec = iter::repeat_with(|| G1Projective::rand(&mut rng).into_affine()) + .take(ell) + .collect(); + + // Derive shuffled outputs + c.bench_function(&format!("shuffling N={}", N), |b| { + b.iter(|| { + let mut vec_T: Vec = vec_R + .iter() + .map(|R| R.mul(k.into_repr()).into_affine()) + .collect(); + let mut vec_U: Vec = vec_S + .iter() + .map(|S| S.mul(k.into_repr()).into_affine()) + .collect(); + vec_T = apply_permutation_group(vec_T, &permutation); + vec_U = apply_permutation_group(vec_U, &permutation); + }) + }); + + let mut vec_T: Vec = vec_R + .iter() + .map(|R| R.mul(k.into_repr()).into_affine()) + .collect(); + let mut vec_U: Vec = vec_S + .iter() + .map(|S| S.mul(k.into_repr()).into_affine()) + .collect(); + vec_T = apply_permutation_group(vec_T, &permutation); + vec_U = apply_permutation_group(vec_U, &permutation); + + let range_as_fr: Vec = (0..ell as u32).into_iter().map(|s| Fr::from(s)).collect(); + let sigma_ell = get_permutation(&range_as_fr, &permutation); + let M = msm(&crs.vec_G, &sigma_ell) + msm(&crs.vec_H, &vec_r_m); + + c.bench_function(&format!("prover N={}", N), |b| { + b.iter(|| { + CurdleproofsProof::new( + &crs, + vec_R.clone(), + vec_S.clone(), + vec_T.clone(), + vec_U.clone(), + M, + permutation.clone(), + k, + vec_r_m.clone(), + &mut rng, + ); + }) + }); + + let shuffle_proof = CurdleproofsProof::new( + &crs, + vec_R.clone(), + vec_S.clone(), + vec_T.clone(), + vec_U.clone(), + M, + permutation, + k, + vec_r_m, + &mut rng, + ); + + c.bench_function(&format!("verifier N={}", N), |b| { + b.iter(|| { + assert!(shuffle_proof + .verify(&crs, &vec_R, &vec_S, &vec_T, &vec_U, &M, &mut rng) + .is_ok()); + }) + }); + } + + // Duty discovery benchmark + + for N in [1, 100, 10000] { + let k = rand_scalar(&mut rng); + let p = g1_generator(); + + c.bench_function(&format!("G1 point multiplication N={}", N), |b| { + b.iter(|| { + for _ in 0..N { + let _ = p == p.mul(k); + } + }) + }); + } } criterion_group! {name = shuffle; - config = Criterion::default().measurement_time(Duration::from_secs(60)); + config = Criterion::default().measurement_time(Duration::from_secs(30)); targets = benchmark_shuffle }