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