1use super::{proof::Proof, Commitment};
11use crate::{
12 error::Error, fft::Polynomial, transcript::TranscriptProtocol, util,
13};
14use dusk_bls12_381::{
15 multiscalar_mul::msm_variable_base, BlsScalar, G1Affine, G1Projective,
16 G2Affine, G2Prepared,
17};
18use dusk_bytes::{DeserializableSlice, Serializable};
19use merlin::Transcript;
20use parity_scale_codec::{Decode, Encode};
21use serde::{Deserialize, Deserializer, Serialize, Serializer};
22use sp_std::vec;
23use sp_std::vec::Vec;
24
25#[derive(Debug, Clone, PartialEq, Encode, Decode, Serialize, Deserialize)]
28pub struct CommitKey {
29 #[serde(
32 serialize_with = "serialize_powers_of_g",
33 deserialize_with = "deserialize_powers_of_g"
34 )]
35 pub(crate) powers_of_g: Vec<G1Affine>,
36}
37
38fn serialize_powers_of_g<S>(
39 powers_of_g: &Vec<G1Affine>,
40 se: S,
41) -> Result<S::Ok, S::Error>
42where
43 S: Serializer,
44{
45 use serde::ser::SerializeSeq;
46 let mut seq = se.serialize_seq(Some(powers_of_g.len()))?;
47 for coeff in powers_of_g {
48 seq.serialize_element(coeff)?;
49 }
50 seq.end()
51}
52
53fn deserialize_powers_of_g<'de, D>(de: D) -> Result<Vec<G1Affine>, D::Error>
54where
55 D: Deserializer<'de>,
56{
57 let s = Deserialize::deserialize(de).unwrap();
58 Ok(vec![s])
59}
60
61impl CommitKey {
62 pub fn to_raw_var_bytes(&self) -> Vec<u8> {
75 let mut bytes = Vec::with_capacity(
76 u64::SIZE + self.powers_of_g.len() * G1Affine::RAW_SIZE,
77 );
78
79 let len = self.powers_of_g.len() as u64;
80 let len = len.to_le_bytes();
81 bytes.extend_from_slice(&len);
82
83 self.powers_of_g
84 .iter()
85 .for_each(|g| bytes.extend_from_slice(&g.to_raw_bytes()));
86
87 bytes
88 }
89
90 pub unsafe fn from_slice_unchecked(bytes: &[u8]) -> Self {
102 let mut len = [0u8; u64::SIZE];
103 len.copy_from_slice(&bytes[..u64::SIZE]);
104 let len = u64::from_le_bytes(len);
105
106 let powers_of_g = bytes[u64::SIZE..]
107 .chunks_exact(G1Affine::RAW_SIZE)
108 .zip(0..len)
109 .map(|(c, _)| G1Affine::from_slice_unchecked(c))
110 .collect();
111
112 Self { powers_of_g }
113 }
114
115 pub fn to_var_bytes(&self) -> Vec<u8> {
117 self.powers_of_g
118 .iter()
119 .flat_map(|item| item.to_bytes().to_vec())
120 .collect()
121 }
122
123 pub fn from_slice(bytes: &[u8]) -> Result<CommitKey, Error> {
133 let powers_of_g = bytes
134 .chunks(G1Affine::SIZE)
135 .map(|chunk| G1Affine::from_slice(chunk))
136 .collect::<Result<Vec<G1Affine>, dusk_bytes::Error>>()?;
137
138 Ok(CommitKey { powers_of_g })
139 }
140
141 pub(crate) fn max_degree(&self) -> usize {
143 self.powers_of_g.len() - 1
144 }
145
146 pub(crate) fn truncate(
150 &self,
151 mut truncated_degree: usize,
152 ) -> Result<CommitKey, Error> {
153 match truncated_degree {
154 0 => Err(Error::TruncatedDegreeIsZero),
156 i if i > self.max_degree() => Err(Error::TruncatedDegreeTooLarge),
158 i => {
159 if i == 1 {
160 truncated_degree += 1
161 };
162 let truncated_powers = Self {
163 powers_of_g: self.powers_of_g[..=truncated_degree].to_vec(),
164 };
165 Ok(truncated_powers)
166 }
167 }
168 }
169
170 fn check_commit_degree_is_within_bounds(
176 &self,
177 poly_degree: usize,
178 ) -> Result<(), Error> {
179 match (poly_degree == 0, poly_degree > self.max_degree()) {
180 (true, _) => Err(Error::PolynomialDegreeIsZero),
181 (false, true) => Err(Error::PolynomialDegreeTooLarge),
182 (false, false) => Ok(()),
183 }
184 }
185
186 pub(crate) fn commit(
191 &self,
192 polynomial: &Polynomial,
193 ) -> Result<Commitment, Error> {
194 self.check_commit_degree_is_within_bounds(polynomial.degree())?;
196
197 Ok(Commitment::from(msm_variable_base(
199 &self.powers_of_g,
200 &polynomial.coeffs,
201 )))
202 }
203
204 pub(crate) fn compute_aggregate_witness(
209 &self,
210 polynomials: &[Polynomial],
211 point: &BlsScalar,
212 transcript: &mut Transcript,
213 ) -> Polynomial {
214 let challenge = transcript.challenge_scalar(b"aggregate_witness");
215 let powers = util::powers_of(&challenge, polynomials.len() - 1);
216
217 assert_eq!(powers.len(), polynomials.len());
218
219 let numerator: Polynomial = polynomials
220 .iter()
221 .zip(powers.iter())
222 .map(|(poly, challenge)| poly * challenge)
223 .sum();
224 numerator.ruffini(*point)
225 }
226}
227
228#[derive(Clone, Debug, Encode, Decode, Serialize, Deserialize, PartialEq)]
231pub struct OpeningKey {
232 pub(crate) g: G1Affine,
234 pub(crate) h: G2Affine,
236 pub(crate) beta_h: G2Affine,
238 pub(crate) prepared_h: G2Prepared,
240 pub(crate) prepared_beta_h: G2Prepared,
242}
243
244impl Serializable<{ G1Affine::SIZE + G2Affine::SIZE * 2 }> for OpeningKey {
245 type Error = dusk_bytes::Error;
246 #[allow(unused_must_use)]
247 fn to_bytes(&self) -> [u8; Self::SIZE] {
248 use dusk_bytes::Write;
249 let mut buf = [0u8; Self::SIZE];
250 let mut writer = &mut buf[..];
251 writer.write(&self.g.to_bytes());
253 writer.write(&self.h.to_bytes());
254 writer.write(&self.beta_h.to_bytes());
255
256 buf
257 }
258
259 fn from_bytes(buf: &[u8; Self::SIZE]) -> Result<Self, Self::Error> {
260 let mut buffer = &buf[..];
261 let g = G1Affine::from_reader(&mut buffer)?;
262 let h = G2Affine::from_reader(&mut buffer)?;
263 let beta_h = G2Affine::from_reader(&mut buffer)?;
264
265 Ok(Self::new(g, h, beta_h))
266 }
267}
268
269impl OpeningKey {
270 pub(crate) fn new(
271 g: G1Affine,
272 h: G2Affine,
273 beta_h: G2Affine,
274 ) -> OpeningKey {
275 let prepared_h = G2Prepared::from(h);
276 let prepared_beta_h = G2Prepared::from(beta_h);
277 OpeningKey {
278 g,
279 h,
280 beta_h,
281 prepared_h,
282 prepared_beta_h,
283 }
284 }
285
286 pub(crate) fn batch_check(
289 &self,
290 points: &[BlsScalar],
291 proofs: &[Proof],
292 transcript: &mut Transcript,
293 ) -> Result<(), Error> {
294 let mut total_c = G1Projective::identity();
295 let mut total_w = G1Projective::identity();
296
297 let challenge = transcript.challenge_scalar(b"batch"); let powers = util::powers_of(&challenge, proofs.len() - 1);
299 let mut g_multiplier = BlsScalar::zero();
303
304 for ((proof, challenge), point) in proofs.iter().zip(powers).zip(points)
305 {
306 let mut c = G1Projective::from(proof.commitment_to_polynomial.0);
307 let w = proof.commitment_to_witness.0;
308 c += w * point;
309 g_multiplier += challenge * proof.evaluated_point;
310
311 total_c += c * challenge;
312 total_w += w * challenge;
313 }
314 total_c -= self.g * g_multiplier;
315
316 let affine_total_w = G1Affine::from(-total_w);
317 let affine_total_c = G1Affine::from(total_c);
318
319 let pairing = dusk_bls12_381::multi_miller_loop(&[
320 (&affine_total_w, &self.prepared_beta_h),
321 (&affine_total_c, &self.prepared_h),
322 ])
323 .final_exponentiation();
324
325 if pairing != dusk_bls12_381::Gt::identity() {
326 return Err(Error::PairingCheckFailure);
327 };
328 Ok(())
329 }
330}
331
332#[cfg(feature = "std")]
333#[cfg(test)]
334mod test {
335 use super::*;
336 use crate::commitment_scheme::{AggregateProof, PublicParameters};
337 use crate::fft::Polynomial;
338 use dusk_bls12_381::BlsScalar;
339 use dusk_bytes::Serializable;
340 use merlin::Transcript;
341 use rand_core::OsRng;
342
343 fn check(op_key: &OpeningKey, point: BlsScalar, proof: Proof) -> bool {
346 let inner_a: G1Affine = (proof.commitment_to_polynomial.0
347 - (op_key.g * proof.evaluated_point))
348 .into();
349
350 let inner_b: G2Affine = (op_key.beta_h - (op_key.h * point)).into();
351 let prepared_inner_b = G2Prepared::from(-inner_b);
352
353 let pairing = dusk_bls12_381::multi_miller_loop(&[
354 (&inner_a, &op_key.prepared_h),
355 (&proof.commitment_to_witness.0, &prepared_inner_b),
356 ])
357 .final_exponentiation();
358
359 pairing == dusk_bls12_381::Gt::identity()
360 }
361
362 fn open_single(
366 ck: &CommitKey,
367 polynomial: &Polynomial,
368 value: &BlsScalar,
369 point: &BlsScalar,
370 ) -> Result<Proof, Error> {
371 let witness_poly = compute_single_witness(polynomial, point);
372 Ok(Proof {
373 commitment_to_witness: ck.commit(&witness_poly)?,
374 evaluated_point: *value,
375 commitment_to_polynomial: ck.commit(polynomial)?,
376 })
377 }
378
379 fn open_multiple(
384 ck: &CommitKey,
385 polynomials: &[Polynomial],
386 evaluations: Vec<BlsScalar>,
387 point: &BlsScalar,
388 transcript: &mut Transcript,
389 ) -> Result<AggregateProof, Error> {
390 let mut polynomial_commitments = Vec::with_capacity(polynomials.len());
392 for poly in polynomials.iter() {
393 polynomial_commitments.push(ck.commit(poly)?)
394 }
395
396 let witness_poly =
398 ck.compute_aggregate_witness(polynomials, point, transcript);
399
400 let witness_commitment = ck.commit(&witness_poly)?;
402
403 let aggregate_proof = AggregateProof {
404 commitment_to_witness: witness_commitment,
405 evaluated_points: evaluations,
406 commitments_to_polynomials: polynomial_commitments,
407 };
408 Ok(aggregate_proof)
409 }
410
411 fn compute_single_witness(
419 polynomial: &Polynomial,
420 point: &BlsScalar,
421 ) -> Polynomial {
422 polynomial.ruffini(*point)
424 }
425
426 fn setup_test(degree: usize) -> Result<(CommitKey, OpeningKey), Error> {
428 let srs = PublicParameters::setup(degree, &mut OsRng)?;
429 srs.trim(degree)
430 }
431 #[test]
432 fn test_basic_commit() -> Result<(), Error> {
433 let degree = 25;
434 let (ck, opening_key) = setup_test(degree)?;
435 let point = BlsScalar::from(10);
436
437 let poly = Polynomial::rand(degree, &mut OsRng);
438 let value = poly.evaluate(&point);
439
440 let proof = open_single(&ck, &poly, &value, &point)?;
441
442 let ok = check(&opening_key, point, proof);
443 assert!(ok);
444 Ok(())
445 }
446 #[test]
447 fn test_batch_verification() -> Result<(), Error> {
448 let degree = 25;
449 let (ck, vk) = setup_test(degree)?;
450
451 let point_a = BlsScalar::from(10);
452 let point_b = BlsScalar::from(11);
453
454 let poly_a = Polynomial::rand(degree, &mut OsRng);
456 let value_a = poly_a.evaluate(&point_a);
457 let proof_a = open_single(&ck, &poly_a, &value_a, &point_a)?;
458 assert!(check(&vk, point_a, proof_a));
459
460 let poly_b = Polynomial::rand(degree, &mut OsRng);
462 let value_b = poly_b.evaluate(&point_b);
463 let proof_b = open_single(&ck, &poly_b, &value_b, &point_b)?;
464 assert!(check(&vk, point_b, proof_b));
465
466 vk.batch_check(
467 &[point_a, point_b],
468 &[proof_a, proof_b],
469 &mut Transcript::new(b""),
470 )
471 }
472 #[test]
473 fn test_aggregate_witness() -> Result<(), Error> {
474 let max_degree = 27;
475 let (ck, opening_key) = setup_test(max_degree)?;
476 let point = BlsScalar::from(10);
477
478 let aggregated_proof = {
480 let poly_a = Polynomial::rand(25, &mut OsRng);
482 let poly_a_eval = poly_a.evaluate(&point);
483
484 let poly_b = Polynomial::rand(26 + 1, &mut OsRng);
485 let poly_b_eval = poly_b.evaluate(&point);
486
487 let poly_c = Polynomial::rand(27, &mut OsRng);
488 let poly_c_eval = poly_c.evaluate(&point);
489
490 open_multiple(
491 &ck,
492 &[poly_a, poly_b, poly_c],
493 vec![poly_a_eval, poly_b_eval, poly_c_eval],
494 &point,
495 &mut Transcript::new(b"agg_flatten"),
496 )?
497 };
498
499 let ok = {
501 let flattened_proof =
502 aggregated_proof.flatten(&mut Transcript::new(b"agg_flatten"));
503 check(&opening_key, point, flattened_proof)
504 };
505
506 assert!(ok);
507 Ok(())
508 }
509
510 #[test]
511 fn test_batch_with_aggregation() -> Result<(), Error> {
512 let max_degree = 28;
513 let (ck, opening_key) = setup_test(max_degree)?;
514 let point_a = BlsScalar::from(10);
515 let point_b = BlsScalar::from(11);
516
517 let (aggregated_proof, single_proof) = {
519 let poly_a = Polynomial::rand(25, &mut OsRng);
521 let poly_a_eval = poly_a.evaluate(&point_a);
522
523 let poly_b = Polynomial::rand(26, &mut OsRng);
524 let poly_b_eval = poly_b.evaluate(&point_a);
525
526 let poly_c = Polynomial::rand(27, &mut OsRng);
527 let poly_c_eval = poly_c.evaluate(&point_a);
528
529 let poly_d = Polynomial::rand(28, &mut OsRng);
530 let poly_d_eval = poly_d.evaluate(&point_b);
531
532 let aggregated_proof = open_multiple(
533 &ck,
534 &[poly_a, poly_b, poly_c],
535 vec![poly_a_eval, poly_b_eval, poly_c_eval],
536 &point_a,
537 &mut Transcript::new(b"agg_batch"),
538 )?;
539
540 let single_proof =
541 open_single(&ck, &poly_d, &poly_d_eval, &point_b)?;
542
543 (aggregated_proof, single_proof)
544 };
545
546 let mut transcript = Transcript::new(b"agg_batch");
549 let flattened_proof = aggregated_proof.flatten(&mut transcript);
550
551 opening_key.batch_check(
552 &[point_a, point_b],
553 &[flattened_proof, single_proof],
554 &mut transcript,
555 )
556 }
557
558 #[test]
559 fn commit_key_serde() -> Result<(), Error> {
560 let (commit_key, _) = setup_test(11)?;
561 let ck_bytes = commit_key.to_var_bytes();
562 let ck_bytes_safe = CommitKey::from_slice(&ck_bytes)?;
563
564 assert_eq!(commit_key.powers_of_g, ck_bytes_safe.powers_of_g);
565 Ok(())
566 }
567
568 #[test]
569 fn opening_key_dusk_bytes() -> Result<(), Error> {
570 let (_, opening_key) = setup_test(7)?;
571 let ok_bytes = opening_key.to_bytes();
572 let obtained_key = OpeningKey::from_bytes(&ok_bytes)?;
573
574 assert_eq!(opening_key.to_bytes(), obtained_key.to_bytes());
575 Ok(())
576 }
577
578 #[test]
579 fn commit_key_bytes_unchecked() -> Result<(), Error> {
580 let (ck, _) = setup_test(7)?;
581
582 let ck_p = unsafe {
583 let bytes = ck.to_raw_var_bytes();
584 CommitKey::from_slice_unchecked(&bytes)
585 };
586
587 assert_eq!(ck, ck_p);
588 Ok(())
589 }
590}