initial integration of hyperplonk snark(#39)

This commit is contained in:
zhenfei
2022-08-01 13:16:55 -04:00
committed by GitHub
parent 229148eb5a
commit a6ea6ac26b
38 changed files with 1946 additions and 444 deletions

View File

@@ -16,6 +16,7 @@ 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 }
derivative = { version = "2", features = ["use_core"] }
transcript = { path = "../transcript" }

View File

@@ -1,7 +1,7 @@
use ark_bls12_381::{Bls12_381, Fr};
use ark_ff::UniformRand;
use ark_poly::{DenseMultilinearExtension, MultilinearExtension};
use ark_std::test_rng;
use ark_std::{rc::Rc, test_rng};
use pcs::{
prelude::{KZGMultilinearPCS, PCSErrors, PolynomialCommitmentScheme},
StructuredReferenceString,
@@ -27,7 +27,7 @@ fn bench_pcs() -> Result<(), PCSErrors> {
10
};
let poly = DenseMultilinearExtension::rand(nv, &mut rng);
let poly = Rc::new(DenseMultilinearExtension::rand(nv, &mut rng));
let (ml_ck, ml_vk) = uni_params.0.trim(nv)?;
let (uni_ck, uni_vk) = uni_params.1.trim(nv)?;
let ck = (ml_ck, uni_ck);

View File

@@ -17,19 +17,19 @@ pub enum PCSErrors {
/// Invalid parameters: {0}
InvalidParameters(String),
/// An error during (de)serialization: {0}
SerializationError(SerializationError),
SerializationErrors(SerializationError),
/// Transcript error {0}
TranscriptError(TranscriptErrors),
TranscriptErrors(TranscriptErrors),
}
impl From<SerializationError> for PCSErrors {
fn from(e: ark_serialize::SerializationError) -> Self {
Self::SerializationError(e)
Self::SerializationErrors(e)
}
}
impl From<TranscriptErrors> for PCSErrors {
fn from(e: TranscriptErrors) -> Self {
Self::TranscriptError(e)
Self::TranscriptErrors(e)
}
}

View File

@@ -6,6 +6,7 @@ mod univariate_kzg;
pub mod prelude;
use ark_ec::PairingEngine;
use ark_serialize::CanonicalSerialize;
use ark_std::rand::RngCore;
use errors::PCSErrors;
@@ -21,10 +22,10 @@ pub trait PolynomialCommitmentScheme<E: PairingEngine> {
type Point;
type Evaluation;
// Commitments and proofs
type Commitment;
type Commitment: CanonicalSerialize;
type BatchCommitment: CanonicalSerialize;
type Proof;
type BatchProof;
type BatchCommitment;
/// Build SRS for testing.
///
@@ -38,6 +39,15 @@ pub trait PolynomialCommitmentScheme<E: PairingEngine> {
log_size: usize,
) -> Result<Self::SRS, PCSErrors>;
/// Trim the universal parameters to specialize the public parameters.
/// Input both `supported_log_degree` for univariate and
/// `supported_num_vars` for multilinear.
fn trim(
srs: &Self::SRS,
supported_log_degree: usize,
supported_num_vars: Option<usize>,
) -> Result<(Self::ProverParam, Self::VerifierParam), PCSErrors>;
/// Generate a commitment for a polynomial
fn commit(
prover_param: &Self::ProverParam,

View File

@@ -12,7 +12,7 @@ use crate::{
};
use ark_ec::PairingEngine;
use ark_poly::{DenseMultilinearExtension, EvaluationDomain, MultilinearExtension, Polynomial};
use ark_std::{end_timer, start_timer, vec::Vec};
use ark_std::{end_timer, rc::Rc, start_timer, vec::Vec};
use transcript::IOPTranscript;
/// Input
@@ -49,7 +49,7 @@ use transcript::IOPTranscript;
pub(super) fn multi_open_internal<E: PairingEngine>(
uni_prover_param: &UnivariateProverParam<E::G1Affine>,
ml_prover_param: &MultilinearProverParam<E>,
polynomials: &[DenseMultilinearExtension<E::Fr>],
polynomials: &[Rc<DenseMultilinearExtension<E::Fr>>],
multi_commitment: &Commitment<E>,
points: &[Vec<E::Fr>],
) -> Result<(BatchProof<E>, Vec<E::Fr>), PCSErrors> {
@@ -309,7 +309,7 @@ mod tests {
fn test_multi_commit_helper<R: RngCore>(
uni_params: &UnivariateUniversalParams<E>,
ml_params: &MultilinearUniversalParams<E>,
polys: &[DenseMultilinearExtension<Fr>],
polys: &[Rc<DenseMultilinearExtension<Fr>>],
rng: &mut R,
) -> Result<(), PCSErrors> {
let merged_nv = get_batched_nv(polys[0].num_vars(), polys.len());
@@ -418,13 +418,13 @@ mod tests {
// normal polynomials
let polys1: Vec<_> = (0..5)
.map(|_| DenseMultilinearExtension::rand(4, &mut rng))
.map(|_| Rc::new(DenseMultilinearExtension::rand(4, &mut rng)))
.collect();
test_multi_commit_helper(&uni_params, &ml_params, &polys1, &mut rng)?;
// single-variate polynomials
let polys1: Vec<_> = (0..5)
.map(|_| DenseMultilinearExtension::rand(1, &mut rng))
.map(|_| Rc::new(DenseMultilinearExtension::rand(1, &mut rng)))
.collect();
test_multi_commit_helper(&uni_params, &ml_params, &polys1, &mut rng)?;

View File

@@ -18,7 +18,7 @@ use ark_ec::{
use ark_ff::PrimeField;
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 ark_std::{end_timer, rand::RngCore, rc::Rc, start_timer, vec::Vec, One, Zero};
use batching::{batch_verify_internal, multi_open_internal};
use srs::{MultilinearProverParam, MultilinearUniversalParams, MultilinearVerifierParam};
use std::marker::PhantomData;
@@ -59,14 +59,14 @@ impl<E: PairingEngine> PolynomialCommitmentScheme<E> for KZGMultilinearPCS<E> {
type VerifierParam = (MultilinearVerifierParam<E>, UnivariateVerifierParam<E>);
type SRS = (MultilinearUniversalParams<E>, UnivariateUniversalParams<E>);
// Polynomial and its associated types
type Polynomial = DenseMultilinearExtension<E::Fr>;
type Polynomial = Rc<DenseMultilinearExtension<E::Fr>>;
type Point = Vec<E::Fr>;
type Evaluation = E::Fr;
// Commitments and proofs
type Commitment = Commitment<E>;
type BatchCommitment = Commitment<E>;
type Proof = Proof<E>;
type BatchProof = BatchProof<E>;
type BatchCommitment = Commitment<E>;
/// Build SRS for testing.
///
@@ -85,6 +85,28 @@ impl<E: PairingEngine> PolynomialCommitmentScheme<E> for KZGMultilinearPCS<E> {
))
}
/// Trim the universal parameters to specialize the public parameters.
/// Input both `supported_log_degree` for univariate and
/// `supported_num_vars` for multilinear.
fn trim(
srs: &Self::SRS,
supported_log_degree: usize,
supported_num_vars: Option<usize>,
) -> Result<(Self::ProverParam, Self::VerifierParam), PCSErrors> {
let supported_num_vars = match supported_num_vars {
Some(p) => p,
None => {
return Err(PCSErrors::InvalidParameters(
"multilinear should receive a num_var param".to_string(),
))
},
};
let (uni_ck, uni_vk) = srs.1.trim(supported_log_degree)?;
let (ml_ck, ml_vk) = srs.0.trim(supported_num_vars)?;
Ok(((ml_ck, uni_ck), (ml_vk, uni_vk)))
}
/// Generate a commitment for a polynomial.
///
/// This function takes `2^num_vars` number of scalar multiplications over
@@ -94,14 +116,20 @@ impl<E: PairingEngine> PolynomialCommitmentScheme<E> for KZGMultilinearPCS<E> {
poly: &Self::Polynomial,
) -> Result<Self::Commitment, PCSErrors> {
let commit_timer = start_timer!(|| "commit");
if prover_param.0.num_vars < poly.num_vars {
return Err(PCSErrors::InvalidParameters(format!(
"Poly length ({}) exceeds param limit ({})",
poly.num_vars, prover_param.0.num_vars
)));
}
let ignored = prover_param.0.num_vars - poly.num_vars;
let scalars: Vec<_> = poly
.to_evaluations()
.into_iter()
.map(|x| x.into_repr())
.collect();
let commitment = VariableBaseMSM::multi_scalar_mul(
&prover_param.0.powers_of_g[0].evals,
&prover_param.0.powers_of_g[ignored].evals,
scalars.as_slice(),
)
.into_affine();
@@ -262,12 +290,23 @@ fn open_internal<E: PairingEngine>(
) -> Result<(Proof<E>, E::Fr), PCSErrors> {
let open_timer = start_timer!(|| format!("open mle with {} variable", polynomial.num_vars));
assert_eq!(
polynomial.num_vars(),
prover_param.num_vars,
"Invalid size of polynomial"
);
if polynomial.num_vars() > prover_param.num_vars {
return Err(PCSErrors::InvalidParameters(format!(
"Polynomial num_vars {} exceed the limit {}",
polynomial.num_vars, prover_param.num_vars
)));
}
if polynomial.num_vars() != point.len() {
return Err(PCSErrors::InvalidParameters(format!(
"Polynomial num_vars {} does not match point len {}",
polynomial.num_vars,
point.len()
)));
}
let nv = polynomial.num_vars();
let ignored = prover_param.num_vars - nv;
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();
@@ -277,7 +316,7 @@ fn open_internal<E: PairingEngine>(
for (i, (&point_at_k, gi)) in point
.iter()
.zip(prover_param.powers_of_g.iter())
.zip(prover_param.powers_of_g[ignored..].iter())
.take(nv)
.enumerate()
{
@@ -327,10 +366,20 @@ fn verify_internal<E: PairingEngine>(
proof: &Proof<E>,
) -> Result<bool, PCSErrors> {
let verify_timer = start_timer!(|| "verify");
let num_var = point.len();
if num_var > verifier_param.num_vars {
return Err(PCSErrors::InvalidParameters(format!(
"point length ({}) exceeds param limit ({})",
num_var, verifier_param.num_vars
)));
}
let ignored = verifier_param.num_vars - num_var;
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 window_size = FixedBaseMSM::get_mul_window_size(num_var);
let h_table = FixedBaseMSM::get_window_table(
scalar_size,
@@ -340,8 +389,8 @@ fn verify_internal<E: PairingEngine>(
let h_mul: Vec<E::G2Projective> =
FixedBaseMSM::multi_scalar_mul(scalar_size, window_size, &h_table, point);
let h_vec: Vec<_> = (0..verifier_param.num_vars)
.map(|i| verifier_param.h_mask[i].into_projective() - h_mul[i])
let h_vec: Vec<_> = (0..num_var)
.map(|i| verifier_param.h_mask[ignored + i].into_projective() - h_mul[i])
.collect();
let h_vec: Vec<E::G2Affine> = E::G2Projective::batch_normalization_into_affine(&h_vec);
end_timer!(prepare_inputs_timer);
@@ -352,12 +401,7 @@ fn verify_internal<E: PairingEngine>(
.proofs
.iter()
.map(|&x| E::G1Prepared::from(x))
.zip(
h_vec
.into_iter()
.take(verifier_param.num_vars)
.map(E::G2Prepared::from),
)
.zip(h_vec.into_iter().take(num_var).map(E::G2Prepared::from))
.collect();
pairings.push((
@@ -377,7 +421,6 @@ fn verify_internal<E: PairingEngine>(
#[cfg(test)]
mod tests {
use super::*;
use crate::StructuredReferenceString;
use ark_bls12_381::Bls12_381;
use ark_ec::PairingEngine;
use ark_poly::{DenseMultilinearExtension, MultilinearExtension};
@@ -387,17 +430,13 @@ mod tests {
fn test_single_helper<R: RngCore>(
params: &(MultilinearUniversalParams<E>, UnivariateUniversalParams<E>),
poly: &DenseMultilinearExtension<Fr>,
poly: &Rc<DenseMultilinearExtension<Fr>>,
rng: &mut R,
) -> Result<(), PCSErrors> {
let nv = poly.num_vars();
assert_ne!(nv, 0);
let uni_degree = 1;
let (uni_ck, uni_vk) = params.1.trim(uni_degree)?;
let (ml_ck, ml_vk) = params.0.trim(nv)?;
let ck = (ml_ck, uni_ck);
let vk = (ml_vk, uni_vk);
let (ck, vk) = KZGMultilinearPCS::trim(params, uni_degree, Some(nv + 1))?;
let point: Vec<_> = (0..nv).map(|_| Fr::rand(rng)).collect();
let com = KZGMultilinearPCS::commit(&ck, poly)?;
let (proof, value) = KZGMultilinearPCS::open(&ck, poly, &point)?;
@@ -421,11 +460,11 @@ mod tests {
let params = KZGMultilinearPCS::<E>::gen_srs_for_testing(&mut rng, 10)?;
// normal polynomials
let poly1 = DenseMultilinearExtension::rand(8, &mut rng);
let poly1 = Rc::new(DenseMultilinearExtension::rand(8, &mut rng));
test_single_helper(&params, &poly1, &mut rng)?;
// single-variate polynomials
let poly2 = DenseMultilinearExtension::rand(1, &mut rng);
let poly2 = Rc::new(DenseMultilinearExtension::rand(1, &mut rng));
test_single_helper(&params, &poly2, &mut rng)?;
Ok(())

View File

@@ -6,8 +6,7 @@ use ark_poly::{
univariate::DensePolynomial, DenseMultilinearExtension, EvaluationDomain, Evaluations,
MultilinearExtension, Polynomial, Radix2EvaluationDomain,
};
use ark_std::{end_timer, log2, start_timer};
use std::cmp::max;
use ark_std::{end_timer, log2, rc::Rc, start_timer};
/// Decompose an integer into a binary vector in little endian.
#[allow(dead_code)]
@@ -29,8 +28,7 @@ pub(crate) fn bit_decompose(input: u64, num_var: usize) -> Vec<bool> {
// - mle has degree one
// - worst case is `\prod_{i=0}^{mle_num_vars-1} l_i(x) < point_len * mle_num_vars`
#[inline]
#[allow(dead_code)]
pub(crate) fn compute_qx_degree(mle_num_vars: usize, point_len: usize) -> usize {
pub fn compute_qx_degree(mle_num_vars: usize, point_len: usize) -> usize {
mle_num_vars * point_len
}
@@ -101,28 +99,14 @@ pub(crate) fn compute_w_circ_l<F: PrimeField>(
/// Return the number of variables that one need for an MLE to
/// batch the list of MLEs
#[inline]
pub(crate) fn get_batched_nv(num_var: usize, polynomials_len: usize) -> usize {
pub fn get_batched_nv(num_var: usize, polynomials_len: usize) -> usize {
num_var + log2(polynomials_len) as usize
}
/// Return the SRS size
// We require an SRS that is the greater of the two:
// - Multilinear srs is bounded by the merged MLS size which is `get_batched_nv(num_var,
// num_witnesses)`
// - Univariate srs is bounded by q_x's degree which is `compute_uni_degree(num_vars,
// num_witnesses)`
#[inline]
#[allow(dead_code)]
pub(crate) fn get_srs_size(num_var: usize, num_wires: usize) -> usize {
max(
num_var + log2(num_wires) as usize,
(log2(num_var) as usize + 2) * num_wires,
)
}
/// merge a set of polynomials. Returns an error if the
/// polynomials do not share a same number of nvs.
pub fn merge_polynomials<F: PrimeField>(
polynomials: &[impl MultilinearExtension<F>],
polynomials: &[Rc<DenseMultilinearExtension<F>>],
) -> Result<DenseMultilinearExtension<F>, PCSErrors> {
let nv = polynomials[0].num_vars();
for poly in polynomials.iter() {
@@ -184,7 +168,7 @@ pub(crate) fn build_l<F: PrimeField>(
// are included in the `batch_proof`.
#[cfg(test)]
pub(crate) fn generate_evaluations<F: PrimeField>(
polynomials: &[DenseMultilinearExtension<F>],
polynomials: &[Rc<DenseMultilinearExtension<F>>],
points: &[Vec<F>],
) -> Result<Vec<F>, PCSErrors> {
if polynomials.len() != points.len() {
@@ -308,7 +292,7 @@ mod test {
// 1, 0 |-> 0
// 1, 1 |-> 5
let w_eval = vec![F::zero(), F::from(2u64), F::zero(), F::from(5u64)];
let w1 = DenseMultilinearExtension::from_evaluations_vec(2, w_eval);
let w1 = Rc::new(DenseMultilinearExtension::from_evaluations_vec(2, w_eval));
// W2 = x1x2 + x1 whose evaluations are
// 0, 0 |-> 0
@@ -316,7 +300,7 @@ mod test {
// 1, 0 |-> 1
// 1, 1 |-> 2
let w_eval = vec![F::zero(), F::zero(), F::from(1u64), F::from(2u64)];
let w2 = DenseMultilinearExtension::from_evaluations_vec(2, w_eval);
let w2 = Rc::new(DenseMultilinearExtension::from_evaluations_vec(2, w_eval));
// W3 = x1 + x2 whose evaluations are
// 0, 0 |-> 0
@@ -324,7 +308,7 @@ mod test {
// 1, 0 |-> 1
// 1, 1 |-> 2
let w_eval = vec![F::zero(), F::one(), F::from(1u64), F::from(2u64)];
let w3 = DenseMultilinearExtension::from_evaluations_vec(2, w_eval);
let w3 = Rc::new(DenseMultilinearExtension::from_evaluations_vec(2, w_eval));
{
// W = (3x1x2 + 2x2)(1-x0) + (x1x2 + x1)x0
@@ -577,15 +561,15 @@ mod test {
// Example from page 53:
// W1 = 3x1x2 + 2x2
let w_eval = vec![Fr::zero(), Fr::from(2u64), Fr::zero(), Fr::from(5u64)];
let w1 = DenseMultilinearExtension::from_evaluations_vec(2, w_eval);
let w1 = Rc::new(DenseMultilinearExtension::from_evaluations_vec(2, w_eval));
// W2 = x1x2 + x1
let w_eval = vec![Fr::zero(), Fr::zero(), Fr::from(1u64), Fr::from(2u64)];
let w2 = DenseMultilinearExtension::from_evaluations_vec(2, w_eval);
let w2 = Rc::new(DenseMultilinearExtension::from_evaluations_vec(2, w_eval));
// W3 = x1 + x2
let w_eval = vec![Fr::zero(), Fr::one(), Fr::from(1u64), Fr::from(2u64)];
let w3 = DenseMultilinearExtension::from_evaluations_vec(2, w_eval);
let w3 = Rc::new(DenseMultilinearExtension::from_evaluations_vec(2, w_eval));
let r = Fr::from(42u64);

View File

@@ -1,3 +0,0 @@
use ark_ec::{AffineCurve, PairingEngine};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Read, SerializationError, Write};
use ark_std::vec::Vec;

View File

@@ -2,7 +2,7 @@ pub use crate::{
errors::PCSErrors,
multilinear_kzg::{
srs::{MultilinearProverParam, MultilinearUniversalParams, MultilinearVerifierParam},
util::merge_polynomials,
util::{compute_qx_degree, get_batched_nv, merge_polynomials},
BatchProof, KZGMultilinearPCS, Proof,
},
structs::Commitment,

View File

@@ -38,9 +38,9 @@ impl<E: PairingEngine> PolynomialCommitmentScheme<E> for KZGUnivariatePCS<E> {
type Evaluation = E::Fr;
// Polynomial and its associated types
type Commitment = Commitment<E>;
type BatchCommitment = Vec<Self::Commitment>;
type Proof = KZGUnivariateOpening<E>;
type BatchProof = Vec<Self::Proof>;
type BatchCommitment = Vec<Self::Commitment>;
/// Build SRS for testing.
///
@@ -56,6 +56,22 @@ impl<E: PairingEngine> PolynomialCommitmentScheme<E> for KZGUnivariatePCS<E> {
Self::SRS::gen_srs_for_testing(rng, log_size)
}
/// Trim the universal parameters to specialize the public parameters.
/// Input `supported_log_degree` for univariate.
/// `supported_num_vars` must be None or an error is returned.
fn trim(
srs: &Self::SRS,
supported_log_degree: usize,
supported_num_vars: Option<usize>,
) -> Result<(Self::ProverParam, Self::VerifierParam), PCSErrors> {
if supported_num_vars.is_some() {
return Err(PCSErrors::InvalidParameters(
"univariate should not receive a num_var param".to_string(),
));
}
srs.trim(supported_log_degree)
}
/// Generate a commitment for a polynomial
/// Note that the scheme is not hidding
fn commit(
@@ -342,7 +358,7 @@ mod tests {
}
let log_degree = log2(degree) as usize;
let pp = KZGUnivariatePCS::<E>::gen_srs_for_testing(rng, log_degree)?;
let (ck, vk) = pp.trim(log_degree)?;
let (ck, vk) = KZGUnivariatePCS::<E>::trim(&pp, log_degree, None)?;
let mut comms = Vec::new();
let mut values = Vec::new();
let mut points = Vec::new();