Skip to main content

ark_bulletproofs/r1cs/
prover.rs

1#![allow(non_snake_case)]
2
3use ark_ec::{AffineRepr, CurveGroup, VariableBaseMSM};
4use ark_ff::{Field, PrimeField, UniformRand};
5use ark_serialize::CanonicalSerialize;
6use ark_std::{borrow::BorrowMut, boxed::Box, mem, vec, vec::Vec, One, Zero};
7use clear_on_drop::clear::Clear;
8use merlin::Transcript;
9use rand_core::{CryptoRng, RngCore};
10
11use super::{
12    ConstraintSystem, LinearCombination, R1CSProof, RandomizableConstraintSystem,
13    RandomizedConstraintSystem, Variable,
14};
15
16use crate::errors::R1CSError;
17use crate::generators::{BulletproofGens, PedersenGens};
18use crate::inner_product_proof::InnerProductProof;
19use crate::transcript::TranscriptProtocol;
20
21/// A [`ConstraintSystem`] implementation for use by the prover.
22///
23/// The prover commits high-level variables and their blinding factors `(v, v_blinding)`,
24/// allocates low-level variables and creates constraints in terms of these
25/// high-level variables and low-level variables.
26///
27/// When all constraints are added, the proving code calls `prove`
28/// which consumes the `Prover` instance, samples random challenges
29/// that instantiate the randomized constraints, and creates a complete proof.
30pub struct Prover<'g, G: AffineRepr, T: BorrowMut<Transcript>> {
31    transcript: T,
32    pc_gens: &'g PedersenGens<G>,
33    /// The constraints accumulated so far.
34    constraints: Vec<LinearCombination<G::ScalarField>>,
35    /// Secret data
36    secrets: Secrets<G>,
37
38    /// This list holds closures that will be called in the second phase of the protocol,
39    /// when non-randomized variables are committed.
40    deferred_constraints:
41        Vec<Box<dyn Fn(&mut RandomizingProver<'g, G, T>) -> Result<(), R1CSError>>>,
42
43    /// Index of a pending multiplier that's not fully assigned yet.
44    pending_multiplier: Option<usize>,
45}
46
47/// Separate struct to implement Drop trait for (for zeroing),
48/// so that compiler does not prohibit us from moving the Transcript out of `prove()`.
49struct Secrets<G: AffineRepr> {
50    /// Stores assignments to the "left" of multiplication gates
51    a_L: Vec<G::ScalarField>,
52    /// Stores assignments to the "right" of multiplication gates
53    a_R: Vec<G::ScalarField>,
54    /// Stores assignments to the "output" of multiplication gates
55    a_O: Vec<G::ScalarField>,
56    /// High-level witness data (value openings to V commitments)
57    v: Vec<G::ScalarField>,
58    /// High-level witness data (blinding openings to V commitments)
59    v_blinding: Vec<G::ScalarField>,
60}
61
62/// Prover in the randomizing phase.
63///
64/// Note: this type is exported because it is used to specify the associated type
65/// in the public impl of a trait `ConstraintSystem`, which boils down to allowing compiler to
66/// monomorphize the closures for the proving and verifying code.
67/// However, this type cannot be instantiated by the user and therefore can only be used within
68/// the callback provided to `specify_randomized_constraints`.
69pub struct RandomizingProver<'g, G: AffineRepr, T: BorrowMut<Transcript>> {
70    prover: Prover<'g, G, T>,
71}
72
73/// Overwrite secrets with null bytes when they go out of scope.
74impl<G: AffineRepr> Drop for Secrets<G> {
75    fn drop(&mut self) {
76        self.v.clear();
77        self.v_blinding.clear();
78
79        // Important: due to how ClearOnDrop auto-implements InitializableFromZeroed
80        // for T: Default, calling .clear() on Vec compiles, but does not
81        // clear the content. Instead, it only clears the Vec's header.
82        // Clearing the underlying buffer item-by-item will do the job, but will
83        // keep the header as-is, which is fine since the header does not contain secrets.
84        for e in self.a_L.iter_mut() {
85            e.clear();
86        }
87        for e in self.a_R.iter_mut() {
88            e.clear();
89        }
90        for e in self.a_O.iter_mut() {
91            e.clear();
92        }
93    }
94}
95
96impl<'g, G: AffineRepr, T: BorrowMut<Transcript>> ConstraintSystem<G::ScalarField>
97    for Prover<'g, G, T>
98{
99    fn transcript(&mut self) -> &mut Transcript {
100        self.transcript.borrow_mut()
101    }
102
103    fn multiply(
104        &mut self,
105        mut left: LinearCombination<G::ScalarField>,
106        mut right: LinearCombination<G::ScalarField>,
107    ) -> (
108        Variable<G::ScalarField>,
109        Variable<G::ScalarField>,
110        Variable<G::ScalarField>,
111    ) {
112        // Synthesize the assignments for l,r,o
113        let l = self.eval(&left);
114        let r = self.eval(&right);
115        let o = l * r;
116
117        // Create variables for l,r,o ...
118        let l_var = Variable::MultiplierLeft(self.secrets.a_L.len());
119        let r_var = Variable::MultiplierRight(self.secrets.a_R.len());
120        let o_var = Variable::MultiplierOutput(self.secrets.a_O.len());
121        // ... and assign them
122        self.secrets.a_L.push(l);
123        self.secrets.a_R.push(r);
124        self.secrets.a_O.push(o);
125
126        // Constrain l,r,o:
127        left.terms.push((l_var, -G::ScalarField::one()));
128        right.terms.push((r_var, -G::ScalarField::one()));
129        self.constrain(left);
130        self.constrain(right);
131
132        (l_var, r_var, o_var)
133    }
134
135    fn allocate(
136        &mut self,
137        assignment: Option<G::ScalarField>,
138    ) -> Result<Variable<G::ScalarField>, R1CSError> {
139        let scalar = assignment.ok_or(R1CSError::MissingAssignment)?;
140
141        match self.pending_multiplier {
142            None => {
143                let i = self.secrets.a_L.len();
144                self.pending_multiplier = Some(i);
145                self.secrets.a_L.push(scalar);
146                self.secrets.a_R.push(G::ScalarField::zero());
147                self.secrets.a_O.push(G::ScalarField::zero());
148                Ok(Variable::MultiplierLeft(i))
149            }
150            Some(i) => {
151                self.pending_multiplier = None;
152                self.secrets.a_R[i] = scalar;
153                self.secrets.a_O[i] = self.secrets.a_L[i] * self.secrets.a_R[i];
154                Ok(Variable::MultiplierRight(i))
155            }
156        }
157    }
158
159    fn allocate_multiplier(
160        &mut self,
161        input_assignments: Option<(G::ScalarField, G::ScalarField)>,
162    ) -> Result<
163        (
164            Variable<G::ScalarField>,
165            Variable<G::ScalarField>,
166            Variable<G::ScalarField>,
167        ),
168        R1CSError,
169    > {
170        let (l, r) = input_assignments.ok_or(R1CSError::MissingAssignment)?;
171        let o = l * r;
172
173        // Create variables for l,r,o ...
174        let l_var = Variable::MultiplierLeft(self.secrets.a_L.len());
175        let r_var = Variable::MultiplierRight(self.secrets.a_R.len());
176        let o_var = Variable::MultiplierOutput(self.secrets.a_O.len());
177        // ... and assign them
178        self.secrets.a_L.push(l);
179        self.secrets.a_R.push(r);
180        self.secrets.a_O.push(o);
181
182        Ok((l_var, r_var, o_var))
183    }
184
185    fn multipliers_len(&self) -> usize {
186        self.secrets.a_L.len()
187    }
188
189    fn constrain(&mut self, lc: LinearCombination<G::ScalarField>) {
190        // TODO: check that the linear combinations are valid
191        // (e.g. that variables are valid, that the linear combination evals to 0 for prover, etc).
192        self.constraints.push(lc);
193    }
194}
195
196impl<'g, G: AffineRepr, T: BorrowMut<Transcript>> RandomizableConstraintSystem<G::ScalarField>
197    for Prover<'g, G, T>
198{
199    type RandomizedCS = RandomizingProver<'g, G, T>;
200
201    fn specify_randomized_constraints<F>(&mut self, callback: F) -> Result<(), R1CSError>
202    where
203        F: 'static + Fn(&mut Self::RandomizedCS) -> Result<(), R1CSError>,
204    {
205        self.deferred_constraints.push(Box::new(callback));
206        Ok(())
207    }
208}
209
210impl<'g, G: AffineRepr, T: BorrowMut<Transcript>> ConstraintSystem<G::ScalarField>
211    for RandomizingProver<'g, G, T>
212{
213    fn transcript(&mut self) -> &mut Transcript {
214        self.prover.transcript.borrow_mut()
215    }
216
217    fn multiply(
218        &mut self,
219        left: LinearCombination<G::ScalarField>,
220        right: LinearCombination<G::ScalarField>,
221    ) -> (
222        Variable<G::ScalarField>,
223        Variable<G::ScalarField>,
224        Variable<G::ScalarField>,
225    ) {
226        self.prover.multiply(left, right)
227    }
228
229    fn allocate(
230        &mut self,
231        assignment: Option<G::ScalarField>,
232    ) -> Result<Variable<G::ScalarField>, R1CSError> {
233        self.prover.allocate(assignment)
234    }
235
236    fn allocate_multiplier(
237        &mut self,
238        input_assignments: Option<(G::ScalarField, G::ScalarField)>,
239    ) -> Result<
240        (
241            Variable<G::ScalarField>,
242            Variable<G::ScalarField>,
243            Variable<G::ScalarField>,
244        ),
245        R1CSError,
246    > {
247        self.prover.allocate_multiplier(input_assignments)
248    }
249
250    fn multipliers_len(&self) -> usize {
251        self.prover.multipliers_len()
252    }
253
254    fn constrain(&mut self, lc: LinearCombination<G::ScalarField>) {
255        self.prover.constrain(lc)
256    }
257}
258
259impl<'g, G: AffineRepr, T: BorrowMut<Transcript>> RandomizedConstraintSystem<G::ScalarField>
260    for RandomizingProver<'g, G, T>
261{
262    fn challenge_scalar(&mut self, label: &'static [u8]) -> G::ScalarField {
263        <Transcript as TranscriptProtocol<G>>::challenge_scalar(
264            self.prover.transcript.borrow_mut(),
265            label,
266        )
267    }
268}
269
270impl<'g, G: AffineRepr, T: BorrowMut<Transcript>> Prover<'g, G, T> {
271    /// Construct an empty constraint system with specified external
272    /// input variables.
273    ///
274    /// # Inputs
275    ///
276    /// The `bp_gens` and `pc_gens` are generators for Bulletproofs
277    /// and for the Pedersen commitments, respectively.  The
278    /// [`BulletproofGens`] should have `gens_capacity` greater than
279    /// the number of multiplication constraints that will eventually
280    /// be added into the constraint system.
281    ///
282    /// The `transcript` parameter is a Merlin proof transcript.  The
283    /// `ProverCS` holds onto the `&mut Transcript` until it consumes
284    /// itself during [`ProverCS::prove`], releasing its borrow of the
285    /// transcript.  This ensures that the transcript cannot be
286    /// altered except by the `ProverCS` before proving is complete.
287    ///
288    /// # Returns
289    ///
290    /// Returns a new `Prover` instance.
291    pub fn new(pc_gens: &'g PedersenGens<G>, mut transcript: T) -> Self {
292        <Transcript as TranscriptProtocol<G>>::r1cs_domain_sep(transcript.borrow_mut());
293
294        Prover {
295            pc_gens,
296            transcript,
297            secrets: Secrets {
298                v: Vec::new(),
299                v_blinding: Vec::new(),
300                a_L: Vec::new(),
301                a_R: Vec::new(),
302                a_O: Vec::new(),
303            },
304            constraints: Vec::new(),
305            deferred_constraints: Vec::new(),
306            pending_multiplier: None,
307        }
308    }
309
310    /// Creates commitment to a high-level variable and adds it to the transcript.
311    ///
312    /// # Inputs
313    ///
314    /// The `v` and `v_blinding` parameters are openings to the
315    /// commitment to the external variable for the constraint
316    /// system.  Passing the opening (the value together with the
317    /// blinding factor) makes it possible to reference pre-existing
318    /// commitments in the constraint system.  All external variables
319    /// must be passed up-front, so that challenges produced by
320    /// [`ConstraintSystem::challenge_scalar`] are bound to the
321    /// external variables.
322    ///
323    /// # Returns
324    ///
325    /// Returns a pair of a Pedersen commitment (as a compressed Ristretto point),
326    /// and a [`Variable`] corresponding to it, which can be used to form constraints.
327    pub fn commit(
328        &mut self,
329        v: G::ScalarField,
330        v_blinding: G::ScalarField,
331    ) -> (G, Variable<G::ScalarField>) {
332        let i = self.secrets.v.len();
333        self.secrets.v.push(v);
334        self.secrets.v_blinding.push(v_blinding);
335
336        // Add the commitment to the transcript.
337        let V = self.pc_gens.commit(v, v_blinding);
338        self.transcript.borrow_mut().append_point(b"V", &V);
339
340        (V, Variable::Committed(i))
341    }
342
343    /// Use a challenge, `z`, to flatten the constraints in the
344    /// constraint system into vectors used for proving and
345    /// verification.
346    ///
347    /// # Output
348    ///
349    /// Returns a tuple of
350    /// ```text
351    /// (wL, wR, wO, wV)
352    /// ```
353    /// where `w{L,R,O}` is \\( z \cdot z^Q \cdot W_{L,R,O} \\).
354    fn flattened_constraints(
355        &mut self,
356        z: &G::ScalarField,
357    ) -> (
358        Vec<G::ScalarField>,
359        Vec<G::ScalarField>,
360        Vec<G::ScalarField>,
361        Vec<G::ScalarField>,
362    ) {
363        let n = self.secrets.a_L.len();
364        let m = self.secrets.v.len();
365
366        let mut wL = vec![G::ScalarField::zero(); n];
367        let mut wR = vec![G::ScalarField::zero(); n];
368        let mut wO = vec![G::ScalarField::zero(); n];
369        let mut wV = vec![G::ScalarField::zero(); m];
370
371        let mut exp_z = *z;
372        for lc in self.constraints.iter() {
373            for (var, coeff) in &lc.terms {
374                match var {
375                    Variable::MultiplierLeft(i) => {
376                        wL[*i] += exp_z * coeff;
377                    }
378                    Variable::MultiplierRight(i) => {
379                        wR[*i] += exp_z * coeff;
380                    }
381                    Variable::MultiplierOutput(i) => {
382                        wO[*i] += exp_z * coeff;
383                    }
384                    Variable::Committed(i) => {
385                        wV[*i] -= exp_z * coeff;
386                    }
387                    Variable::One() => {
388                        // The prover doesn't need to handle constant terms
389                    }
390                    _ => {}
391                }
392            }
393            exp_z *= z;
394        }
395
396        (wL, wR, wO, wV)
397    }
398
399    fn eval(&self, lc: &LinearCombination<G::ScalarField>) -> G::ScalarField {
400        lc.terms
401            .iter()
402            .map(|(var, coeff)| {
403                *coeff
404                    * match var {
405                        Variable::MultiplierLeft(i) => self.secrets.a_L[*i],
406                        Variable::MultiplierRight(i) => self.secrets.a_R[*i],
407                        Variable::MultiplierOutput(i) => self.secrets.a_O[*i],
408                        Variable::Committed(i) => self.secrets.v[*i],
409                        Variable::One() => G::ScalarField::one(),
410                        _ => G::ScalarField::zero(),
411                    }
412            })
413            .sum()
414    }
415
416    /// Calls all remembered callbacks with an API that
417    /// allows generating challenge scalars.
418    fn create_randomized_constraints(mut self) -> Result<Self, R1CSError> {
419        // Clear the pending multiplier (if any) because it was committed into A_L/A_R/S.
420        self.pending_multiplier = None;
421
422        if self.deferred_constraints.len() == 0 {
423            <Transcript as TranscriptProtocol<G>>::r1cs_1phase_domain_sep(
424                self.transcript.borrow_mut(),
425            );
426            Ok(self)
427        } else {
428            <Transcript as TranscriptProtocol<G>>::r1cs_2phase_domain_sep(
429                self.transcript.borrow_mut(),
430            );
431            // Note: the wrapper could've used &mut instead of ownership,
432            // but specifying lifetimes for boxed closures is not going to be nice,
433            // so we move the self into wrapper and then move it back out afterwards.
434            let mut callbacks = mem::replace(&mut self.deferred_constraints, Vec::new());
435            let mut wrapped_self = RandomizingProver { prover: self };
436            for callback in callbacks.drain(..) {
437                callback(&mut wrapped_self)?;
438            }
439            Ok(wrapped_self.prover)
440        }
441    }
442
443    /// Consume this `ConstraintSystem` to produce a proof.
444    pub fn prove<R: CryptoRng + RngCore>(
445        self,
446        prng: &mut R,
447        bp_gens: &BulletproofGens<G>,
448    ) -> Result<R1CSProof<G>, R1CSError> {
449        self.prove_and_return_transcript(prng, bp_gens)
450            .map(|(proof, _transcript)| proof)
451    }
452
453    /// Consume this `ConstraintSystem` to produce a proof. Returns the proof and the transcript passed in `Prover::new`.
454    pub fn prove_and_return_transcript<R: CryptoRng + RngCore>(
455        mut self,
456        prng: &mut R,
457        bp_gens: &BulletproofGens<G>,
458    ) -> Result<(R1CSProof<G>, T), R1CSError> {
459        use crate::util;
460        use ark_std::iter;
461
462        // Commit a length _suffix_ for the number of high-level variables.
463        // We cannot do this in advance because user can commit variables one-by-one,
464        // but this suffix provides safe disambiguation because each variable
465        // is prefixed with a separate label.
466        self.transcript
467            .borrow_mut()
468            .append_u64(b"m", self.secrets.v.len() as u64);
469
470        // Create a `TranscriptRng` from the high-level witness data
471        //
472        // The prover wants to rekey the RNG with its witness data.
473        //
474        // This consists of the high level witness data (the v's and
475        // v_blinding's), as well as the low-level witness data (a_L,
476        // a_R, a_O).  Since the low-level data should (hopefully) be
477        // determined by the high-level data, it doesn't give any
478        // extra entropy for reseeding the RNG.
479        //
480        // Since the v_blindings should be random scalars (in order to
481        // protect the v's in the commitments), we don't gain much by
482        // committing the v's as well as the v_blinding's.
483        let mut rng = {
484            let mut builder = self.transcript.borrow_mut().build_rng();
485
486            // Commit the blinding factors for the input wires
487            for v_b in &self.secrets.v_blinding {
488                let mut bytes = Vec::new();
489                v_b.serialize_uncompressed(&mut bytes).unwrap();
490                builder = builder.rekey_with_witness_bytes(b"v_blinding", &bytes);
491            }
492
493            builder.finalize(prng)
494        };
495
496        // Commit to the first-phase low-level witness variables.
497        let n1 = self.secrets.a_L.len();
498
499        if bp_gens.gens_capacity < n1 {
500            return Err(R1CSError::InvalidGeneratorsLength);
501        }
502
503        // We are performing a single-party circuit proof, so party index is 0.
504        let gens = bp_gens.share(0);
505
506        let i_blinding1 = G::ScalarField::rand(&mut rng);
507        let o_blinding1 = G::ScalarField::rand(&mut rng);
508        let s_blinding1 = G::ScalarField::rand(&mut rng);
509
510        let mut s_L1: Vec<G::ScalarField> =
511            (0..n1).map(|_| G::ScalarField::rand(&mut rng)).collect();
512        let mut s_R1: Vec<G::ScalarField> =
513            (0..n1).map(|_| G::ScalarField::rand(&mut rng)).collect();
514
515        // A_I = <a_L, G> + <a_R, H> + i_blinding * B_blinding
516        let A_I1 = G::Group::msm(
517            &iter::once(&self.pc_gens.B_blinding)
518                .chain(gens.G(n1))
519                .chain(gens.H(n1))
520                .map(|f| f.clone())
521                .collect::<Vec<G>>(),
522            &iter::once(&i_blinding1)
523                .chain(self.secrets.a_L.iter())
524                .chain(self.secrets.a_R.iter())
525                .map(|f| *f)
526                .collect::<Vec<G::ScalarField>>(),
527        )
528        .unwrap()
529        .into_affine();
530
531        // A_O = <a_O, G> + o_blinding * B_blinding
532        let A_O1 = G::Group::msm(
533            &iter::once(&self.pc_gens.B_blinding)
534                .chain(gens.G(n1))
535                .map(|f| f.clone())
536                .collect::<Vec<G>>(),
537            &iter::once(&o_blinding1)
538                .chain(self.secrets.a_O.iter())
539                .map(|f| *f)
540                .collect::<Vec<G::ScalarField>>(),
541        )
542        .unwrap()
543        .into_affine();
544
545        // S = <s_L, G> + <s_R, H> + s_blinding * B_blinding
546        let S1 = G::Group::msm(
547            &iter::once(&self.pc_gens.B_blinding)
548                .chain(gens.G(n1))
549                .chain(gens.H(n1))
550                .map(|f| f.clone())
551                .collect::<Vec<G>>(),
552            &iter::once(&s_blinding1)
553                .chain(s_L1.iter())
554                .chain(s_R1.iter())
555                .map(|f| *f)
556                .collect::<Vec<G::ScalarField>>(),
557        )
558        .unwrap()
559        .into_affine();
560
561        let transcript = self.transcript.borrow_mut();
562        transcript.append_point(b"A_I1", &A_I1);
563        transcript.append_point(b"A_O1", &A_O1);
564        transcript.append_point(b"S1", &S1);
565
566        // Process the remaining constraints.
567        self = self.create_randomized_constraints()?;
568
569        // Pad zeros to the next power of two (or do that implicitly when creating vectors)
570
571        // If the number of multiplications is not 0 or a power of 2, then pad the circuit.
572        let n = self.secrets.a_L.len();
573        let n2 = n - n1;
574        let padded_n = self.secrets.a_L.len().next_power_of_two();
575        let pad = padded_n - n;
576
577        if bp_gens.gens_capacity < padded_n {
578            return Err(R1CSError::InvalidGeneratorsLength);
579        }
580
581        // Commit to the second-phase low-level witness variables
582
583        let has_2nd_phase_commitments = n2 > 0;
584
585        let (i_blinding2, o_blinding2, s_blinding2) = if has_2nd_phase_commitments {
586            (
587                G::ScalarField::rand(&mut rng),
588                G::ScalarField::rand(&mut rng),
589                G::ScalarField::rand(&mut rng),
590            )
591        } else {
592            (
593                G::ScalarField::zero(),
594                G::ScalarField::zero(),
595                G::ScalarField::zero(),
596            )
597        };
598
599        let mut s_L2: Vec<G::ScalarField> =
600            (0..n2).map(|_| G::ScalarField::rand(&mut rng)).collect();
601        let mut s_R2: Vec<G::ScalarField> =
602            (0..n2).map(|_| G::ScalarField::rand(&mut rng)).collect();
603
604        let (A_I2, A_O2, S2) = if has_2nd_phase_commitments {
605            (
606                // A_I = <a_L, G> + <a_R, H> + i_blinding * B_blinding
607                G::Group::msm(
608                    &iter::once(&self.pc_gens.B_blinding)
609                        .chain(gens.G(n).skip(n1))
610                        .chain(gens.H(n).skip(n1))
611                        .map(|f| f.clone())
612                        .collect::<Vec<G>>(),
613                    &iter::once(&i_blinding2)
614                        .chain(self.secrets.a_L.iter().skip(n1))
615                        .chain(self.secrets.a_R.iter().skip(n1))
616                        .map(|f| *f)
617                        .collect::<Vec<G::ScalarField>>(),
618                )
619                .unwrap()
620                .into_affine(),
621                // A_O = <a_O, G> + o_blinding * B_blinding
622                G::Group::msm(
623                    &iter::once(&self.pc_gens.B_blinding)
624                        .chain(gens.G(n).skip(n1))
625                        .map(|f| f.clone())
626                        .collect::<Vec<G>>(),
627                    &iter::once(&o_blinding2)
628                        .chain(self.secrets.a_O.iter().skip(n1))
629                        .map(|f| *f)
630                        .collect::<Vec<G::ScalarField>>(),
631                )
632                .unwrap()
633                .into_affine(),
634                // S = <s_L, G> + <s_R, H> + s_blinding * B_blinding
635                G::Group::msm(
636                    &iter::once(&self.pc_gens.B_blinding)
637                        .chain(gens.G(n).skip(n1))
638                        .chain(gens.H(n).skip(n1))
639                        .map(|f| f.clone())
640                        .collect::<Vec<G>>(),
641                    &iter::once(&s_blinding2)
642                        .chain(s_L2.iter())
643                        .chain(s_R2.iter())
644                        .map(|f| *f)
645                        .collect::<Vec<G::ScalarField>>(),
646                )
647                .unwrap()
648                .into_affine(),
649            )
650        } else {
651            // Since we are using zero blinding factors and
652            // there are no variables to commit,
653            // the commitments _must_ be identity points,
654            // so we can hardcode them saving 3 mults+compressions.
655            (G::zero(), G::zero(), G::zero())
656        };
657
658        let transcript = self.transcript.borrow_mut();
659        transcript.append_point(b"A_I2", &A_I2);
660        transcript.append_point(b"A_O2", &A_O2);
661        transcript.append_point(b"S2", &S2);
662
663        // 4. Compute blinded vector polynomials l(x) and r(x)
664
665        let y: G::ScalarField =
666            <Transcript as TranscriptProtocol<G>>::challenge_scalar(transcript, b"y");
667        let z = <Transcript as TranscriptProtocol<G>>::challenge_scalar(transcript, b"z");
668
669        let (wL, wR, wO, wV) = self.flattened_constraints(&z);
670
671        let mut l_poly = util::VecPoly3::<G>::zero(n);
672        let mut r_poly = util::VecPoly3::<G>::zero(n);
673
674        let mut exp_y = G::ScalarField::one(); // y^n starting at n=0
675        let y_inv = y.inverse().unwrap();
676        let exp_y_inv = util::exp_iter::<G>(y_inv)
677            .take(padded_n)
678            .collect::<Vec<_>>();
679
680        let sLsR = s_L1
681            .iter()
682            .chain(s_L2.iter())
683            .zip(s_R1.iter().chain(s_R2.iter()));
684        for (i, (sl, sr)) in sLsR.enumerate() {
685            // l_poly.0 = 0
686            // l_poly.1 = a_L + y^-n * (z * z^Q * W_R)
687            l_poly.1[i] = self.secrets.a_L[i] + exp_y_inv[i] * wR[i];
688            // l_poly.2 = a_O
689            l_poly.2[i] = self.secrets.a_O[i];
690            // l_poly.3 = s_L
691            l_poly.3[i] = *sl;
692            // r_poly.0 = (z * z^Q * W_O) - y^n
693            r_poly.0[i] = wO[i] - exp_y;
694            // r_poly.1 = y^n * a_R + (z * z^Q * W_L)
695            r_poly.1[i] = exp_y * self.secrets.a_R[i] + wL[i];
696            // r_poly.2 = 0
697            // r_poly.3 = y^n * s_R
698            r_poly.3[i] = exp_y * sr;
699
700            exp_y = exp_y * y; // y^i -> y^(i+1)
701        }
702
703        let t_poly = util::VecPoly3::special_inner_product(&l_poly, &r_poly);
704
705        let t_1_blinding = G::ScalarField::rand(&mut rng);
706        let t_3_blinding = G::ScalarField::rand(&mut rng);
707        let t_4_blinding = G::ScalarField::rand(&mut rng);
708        let t_5_blinding = G::ScalarField::rand(&mut rng);
709        let t_6_blinding = G::ScalarField::rand(&mut rng);
710
711        let T_1 = self.pc_gens.commit(t_poly.t1, t_1_blinding);
712        let T_3 = self.pc_gens.commit(t_poly.t3, t_3_blinding);
713        let T_4 = self.pc_gens.commit(t_poly.t4, t_4_blinding);
714        let T_5 = self.pc_gens.commit(t_poly.t5, t_5_blinding);
715        let T_6 = self.pc_gens.commit(t_poly.t6, t_6_blinding);
716
717        let transcript = self.transcript.borrow_mut();
718        transcript.append_point(b"T_1", &T_1);
719        transcript.append_point(b"T_3", &T_3);
720        transcript.append_point(b"T_4", &T_4);
721        transcript.append_point(b"T_5", &T_5);
722        transcript.append_point(b"T_6", &T_6);
723
724        let u = <Transcript as TranscriptProtocol<G>>::challenge_scalar(transcript, b"u");
725        let x = <Transcript as TranscriptProtocol<G>>::challenge_scalar(transcript, b"x");
726
727        // t_2_blinding = <z*z^Q, W_V * v_blinding>
728        // in the t_x_blinding calculations, line 76.
729        let t_2_blinding: G::ScalarField = wV
730            .iter()
731            .zip(self.secrets.v_blinding.iter())
732            .map(|(c, v_blinding)| *v_blinding * c)
733            .sum();
734
735        let t_blinding_poly = util::Poly6::<G> {
736            t1: t_1_blinding,
737            t2: t_2_blinding,
738            t3: t_3_blinding,
739            t4: t_4_blinding,
740            t5: t_5_blinding,
741            t6: t_6_blinding,
742        };
743
744        let t_x = t_poly.eval(x);
745        let t_x_blinding = t_blinding_poly.eval(x);
746        let mut l_vec = l_poly.eval(x);
747        l_vec.append(&mut vec![G::ScalarField::zero(); pad]);
748
749        let mut r_vec = r_poly.eval(x);
750        r_vec.append(&mut vec![G::ScalarField::zero(); pad]);
751
752        // XXX this should refer to the notes to explain why this is correct
753        for i in n..padded_n {
754            r_vec[i] = -exp_y;
755            exp_y = exp_y * y; // y^i -> y^(i+1)
756        }
757
758        let i_blinding = i_blinding1 + u * i_blinding2;
759        let o_blinding = o_blinding1 + u * o_blinding2;
760        let s_blinding = s_blinding1 + u * s_blinding2;
761
762        let e_blinding = x * (i_blinding + x * (o_blinding + x * s_blinding));
763
764        <Transcript as TranscriptProtocol<G>>::append_scalar(transcript, b"t_x", &t_x);
765        <Transcript as TranscriptProtocol<G>>::append_scalar(
766            transcript,
767            b"t_x_blinding",
768            &t_x_blinding,
769        );
770        <Transcript as TranscriptProtocol<G>>::append_scalar(
771            transcript,
772            b"e_blinding",
773            &e_blinding,
774        );
775
776        // Get a challenge value to combine statements for the IPP
777        let w: G::ScalarField =
778            <Transcript as TranscriptProtocol<G>>::challenge_scalar(transcript, b"w");
779        let Q = self.pc_gens.B.mul_bigint(w.into_bigint());
780
781        let G_factors = iter::repeat(G::ScalarField::one())
782            .take(n1)
783            .chain(iter::repeat(u).take(n2 + pad))
784            .collect::<Vec<_>>();
785        let H_factors = exp_y_inv
786            .into_iter()
787            .zip(G_factors.iter())
788            .map(|(y, u_or_1)| y * u_or_1)
789            .collect::<Vec<_>>();
790
791        let ipp_proof = InnerProductProof::create(
792            transcript,
793            &Q.into_affine(),
794            &G_factors,
795            &H_factors,
796            gens.G(padded_n).cloned().collect(),
797            gens.H(padded_n).cloned().collect(),
798            l_vec,
799            r_vec,
800        );
801
802        // We do not yet have a ClearOnDrop wrapper for Vec<Fr>.
803        // When PR 202 [1] is merged, we can simply wrap s_L and s_R at the point of creation.
804        // [1] https://github.com/dalek-cryptography/curve25519-dalek/pull/202
805        for scalar in s_L1
806            .iter_mut()
807            .chain(s_L2.iter_mut())
808            .chain(s_R1.iter_mut())
809            .chain(s_R2.iter_mut())
810        {
811            scalar.clear();
812        }
813        let proof = R1CSProof {
814            A_I1,
815            A_O1,
816            S1,
817            A_I2,
818            A_O2,
819            S2,
820            T_1,
821            T_3,
822            T_4,
823            T_5,
824            T_6,
825            t_x,
826            t_x_blinding,
827            e_blinding,
828            ipp_proof,
829        };
830        Ok((proof, self.transcript))
831    }
832}