diff --git a/crypto/src/commitments/kzg.rs b/crypto/src/commitments/kzg.rs index 2ecbb483c..467812fd7 100644 --- a/crypto/src/commitments/kzg.rs +++ b/crypto/src/commitments/kzg.rs @@ -1,3 +1,4 @@ +#![deny(clippy::all)] use super::traits::IsCommitmentScheme; use alloc::{borrow::ToOwned, vec::Vec}; use core::{marker::PhantomData, mem}; @@ -283,33 +284,126 @@ mod tests { #[allow(clippy::upper_case_acronyms)] type KZG = KateZaveruchaGoldberg; + const MAX_POLYNOMIAL_DEGREE: usize = 100; + fn create_srs() -> StructuredReferenceString< ::G1Point, ::G2Point, > { let mut rng = rand::thread_rng(); - let toxic_waste = FrElement::new(U256 { + let mut toxic_waste = Some(FrElement::new(U256 { limbs: [ rng.gen::(), rng.gen::(), rng.gen::(), rng.gen::(), ], - }); - let g1 = BLS12381Curve::generator(); - let g2 = BLS12381TwistCurve::generator(); - let powers_main_group: Vec = (0..100) - .map(|exponent| { - g1.operate_with_self(toxic_waste.pow(exponent as u128).representative()) - }) - .collect(); - let powers_secondary_group = [ - g2.clone(), - g2.operate_with_self(toxic_waste.representative()), - ]; + })); + + let powers_main_group: Vec = { + let g1 = BLS12381Curve::generator(); + (0..MAX_POLYNOMIAL_DEGREE) + .map(|exponent| { + let tw = toxic_waste.as_ref().expect("toxic_waste should be available"); + g1.operate_with_self(tw.pow(exponent as u128).representative()) + }) + .collect() + }; + + let powers_secondary_group = { + let g2 = BLS12381TwistCurve::generator(); + [ + g2.clone(), + g2.operate_with_self( + toxic_waste + .as_ref() + .expect("toxic_waste should be available") + .representative(), + ), + ] + }; + + toxic_waste = None; + assert!(toxic_waste.is_none(), "toxic_waste should be poisoned"); StructuredReferenceString::new(&powers_main_group, &powers_secondary_group) } + #[test] + fn e2e_kzg_single_polynomial() { + // Setup phase: create the SRS + let kzg = KZG::new(create_srs()); + + // Commit phase: create the desired polynomial, and commit that polyonmial + let p = Polynomial::::new(&[ + FieldElement::from(7), + FieldElement::from(5), + FieldElement::from(3), + ]); + // ASSERT: the polynomial is not too large + assert!(p.degree() <= MAX_POLYNOMIAL_DEGREE); + let p_commitment: ::G1Point = kzg.commit(&p); + + // Open phase: evaluate the polynomial at the desired point i, and create the proof for that opening + let i = FieldElement::from(1); // Challenge from the verifier + let y = p.evaluate(&i); // Evaluation of the polynomial at challenge + // ASSERT: the evaluation is correct + assert_eq!(y, FieldElement::from(15)); + let proof = kzg.open(&i, &y, &p); + + // Verify phase: the proof should verify + // ASSERT: the proof verifies + assert!(kzg.verify(&i, &y, &p_commitment, &proof)); + } + + #[test] + fn e2e_kzg_batched_polynomials() { + // Setup phase: create the SRS + let kzg = KZG::new(create_srs()); + + // Commit phase: create the polynomials, and compute the commitments. + let p0 = Polynomial::::new(&[ + FieldElement::from(5), + FieldElement::from(4), + -FieldElement::from(7), + ]); + // ASSERT: deg(p0) < MAX_POLYNOMIAL_DEGREE + assert!(p0.degree() < MAX_POLYNOMIAL_DEGREE); + let p0_commitment: ::G1Point = kzg.commit(&p0); + + let p1 = Polynomial::::new(&[ + FieldElement::from(1), + FieldElement::from(2), + -FieldElement::from(1), + ]); + // ASSERT: deg(p1) < MAX_POLYNOMIAL_DEGREE + assert!(p1.degree() < MAX_POLYNOMIAL_DEGREE); + let p1_commitment: ::G1Point = kzg.commit(&p1); + + // Open phase: open the polynomials at point i, and compute the proof for the batch. + let i = FieldElement::from(3); + + let y0 = p0.evaluate(&i); + // ASSERT: evaluation on p0 is correct + assert_eq!(y0, -FieldElement::from(46)); + + // ASSERT: evaluation on p1 is correct + let y1 = p1.evaluate(&i); + assert_eq!(y1, -FieldElement::from(2)); + + let upsilon = &FieldElement::from(1); + + let proof = kzg.open_batch(&i, &[y0.clone(), y1.clone()], &[p0, p1], upsilon); + + assert!(kzg.verify_batch( + &i, + &[y0, y1], + &[p0_commitment, p1_commitment], + &proof, + upsilon + )); + } + + #[test] fn kzg_1() { let kzg = KZG::new(create_srs());