Browse Source

impl KZG based multilinear pcs (#22)

main
zhenfei 2 years ago
committed by GitHub
parent
commit
b9527f8e37
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 741 additions and 37 deletions
  1. +29
    -0
      pcs/Cargo.toml
  2. +81
    -0
      pcs/benches/bench.rs
  3. +257
    -0
      pcs/src/commit.rs
  4. +25
    -0
      pcs/src/errors.rs
  5. +52
    -7
      pcs/src/lib.rs
  6. +259
    -0
      pcs/src/param.rs
  7. +2
    -2
      poly-iop/Cargo.toml
  8. +24
    -18
      poly-iop/benches/bench.rs
  9. +2
    -2
      poly-iop/readme.md
  10. +6
    -6
      poly-iop/src/errors.rs
  11. +1
    -1
      poly-iop/src/lib.rs
  12. +3
    -1
      poly-iop/src/zero_check/mod.rs

+ 29
- 0
pcs/Cargo.toml

@ -6,3 +6,32 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
ark-std = { version = "^0.3.0", default-features = false }
ark-serialize = { version = "^0.3.0", default-features = false, features = [ "derive" ] }
ark-ff = { version = "^0.3.0", default-features = false }
ark-ec = { version = "^0.3.0", default-features = false }
ark-poly = {version = "^0.3.0", default-features = false }
ark-sponge = {version = "^0.3.0", default-features = false}
ark-bls12-381 = { version = "0.3.0", default-features = false, features = [ "curve" ] }
displaydoc = { version = "0.2.3", default-features = false }
# Benchmarks
[[bench]]
name = "pcs-benches"
path = "benches/bench.rs"
harness = false
[features]
default = [ "parallel", "print-trace" ]
# default = [ "parallel" ]
parallel = [
"ark-std/parallel",
"ark-ff/parallel",
"ark-poly/parallel",
"ark-ec/parallel",
]
print-trace = [
"ark-std/print-trace"
]

+ 81
- 0
pcs/benches/bench.rs

@ -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(())
}

+ 257
- 0
pcs/src/commit.rs

@ -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());
}
}

+ 25
- 0
pcs/src/errors.rs

@ -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)
}
}

+ 52
- 7
pcs/src/lib.rs

@ -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>;
} }

+ 259
- 0
pcs/src/param.rs

@ -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(())
}
}

+ 2
- 2
poly-iop/Cargo.toml

