1use super::linearisation_poly::ProofEvaluations;
14use crate::commitment_scheme::Commitment;
15use dusk_bytes::{DeserializableSlice, Serializable};
16use parity_scale_codec::{Decode, Encode};
17
18#[derive(Debug, Eq, PartialEq, Clone, Default, Decode, Encode)]
29pub struct Proof {
30 pub(crate) a_comm: Commitment,
32 pub(crate) b_comm: Commitment,
34 pub(crate) c_comm: Commitment,
36 pub(crate) d_comm: Commitment,
38
39 pub(crate) f_comm: Commitment,
41
42 pub(crate) h_1_comm: Commitment,
44
45 pub(crate) h_2_comm: Commitment,
47
48 pub(crate) z_comm: Commitment,
50
51 pub(crate) p_comm: Commitment,
53
54 pub(crate) t_1_comm: Commitment,
56 pub(crate) t_2_comm: Commitment,
58 pub(crate) t_3_comm: Commitment,
60 pub(crate) t_4_comm: Commitment,
62
63 pub(crate) w_z_comm: Commitment,
65 pub(crate) w_zw_comm: Commitment,
67 pub(crate) evaluations: ProofEvaluations,
69}
70
71impl Serializable<{ 15 * Commitment::SIZE + ProofEvaluations::SIZE }>
72 for Proof
73{
74 type Error = dusk_bytes::Error;
75
76 #[allow(unused_must_use)]
77 fn to_bytes(&self) -> [u8; Self::SIZE] {
78 use dusk_bytes::Write;
79
80 let mut buf = [0u8; Self::SIZE];
81 let mut writer = &mut buf[..];
82 writer.write(&self.a_comm.to_bytes());
83 writer.write(&self.b_comm.to_bytes());
84 writer.write(&self.c_comm.to_bytes());
85 writer.write(&self.d_comm.to_bytes());
86 writer.write(&self.f_comm.to_bytes());
87 writer.write(&self.h_1_comm.to_bytes());
88 writer.write(&self.h_2_comm.to_bytes());
89 writer.write(&self.z_comm.to_bytes());
90 writer.write(&self.p_comm.to_bytes());
91 writer.write(&self.t_1_comm.to_bytes());
92 writer.write(&self.t_2_comm.to_bytes());
93 writer.write(&self.t_3_comm.to_bytes());
94 writer.write(&self.t_4_comm.to_bytes());
95 writer.write(&self.w_z_comm.to_bytes());
96 writer.write(&self.w_zw_comm.to_bytes());
97 writer.write(&self.evaluations.to_bytes());
98
99 buf
100 }
101
102 fn from_bytes(buf: &[u8; Self::SIZE]) -> Result<Self, Self::Error> {
103 let mut buffer = &buf[..];
104
105 let a_comm = Commitment::from_reader(&mut buffer)?;
106 let b_comm = Commitment::from_reader(&mut buffer)?;
107 let c_comm = Commitment::from_reader(&mut buffer)?;
108 let d_comm = Commitment::from_reader(&mut buffer)?;
109 let f_comm = Commitment::from_reader(&mut buffer)?;
110 let h_1_comm = Commitment::from_reader(&mut buffer)?;
111 let h_2_comm = Commitment::from_reader(&mut buffer)?;
112 let z_comm = Commitment::from_reader(&mut buffer)?;
113 let p_comm = Commitment::from_reader(&mut buffer)?;
114 let t_1_comm = Commitment::from_reader(&mut buffer)?;
115 let t_2_comm = Commitment::from_reader(&mut buffer)?;
116 let t_3_comm = Commitment::from_reader(&mut buffer)?;
117 let t_4_comm = Commitment::from_reader(&mut buffer)?;
118 let w_z_comm = Commitment::from_reader(&mut buffer)?;
119 let w_zw_comm = Commitment::from_reader(&mut buffer)?;
120 let evaluations = ProofEvaluations::from_reader(&mut buffer)?;
121
122 Ok(Proof {
123 a_comm,
124 b_comm,
125 c_comm,
126 d_comm,
127 f_comm,
128 h_1_comm,
129 h_2_comm,
130 z_comm,
131 p_comm,
132 t_1_comm,
133 t_2_comm,
134 t_3_comm,
135 t_4_comm,
136 w_z_comm,
137 w_zw_comm,
138 evaluations,
139 })
140 }
141}
142
143use crate::{
144 commitment_scheme::{AggregateProof, OpeningKey},
145 error::Error,
146 fft::EvaluationDomain,
147 proof_system::widget::VerifierKey,
148 transcript::TranscriptProtocol,
149 util::batch_inversion,
150};
151use dusk_bls12_381::{multiscalar_mul::msm_variable_base, BlsScalar, G1Affine};
152use merlin::Transcript;
153use sp_std::vec::Vec;
154
155impl Proof {
156 pub(crate) fn verify(
158 &self,
159 verifier_key: &VerifierKey,
160 transcript: &mut Transcript,
161 opening_key: &OpeningKey,
162 pub_inputs: &[BlsScalar],
163 ) -> Result<(), Error> {
164 let domain = EvaluationDomain::new(verifier_key.n as usize)?;
165
166 transcript.append_commitment(b"w_l", &self.a_comm);
177 transcript.append_commitment(b"w_r", &self.b_comm);
178 transcript.append_commitment(b"w_o", &self.c_comm);
179 transcript.append_commitment(b"w_4", &self.d_comm);
180
181 let zeta = transcript.challenge_scalar(b"zeta");
183
184 transcript.append_commitment(b"f", &self.f_comm);
186
187 let beta = transcript.challenge_scalar(b"beta");
189 transcript.append_scalar(b"beta", &beta);
190 let gamma = transcript.challenge_scalar(b"gamma");
191 let delta = transcript.challenge_scalar(b"delta");
193 let epsilon = transcript.challenge_scalar(b"epsilon");
194
195 transcript.append_commitment(b"z", &self.z_comm);
197
198 let z_challenge = transcript.challenge_scalar(b"z_challenge");
200
201 transcript.append_commitment(b"h1", &self.h_1_comm);
203 transcript.append_commitment(b"h2", &self.h_2_comm);
204
205 transcript.append_commitment(b"p", &self.p_comm);
207
208 let alpha = transcript.challenge_scalar(b"alpha");
210 let range_sep_challenge =
211 transcript.challenge_scalar(b"range separation challenge");
212 let logic_sep_challenge =
213 transcript.challenge_scalar(b"logic separation challenge");
214 let fixed_base_sep_challenge =
215 transcript.challenge_scalar(b"fixed base separation challenge");
216 let var_base_sep_challenge =
217 transcript.challenge_scalar(b"variable base separation challenge");
218 let lookup_sep_challenge =
219 transcript.challenge_scalar(b"lookup challenge");
220
221 transcript.append_commitment(b"t_1", &self.t_1_comm);
223 transcript.append_commitment(b"t_2", &self.t_2_comm);
224 transcript.append_commitment(b"t_3", &self.t_3_comm);
225 transcript.append_commitment(b"t_4", &self.t_4_comm);
226
227 let z_h_eval = domain.evaluate_vanishing_polynomial(&z_challenge);
229
230 let l1_eval =
232 compute_first_lagrange_evaluation(&domain, &z_h_eval, &z_challenge);
233
234 let table_comm = Commitment(G1Affine::from(
235 verifier_key.lookup.table_1.0
236 + verifier_key.lookup.table_2.0 * zeta
237 + verifier_key.lookup.table_3.0 * zeta * zeta
238 + verifier_key.lookup.table_4.0 * zeta * zeta * zeta,
239 ));
240
241 let t_eval = self.compute_quotient_evaluation(
243 &domain,
244 pub_inputs,
245 &alpha,
246 &beta,
247 &gamma,
248 &delta,
249 &epsilon,
250 &z_challenge,
251 &z_h_eval,
252 &l1_eval,
253 &self.evaluations.perm_eval,
254 &lookup_sep_challenge,
255 );
256
257 let t_comm =
261 self.compute_quotient_commitment(&z_challenge, domain.size());
262
263 transcript.append_scalar(b"a_eval", &self.evaluations.a_eval);
265 transcript.append_scalar(b"b_eval", &self.evaluations.b_eval);
266 transcript.append_scalar(b"c_eval", &self.evaluations.c_eval);
267 transcript.append_scalar(b"d_eval", &self.evaluations.d_eval);
268 transcript.append_scalar(b"a_next_eval", &self.evaluations.a_next_eval);
269 transcript.append_scalar(b"b_next_eval", &self.evaluations.b_next_eval);
270 transcript.append_scalar(b"d_next_eval", &self.evaluations.d_next_eval);
271 transcript
272 .append_scalar(b"left_sig_eval", &self.evaluations.left_sigma_eval);
273 transcript.append_scalar(
274 b"right_sig_eval",
275 &self.evaluations.right_sigma_eval,
276 );
277 transcript
278 .append_scalar(b"out_sig_eval", &self.evaluations.out_sigma_eval);
279 transcript
280 .append_scalar(b"q_arith_eval", &self.evaluations.q_arith_eval);
281 transcript.append_scalar(b"q_c_eval", &self.evaluations.q_c_eval);
282 transcript.append_scalar(b"q_l_eval", &self.evaluations.q_l_eval);
283 transcript.append_scalar(b"q_r_eval", &self.evaluations.q_r_eval);
284 transcript
285 .append_scalar(b"q_lookup_eval", &self.evaluations.q_lookup_eval);
286 transcript.append_scalar(b"perm_eval", &self.evaluations.perm_eval);
287 transcript.append_scalar(
288 b"lookup_perm_eval",
289 &self.evaluations.lookup_perm_eval,
290 );
291 transcript.append_scalar(b"h_1_eval", &self.evaluations.h_1_eval);
292 transcript
293 .append_scalar(b"h_1_next_eval", &self.evaluations.h_1_next_eval);
294 transcript.append_scalar(b"h_2_eval", &self.evaluations.h_2_eval);
295 transcript.append_scalar(b"t_eval", &t_eval);
296 transcript.append_scalar(b"r_eval", &self.evaluations.lin_poly_eval);
297
298 let r_comm = self.compute_linearisation_commitment(
300 &alpha,
301 &beta,
302 &gamma,
303 &delta,
304 &epsilon,
305 &zeta,
306 (
307 &range_sep_challenge,
308 &logic_sep_challenge,
309 &fixed_base_sep_challenge,
310 &var_base_sep_challenge,
311 &lookup_sep_challenge,
312 ),
313 &z_challenge,
314 l1_eval,
315 self.evaluations.table_eval,
316 self.evaluations.table_next_eval,
317 verifier_key,
318 );
319
320 let mut aggregate_proof = AggregateProof::with_witness(self.w_z_comm);
331 aggregate_proof.add_part((t_eval, t_comm));
332 aggregate_proof.add_part((self.evaluations.lin_poly_eval, r_comm));
333 aggregate_proof.add_part((self.evaluations.a_eval, self.a_comm));
334 aggregate_proof.add_part((self.evaluations.b_eval, self.b_comm));
335 aggregate_proof.add_part((self.evaluations.c_eval, self.c_comm));
336 aggregate_proof.add_part((self.evaluations.d_eval, self.d_comm));
337 aggregate_proof.add_part((
338 self.evaluations.left_sigma_eval,
339 verifier_key.permutation.left_sigma,
340 ));
341 aggregate_proof.add_part((
342 self.evaluations.right_sigma_eval,
343 verifier_key.permutation.right_sigma,
344 ));
345 aggregate_proof.add_part((
346 self.evaluations.out_sigma_eval,
347 verifier_key.permutation.out_sigma,
348 ));
349 aggregate_proof.add_part((self.evaluations.f_eval, self.f_comm));
350 aggregate_proof.add_part((self.evaluations.h_1_eval, self.h_1_comm));
351 aggregate_proof.add_part((self.evaluations.h_2_eval, self.h_2_comm));
352 aggregate_proof.add_part((self.evaluations.table_eval, table_comm));
353 let flattened_proof_a = aggregate_proof.flatten(transcript);
355
356 let mut shifted_aggregate_proof =
358 AggregateProof::with_witness(self.w_zw_comm);
359 shifted_aggregate_proof
360 .add_part((self.evaluations.perm_eval, self.z_comm));
361 shifted_aggregate_proof
362 .add_part((self.evaluations.a_next_eval, self.a_comm));
363 shifted_aggregate_proof
364 .add_part((self.evaluations.b_next_eval, self.b_comm));
365 shifted_aggregate_proof
366 .add_part((self.evaluations.d_next_eval, self.d_comm));
367 shifted_aggregate_proof
368 .add_part((self.evaluations.h_1_next_eval, self.h_1_comm));
369 shifted_aggregate_proof
370 .add_part((self.evaluations.lookup_perm_eval, self.p_comm));
371 shifted_aggregate_proof
372 .add_part((self.evaluations.table_next_eval, table_comm));
373 let flattened_proof_b = shifted_aggregate_proof.flatten(transcript);
374 transcript.append_commitment(b"w_z", &self.w_z_comm);
376 transcript.append_commitment(b"w_z_w", &self.w_zw_comm);
377 if opening_key
379 .batch_check(
380 &[z_challenge, (z_challenge * domain.group_gen)],
381 &[flattened_proof_a, flattened_proof_b],
382 transcript,
383 )
384 .is_err()
385 {
386 return Err(Error::ProofVerificationError);
387 }
388
389 Ok(())
390 }
391
392 #[allow(clippy::too_many_arguments)]
393 fn compute_quotient_evaluation(
394 &self,
395 domain: &EvaluationDomain,
396 pub_inputs: &[BlsScalar],
397 alpha: &BlsScalar,
398 beta: &BlsScalar,
399 gamma: &BlsScalar,
400 delta: &BlsScalar,
401 epsilon: &BlsScalar,
402 z_challenge: &BlsScalar,
403 z_h_eval: &BlsScalar,
404 l1_eval: &BlsScalar,
405 z_hat_eval: &BlsScalar,
406 lookup_sep_challenge: &BlsScalar,
407 ) -> BlsScalar {
408 let pi_eval = compute_barycentric_eval(pub_inputs, z_challenge, domain);
410
411 let alpha_sq = alpha.square();
413
414 let l_sep_2 = lookup_sep_challenge.square();
416 let l_sep_3 = lookup_sep_challenge * l_sep_2;
417
418 let epsilon_one_plus_delta = epsilon * (BlsScalar::one() + delta);
420
421 let a = self.evaluations.lin_poly_eval + pi_eval;
423
424 let beta_sig1 = beta * self.evaluations.left_sigma_eval;
426 let b_0 = self.evaluations.a_eval + beta_sig1 + gamma;
427
428 let beta_sig2 = beta * self.evaluations.right_sigma_eval;
430 let b_1 = self.evaluations.b_eval + beta_sig2 + gamma;
431
432 let beta_sig3 = beta * self.evaluations.out_sigma_eval;
434 let b_2 = self.evaluations.c_eval + beta_sig3 + gamma;
435
436 let b_3 = (self.evaluations.d_eval + gamma) * z_hat_eval * alpha;
438
439 let b = b_0 * b_1 * b_2 * b_3;
440
441 let c = l1_eval * alpha_sq;
443
444 let e = l1_eval * l_sep_2;
446
447 let f_0 = epsilon_one_plus_delta
450 + self.evaluations.h_1_eval
451 + (delta * self.evaluations.h_2_eval);
452 let f_1 =
453 epsilon_one_plus_delta + (delta * self.evaluations.h_1_next_eval);
454 let f = self.evaluations.lookup_perm_eval * f_0 * f_1 * l_sep_3;
455
456 (a - b - c - e - f)
459 * z_h_eval.invert().unwrap()
460 }
461
462 fn compute_quotient_commitment(
463 &self,
464 z_challenge: &BlsScalar,
465 n: usize,
466 ) -> Commitment {
467 let z_n = z_challenge.pow(&[n as u64, 0, 0, 0]);
468 let z_two_n = z_challenge.pow(&[2 * n as u64, 0, 0, 0]);
469 let z_three_n = z_challenge.pow(&[3 * n as u64, 0, 0, 0]);
470 let t_comm = self.t_1_comm.0
471 + self.t_2_comm.0 * z_n
472 + self.t_3_comm.0 * z_two_n
473 + self.t_4_comm.0 * z_three_n;
474 Commitment::from(t_comm)
475 }
476
477 #[allow(clippy::too_many_arguments)]
479 fn compute_linearisation_commitment(
480 &self,
481 alpha: &BlsScalar,
482 beta: &BlsScalar,
483 gamma: &BlsScalar,
484 delta: &BlsScalar,
485 epsilon: &BlsScalar,
486 zeta: &BlsScalar,
487 (
488 range_sep_challenge,
489 logic_sep_challenge,
490 fixed_base_sep_challenge,
491 var_base_sep_challenge,
492 lookup_sep_challenge,
493 ): (&BlsScalar, &BlsScalar, &BlsScalar, &BlsScalar, &BlsScalar),
494 z_challenge: &BlsScalar,
495 l1_eval: BlsScalar,
496 t_eval: BlsScalar,
497 t_next_eval: BlsScalar,
498 verifier_key: &VerifierKey,
499 ) -> Commitment {
500 let mut scalars: Vec<_> = Vec::with_capacity(6);
501 let mut points: Vec<G1Affine> = Vec::with_capacity(6);
502
503 verifier_key.arithmetic.compute_linearisation_commitment(
504 &mut scalars,
505 &mut points,
506 &self.evaluations,
507 );
508
509 verifier_key.range.compute_linearisation_commitment(
510 range_sep_challenge,
511 &mut scalars,
512 &mut points,
513 &self.evaluations,
514 );
515
516 verifier_key.logic.compute_linearisation_commitment(
517 logic_sep_challenge,
518 &mut scalars,
519 &mut points,
520 &self.evaluations,
521 );
522
523 verifier_key.fixed_base.compute_linearisation_commitment(
524 fixed_base_sep_challenge,
525 &mut scalars,
526 &mut points,
527 &self.evaluations,
528 );
529
530 verifier_key.variable_base.compute_linearisation_commitment(
531 var_base_sep_challenge,
532 &mut scalars,
533 &mut points,
534 &self.evaluations,
535 );
536
537 verifier_key.lookup.compute_linearisation_commitment(
538 lookup_sep_challenge,
539 &mut scalars,
540 &mut points,
541 &self.evaluations,
542 (delta, epsilon),
543 zeta,
544 &l1_eval,
545 &t_eval,
546 &t_next_eval,
547 self.h_2_comm.0,
548 self.p_comm.0,
549 );
550
551 verifier_key.permutation.compute_linearisation_commitment(
552 &mut scalars,
553 &mut points,
554 &self.evaluations,
555 z_challenge,
556 (alpha, beta, gamma),
557 &l1_eval,
558 self.z_comm.0,
559 );
560
561 Commitment::from(msm_variable_base(&points, &scalars))
562 }
563}
564
565fn compute_first_lagrange_evaluation(
566 domain: &EvaluationDomain,
567 z_h_eval: &BlsScalar,
568 z_challenge: &BlsScalar,
569) -> BlsScalar {
570 let n_fr = BlsScalar::from(domain.size() as u64);
571 let denom = n_fr * (z_challenge - BlsScalar::one());
572 z_h_eval * denom.invert().unwrap()
573}
574
575fn compute_barycentric_eval(
576 evaluations: &[BlsScalar],
577 point: &BlsScalar,
578 domain: &EvaluationDomain,
579) -> BlsScalar {
580 let numerator = (point.pow(&[domain.size() as u64, 0, 0, 0])
581 - BlsScalar::one())
582 * domain.size_inv;
583
584 #[cfg(not(feature = "std"))]
586 let range = (0..evaluations.len()).into_iter();
587
588 #[cfg(feature = "std")]
589 let range = (0..evaluations.len()).into_iter();
590
591 let non_zero_evaluations: Vec<usize> = range
592 .filter(|&i| {
593 let evaluation = &evaluations[i];
594 evaluation != &BlsScalar::zero()
595 })
596 .collect();
597
598 #[cfg(not(feature = "std"))]
600 let range = (0..non_zero_evaluations.len()).into_iter();
601
602 #[cfg(feature = "std")]
603 let range = (0..non_zero_evaluations.len()).into_iter();
604
605 let mut denominators: Vec<BlsScalar> = range
606 .clone()
607 .map(|i| {
608 let index = non_zero_evaluations[i];
610
611 (domain.group_gen_inv.pow(&[index as u64, 0, 0, 0]) * point)
612 - BlsScalar::one()
613 })
614 .collect();
615 batch_inversion(&mut denominators);
616
617 let result: BlsScalar = range
618 .map(|i| {
619 let eval_index = non_zero_evaluations[i];
620 let eval = evaluations[eval_index];
621
622 denominators[i] * eval
623 })
624 .sum();
625
626 result * numerator
627}
628
629#[cfg(test)]
630mod proof_tests {
631 use super::*;
632 use dusk_bls12_381::BlsScalar;
633 use rand::SeedableRng;
634 use rand_xorshift::XorShiftRng;
635
636 #[test]
637 fn test_dusk_bytes_serde_proof() {
638 let rng = XorShiftRng::from_seed([
640 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37,
641 0x32, 0x54, 0x06, 0xbc, 0xe5,
642 ]);
643 let proof = Proof {
644 a_comm: Commitment::default(),
645 b_comm: Commitment::default(),
646 c_comm: Commitment::default(),
647 d_comm: Commitment::default(),
648 f_comm: Commitment::default(),
649 h_1_comm: Commitment::default(),
650 h_2_comm: Commitment::default(),
651 z_comm: Commitment::default(),
652 p_comm: Commitment::default(),
653 t_1_comm: Commitment::default(),
654 t_2_comm: Commitment::default(),
655 t_3_comm: Commitment::default(),
656 t_4_comm: Commitment::default(),
657 w_z_comm: Commitment::default(),
658 w_zw_comm: Commitment::default(),
659 evaluations: ProofEvaluations {
660 a_eval: BlsScalar::random(rng.clone()),
661 b_eval: BlsScalar::random(rng.clone()),
662 c_eval: BlsScalar::random(rng.clone()),
663 d_eval: BlsScalar::random(rng.clone()),
664 a_next_eval: BlsScalar::random(rng.clone()),
665 b_next_eval: BlsScalar::random(rng.clone()),
666 d_next_eval: BlsScalar::random(rng.clone()),
667 q_arith_eval: BlsScalar::random(rng.clone()),
668 q_c_eval: BlsScalar::random(rng.clone()),
669 q_l_eval: BlsScalar::random(rng.clone()),
670 q_r_eval: BlsScalar::random(rng.clone()),
671 q_lookup_eval: BlsScalar::random(rng.clone()),
672 left_sigma_eval: BlsScalar::random(rng.clone()),
673 right_sigma_eval: BlsScalar::random(rng.clone()),
674 out_sigma_eval: BlsScalar::random(rng.clone()),
675 lin_poly_eval: BlsScalar::random(rng.clone()),
676 perm_eval: BlsScalar::random(rng.clone()),
677 lookup_perm_eval: BlsScalar::random(rng.clone()),
678 h_1_eval: BlsScalar::random(rng.clone()),
679 h_1_next_eval: BlsScalar::random(rng.clone()),
680 h_2_eval: BlsScalar::random(rng.clone()),
681 f_eval: BlsScalar::random(rng.clone()),
682 table_eval: BlsScalar::random(rng.clone()),
683 table_next_eval: BlsScalar::random(rng.clone()),
684 },
685 };
686
687 let proof_bytes = proof.to_bytes();
688 let got_proof = Proof::from_bytes(&proof_bytes).unwrap();
689 assert_eq!(got_proof, proof);
690 }
691}