1use crate::{
7 commitment::{
8 b_poly, b_poly_coefficients, combine_commitments, shift_scalar, squeeze_challenge,
9 squeeze_prechallenge, BatchEvaluationProof, CommitmentCurve, EndoCurve,
10 },
11 error::CommitmentError,
12 hash_map_cache::HashMapCache,
13 utils::combine_polys,
14 BlindedCommitment, PolyComm, PolynomialsToCombine, SRS as SRSTrait,
15};
16use ark_ec::{AffineRepr, CurveGroup, VariableBaseMSM};
17use ark_ff::{BigInteger, Field, One, PrimeField, UniformRand, Zero};
18use ark_poly::{
19 univariate::DensePolynomial, EvaluationDomain, Evaluations, Radix2EvaluationDomain as D,
20};
21use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
22use blake2::{Blake2b512, Digest};
23use groupmap::GroupMap;
24use mina_poseidon::{sponge::ScalarChallenge, FqSponge};
25use o1_utils::{
26 field_helpers::{inner_prod, pows},
27 math,
28};
29use rand::{CryptoRng, RngCore};
30use rayon::prelude::*;
31use serde::{Deserialize, Serialize};
32use serde_with::serde_as;
33use std::{cmp::min, iter::Iterator, ops::AddAssign};
34
35#[serde_as]
36#[derive(Debug, Clone, Default, Serialize, Deserialize)]
37#[serde(bound = "G: CanonicalDeserialize + CanonicalSerialize")]
38pub struct SRS<G> {
39 #[serde_as(as = "Vec<o1_utils::serialization::SerdeAs>")]
42 pub g: Vec<G>,
43
44 #[serde_as(as = "o1_utils::serialization::SerdeAs")]
46 pub h: G,
47
48 #[serde(skip)]
52 pub lagrange_bases: HashMapCache<usize, Vec<PolyComm<G>>>,
53}
54
55impl<G> PartialEq for SRS<G>
56where
57 G: PartialEq,
58{
59 fn eq(&self, other: &Self) -> bool {
60 self.g == other.g && self.h == other.h
61 }
62}
63
64pub fn endos<G: CommitmentCurve>() -> (G::BaseField, G::ScalarField)
65where
66 G::BaseField: PrimeField,
67{
68 let endo_q: G::BaseField = mina_poseidon::sponge::endo_coefficient();
69 let endo_r = {
70 let potential_endo_r: G::ScalarField = mina_poseidon::sponge::endo_coefficient();
71 let t = G::generator();
72 let (x, y) = t.to_coordinates().unwrap();
73 let phi_t = G::of_coordinates(x * endo_q, y);
74 if t.mul(potential_endo_r) == phi_t.into_group() {
75 potential_endo_r
76 } else {
77 potential_endo_r * potential_endo_r
78 }
79 };
80 (endo_q, endo_r)
81}
82
83fn point_of_random_bytes<G: CommitmentCurve>(map: &G::Map, random_bytes: &[u8]) -> G
84where
85 G::BaseField: Field,
86{
87 const N: usize = 31;
89 let extension_degree = G::BaseField::extension_degree() as usize;
90
91 let mut base_fields = Vec::with_capacity(N * extension_degree);
92
93 for base_count in 0..extension_degree {
94 let mut bits = [false; 8 * N];
95 let offset = base_count * N;
96 for i in 0..N {
97 for j in 0..8 {
98 bits[8 * i + j] = (random_bytes[offset + i] >> j) & 1 == 1;
99 }
100 }
101
102 let n =
103 <<G::BaseField as Field>::BasePrimeField as PrimeField>::BigInt::from_bits_be(&bits);
104 let t = <<G::BaseField as Field>::BasePrimeField as PrimeField>::from_bigint(n)
105 .expect("packing code has a bug");
106 base_fields.push(t)
107 }
108
109 let t = G::BaseField::from_base_prime_field_elems(base_fields).unwrap();
110
111 let (x, y) = map.to_group(t);
112 G::of_coordinates(x, y).mul_by_cofactor()
113}
114
115impl<G: CommitmentCurve> SRS<G> {
117 pub fn verify<EFqSponge, RNG, const FULL_ROUNDS: usize>(
120 &self,
121 group_map: &G::Map,
122 batch: &mut [BatchEvaluationProof<
123 G,
124 EFqSponge,
125 OpeningProof<G, FULL_ROUNDS>,
126 FULL_ROUNDS,
127 >],
128 rng: &mut RNG,
129 ) -> bool
130 where
131 EFqSponge: FqSponge<G::BaseField, G, G::ScalarField, FULL_ROUNDS>,
132 RNG: RngCore + CryptoRng,
133 G::BaseField: PrimeField,
134 {
135 let nonzero_length = self.g.len();
157
158 let max_rounds = math::ceil_log2(nonzero_length);
159
160 let padded_length = 1 << max_rounds;
161
162 let (_, endo_r) = endos::<G>();
163
164 let padding = padded_length - nonzero_length;
166 let mut points = vec![self.h];
167 points.extend(self.g.clone());
168 points.extend(vec![G::zero(); padding]);
169
170 let mut scalars = vec![G::ScalarField::zero(); padded_length + 1];
171 assert_eq!(scalars.len(), points.len());
172
173 let rand_base = G::ScalarField::rand(rng);
175 let sg_rand_base = G::ScalarField::rand(rng);
176
177 let mut rand_base_i = G::ScalarField::one();
178 let mut sg_rand_base_i = G::ScalarField::one();
179
180 for BatchEvaluationProof {
181 sponge,
182 evaluation_points,
183 polyscale,
184 evalscale,
185 evaluations,
186 opening,
187 combined_inner_product,
188 } in batch.iter_mut()
189 {
190 sponge.absorb_fr(&[shift_scalar::<G>(*combined_inner_product)]);
191
192 let u_base: G = {
193 let t = sponge.challenge_fq();
194 let (x, y) = group_map.to_group(t);
195 G::of_coordinates(x, y)
196 };
197
198 let Challenges { chal, chal_inv } = opening.challenges::<EFqSponge>(&endo_r, sponge);
199
200 sponge.absorb_g(&[opening.delta]);
201 let c = ScalarChallenge(sponge.challenge()).to_field(&endo_r);
202
203 let b0 = {
207 let mut scale = G::ScalarField::one();
208 let mut res = G::ScalarField::zero();
209 for &e in evaluation_points.iter() {
210 let term = b_poly(&chal, e);
211 res += &(scale * term);
212 scale *= *evalscale;
213 }
214 res
215 };
216
217 let s = b_poly_coefficients(&chal);
218
219 let neg_rand_base_i = -rand_base_i;
220
221 points.push(opening.sg);
226 scalars.push(neg_rand_base_i * opening.z1 - sg_rand_base_i);
227
228 {
235 let terms: Vec<_> = s.par_iter().map(|s| sg_rand_base_i * s).collect();
236
237 for (i, term) in terms.iter().enumerate() {
238 scalars[i + 1] += term;
239 }
240 }
241
242 scalars[0] -= &(rand_base_i * opening.z2);
245
246 scalars.push(neg_rand_base_i * (opening.z1 * b0));
249 points.push(u_base);
250
251 let rand_base_i_c_i = c * rand_base_i;
257 for ((l, r), (u_inv, u)) in opening.lr.iter().zip(chal_inv.iter().zip(chal.iter())) {
258 points.push(*l);
259 scalars.push(rand_base_i_c_i * u_inv);
260
261 points.push(*r);
262 scalars.push(rand_base_i_c_i * u);
263 }
264
265 combine_commitments(
270 evaluations,
271 &mut scalars,
272 &mut points,
273 *polyscale,
274 rand_base_i_c_i,
275 );
276
277 scalars.push(rand_base_i_c_i * *combined_inner_product);
278 points.push(u_base);
279
280 scalars.push(rand_base_i);
281 points.push(opening.delta);
282
283 rand_base_i *= &rand_base;
284 sg_rand_base_i *= &sg_rand_base;
285 }
286
287 let chunk_size = points.len() / 2;
290 let msm_res = points
291 .into_par_iter()
292 .chunks(chunk_size)
293 .zip(scalars.into_par_iter().chunks(chunk_size))
294 .map(|(bases, coeffs)| {
295 let coeffs_bigint = coeffs
296 .into_iter()
297 .map(|c| c.into_bigint())
298 .collect::<Vec<_>>();
299 G::Group::msm_bigint(&bases, &coeffs_bigint)
300 })
301 .reduce(G::Group::zero, |mut l, r| {
302 l += r;
303 l
304 });
305
306 msm_res == G::Group::zero()
307 }
308
309 pub unsafe fn create_trusted_setup(x: G::ScalarField, depth: usize) -> Self {
317 let m = G::Map::setup();
318
319 let mut x_pow = G::ScalarField::one();
320 let g: Vec<_> = (0..depth)
321 .map(|_| {
322 let res = G::generator().mul(x_pow);
323 x_pow *= x;
324 res.into_affine()
325 })
326 .collect();
327
328 let h = {
330 let mut h = Blake2b512::new();
331 h.update("srs_misc".as_bytes());
332 h.update(0_u32.to_be_bytes());
335 point_of_random_bytes(&m, &h.finalize())
336 };
337
338 Self {
339 g,
340 h,
341 lagrange_bases: HashMapCache::new(),
342 }
343 }
344}
345
346impl<G: CommitmentCurve> SRS<G>
347where
348 <G as CommitmentCurve>::Map: Sync,
349 G::BaseField: PrimeField,
350{
351 pub fn create_parallel(depth: usize) -> Self {
354 let m = G::Map::setup();
355
356 let g: Vec<_> = (0..depth)
357 .into_par_iter()
358 .map(|i| {
359 let mut h = Blake2b512::new();
360 h.update((i as u32).to_be_bytes());
361 point_of_random_bytes(&m, &h.finalize())
362 })
363 .collect();
364
365 let h = {
367 let mut h = Blake2b512::new();
368 h.update("srs_misc".as_bytes());
369 h.update(0_u32.to_be_bytes());
372 point_of_random_bytes(&m, &h.finalize())
373 };
374
375 Self {
376 g,
377 h,
378 lagrange_bases: HashMapCache::new(),
379 }
380 }
381}
382
383impl<G> SRSTrait<G> for SRS<G>
384where
385 G: CommitmentCurve,
386{
387 fn max_poly_size(&self) -> usize {
389 self.g.len()
390 }
391
392 fn blinding_commitment(&self) -> G {
393 self.h
394 }
395
396 fn mask(
400 &self,
401 comm: PolyComm<G>,
402 rng: &mut (impl RngCore + CryptoRng),
403 ) -> BlindedCommitment<G> {
404 let blinders = comm.map(|_| G::ScalarField::rand(rng));
405 self.mask_custom(comm, &blinders).unwrap()
406 }
407
408 fn mask_custom(
409 &self,
410 com: PolyComm<G>,
411 blinders: &PolyComm<G::ScalarField>,
412 ) -> Result<BlindedCommitment<G>, CommitmentError> {
413 let commitment = com
414 .zip(blinders)
415 .ok_or_else(|| CommitmentError::BlindersDontMatch(blinders.len(), com.len()))?
416 .map(|(g, b)| {
417 let mut g_masked = self.h.mul(b);
418 g_masked.add_assign(&g);
419 g_masked.into_affine()
420 });
421 Ok(BlindedCommitment {
422 commitment,
423 blinders: blinders.clone(),
424 })
425 }
426
427 fn commit_non_hiding(
428 &self,
429 plnm: &DensePolynomial<G::ScalarField>,
430 num_chunks: usize,
431 ) -> PolyComm<G> {
432 let is_zero = plnm.is_zero();
433
434 let mut chunks: Vec<_> = if is_zero {
436 vec![G::zero()]
437 } else if plnm.len() < self.g.len() {
438 vec![G::Group::msm(&self.g[..plnm.len()], &plnm.coeffs)
439 .unwrap()
440 .into_affine()]
441 } else if plnm.len() == self.g.len() {
442 let n = self.g.len();
446 let (r1, r2) = rayon::join(
447 || G::Group::msm(&self.g[..n / 2], &plnm.coeffs[..n / 2]).unwrap(),
448 || G::Group::msm(&self.g[n / 2..n], &plnm.coeffs[n / 2..n]).unwrap(),
449 );
450
451 vec![(r1 + r2).into_affine()]
452 } else {
453 plnm.into_par_iter()
455 .chunks(self.g.len())
456 .map(|chunk| {
457 let chunk_coeffs = chunk
458 .into_iter()
459 .map(|c| c.into_bigint())
460 .collect::<Vec<_>>();
461 let chunk_res = G::Group::msm_bigint(&self.g, &chunk_coeffs);
462 chunk_res.into_affine()
463 })
464 .collect()
465 };
466
467 for _ in chunks.len()..num_chunks {
468 chunks.push(G::zero());
469 }
470
471 PolyComm::<G>::new(chunks)
472 }
473
474 fn commit(
475 &self,
476 plnm: &DensePolynomial<G::ScalarField>,
477 num_chunks: usize,
478 rng: &mut (impl RngCore + CryptoRng),
479 ) -> BlindedCommitment<G> {
480 self.mask(self.commit_non_hiding(plnm, num_chunks), rng)
481 }
482
483 fn commit_custom(
484 &self,
485 plnm: &DensePolynomial<G::ScalarField>,
486 num_chunks: usize,
487 blinders: &PolyComm<G::ScalarField>,
488 ) -> Result<BlindedCommitment<G>, CommitmentError> {
489 self.mask_custom(self.commit_non_hiding(plnm, num_chunks), blinders)
490 }
491
492 fn commit_evaluations_non_hiding(
493 &self,
494 domain: D<G::ScalarField>,
495 plnm: &Evaluations<G::ScalarField, D<G::ScalarField>>,
496 ) -> PolyComm<G> {
497 let basis = self.get_lagrange_basis(domain);
498 let commit_evaluations = |evals: &Vec<G::ScalarField>, basis: &Vec<PolyComm<G>>| {
499 PolyComm::<G>::multi_scalar_mul(&basis.iter().collect::<Vec<_>>()[..], &evals[..])
500 };
501 match domain.size.cmp(&plnm.domain().size) {
502 std::cmp::Ordering::Less => {
503 let s = (plnm.domain().size / domain.size) as usize;
504 let v: Vec<_> = (0..(domain.size())).map(|i| plnm.evals[s * i]).collect();
505 commit_evaluations(&v, basis)
506 }
507 std::cmp::Ordering::Equal => commit_evaluations(&plnm.evals, basis),
508 std::cmp::Ordering::Greater => {
509 panic!("desired commitment domain size ({}) greater than evaluations' domain size ({}):", domain.size, plnm.domain().size)
510 }
511 }
512 }
513
514 fn commit_evaluations(
515 &self,
516 domain: D<G::ScalarField>,
517 plnm: &Evaluations<G::ScalarField, D<G::ScalarField>>,
518 rng: &mut (impl RngCore + CryptoRng),
519 ) -> BlindedCommitment<G> {
520 self.mask(self.commit_evaluations_non_hiding(domain, plnm), rng)
521 }
522
523 fn commit_evaluations_custom(
524 &self,
525 domain: D<G::ScalarField>,
526 plnm: &Evaluations<G::ScalarField, D<G::ScalarField>>,
527 blinders: &PolyComm<G::ScalarField>,
528 ) -> Result<BlindedCommitment<G>, CommitmentError> {
529 self.mask_custom(self.commit_evaluations_non_hiding(domain, plnm), blinders)
530 }
531
532 fn create(depth: usize) -> Self {
533 let m = G::Map::setup();
534
535 let g: Vec<_> = (0..depth)
536 .map(|i| {
537 let mut h = Blake2b512::new();
538 h.update((i as u32).to_be_bytes());
539 point_of_random_bytes(&m, &h.finalize())
540 })
541 .collect();
542
543 let h = {
545 let mut h = Blake2b512::new();
546 h.update("srs_misc".as_bytes());
547 h.update(0_u32.to_be_bytes());
550 point_of_random_bytes(&m, &h.finalize())
551 };
552
553 Self {
554 g,
555 h,
556 lagrange_bases: HashMapCache::new(),
557 }
558 }
559
560 fn get_lagrange_basis_from_domain_size(&self, domain_size: usize) -> &Vec<PolyComm<G>> {
561 self.lagrange_bases.get_or_generate(domain_size, || {
562 self.lagrange_basis(D::new(domain_size).unwrap())
563 })
564 }
565
566 fn get_lagrange_basis(&self, domain: D<G::ScalarField>) -> &Vec<PolyComm<G>> {
567 self.lagrange_bases
568 .get_or_generate(domain.size(), || self.lagrange_basis(domain))
569 }
570
571 fn size(&self) -> usize {
572 self.g.len()
573 }
574}
575
576impl<G: CommitmentCurve> SRS<G> {
577 #[allow(clippy::type_complexity)]
578 #[allow(clippy::many_single_char_names)]
579 pub fn open<EFqSponge, RNG, D: EvaluationDomain<G::ScalarField>, const FULL_ROUNDS: usize>(
583 &self,
584 group_map: &G::Map,
585 plnms: PolynomialsToCombine<G, D>,
586 elm: &[G::ScalarField],
587 polyscale: G::ScalarField,
588 evalscale: G::ScalarField,
589 mut sponge: EFqSponge,
590 rng: &mut RNG,
591 ) -> OpeningProof<G, FULL_ROUNDS>
592 where
593 EFqSponge: Clone + FqSponge<G::BaseField, G, G::ScalarField, FULL_ROUNDS>,
594 RNG: RngCore + CryptoRng,
595 G::BaseField: PrimeField,
596 G: EndoCurve,
597 {
598 let (endo_q, endo_r) = endos::<G>();
599
600 let rounds = math::ceil_log2(self.g.len());
601 let padded_length = 1 << rounds;
602
603 let padding = padded_length - self.g.len();
608 let mut g = self.g.clone();
609 g.extend(vec![G::zero(); padding]);
610
611 let (p, blinding_factor) = combine_polys::<G, D>(plnms, polyscale, self.g.len());
618
619 let b_init = {
636 let mut scale = G::ScalarField::one();
638 let mut res: Vec<G::ScalarField> =
639 (0..padded_length).map(|_| G::ScalarField::zero()).collect();
640 for e in elm {
641 for (i, t) in pows(padded_length, *e).iter().enumerate() {
642 res[i] += &(scale * t);
643 }
644 scale *= &evalscale;
645 }
646 res
647 };
648
649 let combined_inner_product = p
651 .coeffs
652 .iter()
653 .zip(b_init.iter())
654 .map(|(a, b)| *a * b)
655 .fold(G::ScalarField::zero(), |acc, x| acc + x);
656
657 sponge.absorb_fr(&[shift_scalar::<G>(combined_inner_product)]);
665
666 let u_base: G = {
669 let t = sponge.challenge_fq();
670 let (x, y) = group_map.to_group(t);
671 G::of_coordinates(x, y)
672 };
673
674 let mut a = p.coeffs;
675 assert!(padded_length >= a.len());
676 a.extend(vec![G::ScalarField::zero(); padded_length - a.len()]);
677
678 let mut b = b_init;
679
680 let mut lr = vec![];
681
682 let mut blinders = vec![];
683
684 let mut chals = vec![];
685 let mut chal_invs = vec![];
686
687 for _ in 0..rounds {
689 let n = g.len() / 2;
690 let (g_lo, g_hi) = (&g[0..n], &g[n..]);
692 let (a_lo, a_hi) = (&a[0..n], &a[n..]);
694 let (b_lo, b_hi) = (&b[0..n], &b[n..]);
696
697 let rand_l = <G::ScalarField as UniformRand>::rand(rng);
699 let rand_r = <G::ScalarField as UniformRand>::rand(rng);
700
701 let l = G::Group::msm_bigint(
703 &[g_lo, &[self.h, u_base]].concat(),
704 &[a_hi, &[rand_l, inner_prod(a_hi, b_lo)]]
705 .concat()
706 .iter()
707 .map(|x| x.into_bigint())
708 .collect::<Vec<_>>(),
709 )
710 .into_affine();
711
712 let r = G::Group::msm_bigint(
713 &[g_hi, &[self.h, u_base]].concat(),
714 &[a_lo, &[rand_r, inner_prod(a_lo, b_hi)]]
715 .concat()
716 .iter()
717 .map(|x| x.into_bigint())
718 .collect::<Vec<_>>(),
719 )
720 .into_affine();
721
722 lr.push((l, r));
723 blinders.push((rand_l, rand_r));
724
725 sponge.absorb_g(&[l]);
726 sponge.absorb_g(&[r]);
727
728 let u_pre = squeeze_prechallenge(&mut sponge);
732 let u = u_pre.to_field(&endo_r);
733 let u_inv = u.inverse().unwrap();
734
735 chals.push(u);
736 chal_invs.push(u_inv);
737
738 a = a_hi
740 .par_iter()
741 .zip(a_lo)
742 .map(|(&hi, &lo)| {
743 let mut res = hi;
745 res *= u_inv;
746 res += &lo;
747 res
748 })
749 .collect();
750
751 b = b_lo
753 .par_iter()
754 .zip(b_hi)
755 .map(|(&lo, &hi)| {
756 let mut res = hi;
758 res *= u;
759 res += &lo;
760 res
761 })
762 .collect();
763
764 g = G::combine_one_endo(endo_r, endo_q, g_lo, g_hi, u_pre);
766 }
767
768 assert!(
769 g.len() == 1 && a.len() == 1 && b.len() == 1,
770 "IPA commitment folding must produce single elements after log rounds"
771 );
772 let a0 = a[0];
773 let b0 = b[0];
774 let g0 = g[0];
775
776 let r_prime = blinders
786 .iter()
787 .zip(chals.iter().zip(chal_invs.iter()))
788 .map(|((rand_l, rand_r), (u, u_inv))| ((*rand_l) * u_inv) + (*rand_r * u))
789 .fold(blinding_factor, |acc, x| acc + x);
790
791 let d = <G::ScalarField as UniformRand>::rand(rng);
792 let r_delta = <G::ScalarField as UniformRand>::rand(rng);
793
794 let delta = ((g0.into_group() + (u_base.mul(b0))).into_affine().mul(d)
799 + self.h.mul(r_delta))
800 .into_affine();
801
802 sponge.absorb_g(&[delta]);
803 let c = ScalarChallenge(sponge.challenge()).to_field(&endo_r);
804
805 let z1 = a0 * c + d;
807 let z2 = r_prime * c + r_delta;
808
809 OpeningProof {
810 delta,
811 lr,
812 z1,
813 z2,
814 sg: g0,
815 }
816 }
817
818 fn lagrange_basis(&self, domain: D<G::ScalarField>) -> Vec<PolyComm<G>> {
819 let n = domain.size();
820
821 let srs_size = self.g.len();
899 let num_elems = n.div_ceil(srs_size);
900 let mut chunks = Vec::with_capacity(num_elems);
901
902 for i in 0..num_elems {
904 let mut lg: Vec<<G as AffineRepr>::Group> = vec![<G as AffineRepr>::Group::zero(); n];
906 let start_offset = i * srs_size;
909 let num_terms = min((i + 1) * srs_size, n) - start_offset;
910 for j in 0..num_terms {
911 lg[start_offset + j] = self.g[j].into_group()
912 }
913 domain.ifft_in_place(&mut lg);
915 chunks.push(<G as AffineRepr>::Group::normalize_batch(lg.as_mut_slice()));
918 }
919
920 (0..n)
921 .map(|i| PolyComm {
922 chunks: chunks.iter().map(|v| v[i]).collect(),
923 })
924 .collect()
925 }
926}
927
928#[serde_as]
929#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq)]
930#[serde(bound = "G: ark_serialize::CanonicalDeserialize + ark_serialize::CanonicalSerialize")]
931pub struct OpeningProof<G: AffineRepr, const FULL_ROUNDS: usize> {
932 #[serde_as(as = "Vec<(o1_utils::serialization::SerdeAs, o1_utils::serialization::SerdeAs)>")]
934 pub lr: Vec<(G, G)>,
935 #[serde_as(as = "o1_utils::serialization::SerdeAs")]
936 pub delta: G,
937 #[serde_as(as = "o1_utils::serialization::SerdeAs")]
938 pub z1: G::ScalarField,
939 #[serde_as(as = "o1_utils::serialization::SerdeAs")]
940 pub z2: G::ScalarField,
941 #[serde_as(as = "o1_utils::serialization::SerdeAs")]
943 pub sg: G,
944}
945
946impl<
947 BaseField: PrimeField,
948 G: AffineRepr<BaseField = BaseField> + CommitmentCurve + EndoCurve,
949 const FULL_ROUNDS: usize,
950 > crate::OpenProof<G, FULL_ROUNDS> for OpeningProof<G, FULL_ROUNDS>
951{
952 type SRS = SRS<G>;
953
954 fn open<EFqSponge, RNG, D: EvaluationDomain<<G as AffineRepr>::ScalarField>>(
955 srs: &Self::SRS,
956 group_map: &<G as CommitmentCurve>::Map,
957 plnms: PolynomialsToCombine<G, D>,
958 elm: &[<G as AffineRepr>::ScalarField],
959 polyscale: <G as AffineRepr>::ScalarField,
960 evalscale: <G as AffineRepr>::ScalarField,
961 sponge: EFqSponge,
962 rng: &mut RNG,
963 ) -> Self
964 where
965 EFqSponge: Clone
966 + FqSponge<<G as AffineRepr>::BaseField, G, <G as AffineRepr>::ScalarField, FULL_ROUNDS>,
967 RNG: RngCore + CryptoRng,
968 {
969 srs.open(group_map, plnms, elm, polyscale, evalscale, sponge, rng)
970 }
971
972 fn verify<EFqSponge, RNG>(
973 srs: &Self::SRS,
974 group_map: &G::Map,
975 batch: &mut [BatchEvaluationProof<G, EFqSponge, Self, FULL_ROUNDS>],
976 rng: &mut RNG,
977 ) -> bool
978 where
979 EFqSponge:
980 FqSponge<<G as AffineRepr>::BaseField, G, <G as AffineRepr>::ScalarField, FULL_ROUNDS>,
981 RNG: RngCore + CryptoRng,
982 {
983 srs.verify(group_map, batch, rng)
984 }
985}
986
987pub struct Challenges<F> {
989 pub chal: Vec<F>,
990 pub chal_inv: Vec<F>,
991}
992
993impl<G: AffineRepr, const FULL_ROUNDS: usize> OpeningProof<G, FULL_ROUNDS> {
994 pub fn prechallenges<EFqSponge: FqSponge<G::BaseField, G, G::ScalarField, FULL_ROUNDS>>(
997 &self,
998 sponge: &mut EFqSponge,
999 ) -> Vec<ScalarChallenge<G::ScalarField>> {
1000 let _t = sponge.challenge_fq();
1001 self.lr
1002 .iter()
1003 .map(|(l, r)| {
1004 sponge.absorb_g(&[*l]);
1005 sponge.absorb_g(&[*r]);
1006 squeeze_prechallenge(sponge)
1007 })
1008 .collect()
1009 }
1010
1011 pub fn challenges<EFqSponge: FqSponge<G::BaseField, G, G::ScalarField, FULL_ROUNDS>>(
1014 &self,
1015 endo_r: &G::ScalarField,
1016 sponge: &mut EFqSponge,
1017 ) -> Challenges<G::ScalarField> {
1018 let chal: Vec<_> = self
1019 .lr
1020 .iter()
1021 .map(|(l, r)| {
1022 sponge.absorb_g(&[*l]);
1023 sponge.absorb_g(&[*r]);
1024 squeeze_challenge(endo_r, sponge)
1025 })
1026 .collect();
1027
1028 let chal_inv = {
1029 let mut cs = chal.clone();
1030 ark_ff::batch_inversion(&mut cs);
1031 cs
1032 };
1033
1034 Challenges { chal, chal_inv }
1035 }
1036}
1037
1038#[cfg(feature = "ocaml_types")]
1039#[allow(non_local_definitions)]
1040pub mod caml {
1041 use super::OpeningProof;
1042 use ark_ec::AffineRepr;
1043 use ocaml;
1044
1045 #[derive(ocaml::IntoValue, ocaml::FromValue, ocaml_gen::Struct)]
1046 pub struct CamlOpeningProof<G, F> {
1047 pub lr: Vec<(G, G)>,
1049 pub delta: G,
1050 pub z1: F,
1051 pub z2: F,
1052 pub sg: G,
1053 }
1054
1055 impl<G, CamlF, CamlG, const FULL_ROUNDS: usize> From<OpeningProof<G, FULL_ROUNDS>>
1056 for CamlOpeningProof<CamlG, CamlF>
1057 where
1058 G: AffineRepr,
1059 CamlG: From<G>,
1060 CamlF: From<G::ScalarField>,
1061 {
1062 fn from(opening_proof: OpeningProof<G, FULL_ROUNDS>) -> Self {
1063 Self {
1064 lr: opening_proof
1065 .lr
1066 .into_iter()
1067 .map(|(g1, g2)| (CamlG::from(g1), CamlG::from(g2)))
1068 .collect(),
1069 delta: CamlG::from(opening_proof.delta),
1070 z1: opening_proof.z1.into(),
1071 z2: opening_proof.z2.into(),
1072 sg: CamlG::from(opening_proof.sg),
1073 }
1074 }
1075 }
1076
1077 impl<G, CamlF, CamlG, const FULL_ROUNDS: usize> From<CamlOpeningProof<CamlG, CamlF>>
1078 for OpeningProof<G, FULL_ROUNDS>
1079 where
1080 G: AffineRepr,
1081 CamlG: Into<G>,
1082 CamlF: Into<G::ScalarField>,
1083 {
1084 fn from(caml: CamlOpeningProof<CamlG, CamlF>) -> Self {
1085 Self {
1086 lr: caml
1087 .lr
1088 .into_iter()
1089 .map(|(g1, g2)| (g1.into(), g2.into()))
1090 .collect(),
1091 delta: caml.delta.into(),
1092 z1: caml.z1.into(),
1093 z2: caml.z2.into(),
1094 sg: caml.sg.into(),
1095 }
1096 }
1097 }
1098}