Skip to content

Commit

Permalink
feat: add benchmark for grand_products
Browse files Browse the repository at this point in the history
  • Loading branch information
sagar-a16z committed Oct 3, 2024
1 parent 1feb779 commit 321bbd0
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 23 deletions.
4 changes: 4 additions & 0 deletions jolt-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ common = { path = "../common" }
name = "iai"
harness = false

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

[lib]
name = "jolt_core"
path = "src/lib.rs"
Expand Down
126 changes: 126 additions & 0 deletions jolt-core/benches/grand_product_quark.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
use ark_bn254::{Bn254, Fr};
use criterion::Criterion;
use jolt_core::field::JoltField;
use jolt_core::poly::commitment::commitment_scheme::{BatchType, CommitShape, CommitmentScheme};
use jolt_core::poly::commitment::hyperkzg::HyperKZG;
use jolt_core::poly::commitment::zeromorph::Zeromorph;
use jolt_core::poly::opening_proof::{ProverOpeningAccumulator, VerifierOpeningAccumulator};
use jolt_core::subprotocols::grand_product::{BatchedGrandProduct, BatchedGrandProductProof};
use jolt_core::subprotocols::grand_product_quarks::QuarkGrandProduct;
use jolt_core::utils::transcript::ProofTranscript;
use rand_chacha::ChaCha20Rng;
use rand_core::SeedableRng;

const SRS_SIZE: usize = 1 << 8;

fn setup_bench<PCS, F>(
num_layers: usize,
layer_size: usize,
) -> (
// Leaves
Vec<Vec<F>>,
PCS::Setup,
// Products of leaves
Vec<F>,
)
where
PCS: CommitmentScheme<Field = F>,
F: JoltField,
{
let mut rng = ChaCha20Rng::seed_from_u64(111111u64);

// Generate leaves
let leaves: Vec<Vec<F>> = (0..num_layers)
.map(|_| {
std::iter::repeat_with(|| F::random(&mut rng))
.take(layer_size)
.collect()
})
.collect();

// Compute known products (one per layer)
let known_products: Vec<F> = leaves.iter().map(|layer| layer.iter().product()).collect();

let setup = PCS::setup(&[CommitShape::new(SRS_SIZE, BatchType::Big)]);

(leaves, setup, known_products)
}

fn benchmark_prove<PCS, F>(c: &mut Criterion, name: &str, num_layer: usize, layer_size: usize)
where
PCS: CommitmentScheme<Field = F>, // Generic over PCS implementing CommitmentScheme for field F
F: JoltField, // Generic over a field F
{
let (leaves, setup, _) = setup_bench::<PCS, F>(num_layer, layer_size);

let mut grand_product =
<QuarkGrandProduct<F> as BatchedGrandProduct<F, PCS>>::construct(leaves);

c.bench_function(&format!("Grand Product Prove - {}", name), |b| {
b.iter(|| {
// Prove the grand product
let mut transcript = ProofTranscript::new(b"test_transcript");
let mut prover_accumulator: ProverOpeningAccumulator<F> =
ProverOpeningAccumulator::new();
let _proof: BatchedGrandProductProof<PCS> = grand_product
.prove_grand_product(Some(&mut prover_accumulator), &mut transcript, Some(&setup))
.0;

let _batched_proof =
prover_accumulator.reduce_and_prove::<PCS>(&setup, &mut transcript);
});
});
}

