1use ark_bn254::{Bn254, Fq12Config, Fr, G1Projective};
2use ark_ec::{pairing::Pairing, AffineRepr, CurveGroup, PrimeGroup, VariableBaseMSM};
3use ark_ff::{AdditiveGroup, Fp12, One, PrimeField};
4use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Compress, Validate};
5use ark_std::{
6 ops::*,
7 rand::{CryptoRng, RngCore},
8 UniformRand, Zero,
9};
10use serde::{Deserialize, Serialize};
11
12use crate::{
13 errors::UzkgeError,
14 poly_commit::{
15 field_polynomial::FpPolynomial,
16 pcs::{HomomorphicPolyComElem, PolyComScheme, ToBytes},
17 },
18 utils::serialization::{ark_deserialize, ark_serialize},
19};
20
21#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Default)]
23pub struct KZGCommitment<G: CanonicalSerialize + CanonicalDeserialize>(
24 #[serde(serialize_with = "ark_serialize", deserialize_with = "ark_deserialize")] pub G,
25);
26
27impl<G> ToBytes for G
28where
29 G: CurveGroup,
30{
31 fn to_bytes(&self) -> Vec<u8> {
32 let mut buf = Vec::new();
33 self.serialize_with_mode(&mut buf, Compress::Yes).unwrap();
34 buf
35 }
36
37 fn to_transcript_bytes(&self) -> Vec<u8> {
38 let aff_repr = self.into_affine();
39 let x: G::BaseField = aff_repr.x().unwrap_or(G::BaseField::ZERO);
40 let y: G::BaseField = aff_repr.y().unwrap_or(G::BaseField::ZERO);
41
42 let mut buf_x = vec![];
43 x.serialize_with_mode(&mut buf_x, Compress::Yes).unwrap();
44 buf_x.reverse();
45
46 let mut buf_y = vec![];
47 y.serialize_with_mode(&mut buf_y, Compress::Yes).unwrap();
48 buf_y.reverse();
49
50 buf_x.extend_from_slice(&buf_y);
51
52 buf_x
53 }
54}
55
56impl<G> ToBytes for KZGCommitment<G>
57where
58 G: CurveGroup,
59{
60 fn to_bytes(&self) -> Vec<u8> {
61 self.0.to_bytes()
62 }
63
64 fn to_transcript_bytes(&self) -> Vec<u8> {
65 self.0.to_transcript_bytes()
66 }
67}
68
69impl HomomorphicPolyComElem for KZGCommitment<G1Projective> {
70 type Scalar = Fr;
71 fn get_base() -> Self {
72 KZGCommitment(G1Projective::generator())
73 }
74
75 fn get_identity() -> Self {
76 KZGCommitment(G1Projective::zero())
77 }
78
79 fn add(&self, other: &Self) -> Self {
80 KZGCommitment(self.0.add(&other.0))
81 }
82
83 fn add_assign(&mut self, other: &Self) {
84 self.0.add_assign(&other.0)
85 }
86
87 fn sub(&self, other: &Self) -> Self {
88 KZGCommitment(self.0.sub(&other.0))
89 }
90
91 fn sub_assign(&mut self, other: &Self) {
92 self.0.sub_assign(&other.0)
93 }
94
95 fn mul(&self, exp: &Fr) -> Self {
96 KZGCommitment(self.0.mul(exp))
97 }
98
99 fn mul_assign(&mut self, exp: &Fr) {
100 self.0.mul_assign(exp)
101 }
102}
103
104impl<F: PrimeField> ToBytes for FpPolynomial<F> {
105 fn to_transcript_bytes(&self) -> Vec<u8> {
106 unimplemented!()
107 }
108
109 fn to_bytes(&self) -> Vec<u8> {
110 unimplemented!()
111 }
112}
113
114impl<F: PrimeField> HomomorphicPolyComElem for FpPolynomial<F> {
115 type Scalar = F;
116
117 fn get_base() -> Self {
118 unimplemented!()
119 }
120
121 fn get_identity() -> Self {
122 unimplemented!()
123 }
124
125 fn add(&self, other: &Self) -> Self {
126 self.add(other)
127 }
128
129 fn add_assign(&mut self, other: &Self) {
130 self.add_assign(other)
131 }
132
133 fn sub(&self, other: &Self) -> Self {
134 self.sub(other)
135 }
136
137 fn sub_assign(&mut self, other: &Self) {
138 self.sub_assign(other)
139 }
140
141 fn mul(&self, exp: &F) -> Self {
142 self.mul_scalar(exp)
143 }
144
145 fn mul_assign(&mut self, exp: &F) {
146 self.mul_scalar_assign(exp)
147 }
148}
149
150#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
152pub struct KZGOpenProof<G1: CanonicalSerialize + CanonicalDeserialize>(
153 #[serde(serialize_with = "ark_serialize", deserialize_with = "ark_deserialize")] pub G1,
154);
155
156impl<G: PrimeGroup> ToBytes for KZGOpenProof<G> {
157 fn to_bytes(&self) -> Vec<u8> {
158 let mut buf = Vec::new();
159 self.0.serialize_with_mode(&mut buf, Compress::Yes).unwrap();
160 buf
161 }
162
163 fn to_transcript_bytes(&self) -> Vec<u8> {
164 unimplemented!()
165 }
166}
167
168#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)]
170pub struct KZGCommitmentScheme<P: Pairing> {
171 #[serde(serialize_with = "ark_serialize", deserialize_with = "ark_deserialize")]
173 pub public_parameter_group_1: Vec<P::G1>,
174 #[serde(serialize_with = "ark_serialize", deserialize_with = "ark_deserialize")]
176 pub public_parameter_group_2: Vec<P::G2>,
177}
178
179impl<P: Pairing> KZGCommitmentScheme<P> {
180 pub fn new<R: CryptoRng + RngCore>(max_degree: usize, prng: &mut R) -> KZGCommitmentScheme<P> {
184 let s = P::ScalarField::rand(prng);
185
186 let mut public_parameter_group_1: Vec<P::G1> = Vec::new();
187
188 let mut elem_g1 = P::G1::generator();
189
190 for _ in 0..=max_degree {
191 public_parameter_group_1.push(elem_g1.clone());
192 elem_g1 = elem_g1.mul(&s);
193 }
194
195 let mut public_parameter_group_2: Vec<P::G2> = Vec::new();
196 let elem_g2 = P::G2::generator();
197 public_parameter_group_2.push(elem_g2.clone());
198 public_parameter_group_2.push(elem_g2.mul(&s));
199
200 KZGCommitmentScheme {
201 public_parameter_group_1,
202 public_parameter_group_2,
203 }
204 }
205
206 pub fn to_unchecked_bytes(&self) -> Result<Vec<u8>, UzkgeError> {
208 let mut bytes = vec![];
209 let len_1 = self.public_parameter_group_1.len() as u32;
210 let len_2 = self.public_parameter_group_2.len() as u32;
211 bytes.extend(len_1.to_le_bytes());
212 bytes.extend(len_2.to_le_bytes());
213
214 for i in &self.public_parameter_group_1 {
215 let mut buf = Vec::new();
216 i.serialize_with_mode(&mut buf, Compress::No).unwrap();
217 bytes.extend(buf);
218 }
219 for i in &self.public_parameter_group_2 {
220 let mut buf = Vec::new();
221 i.serialize_with_mode(&mut buf, Compress::No).unwrap();
222 bytes.extend(buf);
223 }
224 Ok(bytes)
225 }
226
227 pub fn from_unchecked_bytes(bytes: &[u8]) -> Result<Self, UzkgeError> {
229 if bytes.len() < 8 {
230 return Err(UzkgeError::DeserializationError);
231 }
232 let mut len_1_bytes = [0u8; 4];
233 let mut len_2_bytes = [0u8; 4];
234 len_1_bytes.copy_from_slice(&bytes[0..4]);
235 len_2_bytes.copy_from_slice(&bytes[4..8]);
236 let len_1 = u32::from_le_bytes(len_1_bytes) as usize;
237 let len_2 = u32::from_le_bytes(len_2_bytes) as usize;
238 let n_1 = P::G1::default().serialized_size(Compress::No);
239 let n_2 = P::G2::default().serialized_size(Compress::No);
240
241 let bytes_1 = &bytes[8..];
242 let bytes_2 = &bytes[8 + (n_1 * len_1)..];
243 let mut p1 = vec![];
244 let mut p2 = vec![];
245
246 for i in 0..len_1 {
247 let reader = &bytes_1[n_1 * i..n_1 * (i + 1)];
248 let g1 = P::G1::deserialize_with_mode(reader, Compress::No, Validate::No)
249 .map_err(|_| UzkgeError::DeserializationError)?;
250 p1.push(g1);
251 }
252
253 for i in 0..len_2 {
254 let reader = &bytes_2[n_2 * i..n_2 * (i + 1)];
255 let g2 = P::G2::deserialize_with_mode(reader, Compress::No, Validate::No)
256 .map_err(|_| UzkgeError::DeserializationError)?;
257 p2.push(g2);
258 }
259
260 Ok(Self {
261 public_parameter_group_1: p1,
262 public_parameter_group_2: p2,
263 })
264 }
265}
266
267pub type KZGCommitmentSchemeBN254 = KZGCommitmentScheme<Bn254>;
269
270impl<'b> PolyComScheme for KZGCommitmentSchemeBN254 {
271 type Field = Fr;
272 type Commitment = KZGCommitment<G1Projective>;
273
274 fn max_degree(&self) -> usize {
275 self.public_parameter_group_1.len() - 1
276 }
277
278 fn commit(&self, polynomial: &FpPolynomial<Fr>) -> Result<Self::Commitment, UzkgeError> {
279 let coefs = polynomial.get_coefs_ref();
280
281 let degree = polynomial.degree();
282
283 if degree + 1 > self.public_parameter_group_1.len() {
284 return Err(UzkgeError::DegreeError);
285 }
286
287 let points_raw =
288 G1Projective::normalize_batch(&self.public_parameter_group_1[0..degree + 1]);
289
290 let commitment_value = G1Projective::msm(&points_raw, &coefs).unwrap();
291
292 Ok(KZGCommitment(commitment_value))
293 }
294
295 fn eval(&self, poly: &FpPolynomial<Self::Field>, point: &Self::Field) -> Self::Field {
296 poly.eval(point)
297 }
298
299 fn apply_blind_factors(
300 &self,
301 commitment: &Self::Commitment,
302 blinds: &[Self::Field],
303 zeroing_degree: usize,
304 ) -> Self::Commitment {
305 let mut commitment = commitment.0.clone();
306 for (i, blind) in blinds.iter().enumerate() {
307 let mut blind = blind.clone();
308 commitment = commitment + &(self.public_parameter_group_1[i] * &blind);
309 blind = blind.neg();
310 commitment = commitment + &(self.public_parameter_group_1[zeroing_degree + i] * &blind);
311 }
312 KZGCommitment(commitment)
313 }
314
315 fn prove(
316 &self,
317 poly: &FpPolynomial<Self::Field>,
318 x: &Self::Field,
319 max_degree: usize,
320 ) -> Result<Self::Commitment, UzkgeError> {
321 let eval = poly.eval(x);
322
323 if poly.degree() > max_degree {
324 return Err(UzkgeError::DegreeError);
325 }
326
327 let nominator = poly.sub(&FpPolynomial::from_coefs(vec![eval]));
328
329 let point_neg = x.neg();
331
332 let vanishing_poly = FpPolynomial::from_coefs(vec![point_neg, Self::Field::one()]);
334 let (q_poly, r_poly) = nominator.div_rem(&vanishing_poly); if !r_poly.is_zero() {
337 return Err(UzkgeError::PCSProveEvalError);
338 }
339
340 let proof = self.commit(&q_poly).unwrap();
341 Ok(proof)
342 }
343
344 fn verify(
345 &self,
346 cm: &Self::Commitment,
347 _degree: usize,
348 point: &Self::Field,
349 eval: &Self::Field,
350 proof: &Self::Commitment,
351 ) -> Result<(), UzkgeError> {
352 let g1_0 = self.public_parameter_group_1[0].clone();
353 let g2_0 = self.public_parameter_group_2[0].clone();
354 let g2_1 = self.public_parameter_group_2[1].clone();
355
356 let x_minus_point_group_element_group_2 = &g2_1.sub(&g2_0.mul(point));
357
358 let left_pairing_eval = if eval.is_zero() {
359 Bn254::pairing(&cm.0, &g2_0)
360 } else {
361 Bn254::pairing(&cm.0.sub(&g1_0.mul(eval)), &g2_0)
362 };
363
364 let right_pairing_eval = Bn254::pairing(&proof.0, x_minus_point_group_element_group_2);
365
366 if left_pairing_eval == right_pairing_eval {
367 Ok(())
368 } else {
369 Err(UzkgeError::PCSProveEvalError)
370 }
371 }
372
373 fn batch_verify_diff_points(
374 &self,
375 cm_vec: &[Self::Commitment],
376 point_vec: &[Self::Field],
377 eval_vec: &[Self::Field],
378 proofs: &[Self::Commitment],
379 challenge: &Self::Field,
380 ) -> Result<(), UzkgeError> {
381 assert!(proofs.len() > 0);
382 assert_eq!(proofs.len(), point_vec.len());
383 assert_eq!(proofs.len(), eval_vec.len());
384 assert_eq!(proofs.len(), cm_vec.len());
385
386 let g1_0 = self.public_parameter_group_1[0].clone();
387 let g2_0 = self.public_parameter_group_2[0].clone();
388 let g2_1 = self.public_parameter_group_2[1].clone();
389
390 let left_second = g2_1;
391 let right_second = g2_0;
392
393 let mut left_first = proofs[0].0.clone();
394 let mut right_first = proofs[0].0.mul(&point_vec[0]);
395 let mut right_first_val = eval_vec[0].clone();
396 let mut right_first_comm = cm_vec[0].0.clone();
397
398 let mut cur_challenge = challenge.clone();
399 for i in 1..proofs.len() {
400 let new_comm = proofs[i].0.mul(&cur_challenge);
401
402 left_first.add_assign(&new_comm);
403 right_first.add_assign(&new_comm.mul(&point_vec[i]));
404 right_first_val.add_assign(&eval_vec[i].mul(&cur_challenge));
405 right_first_comm.add_assign(&cm_vec[i].0.mul(&cur_challenge));
406
407 cur_challenge.mul_assign(challenge);
408 }
409 right_first.sub_assign(&g1_0.mul(&right_first_val));
410 right_first.add_assign(&right_first_comm);
411
412 let pairing_eval = Bn254::multi_pairing(
413 &[left_first, right_first.neg()],
414 &[left_second, right_second],
415 )
416 .0;
417
418 if pairing_eval == Fp12::<Fq12Config>::one() {
419 Ok(())
420 } else {
421 Err(UzkgeError::PCSProveEvalError)
422 }
423 }
424
425 fn shrink_to_verifier_only(&self) -> Result<Self, UzkgeError> {
426 Ok(Self {
427 public_parameter_group_1: vec![self.public_parameter_group_1[0].clone()],
428 public_parameter_group_2: vec![
429 self.public_parameter_group_2[0].clone(),
430 self.public_parameter_group_2[1].clone(),
431 ],
432 })
433 }
434}
435
436#[cfg(test)]
437mod tests_kzg_impl {
438 use ark_std::rand::SeedableRng;
439 use rand_chacha::ChaChaRng;
440
441 use super::*;
442
443 fn check_public_parameters_generation<P: Pairing>() {
444 let param_size = 5;
445 let mut prng = ChaChaRng::from_entropy();
446 let kzg_scheme = KZGCommitmentScheme::<P>::new(param_size, &mut prng);
447 let g1_power1 = kzg_scheme.public_parameter_group_1[1].clone();
448 let g2_power1 = kzg_scheme.public_parameter_group_2[1].clone();
449
450 for i in 0..param_size - 1 {
452 let elem_first_group_1 = kzg_scheme.public_parameter_group_1[i].clone();
453 let elem_next_group_1 = kzg_scheme.public_parameter_group_1[i + 1].clone();
454 let elem_next_group_1_target = P::pairing(&elem_next_group_1, &P::G2::generator());
455 let elem_next_group_1_target_recomputed = P::pairing(&elem_first_group_1, &g2_power1);
456 assert_eq!(
457 elem_next_group_1_target_recomputed,
458 elem_next_group_1_target
459 );
460 }
461
462 let elem_first_group_2 = kzg_scheme.public_parameter_group_2[0].clone();
464 let elem_second_group_2 = kzg_scheme.public_parameter_group_2[1].clone();
465 let elem_next_group_2_target = P::pairing(&P::G1::generator(), &elem_second_group_2);
466 let elem_next_group_2_target_recomputed = P::pairing(&g1_power1, &elem_first_group_2);
467
468 assert_eq!(
469 elem_next_group_2_target_recomputed,
470 elem_next_group_2_target
471 );
472 }
473
474 fn generation_of_crs<P: Pairing>() {
476 let n = 1 << 5;
477 let mut prng = ChaChaRng::from_entropy();
478 let kzg_scheme = KZGCommitmentScheme::<P>::new(n, &mut prng);
479 assert_eq!(kzg_scheme.public_parameter_group_1.len(), n + 1);
480 assert_eq!(kzg_scheme.public_parameter_group_2.len(), 2);
481 }
482
483 #[test]
484 fn test_homomorphic_poly_com_elem() {
485 let mut prng = ChaChaRng::from_entropy();
486 let pcs = KZGCommitmentSchemeBN254::new(20, &mut prng);
487 type Field = Fr;
488 let one = Field::one();
489 let two = one.add(&one);
490 let three = two.add(&one);
491 let four = three.add(&one);
492 let six = three.add(&three);
493 let eight = six.add(&two);
494 let poly1 = FpPolynomial::from_coefs(vec![two, three, six]);
495
496 let commitment1 = pcs.commit(&poly1).unwrap();
497
498 let poly2 = FpPolynomial::from_coefs(vec![one, eight, four]);
499
500 let commitment2 = pcs.commit(&poly2).unwrap();
501
502 let poly_sum = poly1.add(&poly2);
504 let commitment_sum = pcs.commit(&poly_sum).unwrap();
505 let commitment_sum_computed = commitment1.add(&commitment2);
506 assert_eq!(commitment_sum, commitment_sum_computed);
507
508 let exponent = four.add(&one);
510 let poly1_mult_5 = poly1.mul_scalar(&exponent);
511 let commitment_poly1_mult_5 = pcs.commit(&poly1_mult_5).unwrap();
512 let commitment_poly1_mult_5_hom = commitment1.mul(&exponent);
513 assert_eq!(commitment_poly1_mult_5, commitment_poly1_mult_5_hom);
514 }
515
516 #[test]
517 fn test_public_parameters() {
518 check_public_parameters_generation::<Bn254>();
519 }
520
521 #[test]
522 fn test_generation_of_crs() {
523 generation_of_crs::<Bn254>();
524 }
525
526 #[test]
527 fn test_commit() {
528 let mut prng = ChaChaRng::from_entropy();
529 let pcs = KZGCommitmentSchemeBN254::new(10, &mut prng);
530 type Field = Fr;
531 let one = Field::one();
532 let two = one.add(&one);
533 let three = two.add(&one);
534 let six = three.add(&three);
535
536 let fq_poly = FpPolynomial::from_coefs(vec![two, three, six]);
537 let commitment = pcs.commit(&fq_poly).unwrap();
538
539 let coefs_poly_scalar: Vec<_> = fq_poly.get_coefs_ref().iter().cloned().collect();
540 let mut expected_committed_value = G1Projective::zero();
541
542 for (i, coef) in coefs_poly_scalar.iter().enumerate() {
544 let g_i = pcs.public_parameter_group_1[i].clone();
545 expected_committed_value = expected_committed_value.add(&g_i.mul(coef));
546 }
547 assert_eq!(expected_committed_value, commitment.0);
548 }
549
550 #[test]
551 fn test_eval() {
552 let mut prng = ChaChaRng::from_entropy();
553 let pcs = KZGCommitmentSchemeBN254::new(10, &mut prng);
554 type Field = Fr;
555 let one = Field::one();
556 let two = one.add(&one);
557 let three = two.add(&one);
558 let four = three.add(&one);
559 let six = three.add(&three);
560 let seven = six.add(&one);
561 let fq_poly = FpPolynomial::from_coefs(vec![one, two, four]);
562 let point = one;
563 let max_degree = fq_poly.degree();
564
565 let degree = fq_poly.degree();
566 let commitment_value = pcs.commit(&fq_poly).unwrap();
567
568 let wrong_max_degree = 1;
570 let res = pcs.prove(&fq_poly, &point, wrong_max_degree);
571 assert!(res.is_err());
572
573 let proof = pcs.prove(&fq_poly, &point, max_degree).unwrap();
574
575 pcs.verify(&commitment_value, degree, &point, &seven, &proof)
576 .unwrap();
577
578 let new_pcs = pcs.shrink_to_verifier_only().unwrap();
579 new_pcs
580 .verify(&commitment_value, degree, &point, &seven, &proof)
581 .unwrap();
582
583 let wrong_eval = one;
584 let res = pcs.verify(&commitment_value, degree, &point, &wrong_eval, &proof);
585 assert!(res.is_err());
586 }
587}