@ -26,8 +26,8 @@ path = "benches/bench.rs"
harness = false harness = false
[features] [features]
default = [ "parallel", "print-trace" ]
# default = [ "parallel" ]
# default = [ "parallel", "print-trace" ]
default = [ "parallel" ]
parallel = [ parallel = [
"rayon", "rayon",
"ark-std/parallel", "ark-std/parallel",

+ 24
- 18
poly-iop/benches/bench.rs

@ -1,8 +1,7 @@
use std::time::Instant;
use ark_bls12_381::Fr; use ark_bls12_381::Fr;
use ark_std::test_rng; use ark_std::test_rng;
use poly_iop::{PolyIOP, PolyIOPErrors, SumCheck, VirtualPolynomial, ZeroCheck}; use poly_iop::{PolyIOP, PolyIOPErrors, SumCheck, VirtualPolynomial, ZeroCheck};
use std::time::Instant;
fn main() -> Result<(), PolyIOPErrors> { fn main() -> Result<(), PolyIOPErrors> {
bench_sum_check()?; bench_sum_check()?;
@ -27,8 +26,10 @@ fn bench_sum_check() -> Result<(), PolyIOPErrors> {
let poly_info = poly.domain_info.clone(); let poly_info = poly.domain_info.clone();
let proof = { let proof = {
let start = Instant::now(); let start = Instant::now();
let mut transcript = <PolyIOP<Fr> as SumCheck<Fr>>::init_transcript();
let proof = <PolyIOP<Fr> as SumCheck<Fr>>::prove(&poly, &mut transcript)?;
for _ in 0..repetition {
let mut transcript = <PolyIOP<Fr> as SumCheck<Fr>>::init_transcript();
let _proof = <PolyIOP<Fr> as SumCheck<Fr>>::prove(&poly, &mut transcript)?;
}
println!( println!(
"sum check proving time for {} variables and {} degree: {} ns", "sum check proving time for {} variables and {} degree: {} ns",
@ -36,26 +37,30 @@ fn bench_sum_check() -> Result<(), PolyIOPErrors> {
degree, degree,
start.elapsed().as_nanos() / repetition as u128 start.elapsed().as_nanos() / repetition as u128
); );
proof
let mut transcript = <PolyIOP<Fr> as SumCheck<Fr>>::init_transcript();
<PolyIOP<Fr> as SumCheck<Fr>>::prove(&poly, &mut transcript)?
}; };
{ {
let start = Instant::now(); let start = Instant::now();
let mut transcript = <PolyIOP<Fr> as SumCheck<Fr>>::init_transcript();
let subclaim = <PolyIOP<Fr> as SumCheck<Fr>>::verify(
asserted_sum,
&proof,
&poly_info,
&mut transcript,
)?;
assert!(
poly.evaluate(&subclaim.point).unwrap() == subclaim.expected_evaluation,
"wrong subclaim"
);
for _ in 0..repetition {
let mut transcript = <PolyIOP<Fr> as SumCheck<Fr>>::init_transcript();
let subclaim = <PolyIOP<Fr> as SumCheck<Fr>>::verify(
asserted_sum,
&proof,
&poly_info,
&mut transcript,
)?;
assert!(
poly.evaluate(&subclaim.point).unwrap() == subclaim.expected_evaluation,
"wrong subclaim"
);
}
println!( println!(
"sum check verification time for {} variables: {} ns",
"sum check verification time for {} variables and {} degree: {} ns",
nv, nv,
degree,
start.elapsed().as_nanos() / repetition as u128 start.elapsed().as_nanos() / repetition as u128
); );
} }
@ -106,8 +111,9 @@ fn bench_zero_check() -> Result<(), PolyIOPErrors> {
"wrong subclaim" "wrong subclaim"
); );
println!( println!(
"zero check verification time for {} variables: {} ns",
"zero check verification time for {} variables and {} degree:: {} ns",
nv, nv,
degree,
start.elapsed().as_nanos() / repetition as u128 start.elapsed().as_nanos() / repetition as u128
); );
} }

+ 2
- 2
poly-iop/readme.md

@ -3,5 +3,5 @@ Poly IOP
Implements the following protocols Implements the following protocols
- [ ] sum checks
- [ ] zero checks
- [x] sum checks
- [x] zero checks

+ 6
- 6
poly-iop/src/errors.rs

@ -6,17 +6,17 @@ use displaydoc::Display;
/// A `enum` specifying the possible failure modes of the PolyIOP. /// A `enum` specifying the possible failure modes of the PolyIOP.
#[derive(Display, Debug)] #[derive(Display, Debug)]
pub enum PolyIOPErrors { pub enum PolyIOPErrors {
/// Invalid Prover
/// Invalid Prover: {0}
InvalidProver(String), InvalidProver(String),
/// Invalid Verifier
/// Invalid Verifier: {0}
InvalidVerifier(String), InvalidVerifier(String),
/// Invalid Proof
/// Invalid Proof: {0}
InvalidProof(String), InvalidProof(String),
/// Invalid parameters
/// Invalid parameters: {0}
InvalidParameters(String), InvalidParameters(String),
/// Invalid Transcript
/// Invalid Transcript: {0}
InvalidTranscript(String), InvalidTranscript(String),
/// An error during (de)serialization
/// An error during (de)serialization: {0}
SerializationError(ark_serialize::SerializationError), SerializationError(ark_serialize::SerializationError),
} }

+ 1
- 1
poly-iop/src/lib.rs

@ -12,7 +12,7 @@ mod zero_check;
pub use errors::PolyIOPErrors; pub use errors::PolyIOPErrors;
pub use sum_check::SumCheck; pub use sum_check::SumCheck;
pub use virtual_poly::VirtualPolynomial; pub use virtual_poly::VirtualPolynomial;
pub use zero_check::ZeroCheck;
pub use zero_check::{build_eq_x_r, ZeroCheck};
/// Struct for PolyIOP protocol. /// Struct for PolyIOP protocol.
/// It is instantiated with /// It is instantiated with

+ 3
- 1
poly-iop/src/zero_check/mod.rs

@ -137,7 +137,9 @@ fn build_f_hat(
// eq(x,y) = \prod_i=1^num_var (x_i * y_i + (1-x_i)*(1-y_i)) // eq(x,y) = \prod_i=1^num_var (x_i * y_i + (1-x_i)*(1-y_i))
// over r, which is // over r, which is
// eq(x,y) = \prod_i=1^num_var (x_i * r_i + (1-x_i)*(1-r_i)) // eq(x,y) = \prod_i=1^num_var (x_i * r_i + (1-x_i)*(1-r_i))
fn build_eq_x_r<F: PrimeField>(r: &[F]) -> Result<Rc<DenseMultilinearExtension<F>>, PolyIOPErrors> {
pub fn build_eq_x_r<F: PrimeField>(
r: &[F],
) -> Result<Rc<DenseMultilinearExtension<F>>, PolyIOPErrors> {
let start = start_timer!(|| "zero check build eq_x_r"); let start = start_timer!(|| "zero check build eq_x_r");
// we build eq(x,r) from its evaluations // we build eq(x,r) from its evaluations

Loading…
Cancel
Save