Skip to main content

poly_commitment/
lib.rs

1// Enable unstable `is_multiple_of` on nightly for Wasm builds until nightly is updated
2// See: https://github.com/o1-labs/mina-rust/issues/1997
3#![cfg_attr(target_arch = "wasm32", feature(unsigned_is_multiple_of))]
4#![deny(unsafe_code)]
5#![deny(clippy::all)]
6#![deny(clippy::pedantic)]
7#![deny(clippy::nursery)]
8
9mod combine;
10pub mod commitment;
11pub mod error;
12pub mod hash_map_cache;
13pub mod ipa;
14pub mod kzg;
15pub mod lagrange_basis;
16pub mod precomputed_srs;
17pub mod utils;
18
19// Exposing property based tests for the SRS trait
20pub mod pbt_srs;
21
22pub use commitment::PolyComm;
23
24use crate::{
25    commitment::{BatchEvaluationProof, BlindedCommitment, CommitmentCurve},
26    error::CommitmentError,
27    utils::DensePolynomialOrEvaluations,
28};
29use ark_ec::AffineRepr;
30use ark_ff::UniformRand;
31use ark_poly::{
32    univariate::DensePolynomial, EvaluationDomain, Evaluations, Radix2EvaluationDomain as D,
33};
34use mina_poseidon::FqSponge;
35use rand_core::{CryptoRng, RngCore};
36
37pub trait SRS<G: CommitmentCurve>: Clone + Sized + Sync + Send {
38    /// The maximum polynomial degree that can be committed to
39    fn max_poly_size(&self) -> usize;
40
41    /// Get the group element used for blinding commitments
42    fn blinding_commitment(&self) -> G;
43
44    /// Same as [`SRS::mask`] except you can pass blinders manually.
45    ///
46    /// A [`BlindedCommitment`] object is returned instead of a [`PolyComm`]
47    /// object to keep the blinding factors and the commitment together. The
48    /// blinded commitment is saved in the commitment field of the output.
49    /// The output is wrapped into a [`Result`] to handle the case the blinders
50    /// are not the same length than the number of chunks commitments have.
51    ///
52    /// # Errors
53    ///
54    /// Returns [`CommitmentError::BlindersDontMatch`] if the number of
55    /// blinders does not match the number of commitment chunks.
56    fn mask_custom(
57        &self,
58        com: PolyComm<G>,
59        blinders: &PolyComm<G::ScalarField>,
60    ) -> Result<BlindedCommitment<G>, CommitmentError>;
61
62    /// Turns a non-hiding commitment into a hiding one.
63    ///
64    /// Transforms each given `<a, G>` into `(<a, G> + wH, w)` with
65    /// a random `w` per commitment.
66    /// A [`BlindedCommitment`] object is returned instead of a [`PolyComm`]
67    /// object to keep the blinding factors and the commitment together. The
68    /// blinded commitment is saved in the commitment field of the output.
69    fn mask(
70        &self,
71        comm: PolyComm<G>,
72        rng: &mut (impl RngCore + CryptoRng),
73    ) -> BlindedCommitment<G> {
74        let blinders = comm.map(|_| G::ScalarField::rand(rng));
75        self.mask_custom(comm, &blinders).unwrap()
76    }
77
78    /// This function commits a polynomial using the SRS' basis of size `n`.
79    /// - `plnm`: polynomial to commit to. The polynomial can be of any degree,
80    ///   including higher than `n`.
81    /// - `num_chunks`: the minimal number of commitments to be included in the
82    ///   output polynomial commitment.
83    ///
84    /// The function returns the commitments to the chunks (of size at most `n`) of
85    /// the polynomials.
86    ///
87    /// The function will also pad with zeroes if the polynomial has a degree
88    /// smaller than `n * num_chunks`.
89    ///
90    /// Note that if the polynomial has a degree higher than `n * num_chunks`,
91    /// the output will contain more than `num_chunks` commitments as it will
92    /// also contain the additional chunks.
93    ///
94    /// See the test
95    /// [`crate::pbt_srs::test_regression_commit_non_hiding_expected_number_of_chunks`]
96    /// for an example of the number of chunks returned.
97    fn commit_non_hiding(
98        &self,
99        plnm: &DensePolynomial<G::ScalarField>,
100        num_chunks: usize,
101    ) -> PolyComm<G>;
102
103    /// Commits a polynomial, potentially splitting the result.
104    ///
105    /// It is analogous to [`SRS::commit_evaluations`] but for polynomials.
106    /// A [`BlindedCommitment`] object is returned instead of a [`PolyComm`]
107    /// object to keep the blinding factors and the commitment together. The
108    /// blinded commitment is saved in the commitment field of the output.
109    fn commit(
110        &self,
111        plnm: &DensePolynomial<G::ScalarField>,
112        num_chunks: usize,
113        rng: &mut (impl RngCore + CryptoRng),
114    ) -> BlindedCommitment<G>;
115
116    /// Commit to a polynomial, with custom blinding factors.
117    ///
118    /// It is a combination of [`SRS::commit`] and [`SRS::mask_custom`].
119    /// It is analogous to [`SRS::commit_evaluations_custom`] but for
120    /// polynomials.
121    /// A [`BlindedCommitment`] object is returned instead of a [`PolyComm`]
122    /// object to keep the blinding factors and the commitment together. The
123    /// blinded commitment is saved in the commitment field of the output.
124    /// The output is wrapped into a [`Result`] to handle the case the blinders
125    /// are not the same length than the number of chunks commitments have.
126    ///
127    /// # Errors
128    ///
129    /// Returns [`CommitmentError::BlindersDontMatch`] if the number of
130    /// blinders does not match the number of commitment chunks.
131    fn commit_custom(
132        &self,
133        plnm: &DensePolynomial<G::ScalarField>,
134        num_chunks: usize,
135        blinders: &PolyComm<G::ScalarField>,
136    ) -> Result<BlindedCommitment<G>, CommitmentError>;
137
138    /// Commit to evaluations, without blinding factors.
139    ///
140    /// It is analogous to [`SRS::commit_non_hiding`] but for evaluations.
141    fn commit_evaluations_non_hiding(
142        &self,
143        domain: D<G::ScalarField>,
144        plnm: &Evaluations<G::ScalarField, D<G::ScalarField>>,
145    ) -> PolyComm<G>;
146
147    /// Commit to evaluations with blinding factors.
148    ///
149    /// Generated using the random number generator `rng`.
150    /// It is analogous to [`SRS::commit`] but for evaluations.
151    /// A [`BlindedCommitment`] object is returned instead of a [`PolyComm`]
152    /// object to keep the blinding factors and the commitment together. The
153    /// blinded commitment is saved in the commitment field of the output.
154    fn commit_evaluations(
155        &self,
156        domain: D<G::ScalarField>,
157        plnm: &Evaluations<G::ScalarField, D<G::ScalarField>>,
158        rng: &mut (impl RngCore + CryptoRng),
159    ) -> BlindedCommitment<G>;
160
161    /// Commit to evaluations with custom blinding factors.
162    ///
163    /// It is a combination of [`SRS::commit_evaluations`] and
164    /// [`SRS::mask_custom`].
165    /// It is analogous to [`SRS::commit_custom`] but for evaluations.
166    /// A [`BlindedCommitment`] object is returned instead of a [`PolyComm`]
167    /// object to keep the blinding factors and the commitment together. The
168    /// blinded commitment is saved in the commitment field of the output.
169    /// The output is wrapped into a [`Result`] to handle the case the blinders
170    /// are not the same length than the number of chunks commitments have.
171    ///
172    /// # Errors
173    ///
174    /// Returns [`CommitmentError::BlindersDontMatch`] if the number of
175    /// blinders does not match the number of commitment chunks.
176    fn commit_evaluations_custom(
177        &self,
178        domain: D<G::ScalarField>,
179        plnm: &Evaluations<G::ScalarField, D<G::ScalarField>>,
180        blinders: &PolyComm<G::ScalarField>,
181    ) -> Result<BlindedCommitment<G>, CommitmentError>;
182
183    /// Create an SRS of size `depth`.
184    ///
185    /// Warning: in the case of a trusted setup, as it is required for a
186    /// polynomial commitment scheme like KZG, a toxic waste is generated using
187    /// `rand::thread_rng()`. This is not the behavior you would expect in a
188    /// production environment.
189    /// However, we do accept this behavior for the sake of simplicity in the
190    /// interface, and this method will only be supposed to be used in tests in
191    /// this case.
192    fn create(depth: usize) -> Self;
193
194    /// Compute commitments to the lagrange basis corresponding to the given domain and
195    /// cache them in the SRS
196    fn get_lagrange_basis(&self, domain: D<G::ScalarField>) -> &Vec<PolyComm<G>>;
197
198    /// Same as `get_lagrange_basis` but only using the domain size.
199    fn get_lagrange_basis_from_domain_size(&self, domain_size: usize) -> &Vec<PolyComm<G>>;
200
201    fn size(&self) -> usize;
202}
203
204#[allow(type_alias_bounds)]
205/// An alias to represent a polynomial (in either coefficient or
206/// evaluation form), with a set of *scalar field* elements that
207/// represent the exponent of its blinder.
208// TODO: add a string to name the polynomial
209type PolynomialsToCombine<'a, G: CommitmentCurve, D: EvaluationDomain<G::ScalarField>> = &'a [(
210    DensePolynomialOrEvaluations<'a, G::ScalarField, D>,
211    PolyComm<G::ScalarField>,
212)];
213
214pub trait OpenProof<G: CommitmentCurve, const FULL_ROUNDS: usize>: Sized + Clone {
215    type SRS: SRS<G> + std::fmt::Debug;
216
217    /// Create an opening proof for a batch of polynomials. The parameters are
218    /// the following:
219    /// - `srs`: the structured reference string used to commit
220    ///   to the polynomials
221    /// - `group_map`: the group map
222    /// - `plnms`: the list of polynomials to open, with possible blinders.
223    ///   The type is simply an alias to handle the polynomials in evaluations or
224    ///   coefficients forms.
225    /// - `elm`: the evaluation points
226    /// - `polyscale`: a challenge to bacth the polynomials.
227    /// - `evalscale`: a challenge to bacth the evaluation points
228    /// - `sponge`: Sponge used to coin and absorb values and simulate
229    ///   non-interactivity using the Fiat-Shamir transformation.
230    /// - `rng`: a pseudo random number generator used for zero-knowledge
231    #[allow(clippy::too_many_arguments)]
232    fn open<EFqSponge, RNG, D: EvaluationDomain<<G as AffineRepr>::ScalarField>>(
233        srs: &Self::SRS,
234        group_map: &<G as CommitmentCurve>::Map,
235        plnms: PolynomialsToCombine<G, D>,
236        elm: &[<G as AffineRepr>::ScalarField],
237        polyscale: <G as AffineRepr>::ScalarField,
238        evalscale: <G as AffineRepr>::ScalarField,
239        sponge: EFqSponge,
240        rng: &mut RNG,
241    ) -> Self
242    where
243        EFqSponge: Clone
244            + FqSponge<<G as AffineRepr>::BaseField, G, <G as AffineRepr>::ScalarField, FULL_ROUNDS>,
245        RNG: RngCore + CryptoRng;
246
247    /// Verify the opening proof
248    fn verify<EFqSponge, RNG>(
249        srs: &Self::SRS,
250        group_map: &G::Map,
251        batch: &mut [BatchEvaluationProof<G, EFqSponge, Self, FULL_ROUNDS>],
252        rng: &mut RNG,
253    ) -> bool
254    where
255        EFqSponge: FqSponge<G::BaseField, G, G::ScalarField, FULL_ROUNDS>,
256        RNG: RngCore + CryptoRng;
257}