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