Skip to content

Commit

Permalink
Initial Shplonk prover/verifier implementation (microsoft#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 authored 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
Loading

0 comments on commit 4cc09c8

Please sign in to comment.