arnaucube
arnaucube/hyperplonkPublic Self-hosted repository
hyperplonk/pcs/src/multilinear_kzg/srs.rs
pcs/src/multilinear_kzg/srs.rsRaw
  1//! Implementing Structured Reference Strings for multilinear polynomial KZG
  2
  3use crate::{prelude::PCSErrors, StructuredReferenceString};
  4use ark_ec::{msm::FixedBaseMSM, AffineCurve, PairingEngine, ProjectiveCurve};
  5use ark_ff::{Field, PrimeField};
  6use ark_poly::DenseMultilinearExtension;
  7use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Read, SerializationError, Write};
  8use ark_std::{end_timer, rand::RngCore, start_timer, vec::Vec, UniformRand};
  9use std::collections::LinkedList;
 10
 11/// Evaluations over {0,1}^n for G1 or G2
 12#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug)]
 13pub struct Evaluations<C: AffineCurve> {
 14    /// The evaluations.
 15    pub evals: Vec<C>,
 16}
 17
 18/// Universal Parameter
 19#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug)]
 20pub struct MultilinearUniversalParams<E: PairingEngine> {
 21    /// prover parameters
 22    pub prover_param: MultilinearProverParam<E>,
 23    /// h^randomness: h^t1, h^t2, ..., **h^{t_nv}**
 24    pub h_mask: Vec<E::G2Affine>,
 25}
 26
 27/// Prover Parameters
 28#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug)]
 29pub struct MultilinearProverParam<E: PairingEngine> {
 30    /// number of variables
 31    pub num_vars: usize,
 32    /// `pp_{num_vars}`, `pp_{num_vars - 1}`, `pp_{num_vars - 2}`, ..., defined
 33    /// by XZZPD19
 34    pub powers_of_g: Vec<Evaluations<E::G1Affine>>,
 35    /// generator for G1
 36    pub g: E::G1Affine,
 37    /// generator for G2
 38    pub h: E::G2Affine,
 39}
 40
 41/// Verifier Parameters
 42#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug)]
 43pub struct MultilinearVerifierParam<E: PairingEngine> {
 44    /// number of variables
 45    pub num_vars: usize,
 46    /// generator of G1
 47    pub g: E::G1Affine,
 48    /// generator of G2
 49    pub h: E::G2Affine,
 50    /// h^randomness: h^t1, h^t2, ..., **h^{t_nv}**
 51    pub h_mask: Vec<E::G2Affine>,
 52}
 53
 54impl<E: PairingEngine> StructuredReferenceString<E> for MultilinearUniversalParams<E> {
 55    type ProverParam = MultilinearProverParam<E>;
 56    type VerifierParam = MultilinearVerifierParam<E>;
 57
 58    /// Extract the prover parameters from the public parameters.
 59    fn extract_prover_param(&self, supported_num_vars: usize) -> Self::ProverParam {
 60        let to_reduce = self.prover_param.num_vars - supported_num_vars;
 61
 62        Self::ProverParam {
 63            powers_of_g: self.prover_param.powers_of_g[to_reduce..].to_vec(),
 64            g: self.prover_param.g,
 65            h: self.prover_param.h,
 66            num_vars: supported_num_vars,
 67        }
 68    }
 69
 70    /// Extract the verifier parameters from the public parameters.
 71    fn extract_verifier_param(&self, supported_num_vars: usize) -> Self::VerifierParam {
 72        let to_reduce = self.prover_param.num_vars - supported_num_vars;
 73        Self::VerifierParam {
 74            num_vars: supported_num_vars,
 75            g: self.prover_param.g,
 76            h: self.prover_param.h,
 77            h_mask: self.h_mask[to_reduce..].to_vec(),
 78        }
 79    }
 80
 81    /// Trim the universal parameters to specialize the public parameters
 82    /// for multilinear polynomials to the given `supported_num_vars`, and
 83    /// returns committer key and verifier key. `supported_num_vars` should
 84    /// be in range `1..=params.num_vars`
 85    fn trim(
 86        &self,
 87        supported_num_vars: usize,
 88    ) -> Result<(Self::ProverParam, Self::VerifierParam), PCSErrors> {
 89        if supported_num_vars > self.prover_param.num_vars {
 90            return Err(PCSErrors::InvalidParameters(format!(
 91                "SRS does not support target number of vars {}",
 92                supported_num_vars
 93            )));
 94        }
 95
 96        let to_reduce = self.prover_param.num_vars - supported_num_vars;
 97        let ck = Self::ProverParam {
 98            powers_of_g: self.prover_param.powers_of_g[to_reduce..].to_vec(),
 99            g: self.prover_param.g,
100            h: self.prover_param.h,
101            num_vars: supported_num_vars,
102        };
103        let vk = Self::VerifierParam {
104            num_vars: supported_num_vars,
105            g: self.prover_param.g,
106            h: self.prover_param.h,
107            h_mask: self.h_mask[to_reduce..].to_vec(),
108        };
109        Ok((ck, vk))
110    }
111
112    /// Build SRS for testing.
113    /// WARNING: THIS FUNCTION IS FOR TESTING PURPOSE ONLY.
114    /// THE OUTPUT SRS SHOULD NOT BE USED IN PRODUCTION.
115    fn gen_srs_for_testing<R: RngCore>(rng: &mut R, num_vars: usize) -> Result<Self, PCSErrors> {
116        if num_vars == 0 {
117            return Err(PCSErrors::InvalidParameters(
118                "constant polynomial not supported".to_string(),
119            ));
120        }
121
122        let total_timer = start_timer!(|| "SRS generation");
123
124        let pp_generation_timer = start_timer!(|| "Prover Param generation");
125
126        let g = E::G1Projective::rand(rng);
127        let h = E::G2Projective::rand(rng);
128
129        let mut powers_of_g = Vec::new();
130
131        let t: Vec<_> = (0..num_vars).map(|_| E::Fr::rand(rng)).collect();
132        let scalar_bits = E::Fr::size_in_bits();
133
134        let mut eq: LinkedList<DenseMultilinearExtension<E::Fr>> =
135            LinkedList::from_iter(eq_extension(&t).into_iter());
136        let mut eq_arr = LinkedList::new();
137        let mut base = eq.pop_back().unwrap().evaluations;
138
139        for i in (0..num_vars).rev() {
140            eq_arr.push_front(remove_dummy_variable(&base, i)?);
141            if i != 0 {
142                let mul = eq.pop_back().unwrap().evaluations;
143                base = base
144                    .into_iter()
145                    .zip(mul.into_iter())
146                    .map(|(a, b)| a * b)
147                    .collect();
148            }
149        }
150
151        let mut pp_powers = Vec::new();
152        let mut total_scalars = 0;
153        for i in 0..num_vars {
154            let eq = eq_arr.pop_front().unwrap();
155            let pp_k_powers = (0..(1 << (num_vars - i))).map(|x| eq[x]);
156            pp_powers.extend(pp_k_powers);
157            total_scalars += 1 << (num_vars - i);
158        }
159        let window_size = FixedBaseMSM::get_mul_window_size(total_scalars);
160        let g_table = FixedBaseMSM::get_window_table(scalar_bits, window_size, g);
161
162        let pp_g = E::G1Projective::batch_normalization_into_affine(
163            &FixedBaseMSM::multi_scalar_mul(scalar_bits, window_size, &g_table, &pp_powers),
164        );
165
166        let mut start = 0;
167        for i in 0..num_vars {
168            let size = 1 << (num_vars - i);
169            let pp_k_g = Evaluations {
170                evals: pp_g[start..(start + size)].to_vec(),
171            };
172            powers_of_g.push(pp_k_g);
173            start += size;
174        }
175
176        let pp = Self::ProverParam {
177            num_vars,
178            g: g.into_affine(),
179            h: h.into_affine(),
180            powers_of_g,
181        };
182
183        end_timer!(pp_generation_timer);
184
185        let vp_generation_timer = start_timer!(|| "VP generation");
186        let h_mask = {
187            let window_size = FixedBaseMSM::get_mul_window_size(num_vars);
188            let h_table = FixedBaseMSM::get_window_table(scalar_bits, window_size, h);
189            E::G2Projective::batch_normalization_into_affine(&FixedBaseMSM::multi_scalar_mul(
190                scalar_bits,
191                window_size,
192                &h_table,
193                &t,
194            ))
195        };
196        end_timer!(vp_generation_timer);
197        end_timer!(total_timer);
198        Ok(Self {
199            prover_param: pp,
200            h_mask,
201        })
202    }
203}
204
205/// fix first `pad` variables of `poly` represented in evaluation form to zero
206fn remove_dummy_variable<F: Field>(poly: &[F], pad: usize) -> Result<Vec<F>, PCSErrors> {
207    if pad == 0 {
208        return Ok(poly.to_vec());
209    }
210    if !poly.len().is_power_of_two() {
211        return Err(PCSErrors::InvalidParameters(
212            "Size of polynomial should be power of two.".to_string(),
213        ));
214    }
215    let nv = ark_std::log2(poly.len()) as usize - pad;
216
217    Ok((0..(1 << nv)).map(|x| poly[x << pad]).collect())
218}
219
220/// Generate eq(t,x), a product of multilinear polynomials with fixed t.
221/// eq(a,b) is takes extensions of a,b in {0,1}^num_vars such that if a and b in
222/// {0,1}^num_vars are equal then this polynomial evaluates to 1.
223fn eq_extension<F: PrimeField>(t: &[F]) -> Vec<DenseMultilinearExtension<F>> {
224    let start = start_timer!(|| "eq extension");
225
226    let dim = t.len();
227    let mut result = Vec::new();
228    for (i, &ti) in t.iter().enumerate().take(dim) {
229        let mut poly = Vec::with_capacity(1 << dim);
230        for x in 0..(1 << dim) {
231            let xi = if x >> i & 1 == 1 { F::one() } else { F::zero() };
232            let ti_xi = ti * xi;
233            poly.push(ti_xi + ti_xi - xi - ti + F::one());
234        }
235        result.push(DenseMultilinearExtension::from_evaluations_vec(dim, poly));
236    }
237
238    end_timer!(start);
239    result
240}
241
242#[cfg(test)]
243mod tests {
244    use super::*;
245    use ark_bls12_381::Bls12_381;
246    use ark_std::test_rng;
247    type E = Bls12_381;
248
249    #[test]
250    fn test_srs_gen() -> Result<(), PCSErrors> {
251        let mut rng = test_rng();
252        for nv in 4..10 {
253            let _ = MultilinearUniversalParams::<E>::gen_srs_for_testing(&mut rng, nv)?;
254        }
255
256        Ok(())
257    }
258}