fn benchmark_verify<PCS, F>(c: &mut Criterion, name: &str, num_layers: usize, layer_size: usize)
where
PCS: CommitmentScheme<Field = F>, // Generic over PCS implementing CommitmentScheme for field F
F: JoltField, // Generic over a field F
{
let (leaves, setup, known_products) = setup_bench::<PCS, F>(num_layers, layer_size);

let mut transcript = ProofTranscript::new(b"test_transcript");
let mut grand_product =
<QuarkGrandProduct<F> as BatchedGrandProduct<F, PCS>>::construct(leaves);
let mut prover_accumulator: ProverOpeningAccumulator<F> = ProverOpeningAccumulator::new();
let proof: BatchedGrandProductProof<PCS> = grand_product
.prove_grand_product(Some(&mut prover_accumulator), &mut transcript, Some(&setup))
.0;
let batched_proof = prover_accumulator.reduce_and_prove(&setup, &mut transcript);

c.bench_function(&format!("Grand Product Verify - {}", name), |b| {
b.iter(|| {
// Verify the grand product
transcript = ProofTranscript::new(b"test_transcript");
let mut verifier_accumulator: VerifierOpeningAccumulator<F, PCS> =
VerifierOpeningAccumulator::new();
let _ = QuarkGrandProduct::verify_grand_product(
&proof,
&known_products,
Some(&mut verifier_accumulator),
&mut transcript,
Some(&setup),
);

assert!(verifier_accumulator
.reduce_and_verify(&setup, &batched_proof, &mut transcript)
.is_ok());
});
});
}

fn main() {
let mut criterion = Criterion::default()
.configure_from_args()
.warm_up_time(std::time::Duration::from_secs(5));
let num_layers = 20;
let layer_size = 1 << 10;
// Zeromorph
benchmark_prove::<Zeromorph<Bn254>, Fr>(&mut criterion, "Zeromorph", num_layers, layer_size);
benchmark_verify::<Zeromorph<Bn254>, Fr>(&mut criterion, "Zeromorph", num_layers, layer_size);
// HyperKZG
benchmark_prove::<HyperKZG<Bn254>, Fr>(&mut criterion, "HyperKZG", num_layers, layer_size);
benchmark_verify::<HyperKZG<Bn254>, Fr>(&mut criterion, "HyperKZG", num_layers, layer_size);

criterion.final_summary();
}
2 changes: 1 addition & 1 deletion jolt-core/src/jolt/vm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,7 @@ pub trait Jolt<F: JoltField, PCS: CommitmentScheme<Field = F>, const C: usize, c
// Batch-verify all openings
opening_accumulator.reduce_and_verify(
&preprocessing.generators,
proof.opening_proof,
&proof.opening_proof,
&mut transcript,
)?;

Expand Down
26 changes: 16 additions & 10 deletions jolt-core/src/poly/commitment/hyperkzg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
//! This means that Spartan's polynomial IOP can use commit to its polynomials as-is without incurring any interpolations or FFTs.
//! (2) HyperKZG is specialized to use KZG as the univariate commitment scheme, so it includes several optimizations (both during the transformation of multilinear-to-univariate claims
//! and within the KZG commitment scheme implementation itself).
use super::{commitment_scheme::{BatchType, CommitmentScheme}, kzg, kzg::{KZGProverKey, KZGVerifierKey, UnivariateKZG}};
use super::{
commitment_scheme::{BatchType, CommitmentScheme},
kzg,
kzg::{KZGProverKey, KZGVerifierKey, UnivariateKZG},
};
use crate::field;
use crate::poly::commitment::commitment_scheme::CommitShape;
use crate::utils::mul_0_1_optimized;
Expand Down Expand Up @@ -548,15 +552,17 @@ where
evals.len()
);
match batch_type {
BatchType::GrandProducts => HyperKZGCommitment(UnivariateKZG::commit_slice_with_mode(
&gens.0.kzg_pk,
evals,
kzg::CommitMode::GrandProduct,
)
.unwrap()),
_ => {
HyperKZGCommitment(UnivariateKZG::commit_slice(&gens.0.kzg_pk, evals).unwrap())
}
BatchType::GrandProducts => HyperKZGCommitment(
UnivariateKZG::commit_slice_with_mode(
&gens.0.kzg_pk,
evals,
kzg::CommitMode::GrandProduct,
)
.unwrap(),
),
_ => HyperKZGCommitment(
UnivariateKZG::commit_slice(&gens.0.kzg_pk, evals).unwrap(),
),
}
})
.collect::<Vec<_>>()
Expand Down
28 changes: 19 additions & 9 deletions jolt-core/src/poly/commitment/kzg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ use ark_ec::{pairing::Pairing, AffineRepr, CurveGroup};
use ark_ff::PrimeField;
use ark_std::{One, UniformRand, Zero};
use rand_core::{CryptoRng, RngCore};
use rayon::prelude::*;
use std::marker::PhantomData;
use std::sync::Arc;
use rayon::prelude::*;

