1#![allow(non_snake_case)]
2
3use alloc::{boxed::Box, vec, vec::Vec};
4use core::borrow::BorrowMut;
5use core::mem;
6use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoPoint};
7use curve25519_dalek::scalar::Scalar;
8use curve25519_dalek::traits::{Identity, MultiscalarMul, VartimeMultiscalarMul};
9use merlin::Transcript;
10use rand_core::{CryptoRng, RngCore};
11
12use super::{
13 ConstraintSystem, LinearCombination, R1CSProof, RandomizableConstraintSystem,
14 RandomizedConstraintSystem, Variable,
15};
16
17use crate::errors::R1CSError;
18use crate::generators::{BulletproofGens, PedersenGens};
19use crate::transcript::TranscriptProtocol;
20
21pub struct Verifier<T: BorrowMut<Transcript>> {
31 transcript: T,
32 constraints: Vec<LinearCombination>,
33
34 num_vars: usize,
42 V: Vec<CompressedRistretto>,
43
44 deferred_constraints: Vec<Box<dyn Fn(&mut RandomizingVerifier<T>) -> Result<(), R1CSError>>>,
49
50 pending_multiplier: Option<usize>,
52}
53
54pub struct RandomizingVerifier<T: BorrowMut<Transcript>> {
62 verifier: Verifier<T>,
63}
64
65impl<T: BorrowMut<Transcript>> ConstraintSystem for Verifier<T> {
66 fn transcript(&mut self) -> &mut Transcript {
67 self.transcript.borrow_mut()
68 }
69
70 fn multiply(
71 &mut self,
72 mut left: LinearCombination,
73 mut right: LinearCombination,
74 ) -> (Variable, Variable, Variable) {
75 let var = self.num_vars;
76 self.num_vars += 1;
77
78 let l_var = Variable::MultiplierLeft(var);
80 let r_var = Variable::MultiplierRight(var);
81 let o_var = Variable::MultiplierOutput(var);
82
83 left.terms.push((l_var, -Scalar::one()));
85 right.terms.push((r_var, -Scalar::one()));
86 self.constrain(left);
87 self.constrain(right);
88
89 (l_var, r_var, o_var)
90 }
91
92 fn allocate(&mut self, _: Option<Scalar>) -> Result<Variable, R1CSError> {
93 match self.pending_multiplier {
94 None => {
95 let i = self.num_vars;
96 self.num_vars += 1;
97 self.pending_multiplier = Some(i);
98 Ok(Variable::MultiplierLeft(i))
99 }
100 Some(i) => {
101 self.pending_multiplier = None;
102 Ok(Variable::MultiplierRight(i))
103 }
104 }
105 }
106
107 fn allocate_multiplier(
108 &mut self,
109 _: Option<(Scalar, Scalar)>,
110 ) -> Result<(Variable, Variable, Variable), R1CSError> {
111 let var = self.num_vars;
112 self.num_vars += 1;
113
114 let l_var = Variable::MultiplierLeft(var);
116 let r_var = Variable::MultiplierRight(var);
117 let o_var = Variable::MultiplierOutput(var);
118
119 Ok((l_var, r_var, o_var))
120 }
121
122 fn multipliers_len(&self) -> usize {
123 self.num_vars
124 }
125
126 fn constrain(&mut self, lc: LinearCombination) {
127 self.constraints.push(lc);
131 }
132}
133
134impl<T: BorrowMut<Transcript>> RandomizableConstraintSystem for Verifier<T> {
135 type RandomizedCS = RandomizingVerifier<T>;
136
137 fn specify_randomized_constraints<F>(&mut self, callback: F) -> Result<(), R1CSError>
138 where
139 F: 'static + Fn(&mut Self::RandomizedCS) -> Result<(), R1CSError>,
140 {
141 self.deferred_constraints.push(Box::new(callback));
142 Ok(())
143 }
144}
145
146impl<T: BorrowMut<Transcript>> ConstraintSystem for RandomizingVerifier<T> {
147 fn transcript(&mut self) -> &mut Transcript {
148 self.verifier.transcript.borrow_mut()
149 }
150
151 fn multiply(
152 &mut self,
153 left: LinearCombination,
154 right: LinearCombination,
155 ) -> (Variable, Variable, Variable) {
156 self.verifier.multiply(left, right)
157 }
158
159 fn allocate(&mut self, assignment: Option<Scalar>) -> Result<Variable, R1CSError> {
160 self.verifier.allocate(assignment)
161 }
162
163 fn allocate_multiplier(
164 &mut self,
165 input_assignments: Option<(Scalar, Scalar)>,
166 ) -> Result<(Variable, Variable, Variable), R1CSError> {
167 self.verifier.allocate_multiplier(input_assignments)
168 }
169
170 fn multipliers_len(&self) -> usize {
171 self.verifier.multipliers_len()
172 }
173
174 fn constrain(&mut self, lc: LinearCombination) {
175 self.verifier.constrain(lc)
176 }
177}
178
179impl<T: BorrowMut<Transcript>> RandomizedConstraintSystem for RandomizingVerifier<T> {
180 fn challenge_scalar(&mut self, label: &'static [u8]) -> Scalar {
181 self.verifier
182 .transcript
183 .borrow_mut()
184 .challenge_scalar(label)
185 }
186}
187
188impl<T: BorrowMut<Transcript>> Verifier<T> {
189 pub fn new(mut transcript: T) -> Self {
215 transcript.borrow_mut().r1cs_domain_sep();
216
217 Verifier {
218 transcript,
219 num_vars: 0,
220 V: Vec::new(),
221 constraints: Vec::new(),
222 deferred_constraints: Vec::new(),
223 pending_multiplier: None,
224 }
225 }
226
227 pub fn commit(&mut self, commitment: CompressedRistretto) -> Variable {
242 let i = self.V.len();
243 self.V.push(commitment);
244
245 self.transcript.borrow_mut().append_point(b"V", &commitment);
247
248 Variable::Committed(i)
249 }
250
251 fn flattened_constraints(
267 &mut self,
268 z: &Scalar,
269 ) -> (Vec<Scalar>, Vec<Scalar>, Vec<Scalar>, Vec<Scalar>, Scalar) {
270 let n = self.num_vars;
271 let m = self.V.len();
272
273 let mut wL = vec![Scalar::zero(); n];
274 let mut wR = vec![Scalar::zero(); n];
275 let mut wO = vec![Scalar::zero(); n];
276 let mut wV = vec![Scalar::zero(); m];
277 let mut wc = Scalar::zero();
278
279 let mut exp_z = *z;
280 for lc in self.constraints.iter() {
281 for (var, coeff) in &lc.terms {
282 match var {
283 Variable::MultiplierLeft(i) => {
284 wL[*i] += exp_z * coeff;
285 }
286 Variable::MultiplierRight(i) => {
287 wR[*i] += exp_z * coeff;
288 }
289 Variable::MultiplierOutput(i) => {
290 wO[*i] += exp_z * coeff;
291 }
292 Variable::Committed(i) => {
293 wV[*i] -= exp_z * coeff;
294 }
295 Variable::One() => {
296 wc -= exp_z * coeff;
297 }
298 }
299 }
300 exp_z *= z;
301 }
302
303 (wL, wR, wO, wV, wc)
304 }
305
306 fn create_randomized_constraints(mut self) -> Result<Self, R1CSError> {
309 self.pending_multiplier = None;
311
312 if self.deferred_constraints.len() == 0 {
313 self.transcript.borrow_mut().r1cs_1phase_domain_sep();
314 Ok(self)
315 } else {
316 self.transcript.borrow_mut().r1cs_2phase_domain_sep();
317 let mut callbacks = mem::replace(&mut self.deferred_constraints, Vec::new());
321 let mut wrapped_self = RandomizingVerifier { verifier: self };
322 for callback in callbacks.drain(..) {
323 callback(&mut wrapped_self)?;
324 }
325 Ok(wrapped_self.verifier)
326 }
327 }
328
329 pub(super) fn verification_scalars<R: RngCore + CryptoRng>(
346 mut self,
347 rng: &mut R,
348 proof: &R1CSProof,
349 bp_gens: &BulletproofGens,
350 ) -> Result<(Self, Vec<Scalar>), R1CSError> {
351 let transcript = self.transcript.borrow_mut();
356 transcript.append_u64(b"m", self.V.len() as u64);
357
358 let n1 = self.num_vars;
359 transcript.validate_and_append_point(b"A_I1", &proof.A_I1)?;
360 transcript.validate_and_append_point(b"A_O1", &proof.A_O1)?;
361 transcript.validate_and_append_point(b"S1", &proof.S1)?;
362
363 self = self.create_randomized_constraints()?;
365
366 let transcript = self.transcript.borrow_mut();
367
368 let n = self.num_vars;
370 let n2 = n - n1;
371 let padded_n = self.num_vars.next_power_of_two();
372 let pad = padded_n - n;
373
374 use crate::inner_product_proof::inner_product;
375 use crate::util;
376 use core::iter;
377
378 if bp_gens.gens_capacity < padded_n {
379 return Err(R1CSError::InvalidGeneratorsLength);
380 }
381
382 transcript.append_point(b"A_I2", &proof.A_I2);
384 transcript.append_point(b"A_O2", &proof.A_O2);
385 transcript.append_point(b"S2", &proof.S2);
386
387 let y = transcript.challenge_scalar(b"y");
388 let z = transcript.challenge_scalar(b"z");
389
390 transcript.validate_and_append_point(b"T_1", &proof.T_1)?;
391 transcript.validate_and_append_point(b"T_3", &proof.T_3)?;
392 transcript.validate_and_append_point(b"T_4", &proof.T_4)?;
393 transcript.validate_and_append_point(b"T_5", &proof.T_5)?;
394 transcript.validate_and_append_point(b"T_6", &proof.T_6)?;
395
396 let u = transcript.challenge_scalar(b"u");
397 let x = transcript.challenge_scalar(b"x");
398
399 transcript.append_scalar(b"t_x", &proof.t_x);
400 transcript.append_scalar(b"t_x_blinding", &proof.t_x_blinding);
401 transcript.append_scalar(b"e_blinding", &proof.e_blinding);
402
403 let w = transcript.challenge_scalar(b"w");
404
405 let (wL, wR, wO, wV, wc) = self.flattened_constraints(&z);
406
407 let (u_sq, u_inv_sq, s) = proof
409 .ipp_proof
410 .verification_scalars(padded_n, self.transcript.borrow_mut())
411 .map_err(|_| R1CSError::VerificationError)?;
412
413 let a = proof.ipp_proof.a;
414 let b = proof.ipp_proof.b;
415
416 let y_inv = y.invert();
417 let y_inv_vec = util::exp_iter(y_inv)
418 .take(padded_n)
419 .collect::<Vec<Scalar>>();
420 let yneg_wR = wR
421 .into_iter()
422 .zip(y_inv_vec.iter())
423 .map(|(wRi, exp_y_inv)| wRi * exp_y_inv)
424 .chain(iter::repeat(Scalar::zero()).take(pad))
425 .collect::<Vec<Scalar>>();
426
427 let delta = inner_product(&yneg_wR[0..n], &wL);
428
429 let u_for_g = iter::repeat(Scalar::one())
430 .take(n1)
431 .chain(iter::repeat(u).take(n2 + pad));
432 let u_for_h = u_for_g.clone();
433
434 let g_scalars: Vec<_> = yneg_wR
436 .iter()
437 .zip(u_for_g)
438 .zip(s.iter().take(padded_n))
439 .map(|((yneg_wRi, u_or_1), s_i)| u_or_1 * (x * yneg_wRi - a * s_i))
440 .collect();
441
442 let h_scalars: Vec<_> = y_inv_vec
443 .iter()
444 .zip(u_for_h)
445 .zip(s.iter().rev().take(padded_n))
446 .zip(wL.into_iter().chain(iter::repeat(Scalar::zero()).take(pad)))
447 .zip(wO.into_iter().chain(iter::repeat(Scalar::zero()).take(pad)))
448 .map(|((((y_inv_i, u_or_1), s_i_inv), wLi), wOi)| {
449 u_or_1 * (y_inv_i * (x * wLi + wOi - b * s_i_inv) - Scalar::one())
450 })
451 .collect();
452
453 let mut rng = self.transcript.borrow_mut().build_rng().finalize(rng);
457 let r = Scalar::random(&mut rng);
458
459 let xx = x * x;
460 let rxx = r * xx;
461 let xxx = x * xx;
462
463 let T_scalars = [r * x, rxx * x, rxx * xx, rxx * xxx, rxx * xx * xx];
465
466 let mut scalars: Vec<Scalar> = vec![];
467 scalars.push(w * (proof.t_x - a * b) + r * (xx * (wc + delta) - proof.t_x));
468 scalars.push(-proof.e_blinding - r * proof.t_x_blinding);
469 scalars.extend_from_slice(&g_scalars);
470 scalars.extend_from_slice(&h_scalars);
471 scalars.extend_from_slice(&[x, xx, xxx, u * x, u * xx, u * xxx]);
472 for wVi in wV.iter() {
473 scalars.push(wVi * rxx);
474 }
475 scalars.extend_from_slice(&T_scalars);
476 scalars.extend_from_slice(&u_sq);
477 scalars.extend_from_slice(&u_inv_sq);
478 Ok((self, scalars))
479 }
480
481 pub fn verify<R: RngCore + CryptoRng>(
488 self,
489 rng: &mut R,
490 proof: &R1CSProof,
491 pc_gens: &PedersenGens,
492 bp_gens: &BulletproofGens,
493 ) -> Result<(), R1CSError> {
494 self.verify_and_return_transcript(rng, proof, pc_gens, bp_gens)
495 .map(|_| ())
496 }
497 pub fn verify_and_return_transcript<R: RngCore + CryptoRng>(
499 mut self,
500 rng: &mut R,
501 proof: &R1CSProof,
502 pc_gens: &PedersenGens,
503 bp_gens: &BulletproofGens,
504 ) -> Result<T, R1CSError> {
505 let (verifier, scalars) = self.verification_scalars(rng, proof, bp_gens)?;
506 self = verifier;
507 let T_points = [proof.T_1, proof.T_3, proof.T_4, proof.T_5, proof.T_6];
508
509 let gens = bp_gens.share(0);
511
512 let padded_n = self.num_vars.next_power_of_two();
513
514 use core::iter;
515 let mega_check = RistrettoPoint::optional_multiscalar_mul(
516 scalars,
517 iter::once(Some(pc_gens.B))
518 .chain(iter::once(Some(pc_gens.B_blinding)))
519 .chain(gens.G(padded_n).map(|&G_i| Some(G_i)))
520 .chain(gens.H(padded_n).map(|&H_i| Some(H_i)))
521 .chain(iter::once(proof.A_I1.decompress()))
522 .chain(iter::once(proof.A_O1.decompress()))
523 .chain(iter::once(proof.S1.decompress()))
524 .chain(iter::once(proof.A_I2.decompress()))
525 .chain(iter::once(proof.A_O2.decompress()))
526 .chain(iter::once(proof.S2.decompress()))
527 .chain(self.V.iter().map(|V_i| V_i.decompress()))
528 .chain(T_points.iter().map(|T_i| T_i.decompress()))
529 .chain(proof.ipp_proof.L_vec.iter().map(|L_i| L_i.decompress()))
530 .chain(proof.ipp_proof.R_vec.iter().map(|R_i| R_i.decompress())),
531 )
532 .ok_or_else(|| R1CSError::VerificationError)?;
533
534 use curve25519_dalek::traits::IsIdentity;
535
536 if !mega_check.is_identity() {
537 return Err(R1CSError::VerificationError);
538 }
539
540 Ok(self.transcript)
541 }
542}
543
544pub fn batch_verify<'a, I, R: CryptoRng + RngCore>(
546 prng: &mut R,
547 instances: I,
548 pc_gens: &PedersenGens,
549 bp_gens: &BulletproofGens,
550) -> Result<(), R1CSError>
551where
552 I: IntoIterator<Item = (Verifier<&'a mut Transcript>, &'a R1CSProof)>,
553{
554 let mut max_n_padded = 0;
555 let mut verifiers: Vec<Verifier<_>> = vec![];
556 let mut proofs: Vec<&R1CSProof> = vec![];
557 let mut verification_scalars = vec![];
558 for (verifier, proof) in instances.into_iter() {
559 let (verifier, scalars) = verifier.verification_scalars(prng, proof, bp_gens)?;
561 let n = verifier.num_vars.next_power_of_two();
562 if n > max_n_padded {
563 max_n_padded = n;
564 }
565 verification_scalars.push(scalars);
566 verifiers.push(verifier);
567 proofs.push(proof);
568 }
569 let mut all_scalars = vec![];
570 let mut all_elems = vec![];
571
572 for _ in 0..(2 * max_n_padded + 2) {
573 all_scalars.push(Scalar::zero());
574 }
575 all_elems.push(pc_gens.B);
576 all_elems.push(pc_gens.B_blinding);
577 let gens = bp_gens.share(0);
578 for G in gens.G(max_n_padded) {
579 all_elems.push(*G);
580 }
581 for H in gens.H(max_n_padded) {
582 all_elems.push(*H);
583 }
584
585 for ((verifier, proof), scalars) in verifiers
586 .into_iter()
587 .zip(proofs.iter())
588 .zip(verification_scalars.iter())
589 {
590 let alpha = Scalar::random(prng);
591 let scaled_scalars: Vec<Scalar> = scalars.into_iter().map(|s| alpha * s).collect();
592 let padded_n = verifier.num_vars.next_power_of_two();
593 all_scalars[0] += scaled_scalars[0]; all_scalars[1] += scaled_scalars[1]; for (i, s) in (&scaled_scalars[2..2 + padded_n]).iter().enumerate() {
597 all_scalars[i + 2] += *s;
598 }
599 for (i, s) in (&scaled_scalars[2 + padded_n..2 + 2 * padded_n])
601 .iter()
602 .enumerate()
603 {
604 all_scalars[2 + max_n_padded + i] += *s;
605 }
606
607 for s in (&scaled_scalars[2 + 2 * padded_n..]).iter() {
608 all_scalars.push(*s);
609 }
610 all_elems.push(proof.A_I1.decompress().unwrap());
611 all_elems.push(proof.A_O1.decompress().unwrap());
612 all_elems.push(proof.S1.decompress().unwrap());
613 all_elems.push(proof.A_I2.decompress().unwrap());
614 all_elems.push(proof.A_O2.decompress().unwrap());
615 all_elems.push(proof.S2.decompress().unwrap());
616 let V: Vec<_> = verifier
617 .V
618 .iter()
619 .map(|Vi| Vi.decompress().unwrap())
620 .collect();
621 all_elems.extend_from_slice(V.as_slice());
622 all_elems.push(proof.T_1.decompress().unwrap());
623 all_elems.push(proof.T_3.decompress().unwrap());
624 all_elems.push(proof.T_4.decompress().unwrap());
625 all_elems.push(proof.T_5.decompress().unwrap());
626 all_elems.push(proof.T_6.decompress().unwrap());
627 let L_vec: Vec<_> = proof
628 .ipp_proof
629 .L_vec
630 .iter()
631 .map(|L| L.decompress().unwrap())
632 .collect();
633 let R_vec: Vec<_> = proof
634 .ipp_proof
635 .R_vec
636 .iter()
637 .map(|R| R.decompress().unwrap())
638 .collect();
639 all_elems.extend_from_slice(&L_vec);
640 all_elems.extend_from_slice(&R_vec);
641 }
642
643 let multi_exp = RistrettoPoint::multiscalar_mul(all_scalars, all_elems);
644 if multi_exp != RistrettoPoint::identity() {
645 Err(R1CSError::VerificationError)
646 } else {
647 Ok(())
648 }
649}