1use crate::{
15 commitment::{
16 combine_commitments, BatchEvaluationProof, BlindedCommitment, CommitmentCurve, Evaluation,
17 PolyComm,
18 },
19 error::CommitmentError,
20 ipa::SRS,
21 utils::combine_polys,
22 PolynomialsToCombine, SRS as SRSTrait,
23};
24use alloc::{vec, vec::Vec};
25
26use ark_ec::{pairing::Pairing, AffineRepr, VariableBaseMSM};
27use ark_ff::{One, PrimeField, Zero};
28use ark_poly::{
29 univariate::{DenseOrSparsePolynomial, DensePolynomial},
30 DenseUVPolynomial, EvaluationDomain, Evaluations, Polynomial, Radix2EvaluationDomain as D,
31};
32use core::ops::Neg;
33use mina_poseidon::FqSponge;
34#[cfg(feature = "std")]
35use rand::thread_rng;
36use rand_core::{CryptoRng, RngCore};
37use serde::{Deserialize, Serialize};
38use serde_with::serde_as;
39#[cfg(feature = "std")]
40use std::ops::Deref;
41
42pub fn combine_evaluations<G: CommitmentCurve>(
67 evaluations: &[Evaluation<G>],
68 polyscale: G::ScalarField,
69) -> Vec<G::ScalarField> {
70 let mut polyscale_i = G::ScalarField::one();
71 let mut acc = {
72 let num_evals = evaluations.first().map_or(0, |e| e.evaluations.len());
73 vec![G::ScalarField::zero(); num_evals]
74 };
75
76 for Evaluation { evaluations, .. } in evaluations.iter().filter(|x| !x.commitment.is_empty()) {
77 for chunk_idx in 0..evaluations[0].len() {
83 for eval_pt_idx in 0..evaluations.len() {
85 acc[eval_pt_idx] += evaluations[eval_pt_idx][chunk_idx] * polyscale_i;
86 }
87 polyscale_i *= polyscale;
88 }
89 }
90
91 acc
92}
93
94#[serde_as]
95#[derive(Debug, Serialize, Deserialize)]
96#[serde(
97 bound = "Pair::G1Affine: ark_serialize::CanonicalDeserialize + ark_serialize::CanonicalSerialize"
98)]
99pub struct KZGProof<Pair: Pairing> {
100 #[serde_as(as = "o1_utils::serialization::SerdeAs")]
101 pub quotient: Pair::G1Affine,
102 #[serde_as(as = "o1_utils::serialization::SerdeAs")]
103 pub blinding: <Pair::G1Affine as AffineRepr>::ScalarField,
105}
106
107impl<Pair: Pairing> Default for KZGProof<Pair> {
108 fn default() -> Self {
109 Self {
110 quotient: Pair::G1Affine::generator(),
111 blinding: <Pair::G1Affine as AffineRepr>::ScalarField::zero(),
112 }
113 }
114}
115
116impl<Pair: Pairing> Clone for KZGProof<Pair> {
117 fn clone(&self) -> Self {
118 Self {
119 quotient: self.quotient,
120 blinding: self.blinding,
121 }
122 }
123}
124
125#[derive(Debug, PartialEq, Serialize, Deserialize)]
133pub struct PairingSRS<Pair: Pairing> {
134 pub full_srs: SRS<Pair::G1Affine>,
137 pub verifier_srs: SRS<Pair::G2Affine>,
140}
141
142#[cfg(feature = "std")]
143impl<
144 F: PrimeField,
145 G: CommitmentCurve<ScalarField = F>,
146 G2: CommitmentCurve<ScalarField = F>,
147 Pair: Pairing<G1Affine = G, G2Affine = G2>,
148 > PairingSRS<Pair>
149{
150 pub fn create_trusted_setup_with_toxic_waste(toxic_waste: F, depth: usize) -> Self {
157 let full_srs = SRS::create_trusted_setup_with_toxic_waste(toxic_waste, depth);
158 let verifier_srs = SRS::create_trusted_setup_with_toxic_waste(toxic_waste, 3);
159 Self {
160 full_srs,
161 verifier_srs,
162 }
163 }
164}
165
166impl<Pair: Pairing> Default for PairingSRS<Pair> {
167 fn default() -> Self {
168 Self {
169 full_srs: SRS::default(),
170 verifier_srs: SRS::default(),
171 }
172 }
173}
174
175impl<Pair: Pairing> Clone for PairingSRS<Pair> {
176 fn clone(&self) -> Self {
177 Self {
178 full_srs: self.full_srs.clone(),
179 verifier_srs: self.verifier_srs.clone(),
180 }
181 }
182}
183
184#[cfg(feature = "std")]
185impl<
186 F: PrimeField,
187 G: CommitmentCurve<ScalarField = F>,
188 G2: CommitmentCurve<ScalarField = F>,
189 Pair: Pairing<G1Affine = G, G2Affine = G2>,
190 const FULL_ROUNDS: usize,
191 > crate::OpenProof<G, FULL_ROUNDS> for KZGProof<Pair>
192{
193 type SRS = PairingSRS<Pair>;
194
195 fn open<EFqSponge, RNG, D: EvaluationDomain<F>>(
204 srs: &Self::SRS,
205 _group_map: &<G as CommitmentCurve>::Map,
206 plnms: PolynomialsToCombine<G, D>,
207 elm: &[<G as AffineRepr>::ScalarField],
208 polyscale: <G as AffineRepr>::ScalarField,
209 _evalscale: <G as AffineRepr>::ScalarField,
210 _sponge: EFqSponge,
211 _rng: &mut RNG,
212 ) -> Self
213 where
214 EFqSponge: Clone + FqSponge<<G as AffineRepr>::BaseField, G, F, FULL_ROUNDS>,
215 RNG: RngCore + CryptoRng,
216 {
217 Self::create(srs, plnms, elm, polyscale).unwrap()
218 }
219
220 fn verify<EFqSponge, RNG>(
221 srs: &Self::SRS,
222 _group_map: &G::Map,
223 batch: &mut [BatchEvaluationProof<G, EFqSponge, Self, FULL_ROUNDS>],
224 _rng: &mut RNG,
225 ) -> bool
226 where
227 EFqSponge: FqSponge<G::BaseField, G, F, FULL_ROUNDS>,
228 RNG: RngCore + CryptoRng,
229 {
230 for BatchEvaluationProof {
231 sponge: _,
232 evaluations,
233 evaluation_points,
234 polyscale,
235 evalscale: _,
236 opening,
237 combined_inner_product: _,
238 } in batch.iter()
239 {
240 if !opening.verify(srs, evaluations, *polyscale, evaluation_points) {
241 return false;
242 }
243 }
244 true
245 }
246}
247
248#[cfg(feature = "std")]
249impl<
250 F: PrimeField,
251 G: CommitmentCurve<ScalarField = F>,
252 G2: CommitmentCurve<ScalarField = F>,
253 Pair: Pairing<G1Affine = G, G2Affine = G2>,
254 > SRSTrait<G> for PairingSRS<Pair>
255{
256 fn max_poly_size(&self) -> usize {
257 self.full_srs.max_poly_size()
258 }
259
260 fn get_lagrange_basis(
261 &self,
262 domain: D<G::ScalarField>,
263 ) -> impl Deref<Target = Vec<PolyComm<G>>> + '_ {
264 self.full_srs.get_lagrange_basis(domain)
265 }
266
267 fn get_lagrange_basis_from_domain_size(
268 &self,
269 domain_size: usize,
270 ) -> impl Deref<Target = Vec<PolyComm<G>>> + '_ {
271 self.full_srs
272 .get_lagrange_basis_from_domain_size(domain_size)
273 }
274
275 fn blinding_commitment(&self) -> G {
276 self.full_srs.blinding_commitment()
277 }
278
279 fn mask_custom(
280 &self,
281 com: PolyComm<G>,
282 blinders: &PolyComm<G::ScalarField>,
283 ) -> Result<BlindedCommitment<G>, CommitmentError> {
284 self.full_srs.mask_custom(com, blinders)
285 }
286
287 fn mask(
288 &self,
289 comm: PolyComm<G>,
290 rng: &mut (impl RngCore + CryptoRng),
291 ) -> BlindedCommitment<G> {
292 self.full_srs.mask(comm, rng)
293 }
294
295 fn commit(
296 &self,
297 plnm: &DensePolynomial<F>,
298 num_chunks: usize,
299 rng: &mut (impl RngCore + CryptoRng),
300 ) -> BlindedCommitment<G> {
301 self.full_srs.commit(plnm, num_chunks, rng)
302 }
303
304 fn commit_non_hiding(
305 &self,
306 plnm: &DensePolynomial<G::ScalarField>,
307 num_chunks: usize,
308 ) -> PolyComm<G> {
309 self.full_srs.commit_non_hiding(plnm, num_chunks)
310 }
311
312 fn commit_custom(
313 &self,
314 plnm: &DensePolynomial<<G>::ScalarField>,
315 num_chunks: usize,
316 blinders: &PolyComm<<G>::ScalarField>,
317 ) -> Result<BlindedCommitment<G>, CommitmentError> {
318 self.full_srs.commit_custom(plnm, num_chunks, blinders)
319 }
320
321 fn commit_evaluations_non_hiding(
322 &self,
323 domain: D<G::ScalarField>,
324 plnm: &Evaluations<G::ScalarField, D<G::ScalarField>>,
325 ) -> PolyComm<G> {
326 self.full_srs.commit_evaluations_non_hiding(domain, plnm)
327 }
328
329 fn commit_evaluations(
330 &self,
331 domain: D<G::ScalarField>,
332 plnm: &Evaluations<G::ScalarField, D<G::ScalarField>>,
333 rng: &mut (impl RngCore + CryptoRng),
334 ) -> BlindedCommitment<G> {
335 self.full_srs.commit_evaluations(domain, plnm, rng)
336 }
337
338 fn commit_evaluations_custom(
339 &self,
340 domain: D<<G>::ScalarField>,
341 plnm: &Evaluations<<G>::ScalarField, D<<G>::ScalarField>>,
342 blinders: &PolyComm<<G>::ScalarField>,
343 ) -> Result<BlindedCommitment<G>, CommitmentError> {
344 self.full_srs
345 .commit_evaluations_custom(domain, plnm, blinders)
346 }
347
348 fn create(depth: usize) -> Self {
349 let mut rng = thread_rng();
350 let mut toxic_waste = G::ScalarField::rand(&mut rng);
351 let result = Self::create_trusted_setup_with_toxic_waste(toxic_waste, depth);
352 toxic_waste.zeroize();
353 result
354 }
355
356 fn size(&self) -> usize {
357 self.full_srs.g.len()
358 }
359}
360
361fn eval_polynomial<F: PrimeField>(elm: &[F], evals: &[F]) -> DensePolynomial<F> {
366 assert_eq!(elm.len(), evals.len());
367 let (zeta, zeta_omega) = if elm.len() == 2 {
368 (elm[0], elm[1])
369 } else {
370 todo!()
371 };
372 let (eval_zeta, eval_zeta_omega) = if evals.len() == 2 {
373 (evals[0], evals[1])
374 } else {
375 todo!()
376 };
377
378 let b = (eval_zeta_omega - eval_zeta) / (zeta_omega - zeta);
391 let a = eval_zeta - b * zeta;
392 DensePolynomial::from_coefficients_slice(&[a, b])
393}
394
395fn divisor_polynomial<F: PrimeField>(elm: &[F]) -> DensePolynomial<F> {
397 elm.iter()
398 .map(|value| DensePolynomial::from_coefficients_slice(&[-(*value), F::one()]))
399 .reduce(|poly1, poly2| &poly1 * &poly2)
400 .unwrap()
401}
402
403#[cfg(feature = "std")]
404impl<
405 F: PrimeField,
406 G: CommitmentCurve<ScalarField = F>,
407 G2: CommitmentCurve<ScalarField = F>,
408 Pair: Pairing<G1Affine = G, G2Affine = G2>,
409 > KZGProof<Pair>
410{
411 pub fn create<D: EvaluationDomain<F>>(
422 srs: &PairingSRS<Pair>,
423 plnms: PolynomialsToCombine<G, D>,
424 elm: &[F],
425 polyscale: F,
426 ) -> Option<Self> {
427 let (p, blinding_factor) = combine_polys::<G, D>(plnms, polyscale, srs.full_srs.g.len());
428 let evals: Vec<_> = elm.iter().map(|pt| p.evaluate(pt)).collect();
429
430 let quotient_poly = {
431 let eval_polynomial = eval_polynomial(elm, &evals);
433 let divisor_polynomial = divisor_polynomial(elm);
434 let numerator_polynomial = &p - &eval_polynomial;
435 let (quotient, remainder) = DenseOrSparsePolynomial::divide_with_q_and_r(
436 &numerator_polynomial.into(),
437 &divisor_polynomial.into(),
438 )?;
439 if !remainder.is_zero() {
440 return None;
441 }
442 quotient
443 };
444
445 let quotient = srs
446 .full_srs
447 .commit_non_hiding("ient_poly, 1)
448 .get_first_chunk();
449
450 Some(Self {
451 quotient,
452 blinding: blinding_factor,
453 })
454 }
455
456 pub fn verify(
460 &self,
461 srs: &PairingSRS<Pair>,
462 evaluations: &[Evaluation<G>], polyscale: F, elm: &[F], ) -> bool {
466 let poly_commitment: G::Group = {
467 let mut scalars: Vec<F> = Vec::new();
468 let mut points = Vec::new();
469 combine_commitments(
470 evaluations,
471 &mut scalars,
472 &mut points,
473 polyscale,
474 F::one(), );
476 let scalars: Vec<_> = scalars.iter().map(|x| x.into_bigint()).collect();
477
478 G::Group::msm_bigint(&points, &scalars)
479 };
480
481 let evals = combine_evaluations(evaluations, polyscale);
484 let blinding_commitment = srs.full_srs.h.mul(self.blinding);
485 let divisor_commitment = srs
488 .verifier_srs
489 .commit_non_hiding(&divisor_polynomial(elm), 1)
490 .get_first_chunk();
491 let eval_commitment = srs
494 .full_srs
495 .commit_non_hiding(&eval_polynomial(elm, &evals), 1)
496 .get_first_chunk()
497 .into_group();
498 let numerator_commitment = { poly_commitment - eval_commitment - blinding_commitment };
499 let to_loop_left = [
502 ark_ec::pairing::prepare_g1::<Pair>(numerator_commitment),
503 ark_ec::pairing::prepare_g1::<Pair>(self.quotient.into_group().neg()),
506 ];
507 let to_loop_right = [
508 ark_ec::pairing::prepare_g2::<Pair>(Pair::G2Affine::generator()),
509 ark_ec::pairing::prepare_g2::<Pair>(divisor_commitment),
510 ];
511 let res = Pair::multi_pairing(to_loop_left, to_loop_right);
516
517 res.is_zero()
518 }
519}