arnaucube
arnaucube/testudoPublic Self-hosted repository
testudo/src/bullet.rs
src/bullet.rsRaw
  1#![allow(non_snake_case)]
  2
  3use super::errors::ProofVerifyError;
  4use super::group::{CompressedGroup, GroupElement, VartimeMultiscalarMul};
  5use super::math::Math;
  6use super::scalar::Scalar;
  7use super::transcript::ProofTranscript;
  8use merlin::Transcript;
  9use serde::{Deserialize, Serialize};
 10use std::iter;
 11
 12#[derive(Debug, Serialize, Deserialize)]
 13pub struct BulletReductionProof {
 14  L_vec: Vec<CompressedGroup>,
 15  R_vec: Vec<CompressedGroup>,
 16}
 17
 18impl BulletReductionProof {
 19  /// Create an inner-product proof.
 20  ///
 21  /// The proof is created with respect to the bases \\(G\\).
 22  ///
 23  /// The `transcript` is passed in as a parameter so that the
 24  /// challenges depend on the *entire* transcript (including parent
 25  /// protocols).
 26  ///
 27  /// The lengths of the vectors must all be the same, and must all be
 28  /// either 0 or a power of 2.
 29  pub fn prove(
 30    transcript: &mut Transcript,
 31    Q: &GroupElement,
 32    G_vec: &Vec<GroupElement>,
 33    H: &GroupElement,
 34    a_vec: &Vec<Scalar>,
 35    b_vec: &Vec<Scalar>,
 36    blind: &Scalar,
 37    blinds_vec: &Vec<(Scalar, Scalar)>,
 38  ) -> (
 39    BulletReductionProof,
 40    GroupElement,
 41    Scalar,
 42    Scalar,
 43    GroupElement,
 44    Scalar,
 45  ) {
 46    // Create slices G, H, a, b backed by their respective
 47    // vectors.  This lets us reslice as we compress the lengths
 48    // of the vectors in the main loop below.
 49    let mut G = &mut G_vec.clone()[..];
 50    let mut a = &mut a_vec.clone()[..];
 51    let mut b = &mut b_vec.clone()[..];
 52
 53    // All of the input vectors must have a length that is a power of two.
 54    let mut n = G.len();
 55    assert!(n.is_power_of_two());
 56    let lg_n = n.log2();
 57
 58    let G_factors: Vec<Scalar> = iter::repeat(Scalar::one()).take(n).collect();
 59
 60    // All of the input vectors must have the same length.
 61    assert_eq!(G.len(), n);
 62    assert_eq!(a.len(), n);
 63    assert_eq!(b.len(), n);
 64    assert_eq!(G_factors.len(), n);
 65    assert_eq!(blinds_vec.len(), 2 * lg_n);
 66
 67    //transcript.innerproduct_domain_sep(n as u64);
 68
 69    let mut L_vec = Vec::with_capacity(lg_n);
 70    let mut R_vec = Vec::with_capacity(lg_n);
 71    let mut blinds_iter = blinds_vec.iter();
 72    let mut blind_fin = *blind;
 73
 74    while n != 1 {
 75      n = n / 2;
 76      let (a_L, a_R) = a.split_at_mut(n);
 77      let (b_L, b_R) = b.split_at_mut(n);
 78      let (G_L, G_R) = G.split_at_mut(n);
 79
 80      let c_L = inner_product(&a_L, &b_R);
 81      let c_R = inner_product(&a_R, &b_L);
 82
 83      let (blind_L, blind_R) = blinds_iter.next().unwrap();
 84
 85      let L = GroupElement::vartime_multiscalar_mul(
 86        a_L
 87          .iter()
 88          .chain(iter::once(&c_L))
 89          .chain(iter::once(blind_L)),
 90        G_R.iter().chain(iter::once(Q)).chain(iter::once(H)),
 91      );
 92
 93      let R = GroupElement::vartime_multiscalar_mul(
 94        a_R
 95          .iter()
 96          .chain(iter::once(&c_R))
 97          .chain(iter::once(blind_R)),
 98        G_L.iter().chain(iter::once(Q)).chain(iter::once(H)),
 99      );
100
101      transcript.append_point(b"L", &L.compress());
102      transcript.append_point(b"R", &R.compress());
103
104      let u = transcript.challenge_scalar(b"u");
105      let u_inv = u.invert().unwrap();
106
107      for i in 0..n {
108        a_L[i] = a_L[i] * u + u_inv * a_R[i];
109        b_L[i] = b_L[i] * u_inv + u * b_R[i];
110        G_L[i] = GroupElement::vartime_multiscalar_mul(&[u_inv, u], &[G_L[i], G_R[i]]);
111      }
112
113      blind_fin = blind_fin + blind_L * &u * &u + blind_R * &u_inv * &u_inv;
114
115      L_vec.push(L.compress());
116      R_vec.push(R.compress());
117
118      a = a_L;
119      b = b_L;
120      G = G_L;
121    }
122
123    let Gamma_hat =
124      GroupElement::vartime_multiscalar_mul(&[a[0], a[0] * b[0], blind_fin], &[G[0], *Q, *H]);
125
126    (
127      BulletReductionProof {
128        L_vec: L_vec,
129        R_vec: R_vec,
130      },
131      Gamma_hat,
132      a[0],
133      b[0],
134      G[0],
135      blind_fin,
136    )
137  }
138
139  /// Computes three vectors of verification scalars \\([u\_{i}^{2}]\\), \\([u\_{i}^{-2}]\\) and \\([s\_{i}]\\) for combined multiscalar multiplication
140  /// in a parent protocol. See [inner product protocol notes](index.html#verification-equation) for details.
141  /// The verifier must provide the input length \\(n\\) explicitly to avoid unbounded allocation within the inner product proof.
142  fn verification_scalars(
143    &self,
144    n: usize,
145    transcript: &mut Transcript,
146  ) -> Result<(Vec<Scalar>, Vec<Scalar>, Vec<Scalar>), ProofVerifyError> {
147    let lg_n = self.L_vec.len();
148    if lg_n >= 32 {
149      // 4 billion multiplications should be enough for anyone
150      // and this check prevents overflow in 1<<lg_n below.
151      return Err(ProofVerifyError);
152    }
153    if n != (1 << lg_n) {
154      return Err(ProofVerifyError);
155    }
156
157    // 1. Recompute x_k,...,x_1 based on the proof transcript
158    let mut challenges = Vec::with_capacity(lg_n);
159    for (L, R) in self.L_vec.iter().zip(self.R_vec.iter()) {
160      transcript.append_point(b"L", L);
161      transcript.append_point(b"R", R);
162      challenges.push(transcript.challenge_scalar(b"u"));
163    }
164
165    // 2. Compute 1/(u_k...u_1) and 1/u_k, ..., 1/u_1
166    let mut challenges_inv = challenges.clone();
167    let allinv = Scalar::batch_invert(&mut challenges_inv);
168
169    // 3. Compute u_i^2 and (1/u_i)^2
170    for i in 0..lg_n {
171      challenges[i] = challenges[i] * challenges[i];
172      challenges_inv[i] = challenges_inv[i] * challenges_inv[i];
173    }
174    let challenges_sq = challenges;
175    let challenges_inv_sq = challenges_inv;
176
177    // 4. Compute s values inductively.
178    let mut s = Vec::with_capacity(n);
179    s.push(allinv);
180    for i in 1..n {
181      let lg_i = (32 - 1 - (i as u32).leading_zeros()) as usize;
182      let k = 1 << lg_i;
183      // The challenges are stored in "creation order" as [u_k,...,u_1],
184      // so u_{lg(i)+1} = is indexed by (lg_n-1) - lg_i
185      let u_lg_i_sq = challenges_sq[(lg_n - 1) - lg_i];
186      s.push(s[i - k] * u_lg_i_sq);
187    }
188
189    Ok((challenges_sq, challenges_inv_sq, s))
190  }
191
192  /// This method is for testing that proof generation work,
193  /// but for efficiency the actual protocols would use `verification_scalars`
194  /// method to combine inner product verification with other checks
195  /// in a single multiscalar multiplication.
196  pub fn verify(
197    &self,
198    n: usize,
199    a: &Vec<Scalar>,
200    transcript: &mut Transcript,
201    Gamma: &GroupElement,
202    G: &[GroupElement],
203  ) -> Result<(GroupElement, GroupElement, Scalar), ProofVerifyError> {
204    let (u_sq, u_inv_sq, s) = self.verification_scalars(n, transcript)?;
205
206    let Ls = self
207      .L_vec
208      .iter()
209      .map(|p| p.decompress().ok_or(ProofVerifyError))
210      .collect::<Result<Vec<_>, _>>()?;
211
212    let Rs = self
213      .R_vec
214      .iter()
215      .map(|p| p.decompress().ok_or(ProofVerifyError))
216      .collect::<Result<Vec<_>, _>>()?;
217
218    let G_hat = GroupElement::vartime_multiscalar_mul(s.iter(), G.iter());
219    let a_hat = inner_product(a, &s);
220
221    let Gamma_hat = GroupElement::vartime_multiscalar_mul(
222      u_sq
223        .iter()
224        .chain(u_inv_sq.iter())
225        .chain(iter::once(&Scalar::one())),
226      Ls.iter().chain(Rs.iter()).chain(iter::once(Gamma)),
227    );
228
229    Ok((G_hat, Gamma_hat, a_hat))
230  }
231}
232
233/// Computes an inner product of two vectors
234/// \\[
235///    {\langle {\mathbf{a}}, {\mathbf{b}} \rangle} = \sum\_{i=0}^{n-1} a\_i \cdot b\_i.
236/// \\]
237/// Panics if the lengths of \\(\mathbf{a}\\) and \\(\mathbf{b}\\) are not equal.
238pub fn inner_product(a: &[Scalar], b: &[Scalar]) -> Scalar {
239  let mut out = Scalar::zero();
240  if a.len() != b.len() {
241    panic!("inner_product(a,b): lengths of vectors do not match");
242  }
243  for i in 0..a.len() {
244    out += a[i] * b[i];
245  }
246  out
247}