1use 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
21pub 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 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 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 *= β
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 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() / β
93 for _ in 0..max_degree {
94 neg_powers_of_beta.push(cur);
95 cur /= β
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 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 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 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 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 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 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 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 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 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 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}