monero_bulletproofs/
batch_verifier.rs

1use std_shims::vec::Vec;
2
3use curve25519_dalek::{
4  constants::ED25519_BASEPOINT_POINT,
5  traits::{IsIdentity, VartimeMultiscalarMul},
6  scalar::Scalar,
7  edwards::EdwardsPoint,
8};
9
10use monero_generators::{H as MONERO_H, Generators};
11
12use crate::{original, plus};
13
14#[derive(Default)]
15pub(crate) struct InternalBatchVerifier {
16  pub(crate) g: Scalar,
17  pub(crate) h: Scalar,
18  pub(crate) g_bold: Vec<Scalar>,
19  pub(crate) h_bold: Vec<Scalar>,
20  pub(crate) other: Vec<(Scalar, EdwardsPoint)>,
21}
22
23impl InternalBatchVerifier {
24  #[must_use]
25  fn verify(self, G: EdwardsPoint, H: EdwardsPoint, generators: &Generators) -> bool {
26    let capacity = 2 + self.g_bold.len() + self.h_bold.len() + self.other.len();
27    let mut scalars = Vec::with_capacity(capacity);
28    let mut points = Vec::with_capacity(capacity);
29
30    scalars.push(self.g);
31    points.push(G);
32
33    scalars.push(self.h);
34    points.push(H);
35
36    for (i, g_bold) in self.g_bold.into_iter().enumerate() {
37      scalars.push(g_bold);
38      points.push(generators.G[i]);
39    }
40
41    for (i, h_bold) in self.h_bold.into_iter().enumerate() {
42      scalars.push(h_bold);
43      points.push(generators.H[i]);
44    }
45
46    for (scalar, point) in self.other {
47      scalars.push(scalar);
48      points.push(point);
49    }
50
51    EdwardsPoint::vartime_multiscalar_mul(scalars, points).is_identity()
52  }
53}
54
55#[derive(Default)]
56pub(crate) struct BulletproofsBatchVerifier(pub(crate) InternalBatchVerifier);
57impl BulletproofsBatchVerifier {
58  #[must_use]
59  pub(crate) fn verify(self) -> bool {
60    self.0.verify(ED25519_BASEPOINT_POINT, *MONERO_H, &original::GENERATORS)
61  }
62}
63
64#[derive(Default)]
65pub(crate) struct BulletproofsPlusBatchVerifier(pub(crate) InternalBatchVerifier);
66impl BulletproofsPlusBatchVerifier {
67  #[must_use]
68  pub(crate) fn verify(self) -> bool {
69    // Bulletproofs+ is written as per the paper, with G for the value and H for the mask
70    // Monero uses H for the value and G for the mask
71    self.0.verify(*MONERO_H, ED25519_BASEPOINT_POINT, &plus::GENERATORS)
72  }
73}
74
75/// A batch verifier for Bulletproofs(+).
76///
77/// This uses a fixed layout such that all fixed points only incur a single point scaling,
78/// regardless of the amounts of proofs verified. For all variable points (commitments), they're
79/// accumulated with the fixed points into a single multiscalar multiplication.
80#[derive(Default)]
81pub struct BatchVerifier {
82  pub(crate) original: BulletproofsBatchVerifier,
83  pub(crate) plus: BulletproofsPlusBatchVerifier,
84}
85impl BatchVerifier {
86  /// Create a new batch verifier.
87  pub fn new() -> Self {
88    Self {
89      original: BulletproofsBatchVerifier(InternalBatchVerifier::default()),
90      plus: BulletproofsPlusBatchVerifier(InternalBatchVerifier::default()),
91    }
92  }
93
94  /// Verify all of the proofs queued within this batch verifier.
95  ///
96  /// This uses a variable-time multiscalar multiplication internally.
97  #[must_use]
98  pub fn verify(self) -> bool {
99    self.original.verify() && self.plus.verify()
100  }
101}