| @ -0,0 +1,81 @@ | |||||
|  | use ark_bls12_381::{Bls12_381, Fr};
 | ||||
|  | use ark_ff::UniformRand;
 | ||||
|  | use ark_poly::{DenseMultilinearExtension, MultilinearExtension};
 | ||||
|  | use ark_std::test_rng;
 | ||||
|  | use pcs::{KZGMultilinearPC, MultilinearCommitmentScheme, PCSErrors};
 | ||||
|  | use std::time::Instant;
 | ||||
|  | 
 | ||||
|  | fn main() -> Result<(), PCSErrors> {
 | ||||
|  |     bench_pcs()
 | ||||
|  | }
 | ||||
|  | 
 | ||||
|  | fn bench_pcs() -> Result<(), PCSErrors> {
 | ||||
|  |     let mut rng = test_rng();
 | ||||
|  | 
 | ||||
|  |     // normal polynomials
 | ||||
|  |     let uni_params = KZGMultilinearPC::<Bls12_381>::setup(&mut rng, 18)?;
 | ||||
|  | 
 | ||||
|  |     for nv in 4..19 {
 | ||||
|  |         let repetition = if nv < 10 {
 | ||||
|  |             100
 | ||||
|  |         } else if nv < 20 {
 | ||||
|  |             50
 | ||||
|  |         } else {
 | ||||
|  |             10
 | ||||
|  |         };
 | ||||
|  | 
 | ||||
|  |         let poly = DenseMultilinearExtension::rand(nv, &mut rng);
 | ||||
|  |         let (ck, vk) = uni_params.trim(nv)?;
 | ||||
|  |         let point: Vec<_> = (0..nv).map(|_| Fr::rand(&mut rng)).collect();
 | ||||
|  | 
 | ||||
|  |         // commit
 | ||||
|  |         let com = {
 | ||||
|  |             let start = Instant::now();
 | ||||
|  |             for _ in 0..repetition {
 | ||||
|  |                 let _commit = KZGMultilinearPC::commit(&ck, &poly)?;
 | ||||
|  |             }
 | ||||
|  | 
 | ||||
|  |             println!(
 | ||||
|  |                 "KZG commit for {} variables: {} ns",
 | ||||
|  |                 nv,
 | ||||
|  |                 start.elapsed().as_nanos() / repetition as u128
 | ||||
|  |             );
 | ||||
|  | 
 | ||||
|  |             KZGMultilinearPC::commit(&ck, &poly)?
 | ||||
|  |         };
 | ||||
|  | 
 | ||||
|  |         // open
 | ||||
|  |         let proof = {
 | ||||
|  |             let start = Instant::now();
 | ||||
|  |             for _ in 0..repetition {
 | ||||
|  |                 let _open = KZGMultilinearPC::open(&ck, &poly, &point)?;
 | ||||
|  |             }
 | ||||
|  | 
 | ||||
|  |             println!(
 | ||||
|  |                 "KZG open for {} variables: {} ns",
 | ||||
|  |                 nv,
 | ||||
|  |                 start.elapsed().as_nanos() / repetition as u128
 | ||||
|  |             );
 | ||||
|  |             KZGMultilinearPC::open(&ck, &poly, &point)?
 | ||||
|  |         };
 | ||||
|  |         let value = poly.evaluate(&point).unwrap();
 | ||||
|  | 
 | ||||
|  |         // verify
 | ||||
|  | 
 | ||||
|  |         {
 | ||||
|  |             let start = Instant::now();
 | ||||
|  |             for _ in 0..repetition {
 | ||||
|  |                 assert!(KZGMultilinearPC::verify(&vk, &com, &point, value, &proof)?);
 | ||||
|  |             }
 | ||||
|  |             println!(
 | ||||
|  |                 "KZG verify for {} variables: {} ns",
 | ||||
|  |                 nv,
 | ||||
|  |                 start.elapsed().as_nanos() / repetition as u128
 | ||||
|  |             );
 | ||||
|  |         }
 | ||||
|  | 
 | ||||
|  |         println!("====================================");
 | ||||
|  |     }
 | ||||
|  | 
 | ||||
|  |     Ok(())
 | ||||
|  | }
 | ||||
| @ -0,0 +1,257 @@ | |||||
|  | use ark_ec::{
 | ||||
|  |     msm::{FixedBaseMSM, VariableBaseMSM},
 | ||||
|  |     AffineCurve, PairingEngine, ProjectiveCurve,
 | ||||
|  | };
 | ||||
|  | use ark_ff::PrimeField;
 | ||||
|  | use ark_poly::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,
 | ||||
|  | };
 | ||||
|  | 
 | ||||
|  | #[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug)]
 | ||||
|  | /// commitment
 | ||||
