jf_pcs/univariate_kzg/
srs.rs

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 univariate polynomial KZG
8
9use crate::{PCSError, StructuredReferenceString};
10use ark_ec::pairing::Pairing;
11use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
12use ark_std::{string::ToString, vec::Vec};
13
14/// `UniversalParams` are the universal parameters for the KZG10 scheme.
15// Adapted from
16// https://github.com/arkworks-rs/poly-commit/blob/c724fa666e935bbba8db5a1421603bab542e15ab/poly-commit/src/kzg10/data_structures.rs#L24
17#[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize, Default)]
18pub struct UnivariateUniversalParams<E: Pairing> {
19    /// Group elements of the form `{ \beta^i G }`, where `i` ranges from 0 to
20    /// `degree`.
21    pub powers_of_g: Vec<E::G1Affine>,
22    /// TODO: remove h and beta_h
23    /// The generator of G2.
24    pub h: E::G2Affine,
25    /// \beta times the above generator of G2.
26    pub beta_h: E::G2Affine,
27    /// powers of \beta time the generator h of G2
28    pub powers_of_h: Vec<E::G2Affine>,
29}
30
31impl<E: Pairing> UnivariateUniversalParams<E> {
32    /// Returns the maximum supported degree
33    pub fn max_degree(&self) -> usize {
34        self.powers_of_g.len()
35    }
36}
37
38/// `UnivariateProverParam` is used to generate a proof
39#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug, Eq, PartialEq, Default)]
40pub struct UnivariateProverParam<E: Pairing> {
41    /// Config
42    pub powers_of_g: Vec<E::G1Affine>,
43}
44
45/// `UnivariateVerifierParam` is used to check evaluation proofs for a given
46/// commitment.
47#[derive(Derivative, Clone, Debug, Eq, CanonicalSerialize, CanonicalDeserialize, PartialEq)]
48#[derivative(Default)]
49pub struct UnivariateVerifierParam<E: Pairing> {
50    /// TODO: remove g, h and beta_h
51    /// The generator of G1.
52    pub g: E::G1Affine,
53    /// The generator of G2.
54    pub h: E::G2Affine,
55    /// \beta times the above generator of G2.
56    pub beta_h: E::G2Affine,
57    /// powers of \beta time the generator h of G2: only used for multi-point
58    /// openings
59    pub powers_of_h: Vec<E::G2Affine>,
60    /// powers of \beta time the generator g of G1: only used for multi-point
61    /// openings
62    pub powers_of_g: Vec<E::G1Affine>,
63}
64
65impl<E: Pairing> StructuredReferenceString for UnivariateUniversalParams<E> {
66    type ProverParam = UnivariateProverParam<E>;
67    type VerifierParam = UnivariateVerifierParam<E>;
68
69    /// Extract the prover parameters from the public parameters.
70    fn extract_prover_param(&self, supported_degree: usize) -> Self::ProverParam {
71        let powers_of_g = self.powers_of_g[..=supported_degree].to_vec();
72
73        Self::ProverParam { powers_of_g }
74    }
75
76    /// Extract the verifier parameters from the public parameters.
77    fn extract_verifier_param(&self, supported_degree: usize) -> Self::VerifierParam {
78        Self::VerifierParam {
79            g: self.powers_of_g[0],
80            h: self.h,
81            beta_h: self.beta_h,
82            powers_of_h: self.powers_of_h[..=supported_degree].to_vec(),
83            powers_of_g: self.powers_of_g[..=supported_degree].to_vec(),
84        }
85    }
86
87    /// Trim the universal parameters to specialize the public parameters
88    /// for univariate polynomials to the given `supported_degree`, and
89    /// returns committer key and verifier key. `supported_degree` should
90    /// be in range `1..params.len()`
91    fn trim_with_verifier_degree(
92        &self,
93        prover_supported_degree: usize,
94        verifier_supported_degree: usize,
95    ) -> Result<(Self::ProverParam, Self::VerifierParam), PCSError> {
96        if self.powers_of_g.len() <= prover_supported_degree {
97            return Err(PCSError::InvalidParameters(ark_std::format!(
98                "Largest supported prover degree by the SRS is: {}, but requested: {}",
99                self.powers_of_g.len() - 1,
100                prover_supported_degree,
101            )));
102        }
103        if self.powers_of_h.len() <= verifier_supported_degree {
104            return Err(PCSError::InvalidParameters(ark_std::format!(
105                "Largest supported verifier degree by the SRS is: {}, but requested: {}",
106                self.powers_of_h.len() - 1,
107                verifier_supported_degree,
108            )));
109        }
110        if verifier_supported_degree == 0 {
111            return Err(PCSError::InvalidParameters(
112                "Verifier supported degree should be larger than zero".to_string(),
113            ));
114        }
115        let powers_of_g = self.powers_of_g[..=prover_supported_degree].to_vec();
116
117        let pk = Self::ProverParam { powers_of_g };
118        let vk = Self::VerifierParam {
119            g: self.powers_of_g[0],
120            h: self.h,
121            beta_h: self.beta_h,
122            powers_of_h: self.powers_of_h[..=verifier_supported_degree].to_vec(),
123            powers_of_g: self.powers_of_g[..=verifier_supported_degree].to_vec(),
124        };
125        Ok((pk, vk))
126    }
127
128    /// Trim the universal parameters to specialize the public parameters
129    /// for univariate polynomials to the given `supported_degree`, and
130    /// returns committer key and verifier key. `supported_degree` should
131    /// be in range `1..params.len()`
132    fn trim(
133        &self,
134        supported_degree: usize,
135    ) -> Result<(Self::ProverParam, Self::VerifierParam), PCSError> {
136        self.trim_with_verifier_degree(supported_degree, 1)
137    }
138
139    // (alex): I'm not sure how to import `RngCore, CryptoRng` under `cfg(test)`
140    // when they are unused by the rest. Thus, I use explicit import path.
141    #[cfg(any(test, feature = "test-srs"))]
142    fn gen_srs_for_testing<R>(rng: &mut R, max_degree: usize) -> Result<Self, PCSError>
143    where
144        R: ark_std::rand::RngCore + ark_std::rand::CryptoRng,
145    {
146        tests::gen_srs_for_testing(rng, max_degree, 1)
147    }
148
149    #[cfg(any(test, feature = "test-srs"))]
150    fn gen_srs_for_testing_with_verifier_degree<
151        R: ark_std::rand::prelude::RngCore + ark_std::rand::prelude::CryptoRng,
152    >(
153        rng: &mut R,
154        prover_supported_degree: usize,
155        verifier_supported_degree: usize,
156    ) -> Result<Self, PCSError> {
157        tests::gen_srs_for_testing(rng, prover_supported_degree, verifier_supported_degree)
158    }
159}
160
161#[cfg(any(test, feature = "test-srs"))]
162mod tests {
163    use super::UnivariateUniversalParams;
164    use crate::PCSError;
165    use ark_ec::{pairing::Pairing, scalar_mul::fixed_base::FixedBase, CurveGroup};
166    use ark_ff::PrimeField;
167    use ark_std::{
168        end_timer,
169        rand::{CryptoRng, RngCore},
170        start_timer, vec, One, UniformRand,
171    };
172
173    pub(crate) fn gen_srs_for_testing<E: Pairing, R: RngCore + CryptoRng>(
174        rng: &mut R,
175        prover_degree: usize,
176        verifier_degree: usize,
177    ) -> Result<UnivariateUniversalParams<E>, PCSError> {
178        let setup_time = start_timer!(|| ark_std::format!(
179            "KZG10::Setup with prover degree {} and verifier degree {}",
180            prover_degree,
181            verifier_degree
182        ));
183        let beta = E::ScalarField::rand(rng);
184        let g = E::G1::rand(rng);
185        let h = E::G2::rand(rng);
186
187        let mut powers_of_beta = vec![E::ScalarField::one()];
188
189        let mut cur = beta;
190        let max_degree = ark_std::cmp::max(prover_degree, verifier_degree);
191        for _ in 0..max_degree {
192            powers_of_beta.push(cur);
193            cur *= &beta;
194        }
195
196        let window_size = FixedBase::get_mul_window_size(prover_degree + 1);
197
198        let scalar_bits = E::ScalarField::MODULUS_BIT_SIZE as usize;
199        let g_time = start_timer!(|| "Generating powers of G");
200        // TODO: parallelization
201        let g_table = FixedBase::get_window_table(scalar_bits, window_size, g);
202        let powers_of_g =
203            FixedBase::msm::<E::G1>(scalar_bits, window_size, &g_table, &powers_of_beta);
204        end_timer!(g_time);
205
206        let powers_of_g = E::G1::normalize_batch(&powers_of_g);
207
208        let h = h.into_affine();
209        let beta_h = (h * beta).into_affine();
210
211        let powers_of_h = powers_of_beta
212            .iter()
213            .take(verifier_degree + 1)
214            .map(|x| (h * x).into_affine())
215            .collect();
216
217        let pp = UnivariateUniversalParams {
218            powers_of_g,
219            h,
220            beta_h,
221            powers_of_h,
222        };
223        end_timer!(setup_time);
224        Ok(pp)
225    }
226}