1use crate::{
8 commitment_scheme::CommitKey,
9 constraint_system::{TurboComposer, Witness},
10 error::Error,
11 fft::{EvaluationDomain, Polynomial},
12 plonkup::MultiSet,
13 proof_system::{
14 linearisation_poly, proof::Proof, quotient_poly, ProverKey,
15 },
16 transcript::TranscriptProtocol,
17};
18use dusk_bls12_381::BlsScalar;
19use merlin::Transcript;
20use sp_std::vec;
21use sp_std::vec::Vec;
22
23#[allow(missing_debug_implementations)]
26pub struct Prover {
27 pub prover_key: Option<ProverKey>,
29
30 pub(crate) cs: TurboComposer,
31 pub preprocessed_transcript: Transcript,
34}
35
36impl Prover {
37 pub fn composer_mut(&mut self) -> &mut TurboComposer {
39 &mut self.cs
40 }
41
42 pub fn preprocess(&mut self, commit_key: &CommitKey) -> Result<(), Error> {
44 if self.prover_key.is_some() {
45 return Err(Error::CircuitAlreadyPreprocessed);
46 }
47 let pk = self
48 .cs
49 .preprocess_prover(commit_key, &mut self.preprocessed_transcript)?;
50 self.prover_key = Some(pk);
51 Ok(())
52 }
53}
54
55impl Default for Prover {
56 fn default() -> Prover {
57 Prover::new(b"plonk")
58 }
59}
60
61impl Prover {
62 pub fn new(label: &'static [u8]) -> Prover {
64 Prover {
65 prover_key: None,
66 cs: TurboComposer::new(),
67 preprocessed_transcript: Transcript::new(label),
68 }
69 }
70
71 pub fn with_size(label: &'static [u8], size: usize) -> Prover {
73 Prover {
74 prover_key: None,
75 cs: TurboComposer::with_size(size),
76 preprocessed_transcript: Transcript::new(label),
77 }
78 }
79
80 pub const fn gates(&self) -> u32 {
83 self.cs.gates()
84 }
85
86 pub(crate) fn split_tx_poly(
88 &self,
89 n: usize,
90 t_x: &Polynomial,
91 ) -> (Polynomial, Polynomial, Polynomial, Polynomial) {
92 (
93 Polynomial::from_coefficients_vec(t_x[0..n].to_vec()),
94 Polynomial::from_coefficients_vec(t_x[n..2 * n].to_vec()),
95 Polynomial::from_coefficients_vec(t_x[2 * n..3 * n].to_vec()),
96 Polynomial::from_coefficients_vec(t_x[3 * n..].to_vec()),
97 )
98 }
99
100 fn compute_quotient_opening_poly(
102 n: usize,
103 t_1_poly: &Polynomial,
104 t_2_poly: &Polynomial,
105 t_3_poly: &Polynomial,
106 t_4_poly: &Polynomial,
107 z_challenge: &BlsScalar,
108 ) -> Polynomial {
109 let z_n = z_challenge.pow(&[n as u64, 0, 0, 0]);
111 let z_two_n = z_challenge.pow(&[2 * n as u64, 0, 0, 0]);
112 let z_three_n = z_challenge.pow(&[3 * n as u64, 0, 0, 0]);
113
114 let a = t_1_poly;
115 let b = t_2_poly * &z_n;
116 let c = t_3_poly * &z_two_n;
117 let d = t_4_poly * &z_three_n;
118 let abc = &(a + &b) + &c;
119 &abc + &d
120 }
121
122 pub(crate) fn to_scalars(&self, vars: &[Witness]) -> Vec<BlsScalar> {
124 vars.iter().map(|var| self.cs.witnesses[var]).collect()
125 }
126
127 pub fn clear_witness(&mut self) {
131 self.cs = TurboComposer::new();
132 }
133
134 pub fn clear(&mut self) {
138 self.clear_witness();
139 self.prover_key = None;
140 self.preprocessed_transcript = Transcript::new(b"plonk");
141 }
142
143 pub fn key_transcript(&mut self, label: &'static [u8], message: &[u8]) {
146 self.preprocessed_transcript.append_message(label, message);
147 }
148
149 pub fn prove_with_preprocessed(
156 &self,
157 commit_key: &CommitKey,
158 prover_key: &ProverKey,
159 ) -> Result<Proof, Error> {
160 let domain = EvaluationDomain::new(core::cmp::max(
163 self.cs.gates() as usize,
164 self.cs.lookup_table.0.len(),
165 ))?;
166
167 let mut transcript = self.preprocessed_transcript.clone();
171
172 let pad = vec![BlsScalar::zero(); domain.size() - self.cs.w_l.len()];
177 let w_l_scalar = &[&self.to_scalars(&self.cs.w_l)[..], &pad].concat();
178 let w_r_scalar = &[&self.to_scalars(&self.cs.w_r)[..], &pad].concat();
179 let w_o_scalar = &[&self.to_scalars(&self.cs.w_o)[..], &pad].concat();
180 let w_4_scalar = &[&self.to_scalars(&self.cs.w_4)[..], &pad].concat();
181
182 let padded_q_lookup = [&self.cs.q_lookup[..], &pad].concat();
184
185 let w_l_poly =
188 Polynomial::from_coefficients_vec(domain.ifft(w_l_scalar));
189 let w_r_poly =
190 Polynomial::from_coefficients_vec(domain.ifft(w_r_scalar));
191 let w_o_poly =
192 Polynomial::from_coefficients_vec(domain.ifft(w_o_scalar));
193 let w_4_poly =
194 Polynomial::from_coefficients_vec(domain.ifft(w_4_scalar));
195
196 let w_l_poly_commit = commit_key.commit(&w_l_poly)?;
198 let w_r_poly_commit = commit_key.commit(&w_r_poly)?;
199 let w_o_poly_commit = commit_key.commit(&w_o_poly)?;
200 let w_4_poly_commit = commit_key.commit(&w_4_poly)?;
201
202 transcript.append_commitment(b"w_l", &w_l_poly_commit);
204 transcript.append_commitment(b"w_r", &w_r_poly_commit);
205 transcript.append_commitment(b"w_o", &w_o_poly_commit);
206 transcript.append_commitment(b"w_4", &w_4_poly_commit);
207
208 let zeta = transcript.challenge_scalar(b"zeta");
210
211 let compressed_t_multiset = MultiSet::compress_four_arity(
213 [
214 &prover_key.lookup.table_1.0,
215 &prover_key.lookup.table_2.0,
216 &prover_key.lookup.table_3.0,
217 &prover_key.lookup.table_4.0,
218 ],
219 zeta,
220 );
221
222 let table_poly = Polynomial::from_coefficients_vec(
224 domain.ifft(&compressed_t_multiset.0),
225 );
226
227 let f_1_scalar = w_l_scalar
232 .iter()
233 .zip(&padded_q_lookup)
234 .map(|(w, s)| {
235 w * s + (BlsScalar::one() - s) * compressed_t_multiset.0[0]
236 })
237 .collect::<Vec<BlsScalar>>();
238 let f_2_scalar = w_r_scalar
239 .iter()
240 .zip(&padded_q_lookup)
241 .map(|(w, s)| w * s)
242 .collect::<Vec<BlsScalar>>();
243 let f_3_scalar = w_o_scalar
244 .iter()
245 .zip(&padded_q_lookup)
246 .map(|(w, s)| w * s)
247 .collect::<Vec<BlsScalar>>();
248 let f_4_scalar = w_4_scalar
249 .iter()
250 .zip(&padded_q_lookup)
251 .map(|(w, s)| w * s)
252 .collect::<Vec<BlsScalar>>();
253
254 let compressed_f_multiset = MultiSet::compress_four_arity(
256 [
257 &MultiSet::from(&f_1_scalar[..]),
258 &MultiSet::from(&f_2_scalar[..]),
259 &MultiSet::from(&f_3_scalar[..]),
260 &MultiSet::from(&f_4_scalar[..]),
261 ],
262 zeta,
263 );
264
265 let f_poly = Polynomial::from_coefficients_vec(
267 domain.ifft(&compressed_f_multiset.0),
268 );
269
270 let f_poly_commit = commit_key.commit(&f_poly)?;
272
273 transcript.append_commitment(b"f", &f_poly_commit);
275
276 let beta = transcript.challenge_scalar(b"beta");
282 transcript.append_scalar(b"beta", &beta);
283 let gamma = transcript.challenge_scalar(b"gamma");
284 let delta = transcript.challenge_scalar(b"delta");
285 let epsilon = transcript.challenge_scalar(b"epsilon");
286
287 let z_poly = Polynomial::from_coefficients_slice(
288 &self.cs.perm.compute_permutation_poly(
289 &domain,
290 [w_l_scalar, w_r_scalar, w_o_scalar, w_4_scalar],
291 &beta,
292 &gamma,
293 [
294 &prover_key.permutation.left_sigma.0,
295 &prover_key.permutation.right_sigma.0,
296 &prover_key.permutation.out_sigma.0,
297 &prover_key.permutation.fourth_sigma.0,
298 ],
299 ),
300 );
301
302 let z_poly_commit = commit_key.commit(&z_poly)?;
305
306 transcript.append_commitment(b"z", &z_poly_commit);
308
309 let pi_poly = Polynomial::from_coefficients_vec(
311 domain.ifft(&self.cs.to_dense_public_inputs()),
312 );
313
314 let z_challenge = transcript.challenge_scalar(b"z_challenge");
316
317 let s = compressed_t_multiset
319 .sorted_concat(&compressed_f_multiset)
320 .unwrap();
321
322 let (h_1, h_2) = s.halve_alternating();
324
325 let h_1_poly = Polynomial::from_coefficients_vec(domain.ifft(&h_1.0));
327 let h_2_poly = Polynomial::from_coefficients_vec(domain.ifft(&h_2.0));
328
329 let h_1_poly_commit = commit_key.commit(&h_1_poly).unwrap();
331 let h_2_poly_commit = commit_key.commit(&h_2_poly).unwrap();
332
333 transcript.append_commitment(b"h1", &h_1_poly_commit);
335 transcript.append_commitment(b"h2", &h_2_poly_commit);
336
337 let p_poly = Polynomial::from_coefficients_slice(
339 &self.cs.perm.compute_lookup_permutation_poly(
340 &domain,
341 &compressed_f_multiset.0,
342 &compressed_t_multiset.0,
343 &h_1.0,
344 &h_2.0,
345 &delta,
346 &epsilon,
347 ),
348 );
349
350 let p_poly_commit = commit_key.commit(&p_poly)?;
353
354 transcript.append_commitment(b"p", &p_poly_commit);
356
357 let alpha = transcript.challenge_scalar(b"alpha");
361 let range_sep_challenge =
362 transcript.challenge_scalar(b"range separation challenge");
363 let logic_sep_challenge =
364 transcript.challenge_scalar(b"logic separation challenge");
365 let fixed_base_sep_challenge =
366 transcript.challenge_scalar(b"fixed base separation challenge");
367 let var_base_sep_challenge =
368 transcript.challenge_scalar(b"variable base separation challenge");
369 let lookup_sep_challenge =
370 transcript.challenge_scalar(b"lookup challenge");
371
372 let t_poly = quotient_poly::compute(
373 &domain,
374 prover_key,
375 &z_poly,
376 &p_poly,
377 (&w_l_poly, &w_r_poly, &w_o_poly, &w_4_poly),
378 &f_poly,
379 &table_poly,
380 &h_1_poly,
381 &h_2_poly,
382 &pi_poly,
383 &(
384 alpha,
385 beta,
386 gamma,
387 delta,
388 epsilon,
389 zeta,
390 range_sep_challenge,
391 logic_sep_challenge,
392 fixed_base_sep_challenge,
393 var_base_sep_challenge,
394 lookup_sep_challenge,
395 ),
396 )?;
397
398 let (t_1_poly, t_2_poly, t_3_poly, t_4_poly) =
400 self.split_tx_poly(domain.size(), &t_poly);
401
402 let t_1_commit = commit_key.commit(&t_1_poly)?;
404 let t_2_commit = commit_key.commit(&t_2_poly)?;
405 let t_3_commit = commit_key.commit(&t_3_poly)?;
406 let t_4_commit = commit_key.commit(&t_4_poly)?;
407
408 transcript.append_commitment(b"t_1", &t_1_commit);
410 transcript.append_commitment(b"t_2", &t_2_commit);
411 transcript.append_commitment(b"t_3", &t_3_commit);
412 transcript.append_commitment(b"t_4", &t_4_commit);
413
414 let (lin_poly, evaluations) = linearisation_poly::compute(
418 &domain,
419 prover_key,
420 &(
421 alpha,
422 beta,
423 gamma,
424 delta,
425 epsilon,
426 zeta,
427 range_sep_challenge,
428 logic_sep_challenge,
429 fixed_base_sep_challenge,
430 var_base_sep_challenge,
431 lookup_sep_challenge,
432 z_challenge,
433 ),
434 &w_l_poly,
435 &w_r_poly,
436 &w_o_poly,
437 &w_4_poly,
438 &t_poly,
439 &z_poly,
440 &f_poly,
441 &h_1_poly,
442 &h_2_poly,
443 &table_poly,
444 &p_poly,
445 );
446
447 transcript.append_scalar(b"a_eval", &evaluations.proof.a_eval);
449 transcript.append_scalar(b"b_eval", &evaluations.proof.b_eval);
450 transcript.append_scalar(b"c_eval", &evaluations.proof.c_eval);
451 transcript.append_scalar(b"d_eval", &evaluations.proof.d_eval);
452 transcript
453 .append_scalar(b"a_next_eval", &evaluations.proof.a_next_eval);
454 transcript
455 .append_scalar(b"b_next_eval", &evaluations.proof.b_next_eval);
456 transcript
457 .append_scalar(b"d_next_eval", &evaluations.proof.d_next_eval);
458 transcript.append_scalar(
459 b"left_sig_eval",
460 &evaluations.proof.left_sigma_eval,
461 );
462 transcript.append_scalar(
463 b"right_sig_eval",
464 &evaluations.proof.right_sigma_eval,
465 );
466 transcript
467 .append_scalar(b"out_sig_eval", &evaluations.proof.out_sigma_eval);
468 transcript
469 .append_scalar(b"q_arith_eval", &evaluations.proof.q_arith_eval);
470 transcript.append_scalar(b"q_c_eval", &evaluations.proof.q_c_eval);
471 transcript.append_scalar(b"q_l_eval", &evaluations.proof.q_l_eval);
472 transcript.append_scalar(b"q_r_eval", &evaluations.proof.q_r_eval);
473 transcript
474 .append_scalar(b"q_lookup_eval", &evaluations.proof.q_lookup_eval);
475 transcript.append_scalar(b"perm_eval", &evaluations.proof.perm_eval);
476 transcript.append_scalar(
477 b"lookup_perm_eval",
478 &evaluations.proof.lookup_perm_eval,
479 );
480 transcript.append_scalar(b"h_1_eval", &evaluations.proof.h_1_eval);
481 transcript
482 .append_scalar(b"h_1_next_eval", &evaluations.proof.h_1_next_eval);
483 transcript.append_scalar(b"h_2_eval", &evaluations.proof.h_2_eval);
484 transcript.append_scalar(b"t_eval", &evaluations.quot_eval);
485 transcript.append_scalar(b"r_eval", &evaluations.proof.lin_poly_eval);
486
487 let quot = Self::compute_quotient_opening_poly(
492 domain.size(),
493 &t_1_poly,
494 &t_2_poly,
495 &t_3_poly,
496 &t_4_poly,
497 &z_challenge,
498 );
499
500 let aggregate_witness = commit_key.compute_aggregate_witness(
503 &[
504 quot,
505 lin_poly,
506 w_l_poly.clone(),
507 w_r_poly.clone(),
508 w_o_poly,
509 w_4_poly.clone(),
510 prover_key.permutation.left_sigma.0.clone(),
511 prover_key.permutation.right_sigma.0.clone(),
512 prover_key.permutation.out_sigma.0.clone(),
513 f_poly,
514 h_1_poly.clone(),
515 h_2_poly,
516 table_poly.clone(),
517 ],
518 &z_challenge,
519 &mut transcript,
520 );
521 let w_z_comm = commit_key.commit(&aggregate_witness)?;
522
523 let shifted_aggregate_witness = commit_key.compute_aggregate_witness(
526 &[
527 z_poly, w_l_poly, w_r_poly, w_4_poly, h_1_poly, p_poly,
528 table_poly,
529 ],
530 &(z_challenge * domain.group_gen),
531 &mut transcript,
532 );
533 let w_zx_comm = commit_key.commit(&shifted_aggregate_witness)?;
534
535 Ok(Proof {
537 a_comm: w_l_poly_commit,
538 b_comm: w_r_poly_commit,
539 c_comm: w_o_poly_commit,
540 d_comm: w_4_poly_commit,
541
542 f_comm: f_poly_commit,
543
544 h_1_comm: h_1_poly_commit,
545 h_2_comm: h_2_poly_commit,
546
547 z_comm: z_poly_commit,
548 p_comm: p_poly_commit,
549
550 t_1_comm: t_1_commit,
551 t_2_comm: t_2_commit,
552 t_3_comm: t_3_commit,
553 t_4_comm: t_4_commit,
554
555 w_z_comm,
556 w_zw_comm: w_zx_comm,
557
558 evaluations: evaluations.proof,
559 })
560 }
561
562 pub fn prove(&mut self, commit_key: &CommitKey) -> Result<Proof, Error> {
566 let prover_key: &ProverKey;
567
568 if self.prover_key.is_none() {
569 let prover_key = self.cs.preprocess_prover(
571 commit_key,
572 &mut self.preprocessed_transcript,
573 )?;
574 self.prover_key = Some(prover_key);
576 }
577
578 prover_key = self.prover_key.as_ref().unwrap();
579
580 let proof = self.prove_with_preprocessed(commit_key, prover_key)?;
581
582 self.clear_witness();
584
585 Ok(proof)
586 }
587}