|  | pub struct Commitment<E: PairingEngine> {
 | ||||
|  |     /// number of variables
 | ||||
|  |     pub nv: usize,
 | ||||
|  |     /// product of g as described by the vRAM paper
 | ||||
|  |     pub g_product: E::G1Affine,
 | ||||
|  | }
 | ||||
|  | 
 | ||||
|  | #[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug)]
 | ||||
|  | /// proof of opening
 | ||||
|  | pub struct Proof<E: PairingEngine> {
 | ||||
|  |     /// Evaluation of quotients
 | ||||
|  |     pub proofs: Vec<E::G2Affine>,
 | ||||
|  | }
 | ||||
|  | 
 | ||||
|  | impl<E: PairingEngine> MultilinearCommitmentScheme<E> for KZGMultilinearPC<E> {
 | ||||
|  |     type ProverParam = ProverParam<E>;
 | ||||
|  |     type VerifierParam = VerifierParam<E>;
 | ||||
|  |     type SRS = UniversalParams<E>;
 | ||||
|  |     type Commitment = Commitment<E>;
 | ||||
|  |     type Proof = Proof<E>;
 | ||||
|  | 
 | ||||
|  |     /// Generate SRS from RNG.
 | ||||
|  |     /// WARNING: THIS FUNCTION IS FOR TESTING PURPOSE ONLY.
 | ||||
|  |     /// THE OUTPUT SRS SHOULD NOT BE USED IN PRODUCTION.
 | ||||
|  |     fn setup<R: RngCore>(rng: &mut R, num_vars: usize) -> Result<Self::SRS, PCSErrors> {
 | ||||
|  |         let setup_timer = start_timer!(|| format!("SRS setup for dim {}", num_vars));
 | ||||
|  |         let res = Self::SRS::gen_srs_for_testing(rng, num_vars);
 | ||||
|  |         end_timer!(setup_timer);
 | ||||
|  |         res
 | ||||
|  |     }
 | ||||
|  | 
 | ||||
|  |     /// Generate a commitment for a polynomial.
 | ||||
|  |     ///
 | ||||
|  |     /// This function takes `2^num_vars` number of scalar multiplications over
 | ||||
|  |     /// G1.
 | ||||
|  |     fn commit(
 | ||||
|  |         prover_param: &Self::ProverParam,
 | ||||
|  |         poly: &impl MultilinearExtension<E::Fr>,
 | ||||
|  |     ) -> Result<Self::Commitment, PCSErrors> {
 | ||||
|  |         let commit_timer = start_timer!(|| "commit");
 | ||||
|  | 
 | ||||
|  |         let nv = poly.num_vars();
 | ||||
|  |         let scalars: Vec<_> = poly
 | ||||
|  |             .to_evaluations()
 | ||||
|  |             .into_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, 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.
 | ||||
|  |     ///
 | ||||
|  |     /// 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 open(
 | ||||
|  |         prover_param: &Self::ProverParam,
 | ||||
|  |         polynomial: &impl MultilinearExtension<E::Fr>,
 | ||||
|  |         point: &[E::Fr],
 | ||||
|  |     ) -> Result<Self::Proof, PCSErrors> {
 | ||||
|  |         let open_timer = start_timer!(|| "open");
 | ||||
|  | 
 | ||||
|  |         assert_eq!(
 | ||||
|  |             polynomial.num_vars(),
 | ||||
|  |             prover_param.num_vars,
 | ||||
|  |             "Invalid size of polynomial"
 | ||||
|  |         );
 | ||||
|  |         let nv = polynomial.num_vars();
 | ||||
|  |         let mut r: Vec<Vec<E::Fr>> = (0..nv + 1).map(|_| Vec::new()).collect();
 | ||||
|  |         let mut q: Vec<Vec<E::Fr>> = (0..nv + 1).map(|_| Vec::new()).collect();
 | ||||
|  | 
 | ||||
|  |         r[nv] = polynomial.to_evaluations();
 | ||||
|  | 
 | ||||
|  |         let mut proofs = Vec::new();
 | ||||
|  | 
 | ||||
|  |         for (i, (&point_at_k, hi)) in point
 | ||||
|  |             .iter()
 | ||||
|  |             .zip(prover_param.powers_of_h.iter())
 | ||||
|  |             .take(nv)
 | ||||
|  |             .enumerate()
 | ||||
|  |         {
 | ||||
|  |             let ith_round = start_timer!(|| format!("{}-th round", i));
 | ||||
|  | 
 | ||||
|  |             let k = nv - i;
 | ||||
|  |             let cur_dim = 1 << (k - 1);
 | ||||
|  |             let mut cur_q = vec![E::Fr::zero(); cur_dim];
 | ||||
|  |             let mut cur_r = vec![E::Fr::zero(); cur_dim];
 | ||||
|  | 
 | ||||
|  |             for b in 0..(1 << (k - 1)) {
 | ||||
|  |                 // q_b = pre_r [2^b + 1] - pre_r [2^b]
 | ||||
|  |                 cur_q[b] = r[k][(b << 1) + 1] - r[k][b << 1];
 | ||||
|  | 
 | ||||
|  |                 // r_b = pre_r [2^b]*(1-p) + pre_r [2^b + 1] * p
 | ||||
|  |                 cur_r[b] =
 | ||||
|  |                     r[k][b << 1] * (E::Fr::one() - point_at_k) + (r[k][(b << 1) + 1] * point_at_k);
 | ||||
|  |             }
 | ||||
|  | 
 | ||||
|  |             let scalars: Vec<_> = (0..(1 << k)).map(|x| cur_q[x >> 1].into_repr()).collect();
 | ||||
|  | 
 | ||||
|  |             q[k] = cur_q;
 | ||||
|  |             r[k - 1] = cur_r;
 | ||||
|  | 
 | ||||
|  |             // this is a MSM over G2 and is likely to be the bottleneck
 | ||||
|  |             proofs.push(VariableBaseMSM::multi_scalar_mul(&hi.evals, &scalars).into_affine());
 | ||||
|  |             end_timer!(ith_round);
 | ||||
|  |         }
 | ||||
|  | 
 | ||||
|  |         end_timer!(open_timer);
 | ||||
|  |         Ok(Proof { proofs })
 | ||||
|  |     }
 | ||||
|  | 
 | ||||
|  |     /// Verifies that `value` is the evaluation at `x` of the polynomial
 | ||||
|  |     /// committed inside `comm`.
 | ||||
|  |     ///
 | ||||
|  |     /// This function takes
 | ||||
|  |     /// - num_var number of pairing product.
 | ||||
|  |     /// - num_var number of MSM
 | ||||
|  |     fn verify(
 | ||||
|  |         verifier_param: &Self::VerifierParam,
 | ||||
|  |         commitment: &Self::Commitment,
 | ||||
|  |         point: &[E::Fr],
 | ||||
|  |         value: E::Fr,
 | ||||
|  |         proof: &Self::Proof,
 | ||||
|  |     ) -> Result<bool, PCSErrors> {
 | ||||
|  |         let verify_timer = start_timer!(|| "verify");
 | ||||
|  |         let prepare_inputs_timer = start_timer!(|| "prepare pairing inputs");
 | ||||
|  | 
 | ||||
|  |         let scalar_size = E::Fr::size_in_bits();
 | ||||
|  |         let window_size = FixedBaseMSM::get_mul_window_size(verifier_param.num_vars);
 | ||||
|  | 
 | ||||
|  |         let g_table = FixedBaseMSM::get_window_table(
 | ||||
|  |             scalar_size,
 | ||||
|  |             window_size,
 | ||||
|  |             verifier_param.g.into_projective(),
 | ||||
|  |         );
 | ||||
|  |         let g_mul: Vec<E::G1Projective> =
 | ||||
|  |             FixedBaseMSM::multi_scalar_mul(scalar_size, window_size, &g_table, point);
 | ||||
|  | 
 | ||||
|  |         let mut g1_vec: Vec<_> = (0..verifier_param.num_vars)
 | ||||
|  |             .map(|i| verifier_param.g_mask[i].into_projective() - g_mul[i])
 | ||||
|  |             .collect();
 | ||||
|  |         g1_vec.push(verifier_param.g.mul(value) - commitment.g_product.into_projective());
 | ||||
|  | 
 | ||||
|  |         let g1_vec: Vec<E::G1Affine> = E::G1Projective::batch_normalization_into_affine(&g1_vec);
 | ||||
|  |         let tmp = g1_vec[verifier_param.num_vars];
 | ||||
|  |         end_timer!(prepare_inputs_timer);
 | ||||
|  | 
 | ||||
|  |         let pairing_product_timer = start_timer!(|| "pairing product");
 | ||||
|  | 
 | ||||
|  |         let mut pairings: Vec<_> = g1_vec
 | ||||
|  |             .into_iter()
 | ||||
|  |             .take(verifier_param.num_vars)
 | ||||
|  |             .map(E::G1Prepared::from)
 | ||||
|  |             .zip(proof.proofs.iter().map(|&x| E::G2Prepared::from(x)))
 | ||||
|  |             .collect();
 | ||||
|  | 
 | ||||
|  |         pairings.push((
 | ||||
|  |             E::G1Prepared::from(tmp),
 | ||||
|  |             E::G2Prepared::from(verifier_param.h),
 | ||||
|  |         ));
 | ||||
|  | 
 | ||||
|  |         let res = E::product_of_pairings(pairings.iter()) == E::Fqk::one();
 | ||||
|  | 
 | ||||
|  |         end_timer!(pairing_product_timer);
 | ||||
|  |         end_timer!(verify_timer);
 | ||||
|  |         Ok(res)
 | ||||
|  |     }
 | ||||
|  | }
 | ||||
