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