diff --git a/hyperplonk/src/snark.rs b/hyperplonk/src/snark.rs index ff18ec2..6801ade 100644 --- a/hyperplonk/src/snark.rs +++ b/hyperplonk/src/snark.rs @@ -567,7 +567,7 @@ where // check public evaluation let pi_step = start_timer!(|| "check public evaluation"); - let pi_poly = DenseMultilinearExtension::from_evaluations_slice(ell as usize, pub_input); + let pi_poly = DenseMultilinearExtension::from_evaluations_slice(ell, pub_input); let expect_pi_eval = evaluate_opt(&pi_poly, &r_pi[..]); if expect_pi_eval != *pi_eval { return Err(HyperPlonkErrors::InvalidProver(format!( diff --git a/subroutines/src/pcs/multilinear_kzg/mod.rs b/subroutines/src/pcs/multilinear_kzg/mod.rs index 4b64ee0..d3c0760 100644 --- a/subroutines/src/pcs/multilinear_kzg/mod.rs +++ b/subroutines/src/pcs/multilinear_kzg/mod.rs @@ -209,11 +209,10 @@ impl PolynomialCommitmentScheme for MultilinearKzgPCS { /// 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 +/// This function takes 2^{num_var} number of scalar multiplications over /// G1: /// - 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. +/// - at round i, we compute an MSM for `2^{num_var - i}` number of G1 elements. fn open_internal( prover_param: &MultilinearProverParam, polynomial: &DenseMultilinearExtension, @@ -237,41 +236,35 @@ fn open_internal( } let nv = polynomial.num_vars(); - let ignored = prover_param.num_vars - nv; - let mut r: Vec> = (0..nv + 1).map(|_| Vec::new()).collect(); - let mut q: Vec> = (0..nv + 1).map(|_| Vec::new()).collect(); - - r[nv] = polynomial.to_evaluations(); + // the first `ignored` SRS vectors are unused for opening. + let ignored = prover_param.num_vars - nv + 1; + let mut f = polynomial.to_evaluations(); let mut proofs = Vec::new(); for (i, (&point_at_k, gi)) in point .iter() - .zip(prover_param.powers_of_g[ignored..].iter()) - .take(nv) + .zip(prover_param.powers_of_g[ignored..ignored + nv].iter()) .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]; - let one_minus_point_at_k = E::Fr::one() - point_at_k; + let k = nv - 1 - i; + let cur_dim = 1 << k; + let mut q = vec![E::Fr::zero(); cur_dim]; + let mut r = vec![E::Fr::zero(); cur_dim]; let ith_round_eval = start_timer!(|| format!("{}-th round eval", i)); - 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]; + for b in 0..(1 << k) { + // q[b] = f[1, b] - f[0, b] + q[b] = f[(b << 1) + 1] - f[b << 1]; - // r_b = pre_r [2^b]*(1-p) + pre_r [2^b + 1] * p - cur_r[b] = r[k][b << 1] * one_minus_point_at_k + (r[k][(b << 1) + 1] * point_at_k); + // r[b] = f[0, b] + q[b] * p + r[b] = f[b << 1] + (q[b] * point_at_k); } + f = r; end_timer!(ith_round_eval); - let scalars: Vec<_> = (0..(1 << k)).map(|x| cur_q[x >> 1].into_repr()).collect(); - - q[k] = cur_q; - r[k - 1] = cur_r; + let scalars: Vec<_> = q.iter().map(|x| x.into_repr()).collect(); // this is a MSM over G1 and is likely to be the bottleneck let msm_timer = start_timer!(|| format!("msm of size {} at round {}", gi.evals.len(), i)); @@ -309,7 +302,6 @@ fn verify_internal( ))); } - 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(); @@ -323,6 +315,7 @@ fn verify_internal( let h_mul: Vec = FixedBaseMSM::multi_scalar_mul(scalar_size, window_size, &h_table, point); + let ignored = verifier_param.num_vars - num_var; let h_vec: Vec<_> = (0..num_var) .map(|i| verifier_param.h_mask[ignored + i].into_projective() - h_mul[i]) .collect(); @@ -370,7 +363,7 @@ mod tests { ) -> Result<(), PCSError> { let nv = poly.num_vars(); assert_ne!(nv, 0); - let (ck, vk) = MultilinearKzgPCS::trim(params, None, Some(nv + 1))?; + let (ck, vk) = MultilinearKzgPCS::trim(params, None, Some(nv))?; let point: Vec<_> = (0..nv).map(|_| Fr::rand(rng)).collect(); let com = MultilinearKzgPCS::commit(&ck, poly)?; let (proof, value) = MultilinearKzgPCS::open(&ck, poly, &point)?; diff --git a/subroutines/src/pcs/multilinear_kzg/srs.rs b/subroutines/src/pcs/multilinear_kzg/srs.rs index e82d57e..1594a04 100644 --- a/subroutines/src/pcs/multilinear_kzg/srs.rs +++ b/subroutines/src/pcs/multilinear_kzg/srs.rs @@ -6,10 +6,12 @@ //! Implementing Structured Reference Strings for multilinear polynomial KZG use crate::pcs::{ - multilinear_kzg::util::eq_extension, prelude::PCSError, StructuredReferenceString, + multilinear_kzg::util::{eq_eval, eq_extension}, + prelude::PCSError, + StructuredReferenceString, }; use ark_ec::{msm::FixedBaseMSM, AffineCurve, PairingEngine, ProjectiveCurve}; -use ark_ff::{Field, PrimeField}; +use ark_ff::{Field, PrimeField, Zero}; use ark_poly::DenseMultilinearExtension; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Read, SerializationError, Write}; use ark_std::{ @@ -44,8 +46,9 @@ pub struct MultilinearUniversalParams { pub struct MultilinearProverParam { /// number of variables pub num_vars: usize, - /// `pp_{num_vars}`, `pp_{num_vars - 1}`, `pp_{num_vars - 2}`, ..., defined - /// by XZZPD19 + /// `pp_{0}`, `pp_{1}`, ...,pp_{nu_vars} defined + /// by XZZPD19 where pp_{nv-0}=g and + /// pp_{nv-i}=g^{eq((t_1,..t_i),(X_1,..X_i))} pub powers_of_g: Vec>, /// generator for G1 pub g: E::G1Affine, @@ -187,9 +190,16 @@ impl StructuredReferenceString for MultilinearUniversalPara let pp_k_g = Evaluations { evals: pp_g[start..(start + size)].to_vec(), }; + // check correctness of pp_k_g + let t_eval_0 = eq_eval(&vec![E::Fr::zero(); num_vars - i], &t[i..num_vars])?; + assert_eq!(g.mul(t_eval_0.into_repr()).into_affine(), pp_k_g.evals[0]); powers_of_g.push(pp_k_g); start += size; } + let gg = Evaluations { + evals: [g.into_affine()].to_vec(), + }; + powers_of_g.push(gg); let pp = Self::ProverParam { num_vars,