|  | 
 | ||||
|  | #[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};
 | ||||
|  |     type E = Bls12_381;
 | ||||
|  |     type Fr = <E as PairingEngine>::Fr;
 | ||||
|  | 
 | ||||
|  |     fn test_kzg_mlpc_helper<R: RngCore>(
 | ||||
|  |         uni_params: &UniversalParams<E>,
 | ||||
|  |         poly: &impl MultilinearExtension<Fr>,
 | ||||
|  |         rng: &mut R,
 | ||||
|  |     ) -> Result<(), PCSErrors> {
 | ||||
|  |         let nv = poly.num_vars();
 | ||||
|  |         assert_ne!(nv, 0);
 | ||||
|  |         let (ck, vk) = uni_params.trim(nv)?;
 | ||||
|  |         let point: Vec<_> = (0..nv).map(|_| Fr::rand(rng)).collect();
 | ||||
|  |         let com = KZGMultilinearPC::commit(&ck, poly)?;
 | ||||
|  |         let proof = KZGMultilinearPC::open(&ck, poly, &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 setup_commit_verify_correct_polynomials() -> Result<(), PCSErrors> {
 | ||||
|  |         let mut rng = test_rng();
 | ||||
|  | 
 | ||||
|  |         let uni_params = KZGMultilinearPC::<E>::setup(&mut rng, 10)?;
 | ||||
|  | 
 | ||||
|  |         // normal polynomials
 | ||||
|  |         let poly1 = DenseMultilinearExtension::rand(8, &mut rng);
 | ||||
|  |         test_kzg_mlpc_helper(&uni_params, &poly1, &mut rng)?;
 | ||||
|  | 
 | ||||
|  |         let poly2 = SparseMultilinearExtension::rand_with_config(9, 1 << 5, &mut rng);
 | ||||
|  |         test_kzg_mlpc_helper(&uni_params, &poly2, &mut rng)?;
 | ||||
|  | 
 | ||||
|  |         // single-variate polynomials
 | ||||
|  |         let poly3 = DenseMultilinearExtension::rand(1, &mut rng);
 | ||||
|  |         test_kzg_mlpc_helper(&uni_params, &poly3, &mut rng)?;
 | ||||
|  | 
 | ||||
|  |         let poly4 = SparseMultilinearExtension::rand_with_config(1, 1 << 1, &mut rng);
 | ||||
|  |         test_kzg_mlpc_helper(&uni_params, &poly4, &mut rng)?;
 | ||||
|  |         Ok(())
 | ||||
|  |     }
 | ||||
|  | 
 | ||||
|  |     #[test]
 | ||||
|  |     fn setup_commit_verify_constant_polynomial() {
 | ||||
|  |         let mut rng = test_rng();
 | ||||
|  | 
 | ||||
|  |         // normal polynomials
 | ||||
|  |         assert!(KZGMultilinearPC::<E>::setup(&mut rng, 0).is_err());
 | ||||
|  |     }
 | ||||
|  | }
 | ||||
| @ -0,0 +1,25 @@ | |||||
|  | //! Error module.
 | ||||
|  | 
 | ||||
|  | use ark_std::string::String;
 | ||||
|  | use displaydoc::Display;
 | ||||
|  | 
 | ||||
|  | /// A `enum` specifying the possible failure modes of the PCS.
 | ||||
|  | #[derive(Display, Debug)]
 | ||||
|  | pub enum PCSErrors {
 | ||||
|  |     /// Invalid Prover: {0}
 | ||||
|  |     InvalidProver(String),
 | ||||
|  |     /// Invalid Verifier: {0}
 | ||||
|  |     InvalidVerifier(String),
 | ||||
|  |     /// Invalid Proof: {0}
 | ||||
|  |     InvalidProof(String),
 | ||||
|  |     /// Invalid parameters: {0}
 | ||||
|  |     InvalidParameters(String),
 | ||||
|  |     /// An error during (de)serialization: {0}
 | ||||
|  |     SerializationError(ark_serialize::SerializationError),
 | ||||
|  | }
 | ||||
|  | 
 | ||||
|  | impl From<ark_serialize::SerializationError> for PCSErrors {
 | ||||
|  |     fn from(e: ark_serialize::SerializationError) -> Self {
 | ||||
|  |         Self::SerializationError(e)
 | ||||
|  |     }
 | ||||
|  | }
 | ||||
| @ -1,8 +1,53 @@ | |||||
| #[cfg(test)]
 |  | ||||
| mod tests {
 |  | ||||
|     #[test]
 |  | ||||
|     fn it_works() {
 |  | ||||
|         let result = 2 + 2;
 |  | ||||
|         assert_eq!(result, 4);
 |  | ||||
|     }
 |  | ||||
|  | mod commit;
 | ||||
|  | mod errors;
 | ||||
|  | mod param;
 | ||||
|  | 
 | ||||
|  | use ark_ec::PairingEngine;
 | ||||
|  | use ark_poly::MultilinearExtension;
 | ||||
|  | use ark_std::rand::RngCore;
 | ||||
|  | use std::marker::PhantomData;
 | ||||
|  | 
 | ||||
|  | pub use errors::PCSErrors;
 | ||||
|  | pub use param::{ProverParam, UniversalParams, VerifierParam};
 | ||||
|  | 
 | ||||
|  | /// KZG Polynomial Commitment Scheme on multilinear extensions.
 | ||||
|  | pub struct KZGMultilinearPC<E: PairingEngine> {
 | ||||
|  |     phantom: PhantomData<E>,
 | ||||
|  | }
 | ||||
|  | 
 | ||||
|  | pub trait MultilinearCommitmentScheme<E: PairingEngine> {
 | ||||
|  |     type ProverParam;
 | ||||
|  |     type VerifierParam;
 | ||||
|  |     type SRS;
 | ||||
|  |     type Commitment;
 | ||||
|  |     type Proof;
 | ||||
|  | 
 | ||||
|  |     /// Generate SRS from RNG.
 | ||||
|  |     /// WARNING: THIS FUNCTION IS FOR TESTING PURPOSE ONLY.
 | ||||
|  |     /// THE OUTPUT SRS SHOULD NOT BE USED IN PRODUCTION.
 | ||||
|  |     fn setup<R: RngCore>(rng: &mut R, num_vars: usize) -> Result<Self::SRS, PCSErrors>;
 | ||||
|  | 
 | ||||
|  |     /// Generate a commitment for a polynomial
 | ||||
|  |     fn commit(
 | ||||
|  |         prover_param: &Self::ProverParam,
 | ||||
|  |         poly: &impl MultilinearExtension<E::Fr>,
 | ||||
|  |     ) -> Result<Self::Commitment, PCSErrors>;
 | ||||
|  | 
 | ||||
|  |     /// On input a polynomial `p` and a point `point`, outputs a proof for the
 | ||||
|  |     /// same.
 | ||||
|  |     fn open(
 | ||||
|  |         prover_param: &Self::ProverParam,
 | ||||
|  |         polynomial: &impl MultilinearExtension<E::Fr>,
 | ||||
|  |         point: &[E::Fr],
 | ||||
|  |     ) -> Result<Self::Proof, PCSErrors>;
 | ||||
|  | 
 | ||||
|  |     /// Verifies that `value` is the evaluation at `x` of the polynomial
 | ||||
|  |     /// committed inside `comm`.
 | ||||
|  |     fn verify(
 | ||||
|  |         verifier_param: &Self::VerifierParam,
 | ||||
|  |         commitment: &Self::Commitment,
 | ||||
|  |         point: &[E::Fr],
 | ||||
|  |         value: E::Fr,
 | ||||
|  |         proof: &Self::Proof,
 | ||||
|  |     ) -> Result<bool, PCSErrors>;
 | ||||
| }
 | }
 | ||||
| @ -0,0 +1,259 @@ | |||||
|  | use std::collections::LinkedList;
 | ||||
|  | 
 | ||||
|  | use crate::PCSErrors;
 | ||||
|  | use ark_ec::{msm::FixedBaseMSM, AffineCurve, PairingEngine, ProjectiveCurve};
 | ||||
|  | use ark_ff::{Field, PrimeField};
 | ||||
|  | use ark_poly::DenseMultilinearExtension;
 | ||||
|  | use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Read, SerializationError, Write};
 | ||||
