mod.rs
1 // Copyright (c) 2025 ADnet Contributors 2 // This file is part of the AlphaVM library. 3 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at: 7 8 // http://www.apache.org/licenses/LICENSE-2.0 9 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 //! Here we construct a polynomial commitment that enables users to commit to a 17 //! single polynomial `p`, and then later provide an evaluation proof that 18 //! convinces verifiers that a claimed value `v` is the true evaluation of `p` 19 //! at a chosen point `x`. Our construction follows the template of the 20 //! construction proposed by Kate, Zaverucha, and Goldberg ([KZG11](http://cacr.uwaterloo.ca/techreports/2010/cacr2010-10.pdf)). 21 //! This construction achieves extractability in the algebraic group model 22 //! (AGM). 23 24 use crate::{ 25 fft::{DensePolynomial, Polynomial}, 26 msm::VariableBase, 27 polycommit::PCError, 28 }; 29 use alphavm_curves::traits::{AffineCurve, PairingCurve, PairingEngine, ProjectiveCurve}; 30 use alphavm_fields::{One, PrimeField, Zero}; 31 use alphavm_utilities::{BitIteratorBE, cfg_iter, cfg_iter_mut, rand::Uniform}; 32 33 use anyhow::{Result, anyhow, ensure}; 34 use core::{marker::PhantomData, ops::Mul}; 35 use itertools::Itertools; 36 use rand::RngCore; 37 38 #[cfg(not(feature = "serial"))] 39 use rayon::prelude::*; 40 41 mod data_structures; 42 pub use data_structures::*; 43 44 use super::sonic_pc::LabeledPolynomialWithBasis; 45 46 #[derive(Debug, PartialEq, Eq)] 47 pub enum KZGDegreeBounds { 48 All, 49 Varuna, 50 List(Vec<usize>), 51 None, 52 } 53 54 impl KZGDegreeBounds { 55 pub fn get_list<F: PrimeField>(&self, max_degree: usize) -> Vec<usize> { 56 match self { 57 KZGDegreeBounds::All => (0..max_degree).collect(), 58 KZGDegreeBounds::Varuna => { 59 // In Varuna, the degree bounds are all of the forms `domain_size - 2`. 60 // Consider that we are using radix-2 FFT, 61 // there are only a few possible domain sizes and therefore degree bounds. 62 // 63 // We do not consider mixed-radix FFT for simplicity, as the curves that we 64 // are using have very high two-arity. 65 66 let mut radix_2_possible_domain_sizes = vec![]; 67 68 let mut cur = 2usize; 69 while cur - 2 <= max_degree { 70 radix_2_possible_domain_sizes.push(cur - 2); 71 cur *= 2; 72 } 73 74 radix_2_possible_domain_sizes 75 } 76 KZGDegreeBounds::List(v) => v.clone(), 77 KZGDegreeBounds::None => vec![], 78 } 79 } 80 } 81 82 /// `KZG10` is an implementation of the polynomial commitment scheme of 83 /// [Kate, Zaverucha and Goldbgerg][kzg10] 84 /// 85 /// [kzg10]: http://cacr.uwaterloo.ca/techreports/2010/cacr2010-10.pdf 86 #[derive(Clone, Debug)] 87 pub struct KZG10<E: PairingEngine>(PhantomData<E>); 88 89 impl<E: PairingEngine> KZG10<E> { 90 /// Constructs public parameters when given as input the maximum degree 91 /// `degree` for the polynomial commitment scheme. 92 pub fn load_srs(max_degree: usize) -> Result<UniversalParams<E>, PCError> { 93 let params = UniversalParams::load()?; 94 params.download_powers_for(0..(max_degree + 1))?; 95 Ok(params) 96 } 97 98 /// Outputs a commitment to `polynomial`. 99 pub fn commit( 100 powers: &Powers<E>, 101 polynomial: &Polynomial<'_, E::Fr>, 102 hiding_bound: Option<usize>, 103 rng: Option<&mut dyn RngCore>, 104 ) -> Result<(KZGCommitment<E>, KZGRandomness<E>), PCError> { 105 Self::check_degree_is_too_large(polynomial.degree(), powers.size())?; 106 107 let commit_time = start_timer!(|| format!( 108 "Committing to polynomial of degree {} with hiding_bound: {:?}", 109 polynomial.degree(), 110 hiding_bound, 111 )); 112 113 let mut commitment = match polynomial { 114 Polynomial::Dense(polynomial) => { 115 let (num_leading_zeros, plain_coeffs) = skip_leading_zeros_and_convert_to_bigints(polynomial); 116 117 let bases = &powers.powers_of_beta_g[num_leading_zeros..(num_leading_zeros + plain_coeffs.len())]; 118 119 let msm_time = start_timer!(|| "MSM to compute commitment to plaintext poly"); 120 let commitment = VariableBase::msm(bases, &plain_coeffs); 121 end_timer!(msm_time); 122 123 commitment 124 } 125 Polynomial::Sparse(polynomial) => polynomial 126 .coeffs() 127 .map(|(i, coeff)| { 128 powers.powers_of_beta_g[*i].mul_bits(BitIteratorBE::new_without_leading_zeros(coeff.to_bigint())) 129 }) 130 .sum(), 131 }; 132 133 let mut randomness = KZGRandomness::empty(); 134 if let Some(hiding_degree) = hiding_bound { 135 let mut rng = rng.ok_or(PCError::MissingRng)?; 136 let sample_random_poly_time = 137 start_timer!(|| format!("Sampling a random polynomial of degree {hiding_degree}")); 138 139 randomness = KZGRandomness::rand(hiding_degree, false, &mut rng); 140 Self::check_hiding_bound( 141 randomness.blinding_polynomial.degree(), 142 powers.powers_of_beta_times_gamma_g.len(), 143 )?; 144 end_timer!(sample_random_poly_time); 145 } 146 147 let random_ints = convert_to_bigints(&randomness.blinding_polynomial.coeffs); 148 let msm_time = start_timer!(|| "MSM to compute commitment to random poly"); 149 let random_commitment = 150 VariableBase::msm(&powers.powers_of_beta_times_gamma_g, random_ints.as_slice()).to_affine(); 151 end_timer!(msm_time); 152 153 commitment.add_assign_mixed(&random_commitment); 154 155 end_timer!(commit_time); 156 Ok((KZGCommitment(commitment.into()), randomness)) 157 } 158 159 /// Outputs a commitment to `polynomial`. 160 pub fn commit_lagrange( 161 lagrange_basis: &LagrangeBasis<E>, 162 evaluations: &[E::Fr], 163 hiding_bound: Option<usize>, 164 rng: Option<&mut dyn RngCore>, 165 ) -> Result<(KZGCommitment<E>, KZGRandomness<E>), PCError> { 166 Self::check_degree_is_too_large(evaluations.len() - 1, lagrange_basis.size())?; 167 assert_eq!( 168 evaluations.len().checked_next_power_of_two().ok_or(PCError::LagrangeBasisSizeIsTooLarge)?, 169 lagrange_basis.size() 170 ); 171 172 let commit_time = start_timer!(|| format!( 173 "Committing to polynomial of degree {} with hiding_bound: {:?}", 174 evaluations.len() - 1, 175 hiding_bound, 176 )); 177 178 let evaluations = evaluations.iter().map(|e| e.to_bigint()).collect::<Vec<_>>(); 179 let msm_time = start_timer!(|| "MSM to compute commitment to plaintext poly"); 180 let mut commitment = VariableBase::msm(&lagrange_basis.lagrange_basis_at_beta_g, &evaluations); 181 end_timer!(msm_time); 182 183 let mut randomness = KZGRandomness::empty(); 184 if let Some(hiding_degree) = hiding_bound { 185 let mut rng = rng.ok_or(PCError::MissingRng)?; 186 let sample_random_poly_time = 187 start_timer!(|| format!("Sampling a random polynomial of degree {hiding_degree}")); 188 189 randomness = KZGRandomness::rand(hiding_degree, false, &mut rng); 190 Self::check_hiding_bound( 191 randomness.blinding_polynomial.degree(), 192 lagrange_basis.powers_of_beta_times_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 = 200 VariableBase::msm(&lagrange_basis.powers_of_beta_times_gamma_g, random_ints.as_slice()).to_affine(); 201 end_timer!(msm_time); 202 203 commitment.add_assign_mixed(&random_commitment); 204 205 end_timer!(commit_time); 206 Ok((KZGCommitment(commitment.into()), randomness)) 207 } 208 209 /// Compute witness polynomial. 210 /// 211 /// The witness polynomial w(x) the quotient of the division (p(x) - p(z)) / 212 /// (x - z) Observe that this quotient does not change with z because 213 /// p(z) is the remainder term. We can therefore omit p(z) when computing 214 /// the quotient. 215 pub fn compute_witness_polynomial( 216 polynomial: &DensePolynomial<E::Fr>, 217 point: E::Fr, 218 randomness: &KZGRandomness<E>, 219 ) -> Result<(DensePolynomial<E::Fr>, Option<DensePolynomial<E::Fr>>), PCError> { 220 let divisor = DensePolynomial::from_coefficients_vec(vec![-point, E::Fr::one()]); 221 222 let witness_time = start_timer!(|| "Computing witness polynomial"); 223 let witness_polynomial = polynomial / &divisor; 224 end_timer!(witness_time); 225 226 let random_witness_polynomial = if randomness.is_hiding() { 227 let random_p = &randomness.blinding_polynomial; 228 229 let witness_time = start_timer!(|| "Computing random witness polynomial"); 230 let random_witness_polynomial = random_p / &divisor; 231 end_timer!(witness_time); 232 Some(random_witness_polynomial) 233 } else { 234 None 235 }; 236 237 Ok((witness_polynomial, random_witness_polynomial)) 238 } 239 240 pub(crate) fn open_with_witness_polynomial( 241 powers: &Powers<E>, 242 point: E::Fr, 243 randomness: &KZGRandomness<E>, 244 witness_polynomial: &DensePolynomial<E::Fr>, 245 hiding_witness_polynomial: Option<&DensePolynomial<E::Fr>>, 246 ) -> Result<KZGProof<E>, PCError> { 247 Self::check_degree_is_too_large(witness_polynomial.degree(), powers.size())?; 248 let (num_leading_zeros, witness_coeffs) = skip_leading_zeros_and_convert_to_bigints(witness_polynomial); 249 250 let bases = &powers.powers_of_beta_g[num_leading_zeros..(num_leading_zeros + witness_coeffs.len())]; 251 252 let witness_comm_time = start_timer!(|| "Computing commitment to witness polynomial"); 253 let mut w = VariableBase::msm(bases, &witness_coeffs); 254 end_timer!(witness_comm_time); 255 256 let random_v = if let Some(hiding_witness_polynomial) = hiding_witness_polynomial { 257 let blinding_p = &randomness.blinding_polynomial; 258 let blinding_eval_time = start_timer!(|| "Evaluating random polynomial"); 259 let blinding_evaluation = blinding_p.evaluate(point); 260 end_timer!(blinding_eval_time); 261 262 let random_witness_coeffs = convert_to_bigints(&hiding_witness_polynomial.coeffs); 263 let witness_comm_time = start_timer!(|| "Computing commitment to random witness polynomial"); 264 w += &VariableBase::msm(&powers.powers_of_beta_times_gamma_g, &random_witness_coeffs); 265 end_timer!(witness_comm_time); 266 Some(blinding_evaluation) 267 } else { 268 None 269 }; 270 271 Ok(KZGProof { w: w.to_affine(), random_v }) 272 } 273 274 /// On input a polynomial `p` in Lagrange basis, and a point `point`, 275 /// outputs an evaluation proof for the same. 276 pub fn open_lagrange( 277 lagrange_basis: &LagrangeBasis<E>, 278 domain_elements: &[E::Fr], 279 evaluations: &[E::Fr], 280 point: E::Fr, 281 evaluation_at_point: E::Fr, 282 ) -> Result<KZGProof<E>> { 283 Self::check_degree_is_too_large(evaluations.len() - 1, lagrange_basis.size())?; 284 // Ensure that the point is not in the domain 285 if lagrange_basis.domain.evaluate_vanishing_polynomial(point).is_zero() { 286 Err(anyhow!("Point cannot be in the domain"))?; 287 } 288 if evaluations.len().checked_next_power_of_two().ok_or_else(|| anyhow!("Evaluations length is too large"))? 289 != lagrange_basis.size() 290 { 291 Err(anyhow!("`evaluations.len()` must equal `domain.size()`"))?; 292 } 293 294 let mut divisor_evals = cfg_iter!(domain_elements).map(|&e| e - point).collect::<Vec<_>>(); 295 alphavm_fields::batch_inversion(&mut divisor_evals); 296 ensure!(divisor_evals.len() == evaluations.len()); 297 cfg_iter_mut!(divisor_evals).zip_eq(evaluations).for_each(|(divisor_eval, &eval)| { 298 *divisor_eval *= eval - evaluation_at_point; 299 }); 300 let (witness_comm, _) = Self::commit_lagrange(lagrange_basis, &divisor_evals, None, None)?; 301 302 Ok(KZGProof { w: witness_comm.0, random_v: None }) 303 } 304 305 /// On input a polynomial `p` and a point `point`, outputs a proof for the 306 /// same. 307 pub fn open( 308 powers: &Powers<E>, 309 polynomial: &DensePolynomial<E::Fr>, 310 point: E::Fr, 311 rand: &KZGRandomness<E>, 312 ) -> Result<KZGProof<E>, PCError> { 313 Self::check_degree_is_too_large(polynomial.degree(), powers.size())?; 314 let open_time = start_timer!(|| format!("Opening polynomial of degree {}", polynomial.degree())); 315 316 let witness_time = start_timer!(|| "Computing witness polynomials"); 317 let (witness_poly, hiding_witness_poly) = Self::compute_witness_polynomial(polynomial, point, rand)?; 318 end_timer!(witness_time); 319 320 let proof = 321 Self::open_with_witness_polynomial(powers, point, rand, &witness_poly, hiding_witness_poly.as_ref()); 322 323 end_timer!(open_time); 324 proof 325 } 326 327 /// Verifies that `value` is the evaluation at `point` of the polynomial 328 /// committed inside `commitment`. 329 pub fn check( 330 vk: &VerifierKey<E>, 331 commitment: &KZGCommitment<E>, 332 point: E::Fr, 333 value: E::Fr, 334 proof: &KZGProof<E>, 335 ) -> Result<bool, PCError> { 336 let check_time = start_timer!(|| "Checking evaluation"); 337 let mut inner = commitment.0.to_projective() - vk.g.to_projective().mul(value); 338 if let Some(random_v) = proof.random_v { 339 inner -= &vk.gamma_g.mul(random_v); 340 } 341 let lhs = E::pairing(inner, vk.h); 342 343 let inner = vk.beta_h.to_projective() - vk.h.mul(point); 344 let rhs = E::pairing(proof.w, inner); 345 346 end_timer!(check_time, || format!("Result: {}", lhs == rhs)); 347 Ok(lhs == rhs) 348 } 349 350 /// Check that each `proof_i` in `proofs` is a valid proof of evaluation for 351 /// `commitment_i` at `point_i`. 352 pub fn batch_check<R: RngCore>( 353 vk: &VerifierKey<E>, 354 commitments: &[KZGCommitment<E>], 355 points: &[E::Fr], 356 values: &[E::Fr], 357 proofs: &[KZGProof<E>], 358 rng: &mut R, 359 ) -> Result<bool> { 360 let check_time = start_timer!(|| format!("Checking {} evaluation proofs", commitments.len())); 361 let g = vk.g.to_projective(); 362 let gamma_g = vk.gamma_g.to_projective(); 363 364 let mut total_c = <E::G1Projective>::zero(); 365 let mut total_w = <E::G1Projective>::zero(); 366 367 let combination_time = start_timer!(|| "Combining commitments and proofs"); 368 let mut randomizer = E::Fr::one(); 369 // Instead of multiplying g and gamma_g in each turn, we simply accumulate 370 // their coefficients and perform a final multiplication at the end. 371 let mut g_multiplier = E::Fr::zero(); 372 let mut gamma_g_multiplier = E::Fr::zero(); 373 ensure!(commitments.len() == points.len()); 374 ensure!(commitments.len() == values.len()); 375 ensure!(commitments.len() == proofs.len()); 376 for (((c, z), v), proof) in commitments.iter().zip_eq(points).zip_eq(values).zip_eq(proofs) { 377 let w = proof.w; 378 let mut temp = w.mul(*z); 379 temp.add_assign_mixed(&c.0); 380 let c = temp; 381 g_multiplier += &(randomizer * v); 382 if let Some(random_v) = proof.random_v { 383 gamma_g_multiplier += &(randomizer * random_v); 384 } 385 total_c += &c.mul(randomizer); 386 total_w += &w.mul(randomizer); 387 // We don't need to sample randomizers from the full field, 388 // only from 128-bit strings. 389 randomizer = u128::rand(rng).into(); 390 } 391 total_c -= &g.mul(g_multiplier); 392 total_c -= &gamma_g.mul(gamma_g_multiplier); 393 end_timer!(combination_time); 394 395 let to_affine_time = start_timer!(|| "Converting results to affine for pairing"); 396 let affine_points = E::G1Projective::batch_normalization_into_affine(vec![-total_w, total_c]); 397 let (total_w, total_c) = (affine_points[0], affine_points[1]); 398 end_timer!(to_affine_time); 399 400 let pairing_time = start_timer!(|| "Performing product of pairings"); 401 let result = E::product_of_pairings( 402 [(&total_w.prepare(), &vk.prepared_beta_h), (&total_c.prepare(), &vk.prepared_h)].iter().copied(), 403 ) 404 .is_one(); 405 end_timer!(pairing_time); 406 end_timer!(check_time, || format!("Result: {result}")); 407 Ok(result) 408 } 409 410 pub(crate) fn check_degree_is_too_large(degree: usize, num_powers: usize) -> Result<(), PCError> { 411 let num_coefficients = degree + 1; 412 if num_coefficients > num_powers { 413 Err(PCError::TooManyCoefficients { num_coefficients, num_powers }) 414 } else { 415 Ok(()) 416 } 417 } 418 419 pub(crate) fn check_hiding_bound(hiding_poly_degree: usize, num_powers: usize) -> Result<(), PCError> { 420 if hiding_poly_degree == 0 { 421 Err(PCError::HidingBoundIsZero) 422 } else if hiding_poly_degree >= num_powers { 423 // The above check uses `>=` because committing to a hiding poly with 424 // degree `hiding_poly_degree` requires `hiding_poly_degree + 1` powers. 425 Err(PCError::HidingBoundToolarge { hiding_poly_degree, num_powers }) 426 } else { 427 Ok(()) 428 } 429 } 430 431 pub(crate) fn check_degrees_and_bounds<'a>( 432 max_degree: usize, 433 enforced_degree_bounds: Option<&[usize]>, 434 p: impl Into<LabeledPolynomialWithBasis<'a, E::Fr>>, 435 ) -> Result<(), PCError> { 436 let p = p.into(); 437 if let Some(bound) = p.degree_bound() { 438 let enforced_degree_bounds = enforced_degree_bounds.ok_or(PCError::UnsupportedDegreeBound(bound))?; 439 440 if enforced_degree_bounds.binary_search(&bound).is_err() { 441 Err(PCError::UnsupportedDegreeBound(bound)) 442 } else if bound < p.degree() || bound > max_degree { 443 return Err(PCError::IncorrectDegreeBound { 444 poly_degree: p.degree(), 445 degree_bound: p.degree_bound().unwrap(), 446 max_degree, 447 label: p.label().to_string(), 448 }); 449 } else { 450 Ok(()) 451 } 452 } else { 453 Ok(()) 454 } 455 } 456 } 457 458 fn skip_leading_zeros_and_convert_to_bigints<F: PrimeField>(p: &DensePolynomial<F>) -> (usize, Vec<F::BigInteger>) { 459 if p.coeffs.is_empty() { 460 (0, vec![]) 461 } else { 462 let num_leading_zeros = p.coeffs.iter().take_while(|c| c.is_zero()).count(); 463 let coeffs = if num_leading_zeros == p.coeffs.len() { 464 vec![] 465 } else { 466 convert_to_bigints(&p.coeffs[num_leading_zeros..]) 467 }; 468 (num_leading_zeros, coeffs) 469 } 470 } 471 472 fn convert_to_bigints<F: PrimeField>(p: &[F]) -> Vec<F::BigInteger> { 473 let to_bigint_time = start_timer!(|| "Converting polynomial coeffs to bigints"); 474 let coeffs = cfg_iter!(p).map(|s| s.to_bigint()).collect::<Vec<_>>(); 475 end_timer!(to_bigint_time); 476 coeffs 477 } 478 479 #[cfg(test)] 480 mod tests { 481 #![allow(non_camel_case_types)] 482 #![allow(clippy::needless_borrow)] 483 use super::*; 484 use alphavm_curves::bls12_377::{Bls12_377, Fr}; 485 use alphavm_utilities::{FromBytes, ToBytes, rand::TestRng}; 486 487 use std::borrow::Cow; 488 489 type KZG_Bls12_377 = KZG10<Bls12_377>; 490 491 impl<E: PairingEngine> KZG10<E> { 492 /// Specializes the public parameters for a given maximum degree `d` for 493 /// polynomials `d` should be less that `pp.max_degree()`. 494 pub(crate) fn trim( 495 pp: &UniversalParams<E>, 496 mut supported_degree: usize, 497 hiding_bound: Option<usize>, 498 ) -> (Powers<E>, VerifierKey<E>) { 499 if supported_degree == 1 { 500 supported_degree += 1; 501 } 502 let powers_of_beta_g = pp.powers_of_beta_g(0, supported_degree + 1).unwrap().to_vec(); 503 504 let powers_of_beta_times_gamma_g = if let Some(hiding_bound) = hiding_bound { 505 (0..=(hiding_bound + 1)).map(|i| pp.powers_of_beta_times_gamma_g()[&i]).collect() 506 } else { 507 vec![] 508 }; 509 510 let powers = Powers { 511 powers_of_beta_g: Cow::Owned(powers_of_beta_g), 512 powers_of_beta_times_gamma_g: Cow::Owned(powers_of_beta_times_gamma_g), 513 }; 514 let vk = VerifierKey { 515 g: pp.power_of_beta_g(0).unwrap(), 516 gamma_g: pp.powers_of_beta_times_gamma_g()[&0], 517 h: pp.h, 518 beta_h: pp.beta_h(), 519 prepared_h: pp.prepared_h.clone(), 520 prepared_beta_h: pp.prepared_beta_h.clone(), 521 }; 522 (powers, vk) 523 } 524 } 525 526 #[test] 527 fn test_kzg10_universal_params_serialization() { 528 let degree = 4; 529 let pp = KZG_Bls12_377::load_srs(degree).unwrap(); 530 531 let pp_bytes = pp.to_bytes_le().unwrap(); 532 let pp_recovered: UniversalParams<Bls12_377> = FromBytes::read_le(&pp_bytes[..]).unwrap(); 533 let pp_recovered_bytes = pp_recovered.to_bytes_le().unwrap(); 534 535 assert_eq!(&pp_bytes, &pp_recovered_bytes); 536 } 537 538 fn end_to_end_test_template<E: PairingEngine>() -> Result<(), PCError> { 539 let rng = &mut TestRng::default(); 540 for _ in 0..100 { 541 let mut degree = 0; 542 while degree <= 1 { 543 degree = usize::rand(rng) % 20; 544 } 545 let pp = KZG10::<E>::load_srs(degree)?; 546 let hiding_bound = Some(1); 547 let (ck, vk) = KZG10::trim(&pp, degree, hiding_bound); 548 let p = DensePolynomial::rand(degree, rng); 549 let (comm, rand) = KZG10::<E>::commit(&ck, &(&p).into(), hiding_bound, Some(rng))?; 550 let point = E::Fr::rand(rng); 551 let value = p.evaluate(point); 552 let proof = KZG10::<E>::open(&ck, &p, point, &rand)?; 553 assert!( 554 KZG10::<E>::check(&vk, &comm, point, value, &proof)?, 555 "proof was incorrect for max_degree = {}, polynomial_degree = {}, hiding_bound = {:?}", 556 degree, 557 p.degree(), 558 hiding_bound, 559 ); 560 } 561 Ok(()) 562 } 563 564 fn linear_polynomial_test_template<E: PairingEngine>() -> Result<(), PCError> { 565 let rng = &mut TestRng::default(); 566 for _ in 0..100 { 567 let degree = 50; 568 let pp = KZG10::<E>::load_srs(degree)?; 569 let hiding_bound = Some(1); 570 let (ck, vk) = KZG10::trim(&pp, 2, hiding_bound); 571 let p = DensePolynomial::rand(1, rng); 572 let (comm, rand) = KZG10::<E>::commit(&ck, &(&p).into(), hiding_bound, Some(rng))?; 573 let point = E::Fr::rand(rng); 574 let value = p.evaluate(point); 575 let proof = KZG10::<E>::open(&ck, &p, point, &rand)?; 576 assert!( 577 KZG10::<E>::check(&vk, &comm, point, value, &proof)?, 578 "proof was incorrect for max_degree = {}, polynomial_degree = {}, hiding_bound = {:?}", 579 degree, 580 p.degree(), 581 hiding_bound, 582 ); 583 } 584 Ok(()) 585 } 586 587 fn batch_check_test_template<E: PairingEngine>() -> Result<(), PCError> { 588 let rng = &mut TestRng::default(); 589 for _ in 0..10 { 590 let hiding_bound = Some(1); 591 let mut degree = 0; 592 while degree <= 1 { 593 degree = usize::rand(rng) % 20; 594 } 595 let pp = KZG10::<E>::load_srs(degree)?; 596 let (ck, vk) = KZG10::trim(&pp, degree, hiding_bound); 597 598 let mut comms = Vec::new(); 599 let mut values = Vec::new(); 600 let mut points = Vec::new(); 601 let mut proofs = Vec::new(); 602 603 for _ in 0..10 { 604 let p = DensePolynomial::rand(degree, rng); 605 let (comm, rand) = KZG10::<E>::commit(&ck, &(&p).into(), hiding_bound, Some(rng))?; 606 let point = E::Fr::rand(rng); 607 let value = p.evaluate(point); 608 let proof = KZG10::<E>::open(&ck, &p, point, &rand)?; 609 610 assert!(KZG10::<E>::check(&vk, &comm, point, value, &proof)?); 611 comms.push(comm); 612 values.push(value); 613 points.push(point); 614 proofs.push(proof); 615 } 616 assert!(KZG10::<E>::batch_check(&vk, &comms, &points, &values, &proofs, rng)?); 617 } 618 Ok(()) 619 } 620 621 #[test] 622 fn test_end_to_end() { 623 end_to_end_test_template::<Bls12_377>().expect("test failed for bls12-377"); 624 } 625 626 #[test] 627 fn test_linear_polynomial() { 628 linear_polynomial_test_template::<Bls12_377>().expect("test failed for bls12-377"); 629 } 630 631 #[test] 632 fn test_batch_check() { 633 batch_check_test_template::<Bls12_377>().expect("test failed for bls12-377"); 634 } 635 636 #[test] 637 fn test_degree_is_too_large() { 638 let rng = &mut TestRng::default(); 639 640 let max_degree = 123; 641 let pp = KZG_Bls12_377::load_srs(max_degree).unwrap(); 642 let (powers, _) = KZG_Bls12_377::trim(&pp, max_degree, None); 643 644 let p = DensePolynomial::<Fr>::rand(max_degree + 1, rng); 645 assert!(p.degree() > max_degree); 646 assert!(KZG_Bls12_377::check_degree_is_too_large(p.degree(), powers.size()).is_err()); 647 } 648 }