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_{num_vars}`, `pp_{num_vars - 1}`, `pp_{num_vars - 2}`, ..., defined
 48    /// by XZZPD19
 49    pub powers_of_g: Vec<Evaluations<E::G1Affine>>,
 50    /// generator for G1
 51    pub g: E::G1Affine,
 52    /// generator for G2
 53    pub h: E::G2Affine,
 54}
 55
 56/// Verifier Parameters
 57#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug)]
 58pub struct MultilinearVerifierParam<E: PairingEngine> {
 59    /// number of variables
 60    pub num_vars: usize,
 61    /// generator of G1
 62    pub g: E::G1Affine,
 63    /// generator of G2
 64    pub h: E::G2Affine,
 65    /// h^randomness: h^t1, h^t2, ..., **h^{t_nv}**
 66    pub h_mask: Vec<E::G2Affine>,
 67}
 68
 69impl<E: PairingEngine> StructuredReferenceString<E> for MultilinearUniversalParams<E> {
 70    type ProverParam = MultilinearProverParam<E>;
 71    type VerifierParam = MultilinearVerifierParam<E>;
 72
 73    /// Extract the prover parameters from the public parameters.
 74    fn extract_prover_param(&self, supported_num_vars: usize) -> Self::ProverParam {
 75        let to_reduce = self.prover_param.num_vars - supported_num_vars;
 76
 77        Self::ProverParam {
 78            powers_of_g: self.prover_param.powers_of_g[to_reduce..].to_vec(),
 79            g: self.prover_param.g,
 80            h: self.prover_param.h,
 81            num_vars: supported_num_vars,
 82        }
 83    }
 84
 85    /// Extract the verifier parameters from the public parameters.
 86    fn extract_verifier_param(&self, supported_num_vars: usize) -> Self::VerifierParam {
 87        let to_reduce = self.prover_param.num_vars - supported_num_vars;
 88        Self::VerifierParam {
 89            num_vars: supported_num_vars,
 90            g: self.prover_param.g,
 91            h: self.prover_param.h,
 92            h_mask: self.h_mask[to_reduce..].to_vec(),
 93        }
 94    }
 95
 96    /// Trim the universal parameters to specialize the public parameters
 97    /// for multilinear polynomials to the given `supported_num_vars`, and
 98    /// returns committer key and verifier key. `supported_num_vars` should
 99    /// be in range `1..=params.num_vars`
100    fn trim(
101        &self,
102        supported_num_vars: usize,
103    ) -> Result<(Self::ProverParam, Self::VerifierParam), PCSError> {
104        if supported_num_vars > self.prover_param.num_vars {
105            return Err(PCSError::InvalidParameters(format!(
106                "SRS does not support target number of vars {}",
107                supported_num_vars
108            )));
109        }
110
111        let to_reduce = self.prover_param.num_vars - supported_num_vars;
112        let ck = Self::ProverParam {
113            powers_of_g: self.prover_param.powers_of_g[to_reduce..].to_vec(),
114            g: self.prover_param.g,
115            h: self.prover_param.h,
116            num_vars: supported_num_vars,
117        };
118        let vk = Self::VerifierParam {
119            num_vars: supported_num_vars,
120            g: self.prover_param.g,
121            h: self.prover_param.h,
122            h_mask: self.h_mask[to_reduce..].to_vec(),
123        };
124        Ok((ck, vk))
125    }
126
127    /// Build SRS for testing.
128    /// WARNING: THIS FUNCTION IS FOR TESTING PURPOSE ONLY.
129    /// THE OUTPUT SRS SHOULD NOT BE USED IN PRODUCTION.
130    fn gen_srs_for_testing<R: RngCore + CryptoRng>(
131        rng: &mut R,
132        num_vars: usize,
133    ) -> Result<Self, PCSError> {
134        if num_vars == 0 {
135            return Err(PCSError::InvalidParameters(
136                "constant polynomial not supported".to_string(),
137            ));
138        }
139
140        let total_timer = start_timer!(|| "SRS generation");
141
142        let pp_generation_timer = start_timer!(|| "Prover Param generation");
143
144        let g = E::G1Projective::rand(rng);
145        let h = E::G2Projective::rand(rng);
146
147        let mut powers_of_g = Vec::new();
148
149        let t: Vec<_> = (0..num_vars).map(|_| E::Fr::rand(rng)).collect();
150        let scalar_bits = E::Fr::size_in_bits();
151
152        let mut eq: LinkedList<DenseMultilinearExtension<E::Fr>> =
153            LinkedList::from_iter(eq_extension(&t).into_iter());
154        let mut eq_arr = LinkedList::new();
155        let mut base = eq.pop_back().unwrap().evaluations;
156
157        for i in (0..num_vars).rev() {
158            eq_arr.push_front(remove_dummy_variable(&base, i)?);
159            if i != 0 {
160                let mul = eq.pop_back().unwrap().evaluations;
161                base = base
162                    .into_iter()
163                    .zip(mul.into_iter())
164                    .map(|(a, b)| a * b)
165                    .collect();
166            }
167        }
168
169        let mut pp_powers = Vec::new();
170        let mut total_scalars = 0;
171        for i in 0..num_vars {
172            let eq = eq_arr.pop_front().unwrap();
173            let pp_k_powers = (0..(1 << (num_vars - i))).map(|x| eq[x]);
174            pp_powers.extend(pp_k_powers);
175            total_scalars += 1 << (num_vars - i);
176        }
177        let window_size = FixedBaseMSM::get_mul_window_size(total_scalars);
178        let g_table = FixedBaseMSM::get_window_table(scalar_bits, window_size, g);
179
180        let pp_g = E::G1Projective::batch_normalization_into_affine(
181            &FixedBaseMSM::multi_scalar_mul(scalar_bits, window_size, &g_table, &pp_powers),
182        );
183
184        let mut start = 0;
185        for i in 0..num_vars {
186            let size = 1 << (num_vars - i);
187            let pp_k_g = Evaluations {
188                evals: pp_g[start..(start + size)].to_vec(),
189            };
190            powers_of_g.push(pp_k_g);
191            start += size;
192        }
193
194        let pp = Self::ProverParam {
195            num_vars,
196            g: g.into_affine(),
197            h: h.into_affine(),
198            powers_of_g,
199        };
200
201        end_timer!(pp_generation_timer);
202
203        let vp_generation_timer = start_timer!(|| "VP generation");
204        let h_mask = {
205            let window_size = FixedBaseMSM::get_mul_window_size(num_vars);
206            let h_table = FixedBaseMSM::get_window_table(scalar_bits, window_size, h);
207            E::G2Projective::batch_normalization_into_affine(&FixedBaseMSM::multi_scalar_mul(
208                scalar_bits,
209                window_size,
210                &h_table,
211                &t,
212            ))
213        };
214        end_timer!(vp_generation_timer);
215        end_timer!(total_timer);
216        Ok(Self {
217            prover_param: pp,
218            h_mask,
219        })
220    }
221}
222
223/// fix first `pad` variables of `poly` represented in evaluation form to zero
224fn remove_dummy_variable<F: Field>(poly: &[F], pad: usize) -> Result<Vec<F>, PCSError> {
225    if pad == 0 {
226        return Ok(poly.to_vec());
227    }
228    if !poly.len().is_power_of_two() {
229        return Err(PCSError::InvalidParameters(
230            "Size of polynomial should be power of two.".to_string(),
231        ));
232    }
233    let nv = ark_std::log2(poly.len()) as usize - pad;
234    Ok((0..(1 << nv)).map(|x| poly[x << pad]).collect())
235}
236
237#[cfg(test)]
238mod tests {
239    use super::*;
240    use ark_bls12_381::Bls12_381;
241    use ark_std::test_rng;
242    type E = Bls12_381;
243
244    #[test]
245    fn test_srs_gen() -> Result<(), PCSError> {
246        let mut rng = test_rng();
247        for nv in 4..10 {
248            let _ = MultilinearUniversalParams::<E>::gen_srs_for_testing(&mut rng, nv)?;
249        }
250
251        Ok(())
252    }
253}