|  | use ark_std::{end_timer, rand::RngCore, start_timer, vec::Vec, UniformRand};
 | ||||
|  | 
 | ||||
|  | /// Evaluations over {0,1}^n for G1 or G2
 | ||||
|  | #[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug)]
 | ||||
|  | pub struct Evaluations<C: AffineCurve> {
 | ||||
|  |     pub evals: Vec<C>,
 | ||||
|  | }
 | ||||
|  | 
 | ||||
|  | /// Universal Parameter
 | ||||
|  | #[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug)]
 | ||||
|  | pub struct UniversalParams<E: PairingEngine> {
 | ||||
|  |     /// prover parameters
 | ||||
|  |     pub prover_param: ProverParam<E>,
 | ||||
|  |     /// g^randomness: g^t1, g^t2, ...
 | ||||
|  |     pub g_mask: Vec<E::G1Affine>,
 | ||||
|  | }
 | ||||
|  | 
 | ||||
|  | /// Prover Parameters
 | ||||
|  | #[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug)]
 | ||||
|  | pub struct ProverParam<E: PairingEngine> {
 | ||||
|  |     /// number of variables
 | ||||
|  |     pub num_vars: usize,
 | ||||
|  |     /// `pp_{num_vars}`, `pp_{num_vars - 1}`, `pp_{num_vars - 2}`, ..., defined
 | ||||
|  |     /// by XZZPD19
 | ||||
|  |     pub powers_of_g: Vec<Evaluations<E::G1Affine>>,
 | ||||
|  |     /// `pp_{num_vars}`, `pp_{num_vars - 1}`, `pp_{num_vars - 2}`, ..., defined
 | ||||
|  |     /// by XZZPD19
 | ||||
|  |     pub powers_of_h: Vec<Evaluations<E::G2Affine>>,
 | ||||
|  |     /// generator for G1
 | ||||
|  |     pub g: E::G1Affine,
 | ||||
|  |     /// generator for G2
 | ||||
|  |     pub h: E::G2Affine,
 | ||||
|  | }
 | ||||
