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}