1#![allow(non_snake_case)]
2
3use alloc::{boxed::Box, vec, vec::Vec};
4use clear_on_drop::clear::Clear;
5use core::borrow::BorrowMut;
6use core::mem;
7use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoPoint};
8use curve25519_dalek::scalar::Scalar;
9use curve25519_dalek::traits::{Identity, MultiscalarMul};
10use merlin::Transcript;
11use rand_core::{CryptoRng, RngCore};
12
13use super::{
14 ConstraintSystem, LinearCombination, R1CSProof, RandomizableConstraintSystem,
15 RandomizedConstraintSystem, Variable,
16};
17
18use crate::errors::R1CSError;
19use crate::generators::{BulletproofGens, PedersenGens};
20use crate::inner_product_proof::InnerProductProof;
21use crate::transcript::TranscriptProtocol;
22
23pub struct Prover<'g, T: BorrowMut<Transcript>> {
33 transcript: T,
34 pc_gens: &'g PedersenGens,
35 constraints: Vec<LinearCombination>,
37 secrets: Secrets,
39
40 deferred_constraints: Vec<Box<dyn Fn(&mut RandomizingProver<'g, T>) -> Result<(), R1CSError>>>,
43
44 pending_multiplier: Option<usize>,
46}
47
48struct Secrets {
51 a_L: Vec<Scalar>,
53 a_R: Vec<Scalar>,
55 a_O: Vec<Scalar>,
57 v: Vec<Scalar>,
59 v_blinding: Vec<Scalar>,
61}
62
63pub struct RandomizingProver<'g, T: BorrowMut<Transcript>> {
71 prover: Prover<'g, T>,
72}
73
74impl Drop for Secrets {
76 fn drop(&mut self) {
77 self.v.clear();
78 self.v_blinding.clear();
79
80 for e in self.a_L.iter_mut() {
86 e.clear();
87 }
88 for e in self.a_R.iter_mut() {
89 e.clear();
90 }
91 for e in self.a_O.iter_mut() {
92 e.clear();
93 }
94 }
96}
97
98impl<'g, T: BorrowMut<Transcript>> ConstraintSystem for Prover<'g, T> {
99 fn transcript(&mut self) -> &mut Transcript {
100 self.transcript.borrow_mut()
101 }
102
103 fn multiply(
104 &mut self,
105 mut left: LinearCombination,
106 mut right: LinearCombination,
107 ) -> (Variable, Variable, Variable) {
108 let l = self.eval(&left);
110 let r = self.eval(&right);
111 let o = l * r;
112
113 let l_var = Variable::MultiplierLeft(self.secrets.a_L.len());
115 let r_var = Variable::MultiplierRight(self.secrets.a_R.len());
116 let o_var = Variable::MultiplierOutput(self.secrets.a_O.len());
117 self.secrets.a_L.push(l);
119 self.secrets.a_R.push(r);
120 self.secrets.a_O.push(o);
121
122 left.terms.push((l_var, -Scalar::one()));
124 right.terms.push((r_var, -Scalar::one()));
125 self.constrain(left);
126 self.constrain(right);
127
128 (l_var, r_var, o_var)
129 }
130
131 fn allocate(&mut self, assignment: Option<Scalar>) -> Result<Variable, R1CSError> {
132 let scalar = assignment.ok_or(R1CSError::MissingAssignment)?;
133
134 match self.pending_multiplier {
135 None => {
136 let i = self.secrets.a_L.len();
137 self.pending_multiplier = Some(i);
138 self.secrets.a_L.push(scalar);
139 self.secrets.a_R.push(Scalar::zero());
140 self.secrets.a_O.push(Scalar::zero());
141 Ok(Variable::MultiplierLeft(i))
142 }
143 Some(i) => {
144 self.pending_multiplier = None;
145 self.secrets.a_R[i] = scalar;
146 self.secrets.a_O[i] = self.secrets.a_L[i] * self.secrets.a_R[i];
147 Ok(Variable::MultiplierRight(i))
148 }
149 }
150 }
151
152 fn allocate_multiplier(
153 &mut self,
154 input_assignments: Option<(Scalar, Scalar)>,
155 ) -> Result<(Variable, Variable, Variable), R1CSError> {
156 let (l, r) = input_assignments.ok_or(R1CSError::MissingAssignment)?;
157 let o = l * r;
158
159 let l_var = Variable::MultiplierLeft(self.secrets.a_L.len());
161 let r_var = Variable::MultiplierRight(self.secrets.a_R.len());
162 let o_var = Variable::MultiplierOutput(self.secrets.a_O.len());
163 self.secrets.a_L.push(l);
165 self.secrets.a_R.push(r);
166 self.secrets.a_O.push(o);
167
168 Ok((l_var, r_var, o_var))
169 }
170
171 fn multipliers_len(&self) -> usize {
172 self.secrets.a_L.len()
173 }
174
175 fn constrain(&mut self, lc: LinearCombination) {
176 self.constraints.push(lc);
179 }
180}
181
182impl<'g, T: BorrowMut<Transcript>> RandomizableConstraintSystem for Prover<'g, T> {
183 type RandomizedCS = RandomizingProver<'g, T>;
184
185 fn specify_randomized_constraints<F>(&mut self, callback: F) -> Result<(), R1CSError>
186 where
187 F: 'static + Fn(&mut Self::RandomizedCS) -> Result<(), R1CSError>,
188 {
189 self.deferred_constraints.push(Box::new(callback));
190 Ok(())
191 }
192}
193
194impl<'g, T: BorrowMut<Transcript>> ConstraintSystem for RandomizingProver<'g, T> {
195 fn transcript(&mut self) -> &mut Transcript {
196 self.prover.transcript.borrow_mut()
197 }
198
199 fn multiply(
200 &mut self,
201 left: LinearCombination,
202 right: LinearCombination,
203 ) -> (Variable, Variable, Variable) {
204 self.prover.multiply(left, right)
205 }
206
207 fn allocate(&mut self, assignment: Option<Scalar>) -> Result<Variable, R1CSError> {
208 self.prover.allocate(assignment)
209 }
210
211 fn allocate_multiplier(
212 &mut self,
213 input_assignments: Option<(Scalar, Scalar)>,
214 ) -> Result<(Variable, Variable, Variable), R1CSError> {
215 self.prover.allocate_multiplier(input_assignments)
216 }
217
218 fn multipliers_len(&self) -> usize {
219 self.prover.multipliers_len()
220 }
221
222 fn constrain(&mut self, lc: LinearCombination) {
223 self.prover.constrain(lc)
224 }
225}
226
227impl<'g, T: BorrowMut<Transcript>> RandomizedConstraintSystem for RandomizingProver<'g, T> {
228 fn challenge_scalar(&mut self, label: &'static [u8]) -> Scalar {
229 self.prover.transcript.borrow_mut().challenge_scalar(label)
230 }
231}
232
233impl<'g, T: BorrowMut<Transcript>> Prover<'g, T> {
234 pub fn new(pc_gens: &'g PedersenGens, mut transcript: T) -> Self {
255 transcript.borrow_mut().r1cs_domain_sep();
256
257 Prover {
258 pc_gens,
259 transcript,
260 secrets: Secrets {
261 v: Vec::new(),
262 v_blinding: Vec::new(),
263 a_L: Vec::new(),
264 a_R: Vec::new(),
265 a_O: Vec::new(),
266 },
267 constraints: Vec::new(),
268 deferred_constraints: Vec::new(),
269 pending_multiplier: None,
270 }
271 }
272
273 pub fn commit(&mut self, v: Scalar, v_blinding: Scalar) -> (CompressedRistretto, Variable) {
291 let i = self.secrets.v.len();
292 self.secrets.v.push(v);
293 self.secrets.v_blinding.push(v_blinding);
294
295 let V = self.pc_gens.commit(v, v_blinding).compress();
297 self.transcript.borrow_mut().append_point(b"V", &V);
298
299 (V, Variable::Committed(i))
300 }
301
302 fn flattened_constraints(
314 &mut self,
315 z: &Scalar,
316 ) -> (Vec<Scalar>, Vec<Scalar>, Vec<Scalar>, Vec<Scalar>) {
317 let n = self.secrets.a_L.len();
318 let m = self.secrets.v.len();
319
320 let mut wL = vec![Scalar::zero(); n];
321 let mut wR = vec![Scalar::zero(); n];
322 let mut wO = vec![Scalar::zero(); n];
323 let mut wV = vec![Scalar::zero(); m];
324
325 let mut exp_z = *z;
326 for lc in self.constraints.iter() {
327 for (var, coeff) in &lc.terms {
328 match var {
329 Variable::MultiplierLeft(i) => {
330 wL[*i] += exp_z * coeff;
331 }
332 Variable::MultiplierRight(i) => {
333 wR[*i] += exp_z * coeff;
334 }
335 Variable::MultiplierOutput(i) => {
336 wO[*i] += exp_z * coeff;
337 }
338 Variable::Committed(i) => {
339 wV[*i] -= exp_z * coeff;
340 }
341 Variable::One() => {
342 }
344 }
345 }
346 exp_z *= z;
347 }
348
349 (wL, wR, wO, wV)
350 }
351
352 fn eval(&self, lc: &LinearCombination) -> Scalar {
353 lc.terms
354 .iter()
355 .map(|(var, coeff)| {
356 coeff
357 * match var {
358 Variable::MultiplierLeft(i) => self.secrets.a_L[*i],
359 Variable::MultiplierRight(i) => self.secrets.a_R[*i],
360 Variable::MultiplierOutput(i) => self.secrets.a_O[*i],
361 Variable::Committed(i) => self.secrets.v[*i],
362 Variable::One() => Scalar::one(),
363 }
364 })
365 .sum()
366 }
367
368 fn create_randomized_constraints(mut self) -> Result<Self, R1CSError> {
371 self.pending_multiplier = None;
373
374 if self.deferred_constraints.len() == 0 {
375 self.transcript.borrow_mut().r1cs_1phase_domain_sep();
376 Ok(self)
377 } else {
378 self.transcript.borrow_mut().r1cs_2phase_domain_sep();
379 let mut callbacks = mem::replace(&mut self.deferred_constraints, Vec::new());
383 let mut wrapped_self = RandomizingProver { prover: self };
384 for callback in callbacks.drain(..) {
385 callback(&mut wrapped_self)?;
386 }
387 Ok(wrapped_self.prover)
388 }
389 }
390
391 pub fn prove<R: RngCore + CryptoRng>(
393 self,
394 rng: &mut R,
395 bp_gens: &BulletproofGens,
396 ) -> Result<R1CSProof, R1CSError> {
397 self.prove_and_return_transcript(rng, bp_gens)
398 .map(|(proof, _transcript)| proof)
399 }
400
401 pub fn prove_and_return_transcript<R: RngCore + CryptoRng>(
403 mut self,
404 rng: &mut R,
405 bp_gens: &BulletproofGens,
406 ) -> Result<(R1CSProof, T), R1CSError> {
407 use crate::util;
408 use core::iter;
409
410 self.transcript
415 .borrow_mut()
416 .append_u64(b"m", self.secrets.v.len() as u64);
417
418 let mut rng = {
432 let mut builder = self.transcript.borrow_mut().build_rng();
433
434 for v_b in &self.secrets.v_blinding {
436 builder = builder.rekey_with_witness_bytes(b"v_blinding", v_b.as_bytes());
437 }
438
439 builder.finalize(rng)
440 };
441
442 let n1 = self.secrets.a_L.len();
444
445 if bp_gens.gens_capacity < n1 {
446 return Err(R1CSError::InvalidGeneratorsLength);
447 }
448
449 let gens = bp_gens.share(0);
451
452 let i_blinding1 = Scalar::random(&mut rng);
453 let o_blinding1 = Scalar::random(&mut rng);
454 let s_blinding1 = Scalar::random(&mut rng);
455
456 let mut s_L1: Vec<Scalar> = (0..n1).map(|_| Scalar::random(&mut rng)).collect();
457 let mut s_R1: Vec<Scalar> = (0..n1).map(|_| Scalar::random(&mut rng)).collect();
458
459 let A_I1 = RistrettoPoint::multiscalar_mul(
461 iter::once(&i_blinding1)
462 .chain(self.secrets.a_L.iter())
463 .chain(self.secrets.a_R.iter()),
464 iter::once(&self.pc_gens.B_blinding)
465 .chain(gens.G(n1))
466 .chain(gens.H(n1)),
467 )
468 .compress();
469
470 let A_O1 = RistrettoPoint::multiscalar_mul(
472 iter::once(&o_blinding1).chain(self.secrets.a_O.iter()),
473 iter::once(&self.pc_gens.B_blinding).chain(gens.G(n1)),
474 )
475 .compress();
476
477 let S1 = RistrettoPoint::multiscalar_mul(
479 iter::once(&s_blinding1)
480 .chain(s_L1.iter())
481 .chain(s_R1.iter()),
482 iter::once(&self.pc_gens.B_blinding)
483 .chain(gens.G(n1))
484 .chain(gens.H(n1)),
485 )
486 .compress();
487
488 let transcript = self.transcript.borrow_mut();
489 transcript.append_point(b"A_I1", &A_I1);
490 transcript.append_point(b"A_O1", &A_O1);
491 transcript.append_point(b"S1", &S1);
492
493 self = self.create_randomized_constraints()?;
495
496 let n = self.secrets.a_L.len();
500 let n2 = n - n1;
501 let padded_n = self.secrets.a_L.len().next_power_of_two();
502 let pad = padded_n - n;
503
504 if bp_gens.gens_capacity < padded_n {
505 return Err(R1CSError::InvalidGeneratorsLength);
506 }
507
508 let has_2nd_phase_commitments = n2 > 0;
511
512 let (i_blinding2, o_blinding2, s_blinding2) = if has_2nd_phase_commitments {
513 (
514 Scalar::random(&mut rng),
515 Scalar::random(&mut rng),
516 Scalar::random(&mut rng),
517 )
518 } else {
519 (Scalar::zero(), Scalar::zero(), Scalar::zero())
520 };
521
522 let mut s_L2: Vec<Scalar> = (0..n2).map(|_| Scalar::random(&mut rng)).collect();
523 let mut s_R2: Vec<Scalar> = (0..n2).map(|_| Scalar::random(&mut rng)).collect();
524
525 let (A_I2, A_O2, S2) = if has_2nd_phase_commitments {
526 (
527 RistrettoPoint::multiscalar_mul(
529 iter::once(&i_blinding2)
530 .chain(self.secrets.a_L.iter().skip(n1))
531 .chain(self.secrets.a_R.iter().skip(n1)),
532 iter::once(&self.pc_gens.B_blinding)
533 .chain(gens.G(n).skip(n1))
534 .chain(gens.H(n).skip(n1)),
535 )
536 .compress(),
537 RistrettoPoint::multiscalar_mul(
539 iter::once(&o_blinding2).chain(self.secrets.a_O.iter().skip(n1)),
540 iter::once(&self.pc_gens.B_blinding).chain(gens.G(n).skip(n1)),
541 )
542 .compress(),
543 RistrettoPoint::multiscalar_mul(
545 iter::once(&s_blinding2)
546 .chain(s_L2.iter())
547 .chain(s_R2.iter()),
548 iter::once(&self.pc_gens.B_blinding)
549 .chain(gens.G(n).skip(n1))
550 .chain(gens.H(n).skip(n1)),
551 )
552 .compress(),
553 )
554 } else {
555 (
560 CompressedRistretto::identity(),
561 CompressedRistretto::identity(),
562 CompressedRistretto::identity(),
563 )
564 };
565
566 let transcript = self.transcript.borrow_mut();
567 transcript.append_point(b"A_I2", &A_I2);
568 transcript.append_point(b"A_O2", &A_O2);
569 transcript.append_point(b"S2", &S2);
570
571 let y = transcript.challenge_scalar(b"y");
574 let z = transcript.challenge_scalar(b"z");
575
576 let (wL, wR, wO, wV) = self.flattened_constraints(&z);
577
578 let mut l_poly = util::VecPoly3::zero(n);
579 let mut r_poly = util::VecPoly3::zero(n);
580
581 let mut exp_y = Scalar::one(); let y_inv = y.invert();
583 let exp_y_inv = util::exp_iter(y_inv).take(padded_n).collect::<Vec<_>>();
584
585 let sLsR = s_L1
586 .iter()
587 .chain(s_L2.iter())
588 .zip(s_R1.iter().chain(s_R2.iter()));
589 for (i, (sl, sr)) in sLsR.enumerate() {
590 l_poly.1[i] = self.secrets.a_L[i] + exp_y_inv[i] * wR[i];
593 l_poly.2[i] = self.secrets.a_O[i];
595 l_poly.3[i] = *sl;
597 r_poly.0[i] = wO[i] - exp_y;
599 r_poly.1[i] = exp_y * self.secrets.a_R[i] + wL[i];
601 r_poly.3[i] = exp_y * sr;
604
605 exp_y = exp_y * y; }
607
608 let t_poly = util::VecPoly3::special_inner_product(&l_poly, &r_poly);
609
610 let t_1_blinding = Scalar::random(&mut rng);
611 let t_3_blinding = Scalar::random(&mut rng);
612 let t_4_blinding = Scalar::random(&mut rng);
613 let t_5_blinding = Scalar::random(&mut rng);
614 let t_6_blinding = Scalar::random(&mut rng);
615
616 let T_1 = self.pc_gens.commit(t_poly.t1, t_1_blinding).compress();
617 let T_3 = self.pc_gens.commit(t_poly.t3, t_3_blinding).compress();
618 let T_4 = self.pc_gens.commit(t_poly.t4, t_4_blinding).compress();
619 let T_5 = self.pc_gens.commit(t_poly.t5, t_5_blinding).compress();
620 let T_6 = self.pc_gens.commit(t_poly.t6, t_6_blinding).compress();
621
622 let transcript = self.transcript.borrow_mut();
623 transcript.append_point(b"T_1", &T_1);
624 transcript.append_point(b"T_3", &T_3);
625 transcript.append_point(b"T_4", &T_4);
626 transcript.append_point(b"T_5", &T_5);
627 transcript.append_point(b"T_6", &T_6);
628
629 let u = transcript.challenge_scalar(b"u");
630 let x = transcript.challenge_scalar(b"x");
631
632 let t_2_blinding = wV
635 .iter()
636 .zip(self.secrets.v_blinding.iter())
637 .map(|(c, v_blinding)| c * v_blinding)
638 .sum();
639
640 let t_blinding_poly = util::Poly6 {
641 t1: t_1_blinding,
642 t2: t_2_blinding,
643 t3: t_3_blinding,
644 t4: t_4_blinding,
645 t5: t_5_blinding,
646 t6: t_6_blinding,
647 };
648
649 let t_x = t_poly.eval(x);
650 let t_x_blinding = t_blinding_poly.eval(x);
651 let mut l_vec = l_poly.eval(x);
652 l_vec.append(&mut vec![Scalar::zero(); pad]);
653
654 let mut r_vec = r_poly.eval(x);
655 r_vec.append(&mut vec![Scalar::zero(); pad]);
656
657 for i in n..padded_n {
659 r_vec[i] = -exp_y;
660 exp_y = exp_y * y; }
662
663 let i_blinding = i_blinding1 + u * i_blinding2;
664 let o_blinding = o_blinding1 + u * o_blinding2;
665 let s_blinding = s_blinding1 + u * s_blinding2;
666
667 let e_blinding = x * (i_blinding + x * (o_blinding + x * s_blinding));
668
669 transcript.append_scalar(b"t_x", &t_x);
670 transcript.append_scalar(b"t_x_blinding", &t_x_blinding);
671 transcript.append_scalar(b"e_blinding", &e_blinding);
672
673 let w = transcript.challenge_scalar(b"w");
675 let Q = w * self.pc_gens.B;
676
677 let G_factors = iter::repeat(Scalar::one())
678 .take(n1)
679 .chain(iter::repeat(u).take(n2 + pad))
680 .collect::<Vec<_>>();
681 let H_factors = exp_y_inv
682 .into_iter()
683 .zip(G_factors.iter())
684 .map(|(y, u_or_1)| y * u_or_1)
685 .collect::<Vec<_>>();
686
687 let ipp_proof = InnerProductProof::create(
688 transcript,
689 &Q,
690 &G_factors,
691 &H_factors,
692 gens.G(padded_n).cloned().collect(),
693 gens.H(padded_n).cloned().collect(),
694 l_vec,
695 r_vec,
696 );
697
698 for scalar in s_L1
702 .iter_mut()
703 .chain(s_L2.iter_mut())
704 .chain(s_R1.iter_mut())
705 .chain(s_R2.iter_mut())
706 {
707 scalar.clear();
708 }
709 let proof = R1CSProof {
710 A_I1,
711 A_O1,
712 S1,
713 A_I2,
714 A_O2,
715 S2,
716 T_1,
717 T_3,
718 T_4,
719 T_5,
720 T_6,
721 t_x,
722 t_x_blinding,
723 e_blinding,
724 ipp_proof,
725 };
726 Ok((proof, self.transcript))
727 }
728}