From 052626bd0fff04ac7411ea54c46cd98df93b9055 Mon Sep 17 00:00:00 2001 From: zhenfei Date: Thu, 16 Jun 2022 10:54:50 -0400 Subject: [PATCH] multi-commiting/opening --- pcs/src/commit.rs | 160 ++++++++++++++++++++++++++++++++++++++++------ pcs/src/lib.rs | 14 ++++ 2 files changed, 156 insertions(+), 18 deletions(-) diff --git a/pcs/src/commit.rs b/pcs/src/commit.rs index 8447819a..7cb3cd38 100644 --- a/pcs/src/commit.rs +++ b/pcs/src/commit.rs @@ -1,16 +1,15 @@ +use crate::{ + KZGMultilinearPC, MultilinearCommitmentScheme, PCSErrors, ProverParam, UniversalParams, + VerifierParam, +}; use ark_ec::{ msm::{FixedBaseMSM, VariableBaseMSM}, AffineCurve, PairingEngine, ProjectiveCurve, }; use ark_ff::PrimeField; -use ark_poly::MultilinearExtension; +use ark_poly::{DenseMultilinearExtension, MultilinearExtension}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Read, SerializationError, Write}; -use ark_std::{end_timer, rand::RngCore, start_timer, vec::Vec, One, Zero}; - -use crate::{ - KZGMultilinearPC, MultilinearCommitmentScheme, PCSErrors, ProverParam, UniversalParams, - VerifierParam, -}; +use ark_std::{end_timer, log2, rand::RngCore, start_timer, vec::Vec, One, Zero}; #[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug)] /// commitment @@ -77,6 +76,36 @@ impl MultilinearCommitmentScheme for KZGMultilinearPC { Ok(Commitment { nv, g_product }) } + /// Generate a commitment for a list of polynomials. + /// + /// This function takes `\sum 2^num_vars[i]` number of scalar + /// multiplications over G1. + fn multi_commit( + prover_param: &Self::ProverParam, + polys: &[impl MultilinearExtension], + ) -> Result { + let commit_timer = start_timer!(|| "commit"); + let poly = merge_polynomials(polys); + + let scalars: Vec<_> = poly + .to_evaluations() + .iter() + .map(|x| x.into_repr()) + .collect(); + + let g_product = VariableBaseMSM::multi_scalar_mul( + &prover_param.powers_of_g[0].evals, + scalars.as_slice(), + ) + .into_affine(); + + end_timer!(commit_timer); + Ok(Commitment { + nv: poly.num_vars, + g_product, + }) + } + /// On input a polynomial `p` and a point `point`, outputs a proof for the /// same. This function does not need to take the evaluation value as an /// input. @@ -142,6 +171,30 @@ impl MultilinearCommitmentScheme for KZGMultilinearPC { Ok(Proof { proofs }) } + /// On input a polynomial `p` and a point `point`, outputs a proof for the + /// same. This function does not need to take the evaluation value as an + /// input. + /// + /// This function takes 2^{num_var +1} number of scalar multiplications over + /// G2: + /// - it proceeds with `num_var` number of rounds, + /// - at round i, we compute an MSM for `2^{num_var - i + 1}` number of G2 + /// elements. + fn multi_open( + prover_param: &Self::ProverParam, + polynomials: &[impl MultilinearExtension], + point: &[E::Fr], + ) -> Result { + let open_timer = start_timer!(|| "open"); + + let poly = merge_polynomials(polynomials); + + let proof = Self::open(prover_param, &poly, point)?; + + end_timer!(open_timer); + Ok(proof) + } + /// Verifies that `value` is the evaluation at `x` of the polynomial /// committed inside `comm`. /// @@ -229,17 +282,50 @@ impl MultilinearCommitmentScheme for KZGMultilinearPC { } } +/// Return the number of variables that one need for an MLE to +/// batch the list of MLEs +#[inline] +fn get_nv(polynomials: &[impl MultilinearExtension]) -> usize { + polynomials.iter().map(|x| x.num_vars()).max().unwrap() + log2(polynomials.len()) as usize +} + +fn merge_polynomials( + polynomials: &[impl MultilinearExtension], +) -> DenseMultilinearExtension { + let individual_max = polynomials.iter().map(|x| x.num_vars()).max() + // safe unwrap since polynomials is not empty + .unwrap(); + let new_nv = get_nv(polynomials); + let mut scalars = vec![]; + for poly in polynomials.iter() { + let mut scalar = poly.to_evaluations(); + + if poly.num_vars() < individual_max { + scalar + .extend_from_slice(vec![F::zero(); (1 << individual_max) - scalar.len()].as_ref()); + } + scalars.extend_from_slice(scalar.as_slice()); + } + scalars.extend_from_slice(vec![F::zero(); (1 << new_nv) - scalars.len()].as_ref()); + DenseMultilinearExtension::from_evaluations_vec(new_nv, scalars) +} + #[cfg(test)] mod tests { use super::*; use ark_bls12_381::Bls12_381; use ark_ec::PairingEngine; - use ark_poly::{DenseMultilinearExtension, MultilinearExtension, SparseMultilinearExtension}; - use ark_std::{rand::RngCore, test_rng, vec::Vec, UniformRand}; + use ark_poly::{DenseMultilinearExtension, MultilinearExtension}; + use ark_std::{ + rand::{Rng, RngCore}, + test_rng, + vec::Vec, + UniformRand, + }; type E = Bls12_381; type Fr = ::Fr; - fn test_kzg_mlpc_helper( + fn test_single_helper( uni_params: &UniversalParams, poly: &impl MultilinearExtension, rng: &mut R, @@ -261,24 +347,62 @@ mod tests { } #[test] - fn setup_commit_verify_correct_polynomials() -> Result<(), PCSErrors> { + fn test_single_commit() -> Result<(), PCSErrors> { let mut rng = test_rng(); let uni_params = KZGMultilinearPC::::setup(&mut rng, 10)?; // normal polynomials let poly1 = DenseMultilinearExtension::rand(8, &mut rng); - test_kzg_mlpc_helper(&uni_params, &poly1, &mut rng)?; + test_single_helper(&uni_params, &poly1, &mut rng)?; + + // single-variate polynomials + let poly2 = DenseMultilinearExtension::rand(1, &mut rng); + test_single_helper(&uni_params, &poly2, &mut rng)?; + + Ok(()) + } - let poly2 = SparseMultilinearExtension::rand_with_config(9, 1 << 5, &mut rng); - test_kzg_mlpc_helper(&uni_params, &poly2, &mut rng)?; + fn test_multi_commit_helper( + uni_params: &UniversalParams, + polys: &[impl MultilinearExtension], + rng: &mut R, + ) -> Result<(), PCSErrors> { + let poly = merge_polynomials(polys); + let nv = poly.num_vars; + + let (ck, vk) = uni_params.trim(nv)?; + let point: Vec<_> = (0..nv).map(|_| Fr::rand(rng)).collect(); + let com = KZGMultilinearPC::multi_commit(&ck, polys)?; + let proof = KZGMultilinearPC::multi_open(&ck, polys, &point)?; + + let value = poly.evaluate(&point).unwrap(); + assert!(KZGMultilinearPC::verify(&vk, &com, &point, value, &proof)?); + + let value = Fr::rand(rng); + assert!(!KZGMultilinearPC::verify(&vk, &com, &point, value, &proof)?); + + Ok(()) + } + + #[test] + fn test_multi_commit() -> Result<(), PCSErrors> { + let mut rng = test_rng(); + + let uni_params = KZGMultilinearPC::::setup(&mut rng, 20)?; + + // normal polynomials + let polys1: Vec<_> = (0..5) + .map(|_| DenseMultilinearExtension::rand(rng.gen_range(5..9), &mut rng)) + .collect(); + test_multi_commit_helper(&uni_params, &polys1, &mut rng)?; // single-variate polynomials - let poly3 = DenseMultilinearExtension::rand(1, &mut rng); - test_kzg_mlpc_helper(&uni_params, &poly3, &mut rng)?; + let polys1: Vec<_> = (0..5) + .map(|_| DenseMultilinearExtension::rand(1, &mut rng)) + .collect(); + test_multi_commit_helper(&uni_params, &polys1, &mut rng)?; - let poly4 = SparseMultilinearExtension::rand_with_config(1, 1 << 1, &mut rng); - test_kzg_mlpc_helper(&uni_params, &poly4, &mut rng)?; Ok(()) } diff --git a/pcs/src/lib.rs b/pcs/src/lib.rs index 52c247b5..29feacd0 100644 --- a/pcs/src/lib.rs +++ b/pcs/src/lib.rs @@ -33,6 +33,12 @@ pub trait MultilinearCommitmentScheme { poly: &impl MultilinearExtension, ) -> Result; + /// Generate a commitment for a list of polynomials + fn multi_commit( + prover_param: &Self::ProverParam, + polys: &[impl MultilinearExtension], + ) -> Result; + /// On input a polynomial `p` and a point `point`, outputs a proof for the /// same. fn open( @@ -41,6 +47,14 @@ pub trait MultilinearCommitmentScheme { point: &[E::Fr], ) -> Result; + /// On input a polynomial `p` and a point `point`, outputs a proof for the + /// same. + fn multi_open( + prover_param: &Self::ProverParam, + polynomial: &[impl MultilinearExtension], + point: &[E::Fr], + ) -> Result; + /// Verifies that `value` is the evaluation at `x` of the polynomial /// committed inside `comm`. fn verify(