|  | 
 | ||||
|  | /// Verifier Parameters
 | ||||
|  | #[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug)]
 | ||||
|  | pub struct VerifierParam<E: PairingEngine> {
 | ||||
|  |     /// number of variables
 | ||||
|  |     pub num_vars: usize,
 | ||||
|  |     /// generator of G1
 | ||||
|  |     pub g: E::G1Affine,
 | ||||
|  |     /// generator of G2
 | ||||
|  |     pub h: E::G2Affine,
 | ||||
|  |     /// g^t1, g^t2, ...
 | ||||
|  |     pub g_mask: Vec<E::G1Affine>,
 | ||||
|  | }
 | ||||
|  | 
 | ||||
|  | impl<E: PairingEngine> UniversalParams<E> {
 | ||||
|  |     /// Extract the prover parameters from the public parameters.
 | ||||
|  |     pub fn extract_prover_param(&self) -> ProverParam<E> {
 | ||||
|  |         self.prover_param.clone()
 | ||||
|  |     }
 | ||||
|  | 
 | ||||
|  |     /// Extract the verifier parameters from the public parameters.
 | ||||
|  |     pub fn extract_verifier_param(&self) -> VerifierParam<E> {
 | ||||
|  |         VerifierParam {
 | ||||
|  |             num_vars: self.prover_param.num_vars,
 | ||||
|  |             g: self.prover_param.g,
 | ||||
|  |             h: self.prover_param.h,
 | ||||
|  |             g_mask: self.g_mask.clone(),
 | ||||
|  |         }
 | ||||
|  |     }
 | ||||
|  | 
 | ||||
|  |     /// Trim the universal parameters to specialize the public parameters
 | ||||
|  |     /// for multilinear polynomials to the given `supported_num_vars`, and
 | ||||
|  |     /// returns committer key and verifier key. `supported_num_vars` should
 | ||||
|  |     /// be in range `1..=params.num_vars`
 | ||||
|  |     pub fn trim(
 | ||||
|  |         &self,
 | ||||
|  |         supported_num_vars: usize,
 | ||||
|  |     ) -> Result<(ProverParam<E>, VerifierParam<E>), PCSErrors> {
 | ||||
|  |         if supported_num_vars > self.prover_param.num_vars {
 | ||||
|  |             return Err(PCSErrors::InvalidParameters(format!(
 | ||||
|  |                 "SRS does not support target number of vars {}",
 | ||||
|  |                 supported_num_vars
 | ||||
|  |             )));
 | ||||
|  |         }
 | ||||
|  | 
 | ||||
|  |         let to_reduce = self.prover_param.num_vars - supported_num_vars;
 | ||||
|  |         let ck = ProverParam {
 | ||||
|  |             powers_of_h: self.prover_param.powers_of_h[to_reduce..].to_vec(),
 | ||||
|  |             powers_of_g: self.prover_param.powers_of_g[to_reduce..].to_vec(),
 | ||||
|  |             g: self.prover_param.g,
 | ||||
|  |             h: self.prover_param.h,
 | ||||
|  |             num_vars: supported_num_vars,
 | ||||
|  |         };
 | ||||
|  |         let vk = VerifierParam {
 | ||||
|  |             num_vars: supported_num_vars,
 | ||||
|  |             g: self.prover_param.g,
 | ||||
|  |             h: self.prover_param.h,
 | ||||
|  |             g_mask: self.g_mask[to_reduce..].to_vec(),
 | ||||
|  |         };
 | ||||
|  |         Ok((ck, vk))
 | ||||
|  |     }
 | ||||
|  | 
 | ||||
|  |     /// Build SRS for testing.
 | ||||
|  |     /// WARNING: THIS FUNCTION IS FOR TESTING PURPOSE ONLY.
 | ||||
|  |     /// THE OUTPUT SRS SHOULD NOT BE USED IN PRODUCTION.
 | ||||
|  |     pub fn gen_srs_for_testing<R: RngCore>(
 | ||||
|  |         rng: &mut R,
 | ||||
|  |         num_vars: usize,
 | ||||
|  |     ) -> Result<Self, PCSErrors> {
 | ||||
|  |         if num_vars == 0 {
 | ||||
|  |             return Err(PCSErrors::InvalidParameters(
 | ||||
|  |                 "constant polynomial not supported".to_string(),
 | ||||
|  |             ));
 | ||||
|  |         }
 | ||||
|  | 
 | ||||
|  |         let total_timer = start_timer!(|| "SRS generation");
 | ||||
|  | 
 | ||||
|  |         let pp_generation_timer = start_timer!(|| "Prover Param generation");
 | ||||
|  |         let g = E::G1Projective::rand(rng);
 | ||||
|  |         let h = E::G2Projective::rand(rng);
 | ||||
|  | 
 | ||||
|  |         let mut powers_of_g = Vec::new();
 | ||||
|  |         let mut powers_of_h = Vec::new();
 | ||||
|  |         let t: Vec<_> = (0..num_vars).map(|_| E::Fr::rand(rng)).collect();
 | ||||
|  |         let scalar_bits = E::Fr::size_in_bits();
 | ||||
|  | 
 | ||||
|  |         let mut eq: LinkedList<DenseMultilinearExtension<E::Fr>> =
 | ||||
|  |             LinkedList::from_iter(eq_extension(&t).into_iter());
 | ||||
|  |         let mut eq_arr = LinkedList::new();
 | ||||
|  |         let mut base = eq.pop_back().unwrap().evaluations;
 | ||||
|  | 
 | ||||
|  |         for i in (0..num_vars).rev() {
 | ||||
|  |             eq_arr.push_front(remove_dummy_variable(&base, i)?);
 | ||||
|  |             if i != 0 {
 | ||||
|  |                 let mul = eq.pop_back().unwrap().evaluations;
 | ||||
|  |                 base = base
 | ||||
|  |                     .into_iter()
 | ||||
|  |                     .zip(mul.into_iter())
 | ||||
|  |                     .map(|(a, b)| a * b)
 | ||||
|  |                     .collect();
 | ||||
|  |             }
 | ||||
|  |         }
 | ||||
|  | 
 | ||||
|  |         let mut pp_powers = Vec::new();
 | ||||
|  |         let mut total_scalars = 0;
 | ||||
|  |         for i in 0..num_vars {
 | ||||
|  |             let eq = eq_arr.pop_front().unwrap();
 | ||||
|  |             let pp_k_powers = (0..(1 << (num_vars - i))).map(|x| eq[x]);
 | ||||
|  |             pp_powers.extend(pp_k_powers);
 | ||||
|  |             total_scalars += 1 << (num_vars - i);
 | ||||
|  |         }
 | ||||
|  |         let window_size = FixedBaseMSM::get_mul_window_size(total_scalars);
 | ||||
|  |         let g_table = FixedBaseMSM::get_window_table(scalar_bits, window_size, g);
 | ||||
|  |         let h_table = FixedBaseMSM::get_window_table(scalar_bits, window_size, h);
 | ||||
|  | 
 | ||||
|  |         let pp_g = E::G1Projective::batch_normalization_into_affine(
 | ||||
|  |             &FixedBaseMSM::multi_scalar_mul(scalar_bits, window_size, &g_table, &pp_powers),
 | ||||
|  |         );
 | ||||
|  |         let pp_h = E::G2Projective::batch_normalization_into_affine(
 | ||||
|  |             &FixedBaseMSM::multi_scalar_mul(scalar_bits, window_size, &h_table, &pp_powers),
 | ||||
|  |         );
 | ||||
|  |         let mut start = 0;
 | ||||
|  |         for i in 0..num_vars {
 | ||||
|  |             let size = 1 << (num_vars - i);
 | ||||
|  |             let pp_k_g = Evaluations {
 | ||||
|  |                 evals: pp_g[start..(start + size)].to_vec(),
 | ||||
|  |             };
 | ||||
|  |             let pp_k_h = Evaluations {
 | ||||
|  |                 evals: pp_h[start..(start + size)].to_vec(),
 | ||||
|  |             };
 | ||||
|  |             powers_of_g.push(pp_k_g);
 | ||||
|  |             powers_of_h.push(pp_k_h);
 | ||||
|  |             start += size;
 | ||||
|  |         }
 | ||||
|  | 
 | ||||
|  |         let pp = ProverParam {
 | ||||
|  |             num_vars,
 | ||||
|  |             g: g.into_affine(),
 | ||||
|  |             h: h.into_affine(),
 | ||||
|  |             powers_of_g,
 | ||||
|  |             powers_of_h,
 | ||||
|  |         };
 | ||||
|  | 
 | ||||
|  |         end_timer!(pp_generation_timer);
 | ||||
|  | 
 | ||||
|  |         let vp_generation_timer = start_timer!(|| "VP generation");
 | ||||
|  |         let g_mask = {
 | ||||
|  |             let window_size = FixedBaseMSM::get_mul_window_size(num_vars);
 | ||||
|  |             let g_table = FixedBaseMSM::get_window_table(scalar_bits, window_size, g);
 | ||||
|  |             E::G1Projective::batch_normalization_into_affine(&FixedBaseMSM::multi_scalar_mul(
 | ||||
|  |                 scalar_bits,
 | ||||
|  |                 window_size,
 | ||||
|  |                 &g_table,
 | ||||
|  |                 &t,
 | ||||
|  |             ))
 | ||||
|  |         };
 | ||||
|  |         end_timer!(vp_generation_timer);
 | ||||
|  |         end_timer!(total_timer);
 | ||||
|  |         Ok(Self {
 | ||||
|  |             prover_param: pp,
 | ||||
|  |             g_mask,
 | ||||
|  |         })
 | ||||
|  |     }
 | ||||
|  | }
 | ||||
