ark_poly_commit/kzg10/
mod.rs

1//! Here we construct a polynomial commitment that enables users to commit to a
2//! single polynomial `p`, and then later provide an evaluation proof that
3//! convinces verifiers that a claimed value `v` is the true evaluation of `p`
4//! at a chosen point `x`. Our construction follows the template of the construction
5//! proposed by Kate, Zaverucha, and Goldberg ([KZG10](http://cacr.uwaterloo.ca/techreports/2010/cacr2010-10.pdf)).
6//! This construction achieves extractability in the algebraic group model (AGM).
7
8use crate::{BTreeMap, Error, LabeledPolynomial, PCCommitmentState};
9use ark_ec::{pairing::Pairing, scalar_mul::ScalarMul, AffineRepr, CurveGroup, VariableBaseMSM};
10use ark_ff::{One, PrimeField, UniformRand, Zero};
11use ark_poly::DenseUVPolynomial;
12use ark_std::{format, marker::PhantomData, ops::Div, ops::Mul, rand::RngCore};
13#[cfg(not(feature = "std"))]
14use ark_std::{string::ToString, vec::Vec};
15#[cfg(feature = "parallel")]
16use rayon::prelude::*;
17
18mod data_structures;
19pub use data_structures::*;
20
21/// `KZG10` is an implementation of the polynomial commitment scheme of
22/// [Kate, Zaverucha and Goldbgerg][kzg10]
23///
24/// [kzg10]: http://cacr.uwaterloo.ca/techreports/2010/cacr2010-10.pdf
25pub struct KZG10<E: Pairing, P: DenseUVPolynomial<E::ScalarField>> {
26    _engine: PhantomData<E>,
27    _poly: PhantomData<P>,
28}
29
30impl<E, P> KZG10<E, P>
31where
32    E: Pairing,
33    P: DenseUVPolynomial<E::ScalarField, Point = E::ScalarField>,
34    for<'a, 'b> &'a P: Div<&'b P, Output = P>,
35{
36    /// Constructs public parameters when given as input the maximum degree `degree`
37    /// for the polynomial commitment scheme.
38    ///
39    /// # Examples
40    ///
41    /// ```
42    /// use ark_poly_commit::kzg10::KZG10;
43    /// use ark_bls12_381::Bls12_381;
44    /// use ark_bls12_381::Fr;
45    /// use ark_poly::univariate::DensePolynomial;
46    /// use ark_ec::pairing::Pairing;
47    /// use ark_std::test_rng;
48    /// type UniPoly_381 = DensePolynomial<<Bls12_381 as Pairing>::ScalarField>;
49    ///
50    /// let rng = &mut test_rng();
51    /// let params = KZG10::<Bls12_381, UniPoly_381>::setup(10, false, rng).expect("Setup failed");
52    /// ```
53    pub fn setup<R: RngCore>(
54        max_degree: usize,
55        produce_g2_powers: bool,
56        rng: &mut R,
57    ) -> Result<UniversalParams<E>, Error> {
58        if max_degree < 1 {
59            return Err(Error::DegreeIsZero);
60        }
61        let setup_time = start_timer!(|| format!("KZG10::Setup with degree {}", max_degree));
62        let beta = E::ScalarField::rand(rng);
63        let g = E::G1::rand(rng);
64        let gamma_g = E::G1::rand(rng);
65        let h = E::G2::rand(rng);
66
67        // powers_of_beta = [1, b, ..., b^(max_degree + 1)], len = max_degree + 2
68        let mut powers_of_beta = vec![E::ScalarField::one()];
69        let mut cur = beta;
70        for _ in 0..=max_degree {
71            powers_of_beta.push(cur);
72            cur *= &beta;
73        }
74
75        let g_time = start_timer!(|| "Generating powers of G");
76        let powers_of_g = g.batch_mul(&powers_of_beta[0..max_degree + 1]);
77        end_timer!(g_time);
78
79        // Use the entire `powers_of_beta`, since we want to be able to support
80        // up to D queries.
81        let gamma_g_time = start_timer!(|| "Generating powers of gamma * G");
82        let powers_of_gamma_g = gamma_g
83            .batch_mul(&powers_of_beta)
84            .into_iter()
85            .enumerate()
86            .collect();
87        end_timer!(gamma_g_time);
88
89        let neg_powers_of_h_time = start_timer!(|| "Generating negative powers of h in G2");
90        let neg_powers_of_h = if produce_g2_powers {
91            let mut neg_powers_of_beta = vec![E::ScalarField::one()];
92            let mut cur = E::ScalarField::one() / &beta;
93            for _ in 0..max_degree {
94                neg_powers_of_beta.push(cur);
95                cur /= &beta;
96            }
97
98            h.batch_mul(&neg_powers_of_beta)
99                .into_iter()
100                .enumerate()
101                .collect()
102        } else {
103            BTreeMap::new()
104        };
105
106        end_timer!(neg_powers_of_h_time);
107
108        let h = h.into_affine();
109        let beta_h = h.mul(beta).into_affine();
110        let prepared_h = h.into();
111        let prepared_beta_h = beta_h.into();
112
113        let pp = UniversalParams {
114            powers_of_g,
115            powers_of_gamma_g,
116            h,
117            beta_h,
118            neg_powers_of_h,
119            prepared_h,
120            prepared_beta_h,
121        };
122        end_timer!(setup_time);
123        Ok(pp)
124    }
125
126    /// Outputs a commitment to `polynomial`.
127    ///
128    /// # Examples
129    ///
130    /// ```
131    /// use ark_poly_commit::kzg10::{KZG10, Powers};
132    /// use ark_bls12_381::Bls12_381;
133    /// use ark_bls12_381::Fr;
134    /// use ark_poly::DenseUVPolynomial;
135    /// use ark_poly::univariate::DensePolynomial;
136    /// use ark_ec::pairing::Pairing;
137    /// use ark_ec::AffineRepr;
138    /// use ark_std::test_rng;
139    /// use ark_std::Zero;
140    /// type UniPoly_381 = DensePolynomial<<Bls12_381 as Pairing>::ScalarField>;
141    ///
142    /// let rng = &mut test_rng();
143    /// let params = KZG10::<Bls12_381, UniPoly_381>::setup(10, false, rng).expect("Setup failed");
144    /// let powers_of_g = params.powers_of_g[..=10].to_vec();
145    /// let powers_of_gamma_g = (0..=10)
146    ///     .map(|i| params.powers_of_gamma_g[&i])
147    ///     .collect();
148    /// let powers = Powers {
149    ///     powers_of_g: ark_std::borrow::Cow::Owned(powers_of_g),
150    ///     powers_of_gamma_g: ark_std::borrow::Cow::Owned(powers_of_gamma_g),
151    /// };
152    /// let secret_poly = UniPoly_381::rand(10, rng);
153    /// let (comm, r) = KZG10::<Bls12_381, UniPoly_381>::commit(&powers, &secret_poly, None, None).expect("Commitment failed");
154    /// assert!(!comm.0.is_zero(), "Commitment should not be zero");
155    /// assert!(!r.is_hiding(), "Commitment should not be hiding");
156    /// ```
157    pub fn commit(
158        powers: &Powers<E>,
159        polynomial: &P,
160        hiding_bound: Option<usize>,
161        rng: Option<&mut dyn RngCore>,
162    ) -> Result<(Commitment<E>, Randomness<E::ScalarField, P>), Error> {
163        Self::check_degree_is_too_large(polynomial.degree(), powers.size())?;
164
165        let commit_time = start_timer!(|| format!(
166            "Committing to polynomial of degree {} with hiding_bound: {:?}",
167            polynomial.degree(),
168            hiding_bound,
169        ));
170
171        let (num_leading_zeros, plain_coeffs) =
172            skip_leading_zeros_and_convert_to_bigints(polynomial);
173
174        let msm_time = start_timer!(|| "MSM to compute commitment to plaintext poly");
175        let mut commitment = <E::G1 as VariableBaseMSM>::msm_bigint(
176            &powers.powers_of_g[num_leading_zeros..],
177            &plain_coeffs,
178        );
179        end_timer!(msm_time);
180
181        let mut randomness = Randomness::<E::ScalarField, P>::empty();
182        if let Some(hiding_degree) = hiding_bound {
183            let mut rng = rng.ok_or(Error::MissingRng)?;
184            let sample_random_poly_time = start_timer!(|| format!(
185                "Sampling a random polynomial of degree {}",
186                hiding_degree
187            ));
188
189            randomness = Randomness::rand(hiding_degree, false, None, &mut rng);
190            Self::check_hiding_bound(
191                randomness.blinding_polynomial.degree(),
192                powers.powers_of_gamma_g.len(),
193            )?;
194            end_timer!(sample_random_poly_time);
195        }
196
197        let random_ints = convert_to_bigints(&randomness.blinding_polynomial.coeffs());
198        let msm_time = start_timer!(|| "MSM to compute commitment to random poly");
199        let random_commitment = <E::G1 as VariableBaseMSM>::msm_bigint(
200            &powers.powers_of_gamma_g,
201            random_ints.as_slice(),
202        )
203        .into_affine();
204        end_timer!(msm_time);
205
206        commitment += &random_commitment;
207
208        end_timer!(commit_time);
209        Ok((Commitment(commitment.into()), randomness))
210    }
211
212    /// Compute witness polynomial.
213    ///
214    /// The witness polynomial $w(x)$ the quotient of the division (p(x) - p(z)) / (x - z)
215    /// Observe that this quotient does not change with $z$ because
216    /// $p(z)$ is the remainder term. We can therefore omit $p(z)$ when computing the quotient.
217    pub fn compute_witness_polynomial(
218        p: &P,
219        point: P::Point,
220        randomness: &Randomness<E::ScalarField, P>,
221    ) -> Result<(P, Option<P>), Error> {
222        let divisor = P::from_coefficients_vec(vec![-point, E::ScalarField::one()]);
223
224        let witness_time = start_timer!(|| "Computing witness polynomial");
225        let witness_polynomial = p / &divisor;
226        end_timer!(witness_time);
227
228        let random_witness_polynomial = if randomness.is_hiding() {
229            let random_p = &randomness.blinding_polynomial;
230
231            let witness_time = start_timer!(|| "Computing random witness polynomial");
232            let random_witness_polynomial = random_p / &divisor;
233            end_timer!(witness_time);
234            Some(random_witness_polynomial)
235        } else {
236            None
237        };
238
239        Ok((witness_polynomial, random_witness_polynomial))
240    }
241
242    /// Yields a [`Proof`] with a witness polynomial.
243    pub fn open_with_witness_polynomial<'a>(
244        powers: &Powers<E>,
245        point: P::Point,
246        randomness: &Randomness<E::ScalarField, P>,
247        witness_polynomial: &P,
248        hiding_witness_polynomial: Option<&P>,
249    ) -> Result<Proof<E>, Error> {
250        Self::check_degree_is_too_large(witness_polynomial.degree(), powers.size())?;
251        let (num_leading_zeros, witness_coeffs) =
252            skip_leading_zeros_and_convert_to_bigints(witness_polynomial);
253
254        let witness_comm_time = start_timer!(|| "Computing commitment to witness polynomial");
255        let mut w = <E::G1 as VariableBaseMSM>::msm_bigint(
256            &powers.powers_of_g[num_leading_zeros..],
257            &witness_coeffs,
258        );
259        end_timer!(witness_comm_time);
260
261        let random_v = if let Some(hiding_witness_polynomial) = hiding_witness_polynomial {
262            let blinding_p = &randomness.blinding_polynomial;
263            let blinding_eval_time = start_timer!(|| "Evaluating random polynomial");
264            let blinding_evaluation = blinding_p.evaluate(&point);
265            end_timer!(blinding_eval_time);
266
267            let random_witness_coeffs = convert_to_bigints(&hiding_witness_polynomial.coeffs());
268            let witness_comm_time =
269                start_timer!(|| "Computing commitment to random witness polynomial");
270            w += &<E::G1 as VariableBaseMSM>::msm_bigint(
271                &powers.powers_of_gamma_g,
272                &random_witness_coeffs,
273            );
274            end_timer!(witness_comm_time);
275            Some(blinding_evaluation)
276        } else {
277            None
278        };
279
280        Ok(Proof {
281            w: w.into_affine(),
282            random_v,
283        })
284    }
285
286    /// On input a polynomial `p` and a `point`, outputs a [`Proof`] for the same.
287    pub fn open<'a>(
288        powers: &Powers<E>,
289        p: &P,
290        point: P::Point,
291        rand: &Randomness<E::ScalarField, P>,
292    ) -> Result<Proof<E>, Error> {
293        Self::check_degree_is_too_large(p.degree(), powers.size())?;
294        let open_time = start_timer!(|| format!("Opening polynomial of degree {}", p.degree()));
295
296        let witness_time = start_timer!(|| "Computing witness polynomials");
297        let (witness_poly, hiding_witness_poly) = Self::compute_witness_polynomial(p, point, rand)?;
298        end_timer!(witness_time);
299
300        let proof = Self::open_with_witness_polynomial(
301            powers,
302            point,
303            rand,
304            &witness_poly,
305            hiding_witness_poly.as_ref(),
306        );
307
308        end_timer!(open_time);
309        proof
310    }
311
312    /// Verifies that `value` is the evaluation at `point` of the polynomial
313    /// committed inside `comm`.
314    pub fn check(
315        vk: &VerifierKey<E>,
316        comm: &Commitment<E>,
317        point: E::ScalarField,
318        value: E::ScalarField,
319        proof: &Proof<E>,
320    ) -> Result<bool, Error> {
321        let check_time = start_timer!(|| "Checking evaluation");
322        let mut inner = comm.0.into_group() - &vk.g.mul(value);
323        if let Some(random_v) = proof.random_v {
324            inner -= &vk.gamma_g.mul(random_v);
325        }
326        let lhs = E::pairing(inner, vk.h);
327
328        let inner = vk.beta_h.into_group() - &vk.h.mul(point);
329        let rhs = E::pairing(proof.w, inner);
330
331        end_timer!(check_time, || format!("Result: {}", lhs == rhs));
332        Ok(lhs == rhs)
333    }
334
335    /// Check that each `proof_i` in `proofs` is a valid proof of evaluation for
336    /// `commitment_i` at `point_i`.
337    pub fn batch_check<R: RngCore>(
338        vk: &VerifierKey<E>,
339        commitments: &[Commitment<E>],
340        points: &[E::ScalarField],
341        values: &[E::ScalarField],
342        proofs: &[Proof<E>],
343        rng: &mut R,
344    ) -> Result<bool, Error> {
345        let check_time =
346            start_timer!(|| format!("Checking {} evaluation proofs", commitments.len()));
347
348        let mut total_c = <E::G1>::zero();
349        let mut total_w = <E::G1>::zero();
350
351        let combination_time = start_timer!(|| "Combining commitments and proofs");
352        let mut randomizer = E::ScalarField::one();
353        // Instead of multiplying g and gamma_g in each turn, we simply accumulate
354        // their coefficients and perform a final multiplication at the end.
355        let mut g_multiplier = E::ScalarField::zero();
356        let mut gamma_g_multiplier = E::ScalarField::zero();
357        for (((c, z), v), proof) in commitments.iter().zip(points).zip(values).zip(proofs) {
358            let w = proof.w;
359            let mut temp = w.mul(*z);
360            temp += &c.0;
361            let c = temp;
362            g_multiplier += &(randomizer * v);
363            if let Some(random_v) = proof.random_v {
364                gamma_g_multiplier += &(randomizer * &random_v);
365            }
366            total_c += &c.mul(randomizer);
367            total_w += &w.mul(randomizer);
368            // We don't need to sample randomizers from the full field,
369            // only from 128-bit strings.
370            randomizer = u128::rand(rng).into();
371        }
372        total_c -= &vk.g.mul(g_multiplier);
373        total_c -= &vk.gamma_g.mul(gamma_g_multiplier);
374        end_timer!(combination_time);
375
376        let to_affine_time = start_timer!(|| "Converting results to affine for pairing");
377        let affine_points = E::G1::normalize_batch(&[-total_w, total_c]);
378        let (total_w, total_c) = (affine_points[0], affine_points[1]);
379        end_timer!(to_affine_time);
380
381        let pairing_time = start_timer!(|| "Performing product of pairings");
382        let result = E::multi_pairing(
383            [total_w, total_c],
384            [vk.prepared_beta_h.clone(), vk.prepared_h.clone()],
385        )
386        .0
387        .is_one();
388        end_timer!(pairing_time);
389        end_timer!(check_time, || format!("Result: {}", result));
390        Ok(result)
391    }
392
393    pub(crate) fn check_degree_is_too_large(degree: usize, num_powers: usize) -> Result<(), Error> {
394        let num_coefficients = degree + 1;
395        if num_coefficients > num_powers {
396            Err(Error::TooManyCoefficients {
397                num_coefficients,
398                num_powers,
399            })
400        } else {
401            Ok(())
402        }
403    }
404
405    pub(crate) fn check_hiding_bound(
406        hiding_poly_degree: usize,
407        num_powers: usize,
408    ) -> Result<(), Error> {
409        if hiding_poly_degree == 0 {
410            Err(Error::HidingBoundIsZero)
411        } else if hiding_poly_degree >= num_powers {
412            // The above check uses `>=` because committing to a hiding poly with
413            // degree `hiding_poly_degree` requires `hiding_poly_degree + 1`
414            // powers.
415            Err(Error::HidingBoundToolarge {
416                hiding_poly_degree,
417                num_powers,
418            })
419        } else {
420            Ok(())
421        }
422    }
423
424    pub(crate) fn check_degrees_and_bounds<'a>(
425        supported_degree: usize,
426        max_degree: usize,
427        enforced_degree_bounds: Option<&[usize]>,
428        p: &'a LabeledPolynomial<E::ScalarField, P>,
429    ) -> Result<(), Error> {
430        if let Some(bound) = p.degree_bound() {
431            let enforced_degree_bounds =
432                enforced_degree_bounds.ok_or(Error::UnsupportedDegreeBound(bound))?;
433
434            if enforced_degree_bounds.binary_search(&bound).is_err() {
435                Err(Error::UnsupportedDegreeBound(bound))
436            } else if bound < p.degree() || bound > max_degree {
437                return Err(Error::IncorrectDegreeBound {
438                    poly_degree: p.degree(),
439                    degree_bound: p.degree_bound().unwrap(),
440                    supported_degree,
441                    label: p.label().to_string(),
442                });
443            } else {
444                Ok(())
445            }
446        } else {
447            Ok(())
448        }
449    }
450}
451
452fn skip_leading_zeros_and_convert_to_bigints<F: PrimeField, P: DenseUVPolynomial<F>>(
453    p: &P,
454) -> (usize, Vec<F::BigInt>) {
455    let mut num_leading_zeros = 0;
456    while num_leading_zeros < p.coeffs().len() && p.coeffs()[num_leading_zeros].is_zero() {
457        num_leading_zeros += 1;
458    }
459    let coeffs = convert_to_bigints(&p.coeffs()[num_leading_zeros..]);
460    (num_leading_zeros, coeffs)
461}
462
463fn convert_to_bigints<F: PrimeField>(p: &[F]) -> Vec<F::BigInt> {
464    let to_bigint_time = start_timer!(|| "Converting polynomial coeffs to bigints");
465    let coeffs = ark_std::cfg_iter!(p)
466        .map(|s| s.into_bigint())
467        .collect::<Vec<_>>();
468    end_timer!(to_bigint_time);
469    coeffs
470}
471
472#[cfg(test)]
473mod tests {
474    #![allow(non_camel_case_types)]
475    use crate::kzg10::*;
476    use crate::*;
477
478    use ark_bls12_377::Bls12_377;
479    use ark_bls12_381::Bls12_381;
480    use ark_bls12_381::Fr;
481    use ark_poly::univariate::DensePolynomial as DensePoly;
482    use ark_std::test_rng;
483
484    type UniPoly_381 = DensePoly<<Bls12_381 as Pairing>::ScalarField>;
485    type UniPoly_377 = DensePoly<<Bls12_377 as Pairing>::ScalarField>;
486    type KZG_Bls12_381 = KZG10<Bls12_381, UniPoly_381>;
487
488    impl<E: Pairing, P: DenseUVPolynomial<E::ScalarField>> KZG10<E, P> {
489        /// Specializes the public parameters for a given maximum degree `d` for polynomials
490        /// `d` should be less that `pp.max_degree()`.
491        pub(crate) fn trim(
492            pp: &UniversalParams<E>,
493            mut supported_degree: usize,
494        ) -> Result<(Powers<E>, VerifierKey<E>), Error> {
495            if supported_degree == 1 {
496                supported_degree += 1;
497            }
498            let powers_of_g = pp.powers_of_g[..=supported_degree].to_vec();
499            let powers_of_gamma_g = (0..=supported_degree)
500                .map(|i| pp.powers_of_gamma_g[&i])
501                .collect();
502
503            let powers = Powers {
504                powers_of_g: ark_std::borrow::Cow::Owned(powers_of_g),
505                powers_of_gamma_g: ark_std::borrow::Cow::Owned(powers_of_gamma_g),
506            };
507            let vk = VerifierKey {
508                g: pp.powers_of_g[0],
509                gamma_g: pp.powers_of_gamma_g[&0],
510                h: pp.h,
511                beta_h: pp.beta_h,
512                prepared_h: pp.prepared_h.clone(),
513                prepared_beta_h: pp.prepared_beta_h.clone(),
514            };
515            Ok((powers, vk))
516        }
517    }
518
519    #[test]
520    fn add_commitments_test() {
521        let rng = &mut test_rng();
522        let p = DensePoly::from_coefficients_slice(&[
523            Fr::rand(rng),
524            Fr::rand(rng),
525            Fr::rand(rng),
526            Fr::rand(rng),
527            Fr::rand(rng),
528        ]);
529        let f = Fr::rand(rng);
530        let mut f_p = DensePoly::zero();
531        f_p += (f, &p);
532
533        let degree = 4;
534        let pp = KZG_Bls12_381::setup(degree, false, rng).unwrap();
535        let (powers, _) = KZG_Bls12_381::trim(&pp, degree).unwrap();
536
537        let hiding_bound = None;
538        let (comm, _) = KZG10::commit(&powers, &p, hiding_bound, Some(rng)).unwrap();
539        let (f_comm, _) = KZG10::commit(&powers, &f_p, hiding_bound, Some(rng)).unwrap();
540        let mut f_comm_2 = Commitment::empty();
541        f_comm_2 += (f, &comm);
542
543        assert_eq!(f_comm, f_comm_2);
544    }
545
546    fn end_to_end_test_template<E, P>() -> Result<(), Error>
547    where
548        E: Pairing,
549        P: DenseUVPolynomial<E::ScalarField, Point = E::ScalarField>,
550        for<'a, 'b> &'a P: Div<&'b P, Output = P>,
551    {
552        let rng = &mut test_rng();
553        for _ in 0..100 {
554            let mut degree = 0;
555            while degree <= 1 {
556                degree = usize::rand(rng) % 20;
557            }
558            let pp = KZG10::<E, P>::setup(degree, false, rng)?;
559            let (ck, vk) = KZG10::<E, P>::trim(&pp, degree)?;
560            let p = P::rand(degree, rng);
561            let hiding_bound = Some(1);
562            let (comm, rand) = KZG10::<E, P>::commit(&ck, &p, hiding_bound, Some(rng))?;
563            let point = E::ScalarField::rand(rng);
564            let value = p.evaluate(&point);
565            let proof = KZG10::<E, P>::open(&ck, &p, point, &rand)?;
566            assert!(
567                KZG10::<E, P>::check(&vk, &comm, point, value, &proof)?,
568                "proof was incorrect for max_degree = {}, polynomial_degree = {}, hiding_bound = {:?}",
569                degree,
570                p.degree(),
571                hiding_bound,
572            );
573        }
574        Ok(())
575    }
576
577    fn linear_polynomial_test_template<E, P>() -> Result<(), Error>
578    where
579        E: Pairing,
580        P: DenseUVPolynomial<E::ScalarField, Point = E::ScalarField>,
581        for<'a, 'b> &'a P: Div<&'b P, Output = P>,
582    {
583        let rng = &mut test_rng();
584        for _ in 0..100 {
585            let degree = 50;
586            let pp = KZG10::<E, P>::setup(degree, false, rng)?;
587            let (ck, vk) = KZG10::<E, P>::trim(&pp, 2)?;
588            let p = P::rand(1, rng);
589            let hiding_bound = Some(1);
590            let (comm, rand) = KZG10::<E, P>::commit(&ck, &p, hiding_bound, Some(rng))?;
591            let point = E::ScalarField::rand(rng);
592            let value = p.evaluate(&point);
593            let proof = KZG10::<E, P>::open(&ck, &p, point, &rand)?;
594            assert!(
595                KZG10::<E, P>::check(&vk, &comm, point, value, &proof)?,
596                "proof was incorrect for max_degree = {}, polynomial_degree = {}, hiding_bound = {:?}",
597                degree,
598                p.degree(),
599                hiding_bound,
600            );
601        }
602        Ok(())
603    }
604
605    fn batch_check_test_template<E, P>() -> Result<(), Error>
606    where
607        E: Pairing,
608        P: DenseUVPolynomial<E::ScalarField, Point = E::ScalarField>,
609        for<'a, 'b> &'a P: Div<&'b P, Output = P>,
610    {
611        let rng = &mut test_rng();
612        for _ in 0..10 {
613            let mut degree = 0;
614            while degree <= 1 {
615                degree = usize::rand(rng) % 20;
616            }
617            let pp = KZG10::<E, P>::setup(degree, false, rng)?;
618            let (ck, vk) = KZG10::<E, P>::trim(&pp, degree)?;
619            let mut comms = Vec::new();
620            let mut values = Vec::new();
621            let mut points = Vec::new();
622            let mut proofs = Vec::new();
623            for _ in 0..10 {
624                let p = P::rand(degree, rng);
625                let hiding_bound = Some(1);
626                let (comm, rand) = KZG10::<E, P>::commit(&ck, &p, hiding_bound, Some(rng))?;
627                let point = E::ScalarField::rand(rng);
628                let value = p.evaluate(&point);
629                let proof = KZG10::<E, P>::open(&ck, &p, point, &rand)?;
630
631                assert!(KZG10::<E, P>::check(&vk, &comm, point, value, &proof)?);
632                comms.push(comm);
633                values.push(value);
634                points.push(point);
635                proofs.push(proof);
636            }
637            assert!(KZG10::<E, P>::batch_check(
638                &vk, &comms, &points, &values, &proofs, rng
639            )?);
640        }
641        Ok(())
642    }
643
644    #[test]
645    fn end_to_end_test() {
646        end_to_end_test_template::<Bls12_377, UniPoly_377>().expect("test failed for bls12-377");
647        end_to_end_test_template::<Bls12_381, UniPoly_381>().expect("test failed for bls12-381");
648    }
649
650    #[test]
651    fn linear_polynomial_test() {
652        linear_polynomial_test_template::<Bls12_377, UniPoly_377>()
653            .expect("test failed for bls12-377");
654        linear_polynomial_test_template::<Bls12_381, UniPoly_381>()
655            .expect("test failed for bls12-381");
656    }
657    #[test]
658    fn batch_check_test() {
659        batch_check_test_template::<Bls12_377, UniPoly_377>().expect("test failed for bls12-377");
660        batch_check_test_template::<Bls12_381, UniPoly_381>().expect("test failed for bls12-381");
661    }
662
663    #[test]
664    fn test_degree_is_too_large() {
665        let rng = &mut test_rng();
666
667        let max_degree = 123;
668        let pp = KZG_Bls12_381::setup(max_degree, false, rng).unwrap();
669        let (powers, _) = KZG_Bls12_381::trim(&pp, max_degree).unwrap();
670
671        let p = DensePoly::<Fr>::rand(max_degree + 1, rng);
672        assert!(p.degree() > max_degree);
673        assert!(KZG_Bls12_381::check_degree_is_too_large(p.degree(), powers.size()).is_err());
674    }
675}