Skip to content

Commit

Permalink
Initial Shplonk prover/verifier implementation (#301)
Browse files Browse the repository at this point in the history
* feat: Initial Shplonk prover/verifier as EvaluationEngine

* feat: More optimal pairing check

* feat: Avoid including C_P to the proof/transcript

* feat: Check R / evals correlation on verification

* feat: Verify correctness of P_i polynomials computing

* chore: Add TODOs about avoiding operations with constant polynomial

* chore: Fix clippy issues

* chore: Review iteration fixes

* feat: Include Shplonk PCS into the benchmark
  • Loading branch information
storojs72 committed Feb 13, 2024
1 parent 4ae3a57 commit 4cc09c8
Show file tree
Hide file tree
Showing 6 changed files with 694 additions and 46 deletions.
17 changes: 9 additions & 8 deletions benches/pcs.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use arecibo::provider::{
hyperkzg::EvaluationEngine as MLEvaluationEngine,
ipa_pc::EvaluationEngine as IPAEvaluationEngine, non_hiding_zeromorph::ZMPCS, Bn256Engine,
Bn256EngineKZG, Bn256EngineZM,
ipa_pc::EvaluationEngine as IPAEvaluationEngine, non_hiding_zeromorph::ZMPCS,
shplonk::EvaluationEngine as Shplonk, Bn256Engine, Bn256EngineKZG, Bn256EngineZM,
};
use arecibo::spartan::polys::multilinear::MultilinearPolynomial;
use arecibo::traits::{
Expand Down Expand Up @@ -41,7 +41,7 @@ criterion_main!(pcs);

const NUM_VARS_TEST_VECTOR: [usize; 6] = [10, 12, 14, 16, 18, 20];

struct BenchAssests<E: Engine, EE: EvaluationEngineTrait<E>> {
struct BenchAssets<E: Engine, EE: EvaluationEngineTrait<E>> {
poly: MultilinearPolynomial<<E as Engine>::Scalar>,
point: Vec<<E as Engine>::Scalar>,
eval: <E as Engine>::Scalar,
Expand Down Expand Up @@ -73,7 +73,7 @@ pub fn random_poly_with_eval<E: Engine, R: RngCore + CryptoRng>(
(poly, point, eval)
}

impl<E: Engine, EE: EvaluationEngineTrait<E>> BenchAssests<E, EE> {
impl<E: Engine, EE: EvaluationEngineTrait<E>> BenchAssets<E, EE> {
pub(crate) fn from_num_vars<R: CryptoRng + RngCore>(num_vars: usize, rng: &mut R) -> Self {
let (poly, point, eval) = random_poly_with_eval::<E, R>(num_vars, rng);

Expand Down Expand Up @@ -117,7 +117,7 @@ macro_rules! benchmark_all_engines {
let mut rng = rand::rngs::StdRng::seed_from_u64(*num_vars as u64);

$(
let $assets: BenchAssests<_, $eval_engine> = BenchAssests::from_num_vars::<StdRng>(*num_vars, &mut rng);
let $assets: BenchAssets<_, $eval_engine> = BenchAssets::from_num_vars::<StdRng>(*num_vars, &mut rng);
)*

// Proving group
Expand Down Expand Up @@ -159,13 +159,14 @@ fn bench_pcs(c: &mut Criterion) {
bench_pcs_verifying_internal,
(ipa_assets, IPAEvaluationEngine<Bn256Engine>),
(hyperkzg_assets, MLEvaluationEngine<Bn256, Bn256EngineKZG>),
(zm_assets, ZMPCS<Bn256, Bn256EngineZM>)
(zm_assets, ZMPCS<Bn256, Bn256EngineZM>),
(shplonk_assets, Shplonk<Bn256, Bn256EngineKZG>)
);
}

fn bench_pcs_proving_internal<E: Engine, EE: EvaluationEngineTrait<E>>(
b: &mut Bencher<'_>,
bench_assets: &BenchAssests<E, EE>,
bench_assets: &BenchAssets<E, EE>,
) {
// Bench generate proof.
b.iter(|| {
Expand All @@ -184,7 +185,7 @@ fn bench_pcs_proving_internal<E: Engine, EE: EvaluationEngineTrait<E>>(

fn bench_pcs_verifying_internal<E: Engine, EE: EvaluationEngineTrait<E>>(
b: &mut Bencher<'_>,
bench_assets: &BenchAssests<E, EE>,
bench_assets: &BenchAssets<E, EE>,
) {
// Bench verify proof.
b.iter(|| {
Expand Down
15 changes: 9 additions & 6 deletions src/provider/hyperkzg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,18 +61,20 @@ where
E::Fr: TranscriptReprTrait<E::G1>,
E::G1Affine: TranscriptReprTrait<E::G1>, // TODO: this bound on DlogGroup is really unusable!
{
fn compute_challenge(
/// TODO: write doc
pub fn compute_challenge(
com: &[E::G1Affine],
transcript: &mut impl TranscriptEngineTrait<NE>,
) -> E::Fr {
transcript.absorb(b"c", &com.to_vec().as_slice());
transcript.absorb(b"c", &com);
transcript.squeeze(b"c").unwrap()
}

/// TODO: write doc
// Compute challenge q = Hash(vk, C0, ..., C_{k-1}, u0, ...., u_{t-1},
// (f_i(u_j))_{i=0..k-1,j=0..t-1})
// It is assumed that both 'C' and 'u' are already absorbed by the transcript
fn get_batch_challenge(
pub fn get_batch_challenge(
v: &[Vec<E::Fr>],
transcript: &mut impl TranscriptEngineTrait<NE>,
) -> E::Fr {
Expand All @@ -88,14 +90,15 @@ where
transcript.squeeze(b"r").unwrap()
}

fn batch_challenge_powers(q: E::Fr, k: usize) -> Vec<E::Fr> {
// Compute powers of q : (1, q, q^2, ..., q^(k-1))
/// Compute powers of q : (1, q, q^2, ..., q^(k-1))
pub fn batch_challenge_powers(q: E::Fr, k: usize) -> Vec<E::Fr> {
std::iter::successors(Some(E::Fr::ONE), |&x| Some(x * q))
.take(k)
.collect()
}

fn verifier_second_challenge(
/// TODO: write doc
pub fn verifier_second_challenge(
W: &[E::G1Affine],
transcript: &mut impl TranscriptEngineTrait<NE>,
) -> E::Fr {
Expand Down
1 change: 1 addition & 0 deletions src/provider/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
pub mod hyperkzg;
pub mod ipa_pc;
pub mod non_hiding_zeromorph;
pub mod shplonk;

// crate-public modules, made crate-public mostly for tests
pub(crate) mod bn256_grumpkin;
Expand Down
2 changes: 1 addition & 1 deletion src/provider/non_hiding_kzg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ pub struct UVKZGProof<E: Engine> {
}

/// Polynomial and its associated types
pub type UVKZGPoly<F> = crate::spartan::polys::univariate::UniPoly<F>;
type UVKZGPoly<F> = crate::spartan::polys::univariate::UniPoly<F>;

#[derive(Debug, Eq, PartialEq, Default)]
/// KZG Polynomial Commitment Scheme on univariate polynomial.
Expand Down
53 changes: 22 additions & 31 deletions src/provider/non_hiding_zeromorph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::{
errors::{NovaError, PCSError},
provider::{
non_hiding_kzg::{
KZGProverKey, KZGVerifierKey, UVKZGCommitment, UVKZGEvaluation, UVKZGPoly, UVKZGProof,
KZGProverKey, KZGVerifierKey, UVKZGCommitment, UVKZGEvaluation, UVKZGProof,
UniversalKZGParam, UVKZGPCS,
},
traits::DlogGroup,
Expand All @@ -33,6 +33,7 @@ use std::sync::Arc;
use std::{borrow::Borrow, iter, marker::PhantomData};

use crate::provider::kzg_commitment::KZGCommitmentEngine;
use crate::spartan::polys::univariate::UniPoly;

/// `ZMProverKey` is used to generate a proof
#[derive(Clone, Debug, Eq, PartialEq)]
Expand Down Expand Up @@ -156,7 +157,7 @@ where
if pp.commit_pp.powers_of_g().len() < poly.Z.len() {
return Err(PCSError::LengthError.into());
}
UVKZGPCS::commit(&pp.commit_pp, UVKZGPoly::ref_cast(&poly.Z)).map(|c| c.into())
UVKZGPCS::commit(&pp.commit_pp, UniPoly::ref_cast(&poly.Z)).map(|c| c.into())
}

/// On input a polynomial `poly` and a point `point`, outputs a proof for the
Expand Down Expand Up @@ -184,10 +185,7 @@ where
debug_assert_eq!(remainder, eval.0);

// Compute the multilinear quotients q_k = q_k(X_0, ..., X_{k-1})
let quotients_polys = quotients
.into_iter()
.map(UVKZGPoly::new)
.collect::<Vec<_>>();
let quotients_polys = quotients.into_iter().map(UniPoly::new).collect::<Vec<_>>();

// Compute and absorb commitments C_{q_k} = [q_k], k = 0,...,d-1
let q_comms = quotients_polys
Expand Down Expand Up @@ -215,7 +213,7 @@ where
let (eval_scalar, (degree_check_q_scalars, zmpoly_q_scalars)) =
eval_and_quotient_scalars(y, x, z, point);
// f = z * poly.Z + q_hat + (-z * Φ_n(x) * e) + ∑_k (q_scalars_k * q_k)
let mut f = UVKZGPoly::new(poly.Z.clone());
let mut f = UniPoly::new(poly.Z.clone());
f *= &z;
f += &q_hat;
f[0] += eval_scalar * eval.0;
Expand Down Expand Up @@ -360,8 +358,8 @@ fn quotients<F: PrimeField>(poly: &MultilinearPolynomial<F>, point: &[F]) -> (Ve
// Compute the batched, lifted-degree quotient `\hat{q}`
fn batched_lifted_degree_quotient<F: PrimeField>(
y: F,
quotients_polys: &[UVKZGPoly<F>],
) -> (UVKZGPoly<F>, usize) {
quotients_polys: &[UniPoly<F>],
) -> (UniPoly<F>, usize) {
let num_vars = quotients_polys.len();

let powers_of_y = (0..num_vars)
Expand Down Expand Up @@ -390,7 +388,7 @@ fn batched_lifted_degree_quotient<F: PrimeField>(
},
);

(UVKZGPoly::new(q_hat), 1 << (num_vars - 1))
(UniPoly::new(q_hat), 1 << (num_vars - 1))
}

/// Computes some key terms necessary for computing the partially evaluated univariate ZM polynomial
Expand Down Expand Up @@ -523,12 +521,11 @@ mod test {

use super::quotients;

use crate::spartan::polys::univariate::UniPoly;
use crate::{
errors::PCSError,
provider::{
non_hiding_kzg::{
trim, KZGProverKey, UVKZGCommitment, UVKZGPoly, UniversalKZGParam, UVKZGPCS,
},
non_hiding_kzg::{trim, KZGProverKey, UVKZGCommitment, UniversalKZGParam, UVKZGPCS},
non_hiding_zeromorph::{batched_lifted_degree_quotient, eval_and_quotient_scalars, ZMPCS},
traits::DlogGroup,
util::test_utils::prove_verify_from_num_vars,
Expand Down Expand Up @@ -598,9 +595,9 @@ mod test {
let n = 1 << num_vars; // Assuming N = 2^num_vars

// Define mock q_k with deg(q_k) = 2^k - 1
let q_0 = UVKZGPoly::new(vec![Scalar::one()]);
let q_1 = UVKZGPoly::new(vec![Scalar::from(2), Scalar::from(3)]);
let q_2 = UVKZGPoly::new(vec![
let q_0 = UniPoly::new(vec![Scalar::one()]);
let q_1 = UniPoly::new(vec![Scalar::from(2), Scalar::from(3)]);
let q_2 = UniPoly::new(vec![
Scalar::from(4),
Scalar::from(5),
Scalar::from(6),
Expand Down Expand Up @@ -644,10 +641,7 @@ mod test {
});

// Compare the computed and expected batched quotients
assert_eq!(
batched_quotient.0,
UVKZGPoly::new(batched_quotient_expected)
);
assert_eq!(batched_quotient.0, UniPoly::new(batched_quotient_expected));
}

#[test]
Expand All @@ -657,9 +651,9 @@ mod test {
let num_vars = 3;

// Define some mock q_k with deg(q_k) = 2^k - 1
let _q_0 = UVKZGPoly::new(vec![Scalar::one()]);
let _q_1 = UVKZGPoly::new(vec![Scalar::from(2), Scalar::from(3)]);
let _q_2 = UVKZGPoly::new(vec![
let _q_0 = UniPoly::new(vec![Scalar::one()]);
let _q_1 = UniPoly::new(vec![Scalar::from(2), Scalar::from(3)]);
let _q_2 = UniPoly::new(vec![
Scalar::from(4),
Scalar::from(5),
Scalar::from(6),
Expand Down Expand Up @@ -713,9 +707,9 @@ mod test {
let mut rng = ChaCha20Rng::from_seed([0u8; 32]);

// Define some mock q_k with deg(q_k) = 2^k - 1
let _q_0 = UVKZGPoly::new(vec![Scalar::one()]);
let _q_1 = UVKZGPoly::new(vec![Scalar::from(2), Scalar::from(3)]);
let _q_2 = UVKZGPoly::new(vec![
let _q_0 = UniPoly::new(vec![Scalar::one()]);
let _q_1 = UniPoly::new(vec![Scalar::from(2), Scalar::from(3)]);
let _q_2 = UniPoly::new(vec![
Scalar::from(4),
Scalar::from(5),
Scalar::from(6),
Expand Down Expand Up @@ -755,7 +749,7 @@ mod test {

fn commit_filtered<E>(
prover_param: impl Borrow<KZGProverKey<E>>,
poly: &UVKZGPoly<E::Fr>,
poly: &UniPoly<E::Fr>,
) -> Result<UVKZGCommitment<E>, NovaError>
where
E: MultiMillerLoop,
Expand Down Expand Up @@ -802,10 +796,7 @@ mod test {
}

let (quotients, _remainder) = quotients(&multilinear_poly, random_points.as_slice());
let quotients_polys = quotients
.into_iter()
.map(UVKZGPoly::new)
.collect::<Vec<_>>();
let quotients_polys = quotients.into_iter().map(UniPoly::new).collect::<Vec<_>>();

let (q_hat, offset) = batched_lifted_degree_quotient(E::Fr::random(&mut rng), &quotients_polys);

Expand Down

1 comment on commit 4cc09c8

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmarks

Table of Contents

Overview

This benchmark report shows the Arecibo GPU benchmarks.
NVIDIA L4
Intel(R) Xeon(R) CPU @ 2.20GHz
32 vCPUs
125 GB RAM
Workflow run: https://github.com/lurk-lab/arecibo/actions/runs/7889878726

Benchmark Results

RecursiveSNARK-NIVC-2

ref=4ae3a57 ref=4cc09c8
Prove-NumCons-6540 53.31 ms (✅ 1.00x) 53.13 ms (✅ 1.00x faster)
Verify-NumCons-6540 33.05 ms (✅ 1.00x) 33.00 ms (✅ 1.00x faster)
Prove-NumCons-1028888 342.70 ms (✅ 1.00x) 342.83 ms (✅ 1.00x slower)
Verify-NumCons-1028888 255.36 ms (✅ 1.00x) 255.37 ms (✅ 1.00x slower)

CompressedSNARK-NIVC-Commitments-2

ref=4ae3a57 ref=4cc09c8
Prove-NumCons-6540 13.97 s (✅ 1.00x) 14.03 s (✅ 1.00x slower)
Verify-NumCons-6540 81.88 ms (✅ 1.00x) 81.73 ms (✅ 1.00x faster)
Prove-NumCons-1028888 110.72 s (✅ 1.00x) 110.46 s (✅ 1.00x faster)
Verify-NumCons-1028888 779.31 ms (✅ 1.00x) 773.93 ms (✅ 1.01x faster)

Made with criterion-table

Please sign in to comment.