|  | 
 | ||||
|  | /// fix first `pad` variables of `poly` represented in evaluation form to zero
 | ||||
|  | fn remove_dummy_variable<F: Field>(poly: &[F], pad: usize) -> Result<Vec<F>, PCSErrors> {
 | ||||
|  |     if pad == 0 {
 | ||||
|  |         return Ok(poly.to_vec());
 | ||||
|  |     }
 | ||||
|  |     if !poly.len().is_power_of_two() {
 | ||||
|  |         return Err(PCSErrors::InvalidParameters(
 | ||||
|  |             "Size of polynomial should be power of two.".to_string(),
 | ||||
|  |         ));
 | ||||
|  |     }
 | ||||
|  |     let nv = ark_std::log2(poly.len()) as usize - pad;
 | ||||
|  | 
 | ||||
|  |     Ok((0..(1 << nv)).map(|x| poly[x << pad]).collect())
 | ||||
|  | }
 | ||||
|  | 
 | ||||
|  | /// Generate eq(t,x), a product of multilinear polynomials with fixed t.
 | ||||
|  | /// eq(a,b) is takes extensions of a,b in {0,1}^num_vars such that if a and b in
 | ||||
|  | /// {0,1}^num_vars are equal then this polynomial evaluates to 1.
 | ||||