#[derive(Clone, Debug)]
pub struct SRS<P: Pairing> {
Expand Down Expand Up @@ -67,11 +67,13 @@ impl<P: Pairing> SRS<P> {
let num_powers = (g1_powers.len() as f64).log2().floor() as usize + 1;
let all_ones_coeffs: Vec<P::ScalarField> = vec![P::ScalarField::one(); num_g1_powers + 1];
let powers_of_2 = (0..num_powers).into_par_iter().map(|i| 1usize << i);
let g_products= powers_of_2.map(|power| {
<P::G1 as VariableBaseMSM>::msm(&g1_powers[..power], &all_ones_coeffs[..power])
.unwrap()
.into_affine()
}).collect();
let g_products = powers_of_2
.map(|power| {
<P::G1 as VariableBaseMSM>::msm(&g1_powers[..power], &all_ones_coeffs[..power])
.unwrap()
.into_affine()
})
.collect();

Self {
g1_powers,
Expand Down Expand Up @@ -210,9 +212,13 @@ where

match mode {
CommitMode::Default => {
let c = <P::G1 as VariableBaseMSM>::msm(&pk.g1_powers()[offset..coeffs.len()], &coeffs[offset..]).unwrap();
let c = <P::G1 as VariableBaseMSM>::msm(
&pk.g1_powers()[offset..coeffs.len()],
&coeffs[offset..],
)
.unwrap();
Ok(c.into_affine())
},
}
CommitMode::GrandProduct => {
let g1_powers = &pk.g1_powers()[offset..coeffs.len()];
let coeffs = &coeffs[offset..];
Expand All @@ -234,6 +240,7 @@ where
let non_one_commitment = if !non_one_coeffs.is_empty() {
<P::G1 as VariableBaseMSM>::msm(&non_one_bases, &non_one_coeffs).unwrap()
} else {
// TODO(sagar): is this right?
P::G1::zero()
};

Expand All @@ -244,10 +251,13 @@ where
}

let num_powers = num_powers.floor() as usize;
//TODO(sagar): Remove this print
// println!("KZG GrandProduct Optimization: non_one_coeffs: {}, total coeffs: {}, non-1%: {}%", non_one_coeffs.len(), coeffs.len(), (non_one_coeffs.len() as f64)/coeffs.len() as f64 * 100.0);

// Combine G * H: Multiply the precomputed G commitment with the non-1 commitment (H)
let final_commitment = pk.srs.g_products[num_powers] + non_one_commitment;
Ok(final_commitment.into_affine())
},
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion jolt-core/src/poly/opening_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,7 @@ impl<F: JoltField, PCS: CommitmentScheme<Field = F>> VerifierOpeningAccumulator<
pub fn reduce_and_verify(
&self,
pcs_setup: &PCS::Setup,
reduced_opening_proof: ReducedOpeningProof<F, PCS>,
reduced_opening_proof: &ReducedOpeningProof<F, PCS>,
transcript: &mut ProofTranscript,
) -> Result<(), ProofVerifyError> {
let num_sumcheck_rounds = self
Expand Down
4 changes: 2 additions & 2 deletions jolt-core/src/subprotocols/grand_product_quarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,7 @@ mod quark_grand_product_tests {
assert!(result.is_ok(), "Proof did not verify");

assert!(verifier_accumulator
.reduce_and_verify(&setup, batched_proof, &mut transcript)
.reduce_and_verify(&setup, &batched_proof, &mut transcript)
.is_ok());
}

Expand Down Expand Up @@ -707,7 +707,7 @@ mod quark_grand_product_tests {
Some(&setup),
);
assert!(verifier_accumulator
.reduce_and_verify(&setup, batched_proof, &mut transcript)
.reduce_and_verify(&setup, &batched_proof, &mut transcript)
.is_ok());
}
}

0 comments on commit 321bbd0

Please sign in to comment.