|  | fn eq_extension<F: PrimeField>(t: &[F]) -> Vec<DenseMultilinearExtension<F>> {
 | ||||
|  |     let start = start_timer!(|| "eq extension");
 | ||||
|  | 
 | ||||
|  |     let dim = t.len();
 | ||||
|  |     let mut result = Vec::new();
 | ||||
|  |     for (i, &ti) in t.iter().enumerate().take(dim) {
 | ||||
|  |         let mut poly = Vec::with_capacity(1 << dim);
 | ||||
|  |         for x in 0..(1 << dim) {
 | ||||
|  |             let xi = if x >> i & 1 == 1 { F::one() } else { F::zero() };
 | ||||
|  |             let ti_xi = ti * xi;
 | ||||
|  |             poly.push(ti_xi + ti_xi - xi - ti + F::one());
 | ||||
|  |         }
 | ||||
|  |         result.push(DenseMultilinearExtension::from_evaluations_vec(dim, poly));
 | ||||
|  |     }
 | ||||
|  | 
 | ||||
|  |     end_timer!(start);
 | ||||
|  |     result
 | ||||
|  | }
 | ||||
|  | 
 | ||||
|  | #[cfg(test)]
 | ||||
|  | mod tests {
 | ||||
|  |     use super::*;
 | ||||
|  |     use ark_bls12_381::Bls12_381;
 | ||||
|  |     use ark_std::test_rng;
 | ||||
|  |     type E = Bls12_381;
 | ||||
|  | 
 | ||||
|  |     #[test]
 | ||||
|  |     fn test_srs_gen() -> Result<(), PCSErrors> {
 | ||||
|  |         let mut rng = test_rng();
 | ||||
|  |         for nv in 4..10 {
 | ||||
|  |             let _ = UniversalParams::<E>::gen_srs_for_testing(&mut rng, nv)?;
 | ||||
|  |         }
 | ||||
|  | 
 | ||||
|  |         Ok(())
 | ||||
|  |     }
 | ||||
|  | }
 | ||||