bulletproof/proofs/
range_proof.rs

1#![allow(non_snake_case)]
2
3/*
4
5Copyright 2018 by Kzen Networks
6
7This file is part of bulletproof library
8(https://github.com/KZen-networks/bulletproof)
9
10bulletproof is free software: you can redistribute
11it and/or modify it under the terms of the GNU General Public
12License as published by the Free Software Foundation, either
13version 3 of the License, or (at your option) any later version.
14
15@license GPL-3.0+ <https://github.com/KZen-networks/bulletproof/blob/master/LICENSE>
16*/
17
18// based on the paper: https://eprint.iacr.org/2017/1066.pdf
19
20use curv::arithmetic::traits::*;
21use curv::cryptographic_primitives::hashing::{Digest, DigestExt};
22use curv::elliptic::curves::{secp256_k1::Secp256k1, Curve, ECPoint, Point, Scalar};
23use curv::BigInt;
24use sha2::Sha256;
25
26use generic_array::{typenum::Unsigned, GenericArray};
27use itertools::iterate;
28use proofs::inner_product::InnerProductArg;
29use std::ops::{Shl, Shr};
30use Errors::{self, RangeProofError};
31
32#[derive(Clone, Debug, Serialize, Deserialize)]
33pub struct RangeProof {
34    A: Point<Secp256k1>,
35    S: Point<Secp256k1>,
36    T1: Point<Secp256k1>,
37    T2: Point<Secp256k1>,
38    tau_x: Scalar<Secp256k1>,
39    miu: Scalar<Secp256k1>,
40    tx: Scalar<Secp256k1>,
41    inner_product_proof: InnerProductArg,
42}
43
44impl RangeProof {
45    pub fn prove(
46        g_vec: &[Point<Secp256k1>],
47        h_vec: &[Point<Secp256k1>],
48        G: &Point<Secp256k1>,
49        H: &Point<Secp256k1>,
50        mut secret: Vec<Scalar<Secp256k1>>,
51        blinding: &[Scalar<Secp256k1>],
52        bit_length: usize,
53    ) -> RangeProof {
54        let num_of_proofs = secret.len();
55        //num of proofs times bit length
56        let nm = num_of_proofs * bit_length;
57        let alpha = Scalar::<Secp256k1>::random();
58        let rho = Scalar::<Secp256k1>::random();
59
60        let g_vec = g_vec.to_vec();
61        let h_vec = h_vec.to_vec();
62
63        let mut A = H * &alpha;
64        let mut S = H * &rho;
65        let two = BigInt::from(2);
66        let one = BigInt::from(1);
67        let order = Scalar::<Secp256k1>::group_order();
68
69        //concat all secrets:
70        secret.reverse();
71        let secret_agg = secret
72            .iter()
73            .fold(BigInt::zero(), |acc, x| acc.shl(bit_length) + x.to_bigint());
74
75        let aL = (0..nm)
76            .map(|i| {
77                let shr_secret = secret_agg.clone().shr(i);
78                shr_secret.modulus(&two)
79            })
80            .collect::<Vec<BigInt>>();
81        let aR = (0..nm)
82            .map(|i| BigInt::mod_sub(&aL[i], &one, order))
83            .collect::<Vec<BigInt>>();
84
85        let secret_bits = (0..nm)
86            .map(|i| {
87                let bignum_bit: BigInt = aL[i].clone() & BigInt::one();
88                let byte = BigInt::to_bytes(&bignum_bit);
89                byte[0] == 1
90            })
91            .collect::<Vec<bool>>();
92        let mut index: usize = 0;
93        A = g_vec.iter().zip(secret_bits.clone()).fold(
94            A,
95            |acc, x| {
96                if x.1 {
97                    acc + x.0
98                } else {
99                    acc
100                }
101            },
102        );
103
104        A = h_vec
105            .iter()
106            .zip(secret_bits)
107            .fold(A, |acc, x| if !x.1 { acc - x.0 } else { acc });
108
109        let SR = (0..nm)
110            .map(|_| Scalar::<Secp256k1>::random())
111            .collect::<Vec<Scalar<Secp256k1>>>();
112        let SL = (0..nm)
113            .map(|_| Scalar::<Secp256k1>::random())
114            .collect::<Vec<Scalar<Secp256k1>>>();
115
116        S = SL.iter().zip(&SR).fold(S, |acc, x| {
117            let g_vec_i_SLi = &g_vec[index] * x.0;
118            let h_vec_i_SRi = &h_vec[index] * x.1;
119            index += 1;
120            let SRhi_plus_SLgi = h_vec_i_SRi + g_vec_i_SLi;
121            acc + SRhi_plus_SLgi
122        });
123
124        let y = Sha256::new().chain_points([&A, &S]).result_scalar();
125        let base_point = Point::<Secp256k1>::generator();
126        let yG: Point<Secp256k1> = base_point * &y;
127        let z: Scalar<Secp256k1> = Sha256::new().chain_points([&yG]).result_scalar();
128        let z_bn = z.to_bigint();
129
130        let one_fe = Scalar::<Secp256k1>::from(&one);
131        let yi = iterate(one_fe.clone(), |i| i.clone() * &y)
132            .take(nm)
133            .collect::<Vec<Scalar<Secp256k1>>>();
134
135        let t2 = (0..nm)
136            .map(|i| SR[i].clone() * &yi[i] * &SL[i])
137            .fold(Scalar::<Secp256k1>::zero(), |acc, x| acc + x);
138        let t2 = t2.to_bigint();
139
140        let two_fe = Scalar::<Secp256k1>::from(&two);
141        let vec_2n = iterate(one_fe, |i| i.clone() * &two_fe)
142            .take(bit_length)
143            .collect::<Vec<Scalar<Secp256k1>>>();
144
145        let t1 = (0..nm)
146            .map(|i| {
147                let t1_1 = BigInt::mod_add(&aR[i], &z_bn, order);
148                let t1_2 = BigInt::mod_mul(&t1_1, &yi[i].to_bigint(), order);
149                let t1_3 = BigInt::mod_mul(&SL[i].to_bigint(), &t1_2, order);
150                let t1_4 = BigInt::mod_sub(&aL[i], &z_bn, order);
151                let t1_5 = BigInt::mod_mul(&SR[i].to_bigint(), &yi[i].to_bigint(), order);
152                let t1_6 = BigInt::mod_mul(&t1_4, &t1_5, order);
153                let j = i / bit_length + 2;
154                let k = i % bit_length;
155                let z_index = BigInt::mod_pow(&z_bn, &BigInt::from(j as u32), order);
156                let two_to_the_i = vec_2n[k].clone().to_bigint();
157                let t1_7 = BigInt::mod_mul(&z_index, &two_to_the_i, order);
158                let t1_8 = BigInt::mod_mul(&t1_7, &SL[i].to_bigint(), order);
159                let t1_68 = BigInt::mod_add(&t1_6, &t1_8, order);
160                BigInt::mod_add(&t1_3, &t1_68, order)
161            })
162            .fold(BigInt::zero(), |acc, x| BigInt::mod_add(&acc, &x, order));
163
164        let tau1 = Scalar::<Secp256k1>::random();
165        let tau2 = Scalar::<Secp256k1>::random();
166        let t1_fe = Scalar::<Secp256k1>::from(&t1);
167        let t2_fe = Scalar::<Secp256k1>::from(&t2);
168        let T1 = G * &t1_fe + H * &tau1;
169        let T2 = G * &t2_fe + H * &tau2;
170
171        let fs_challenge = Sha256::new().chain_points([&T1, &T2, G, H]).result_scalar();
172        let fs_challenge_square = &fs_challenge * &fs_challenge;
173        let taux_1 = &fs_challenge * &tau1;
174        let taux_2 = fs_challenge_square * &tau2;
175        let taux_3 = (0..num_of_proofs)
176            .map(|i| {
177                let j = BigInt::mod_add(&two, &BigInt::from(i as u32), order);
178                let z_j = BigInt::mod_pow(&z_bn, &j, order);
179                let z_j_fe = Scalar::<Secp256k1>::from(&z_j);
180                z_j_fe * &blinding[i]
181            })
182            .fold(taux_2, |acc, x| acc + &x);
183        let tau_x = taux_1 + &taux_3;
184        let miu = (rho * &fs_challenge) + &alpha;
185
186        let Lp = (0..nm)
187            .map(|i| {
188                let Lp_1 = (&SL[i] * &fs_challenge).to_bigint();
189                let Lp_2 = BigInt::mod_sub(&aL[i], &z_bn, order);
190                BigInt::mod_add(&Lp_1, &Lp_2, order)
191            })
192            .collect::<Vec<BigInt>>();
193
194        let Rp = (0..nm)
195            .map(|i| {
196                let Rp_1 = (&SR[i] * &fs_challenge).to_bigint();
197
198                let j = i / bit_length + 2;
199                let k = i % bit_length;
200                let z_index = BigInt::mod_pow(&z_bn, &BigInt::from(j as u32), order);
201                let two_to_the_i = vec_2n[k].clone().to_bigint();
202                let Rp_2 = BigInt::mod_mul(&z_index, &two_to_the_i, order);
203                let Rp_3 = BigInt::mod_add(&BigInt::mod_add(&z_bn, &aR[i], order), &Rp_1, order);
204                let Rp_4 = BigInt::mod_mul(&yi[i].to_bigint(), &Rp_3, order);
205                BigInt::mod_add(&Rp_4, &Rp_2, order)
206            })
207            .collect::<Vec<BigInt>>();
208        let tx = Lp.iter().zip(&Rp).fold(BigInt::zero(), |acc, x| {
209            let Lp_iRp_i = BigInt::mod_mul(x.0, x.1, order);
210            BigInt::mod_add(&acc, &Lp_iRp_i, order)
211        });
212        let tx_fe = Scalar::<Secp256k1>::from(&tx);
213
214        let challenge_x: Scalar<Secp256k1> = Sha256::new()
215            .chain_bigint(&tau_x.to_bigint())
216            .chain_bigint(&miu.to_bigint())
217            .chain_bigint(&tx)
218            .result_scalar();
219        let Gx = G * &challenge_x;
220        // P' = u^{xc}
221        let P = &Gx * &tx_fe;
222
223        let yi_inv = (0..nm)
224            .map(|i| {
225                //     let yi_fe = Scalar::<Secp256k1>::from(&yi[i]);
226                //     yi_fe.invert()
227                yi[i].invert().unwrap()
228            })
229            .collect::<Vec<Scalar<Secp256k1>>>();
230
231        let hi_tag = (0..nm)
232            .map(|i| &h_vec[i] * &yi_inv[i])
233            .collect::<Vec<Point<Secp256k1>>>();
234
235        // P' = P' g^l
236        let P = g_vec.iter().zip(&Lp).fold(P, |acc, x| {
237            let g_vec_i_lp_i = x.0 * &Scalar::<Secp256k1>::from(x.1);
238            acc + g_vec_i_lp_i
239        });
240        // P' = P' h'^r
241        let P = hi_tag.iter().zip(&Rp).fold(P, |acc, x| {
242            let h_vec_i_rp_i = x.0 * &Scalar::<Secp256k1>::from(x.1);
243            acc + h_vec_i_rp_i
244        });
245        // line 9
246        // public input : g,h,u^x,P' = g_vec, hi_tag, Gx,P
247        // private input: a,b  = Lp,Rp
248        let L_vec = Vec::with_capacity(nm);
249        let R_vec = Vec::with_capacity(nm);
250        let inner_product_proof =
251            InnerProductArg::prove(&g_vec, &hi_tag, &Gx, &P, &Lp, &Rp, L_vec, R_vec);
252
253        RangeProof {
254            A,
255            S,
256            T1,
257            T2,
258            tau_x,
259            miu,
260            tx: tx_fe,
261            inner_product_proof,
262        }
263    }
264
265    pub fn verify(
266        &self,
267        g_vec: &[Point<Secp256k1>],
268        h_vec: &[Point<Secp256k1>],
269        G: &Point<Secp256k1>,
270        H: &Point<Secp256k1>,
271        ped_com: &[Point<Secp256k1>],
272        bit_length: usize,
273    ) -> Result<(), Errors> {
274        let num_of_proofs = ped_com.len();
275        let nm = num_of_proofs * bit_length;
276
277        let y = Sha256::new()
278            .chain_points([&self.A, &self.S])
279            .result_scalar();
280        let base_point = Point::<Secp256k1>::generator();
281        let yG: Point<Secp256k1> = base_point * &y;
282        let z: Scalar<Secp256k1> = Sha256::new().chain_points([&yG]).result_scalar();
283        let z_bn = z.to_bigint();
284        let order = Scalar::<Secp256k1>::group_order();
285        let z_minus = BigInt::mod_sub(order, &z.to_bigint(), order);
286        let z_minus_fe = Scalar::<Secp256k1>::from(&z_minus);
287        let z_squared = BigInt::mod_pow(&z.to_bigint(), &BigInt::from(2), order);
288        // delta(x,y):
289        let one_bn = BigInt::one();
290        let one_fe = Scalar::<Secp256k1>::from(&one_bn);
291        let yi = iterate(one_fe.clone(), |i| i.clone() * &y)
292            .take(nm)
293            .collect::<Vec<Scalar<Secp256k1>>>();
294
295        let scalar_mul_yn = yi
296            .iter()
297            .fold(Scalar::<Secp256k1>::zero(), |acc, x| acc + x);
298        let scalar_mul_yn = scalar_mul_yn.to_bigint();
299        let two = BigInt::from(2);
300
301        let two_fe = Scalar::<Secp256k1>::from(&two);
302        let vec_2n = iterate(one_fe, |i| i.clone() * &two_fe)
303            .take(bit_length)
304            .collect::<Vec<Scalar<Secp256k1>>>();
305
306        let scalar_mul_2n = vec_2n
307            .iter()
308            .fold(Scalar::<Secp256k1>::zero(), |acc, x| acc + x);
309        let scalar_mul_2n = scalar_mul_2n.to_bigint();
310
311        let z_cubed_scalar_mul_2n = (0..num_of_proofs)
312            .map(|i| {
313                let j = BigInt::mod_add(&BigInt::from(3), &BigInt::from(i as u32), order);
314                let z_j = BigInt::mod_pow(&z_bn, &j, order);
315                BigInt::mod_mul(&z_j, &scalar_mul_2n, order)
316            })
317            .fold(BigInt::zero(), |acc, x| BigInt::mod_add(&acc, &x, order));
318
319        let z_minus_zsq = BigInt::mod_sub(&z_bn, &z_squared, order);
320        let z_minus_zsq_scalar_mul_yn = BigInt::mod_mul(&z_minus_zsq, &scalar_mul_yn, order);
321        let delta = BigInt::mod_sub(&z_minus_zsq_scalar_mul_yn, &z_cubed_scalar_mul_2n, order);
322
323        let yi_inv = (0..nm)
324            .map(|i| yi[i].invert().unwrap())
325            .collect::<Vec<Scalar<Secp256k1>>>();
326
327        let hi_tag = (0..nm)
328            .map(|i| &h_vec[i] * &yi_inv[i])
329            .collect::<Vec<Point<Secp256k1>>>();
330
331        let fs_challenge = Sha256::new()
332            .chain_points([&self.T1, &self.T2, G, H])
333            .result_scalar();
334        let fs_challenge_square = &fs_challenge * &fs_challenge;
335
336        // eq 65:
337        let Gtx = G * &self.tx;
338        let Htaux = H * &self.tau_x;
339        let left_side = Gtx + Htaux;
340        let delta_fe = Scalar::<Secp256k1>::from(&delta);
341        let Gdelta = G * &delta_fe;
342        let Tx = &self.T1 * &fs_challenge;
343        let Tx_sq = &self.T2 * &fs_challenge_square;
344
345        let mut vec_ped_zm = (0..num_of_proofs)
346            .map(|i| {
347                let z_2_m = BigInt::mod_pow(&z_bn, &BigInt::from((2 + i) as u32), order);
348                let z_2_m_fe = Scalar::<Secp256k1>::from(&z_2_m);
349                &ped_com[i] * &z_2_m_fe
350            })
351            .collect::<Vec<Point<Secp256k1>>>();
352        let vec_ped_zm_1 = vec_ped_zm.remove(0);
353        let ped_com_sum = vec_ped_zm.iter().fold(vec_ped_zm_1, |acc, x| acc + x);
354        let right_side = ped_com_sum + Gdelta + Tx + Tx_sq;
355
356        let challenge_x = Sha256::new()
357            .chain_bigint(&self.tau_x.to_bigint())
358            .chain_bigint(&self.miu.to_bigint())
359            .chain_bigint(&self.tx.to_bigint())
360            .result_scalar();
361        let Gx = G * &challenge_x;
362        // P' = u^{xc}
363
364        let P = &Gx * &self.tx;
365        let minus_miu = BigInt::mod_sub(
366            Scalar::<Secp256k1>::group_order(),
367            &self.miu.to_bigint(),
368            Scalar::<Secp256k1>::group_order(),
369        );
370        let minus_miu_fe = Scalar::<Secp256k1>::from(&minus_miu);
371        let Hmiu = H * &minus_miu_fe;
372        let Sx = &self.S * &fs_challenge;
373        let P = Hmiu + P + self.A.clone() + Sx;
374
375        let P1 = (0..nm)
376            .map(|i| {
377                let z_yn = BigInt::mod_mul(&z_bn, &yi[i].to_bigint(), order);
378                let j = i / bit_length;
379                let k = i % bit_length;
380                let z_j = BigInt::mod_pow(&z_bn, &BigInt::from((2 + j) as u32), order);
381                let z_j_2_n = BigInt::mod_mul(&z_j, &vec_2n[k].to_bigint(), order);
382                // let z_sq_2n = BigInt::mod_mul(&z_squared, &vec_2n[i], &order);
383                let zyn_zsq2n = BigInt::mod_add(&z_yn, &z_j_2_n, order);
384                let zyn_zsq2n_fe = Scalar::<Secp256k1>::from(&zyn_zsq2n);
385                &hi_tag[i] * &zyn_zsq2n_fe
386            })
387            .fold(P, |acc, x| acc + x);
388
389        let P = (0..nm)
390            .map(|i| &g_vec[i] * &z_minus_fe)
391            .fold(P1, |acc, x| acc + x);
392        let verify = self.inner_product_proof.verify(g_vec, &hi_tag, &Gx, &P);
393        if verify.is_ok() && left_side == right_side {
394            Ok(())
395        } else {
396            Err(RangeProofError)
397        }
398    }
399
400    pub fn fast_verify(
401        &self,
402        g_vec: &[Point<Secp256k1>],
403        h_vec: &[Point<Secp256k1>],
404        G: &Point<Secp256k1>,
405        H: &Point<Secp256k1>,
406        ped_com: &[Point<Secp256k1>],
407        bit_length: usize,
408    ) -> Result<(), Errors> {
409        let num_of_proofs = ped_com.len();
410        let nm = num_of_proofs * bit_length;
411
412        let y = Sha256::new()
413            .chain_points([&self.A, &self.S])
414            .result_scalar();
415        let base_point = Point::<Secp256k1>::generator();
416        let yG: Point<Secp256k1> = base_point * &y;
417        let z: Scalar<Secp256k1> = Sha256::new().chain_points([&yG]).result_scalar();
418        let z_bn = z.to_bigint();
419        let order = Scalar::<Secp256k1>::group_order();
420        let z_minus = BigInt::mod_sub(order, &z.to_bigint(), order);
421        let z_minus_fe = Scalar::<Secp256k1>::from(&z_minus);
422        let z_squared = BigInt::mod_pow(&z.to_bigint(), &BigInt::from(2), order);
423        // delta(x,y):
424        let one_bn = BigInt::one();
425        let one_fe = Scalar::<Secp256k1>::from(&one_bn);
426        let yi = iterate(one_fe.clone(), |i| i.clone() * &y)
427            .take(nm)
428            .collect::<Vec<Scalar<Secp256k1>>>();
429
430        let scalar_mul_yn = yi
431            .iter()
432            .fold(Scalar::<Secp256k1>::zero(), |acc, x| acc + x);
433        let scalar_mul_yn = scalar_mul_yn.to_bigint();
434        let two = BigInt::from(2);
435
436        let two_fe = Scalar::<Secp256k1>::from(&two);
437        let vec_2n = iterate(one_fe, |i| i.clone() * &two_fe)
438            .take(bit_length)
439            .collect::<Vec<Scalar<Secp256k1>>>();
440
441        let scalar_mul_2n = vec_2n
442            .iter()
443            .fold(Scalar::<Secp256k1>::zero(), |acc, x| acc + x);
444        let scalar_mul_2n = scalar_mul_2n.to_bigint();
445
446        let z_cubed_scalar_mul_2n = (0..num_of_proofs)
447            .map(|i| {
448                let j = BigInt::mod_add(&BigInt::from(3), &BigInt::from(i as u32), order);
449                let z_j = BigInt::mod_pow(&z_bn, &j, order);
450                BigInt::mod_mul(&z_j, &scalar_mul_2n, order)
451            })
452            .fold(BigInt::zero(), |acc, x| BigInt::mod_add(&acc, &x, order));
453
454        let z_minus_zsq = BigInt::mod_sub(&z_bn, &z_squared, order);
455        let z_minus_zsq_scalar_mul_yn = BigInt::mod_mul(&z_minus_zsq, &scalar_mul_yn, order);
456        let delta = BigInt::mod_sub(&z_minus_zsq_scalar_mul_yn, &z_cubed_scalar_mul_2n, order);
457
458        let yi_inv = (0..nm)
459            .map(|i| yi[i].invert().unwrap())
460            .collect::<Vec<Scalar<Secp256k1>>>();
461
462        let hi_tag = (0..nm)
463            .map(|i| &h_vec[i] * &yi_inv[i])
464            .collect::<Vec<Point<Secp256k1>>>();
465
466        let fs_challenge = Sha256::new()
467            .chain_points([&self.T1, &self.T2, G, H])
468            .result_scalar();
469        let fs_challenge_square = &fs_challenge * &fs_challenge;
470
471        // eq 65:
472        let Gtx = G * &self.tx;
473        let Htaux = H * &self.tau_x;
474        let left_side = Gtx + Htaux;
475        let delta_fe = Scalar::<Secp256k1>::from(&delta);
476        let Gdelta = G * &delta_fe;
477        let Tx = &self.T1 * &fs_challenge;
478        let Tx_sq = &self.T2 * &fs_challenge_square;
479
480        let mut vec_ped_zm = (0..num_of_proofs)
481            .map(|i| {
482                let z_2_m = BigInt::mod_pow(&z_bn, &BigInt::from((2 + i) as u32), order);
483                let z_2_m_fe = Scalar::<Secp256k1>::from(&z_2_m);
484                &ped_com[i] * &z_2_m_fe
485            })
486            .collect::<Vec<Point<Secp256k1>>>();
487        let vec_ped_zm_1 = vec_ped_zm.remove(0);
488        let ped_com_sum = vec_ped_zm.iter().fold(vec_ped_zm_1, |acc, x| acc + x);
489        let right_side = ped_com_sum + Gdelta + Tx + Tx_sq;
490
491        let challenge_x = Sha256::new()
492            .chain_bigint(&self.tau_x.to_bigint())
493            .chain_bigint(&self.miu.to_bigint())
494            .chain_bigint(&self.tx.to_bigint())
495            .result_scalar();
496        let Gx = G * &challenge_x;
497        // P' = u^{xc}
498
499        let P = &Gx * &self.tx;
500        let minus_miu = BigInt::mod_sub(
501            Scalar::<Secp256k1>::group_order(),
502            &self.miu.to_bigint(),
503            Scalar::<Secp256k1>::group_order(),
504        );
505        let minus_miu_fe = Scalar::<Secp256k1>::from(&minus_miu);
506        let Hmiu = H * &minus_miu_fe;
507        let Sx = &self.S * &fs_challenge;
508        let P = Hmiu + P + self.A.clone() + Sx;
509
510        let P1 = (0..nm)
511            .map(|i| {
512                let z_yn = BigInt::mod_mul(&z_bn, &yi[i].to_bigint(), order);
513                let j = i / bit_length;
514                let k = i % bit_length;
515                let z_j = BigInt::mod_pow(&z_bn, &BigInt::from((2 + j) as u32), order);
516                let z_j_2_n = BigInt::mod_mul(&z_j, &vec_2n[k].to_bigint(), order);
517                // let z_sq_2n = BigInt::mod_mul(&z_squared, &vec_2n[i], &order);
518                let zyn_zsq2n = BigInt::mod_add(&z_yn, &z_j_2_n, order);
519                let zyn_zsq2n_fe = Scalar::<Secp256k1>::from(&zyn_zsq2n);
520                &hi_tag[i] * &zyn_zsq2n_fe
521            })
522            .fold(P, |acc, x| acc + x);
523
524        let P = (0..nm)
525            .map(|i| &g_vec[i] * &z_minus_fe)
526            .fold(P1, |acc, x| acc + x);
527        let verify = self
528            .inner_product_proof
529            .fast_verify(g_vec, &hi_tag, &Gx, &P);
530        if verify.is_ok() && left_side == right_side {
531            Ok(())
532        } else {
533            Err(RangeProofError)
534        }
535    }
536
537    pub fn aggregated_verify(
538        &self,
539        g_vec: &[Point<Secp256k1>],
540        h_vec: &[Point<Secp256k1>],
541        G: &Point<Secp256k1>,
542        H: &Point<Secp256k1>,
543        ped_com: &[Point<Secp256k1>],
544        bit_length: usize,
545    ) -> Result<(), Errors> {
546        let n = bit_length;
547        let m = ped_com.len();
548        let nm = m * n;
549        let lg_nm = self.inner_product_proof.L.len();
550        let order = Scalar::<Secp256k1>::group_order();
551        let two = BigInt::from(2);
552        let one = BigInt::from(1);
553        let zero = BigInt::zero();
554
555        // All of the input vectors must have the same length.
556        assert_eq!(g_vec.len(), nm);
557        assert_eq!(h_vec.len(), nm);
558        assert!(nm.is_power_of_two(), "(n*m) must be a power of two!");
559        assert!(
560            lg_nm <= 64,
561            "Not compatible for vector sizes greater than 2^64!"
562        );
563
564        // regenerate challenges y, z, x, x_u from transcript
565        let y = Sha256::new()
566            .chain_points([&self.A, &self.S])
567            .result_scalar();
568        let y_bn = y.to_bigint();
569        let y_inv_bn = BigInt::mod_inv(&y_bn, order).unwrap();
570        let base_point = Point::<Secp256k1>::generator();
571        let yG: Point<Secp256k1> = base_point * &y;
572        let z: Scalar<Secp256k1> = Sha256::new().chain_points([&yG]).result_scalar();
573        let z_bn = z.to_bigint();
574        let z_squared = BigInt::mod_pow(&z_bn, &BigInt::from(2), order);
575
576        let challenge_x: Scalar<Secp256k1> = Sha256::new()
577            .chain_points([&self.T1, &self.T2, G, H])
578            .result_scalar();
579        let challenge_x_sq = &challenge_x * &challenge_x;
580
581        let x_u_fe = Sha256::new()
582            .chain_bigint(&self.tau_x.to_bigint())
583            .chain_bigint(&self.miu.to_bigint())
584            .chain_bigint(&self.tx.to_bigint())
585            .result_scalar();
586
587        // ux = g^{x_u}
588        let ux = G * &x_u_fe;
589
590        // generate a random scalar to combine 2 verification equations
591        let challenge_ver: Scalar<Secp256k1> = Sha256::new()
592            .chain_points([&self.A, &self.S, &self.T1, &self.T2, G, H])
593            .result_scalar();
594        let challenge_ver_bn = challenge_ver.to_bigint();
595
596        // z2_vec = (z^2, z^3, z^4, ..., z^{m+1})
597        let z2_vec = iterate(z_squared.clone(), |i| i.clone() * &z_bn)
598            .take(m)
599            .collect::<Vec<BigInt>>();
600
601        // y_vec = (1, y, y^2, ..., y^{nm-1})
602        let y_vec = iterate(one.clone(), |i| i.clone() * &y_bn)
603            .take(nm)
604            .collect::<Vec<BigInt>>();
605
606        // sum_y_pow = 1 + y + ... + y^{nm}
607        let sum_y_pow = y_vec
608            .iter()
609            .fold(zero.clone(), |acc, x| BigInt::mod_add(&acc, x, order));
610
611        // vec_2n = (1, 2, 2^2, 2^3, ..., 2^{n})
612        let vec_2n = iterate(one.clone(), |i| i.clone() * &two)
613            .take(n)
614            .collect::<Vec<BigInt>>();
615
616        // y_inv_vec = (1, y^{-1}, y^{-2}, ..., y^{-(nm-1)})
617        let y_inv_vec = iterate(one, |i| i.clone() * &y_inv_bn)
618            .take(nm)
619            .collect::<Vec<BigInt>>();
620
621        // d = z^2 d1 + z^3 d2 + ... + z^{m+1} dm
622        // where dj = (0^{(j-1)n} || 2^{n} || 0^{(m-j)n}) \in \Z_q^{mn}
623        let d = (0..nm)
624            .map(|i| {
625                let k = i % n;
626                let two_i = vec_2n[k].clone();
627                let j = i / n;
628                let z_j_2 = z2_vec[j].clone();
629                BigInt::mod_mul(&two_i, &z_j_2, order)
630            })
631            .collect::<Vec<BigInt>>();
632
633        // sum_d = <1^{mn}, d>
634        let sum_d = d
635            .iter()
636            .fold(zero.clone(), |acc, x| BigInt::mod_add(&acc, x, order));
637
638        // compute delta(y, z):
639        let z_minus_zsq = BigInt::mod_sub(&z_bn, &z_squared, order);
640        let z_minus_zsq_sum_y = BigInt::mod_mul(&z_minus_zsq, &sum_y_pow, order);
641        let sum_d_z = BigInt::mod_mul(&sum_d, &z_bn, order);
642        let delta = BigInt::mod_sub(&z_minus_zsq_sum_y, &sum_d_z, order);
643
644        // compute sg and sh vectors (unrolling ipp verification)
645        let mut x_sq_vec: Vec<BigInt> = Vec::with_capacity(lg_nm);
646        let mut x_inv_sq_vec: Vec<BigInt> = Vec::with_capacity(lg_nm);
647        let mut minus_x_sq_vec: Vec<BigInt> = Vec::with_capacity(lg_nm);
648        let mut minus_x_inv_sq_vec: Vec<BigInt> = Vec::with_capacity(lg_nm);
649        let mut allinv = BigInt::one();
650        for (Li, Ri) in self
651            .inner_product_proof
652            .L
653            .iter()
654            .zip(self.inner_product_proof.R.iter())
655        {
656            let x: Scalar<Secp256k1> = Sha256::new().chain_points([Li, Ri, &ux]).result_scalar();
657            let x_bn = x.to_bigint();
658            let x_inv_fe = x.invert().unwrap();
659            let x_inv_bn = x_inv_fe.to_bigint();
660            let x_sq_bn = BigInt::mod_mul(&x_bn, &x_bn, order);
661            let x_inv_sq_bn = BigInt::mod_mul(&x_inv_fe.to_bigint(), &x_inv_fe.to_bigint(), order);
662
663            x_sq_vec.push(x_sq_bn.clone());
664            x_inv_sq_vec.push(x_inv_sq_bn.clone());
665            minus_x_sq_vec.push(BigInt::mod_sub(&BigInt::zero(), &x_sq_bn, order));
666            minus_x_inv_sq_vec.push(BigInt::mod_sub(&BigInt::zero(), &x_inv_sq_bn, order));
667            allinv *= x_inv_bn;
668        }
669
670        let mut s: Vec<BigInt> = Vec::with_capacity(nm);
671        s.push(allinv);
672        for i in 1..nm {
673            let lg_i =
674                (std::mem::size_of_val(&nm) * 8) - 1 - ((i as usize).leading_zeros() as usize);
675            let k = 1 << lg_i;
676            // The challenges are stored in "creation order" as [x_k,...,x_1],
677            // so u_{lg(i)+1} = is indexed by (lg_n-1) - lg_i
678            let x_lg_i_sq = x_sq_vec[(lg_nm - 1) - lg_i].clone();
679            s.push(s[i - k].clone() * x_lg_i_sq);
680        }
681
682        let a_times_s: Vec<BigInt> = (0..nm)
683            .map(|i| BigInt::mod_mul(&s[i], &self.inner_product_proof.a_tag, order))
684            .collect();
685
686        let b_times_sinv: Vec<BigInt> = (0..nm)
687            .map(|i| {
688                let s_inv_i = BigInt::mod_inv(&s[i], order).unwrap();
689                BigInt::mod_mul(&s_inv_i, &self.inner_product_proof.b_tag, order)
690            })
691            .collect();
692
693        // exponent of g_vec
694        let scalar_g_vec: Vec<BigInt> = (0..nm)
695            .map(|i| BigInt::mod_add(&a_times_s[i], &z_bn, order))
696            .collect();
697
698        // exponent of h_vec
699        let scalar_h_vec: Vec<BigInt> = (0..nm)
700            .map(|i| {
701                let b_sinv_plus_di = BigInt::mod_sub(&b_times_sinv[i], &d[i], order);
702                let y_inv_b_sinv_plus_di = BigInt::mod_mul(&y_inv_vec[i], &b_sinv_plus_di, order);
703                BigInt::mod_sub(&y_inv_b_sinv_plus_di, &z_bn, order)
704            })
705            .collect();
706
707        // exponent of G
708        let ab = BigInt::mod_mul(
709            &self.inner_product_proof.a_tag,
710            &self.inner_product_proof.b_tag,
711            order,
712        );
713        let ab_minus_tx = BigInt::mod_sub(&ab, &self.tx.to_bigint(), order);
714        let scalar_G1 = BigInt::mod_mul(&x_u_fe.to_bigint(), &ab_minus_tx, order);
715
716        let delta_minus_tx = BigInt::mod_sub(&delta, &self.tx.to_bigint(), order);
717        let scalar_G2 = BigInt::mod_mul(&challenge_ver_bn, &delta_minus_tx, order);
718
719        let scalar_G = BigInt::mod_add(&scalar_G1, &scalar_G2, order);
720
721        // exponent of H
722        let c_times_taux = BigInt::mod_mul(&challenge_ver_bn, &self.tau_x.to_bigint(), order);
723        let scalar_H = BigInt::mod_sub(&self.miu.to_bigint(), &c_times_taux, order);
724
725        // exponents of A, S
726        // let scalar_A = BigInt::mod_sub(&zero, &one, &order);
727        let scalar_S = BigInt::mod_sub(&zero, &challenge_x.to_bigint(), order);
728
729        // exponent of L, R
730        let scalar_L = minus_x_sq_vec.clone();
731        let scalar_R = minus_x_inv_sq_vec.clone();
732
733        // exponents of commitments
734        let scalar_coms: Vec<BigInt> = (0..m)
735            .map(|i| BigInt::mod_mul(&challenge_ver_bn, &z2_vec[i], order))
736            .collect();
737
738        // exponents of T_1, T_2
739        let scalar_T1 = BigInt::mod_mul(&challenge_ver_bn, &challenge_x.to_bigint(), order);
740        let scalar_T2 = BigInt::mod_mul(&challenge_ver_bn, &challenge_x_sq.to_bigint(), order);
741
742        // compute concatenated exponent vector
743        let mut scalars: Vec<BigInt> = Vec::with_capacity(2 * nm + 2 * lg_nm + m + 6);
744        scalars.extend_from_slice(&scalar_g_vec);
745        scalars.extend_from_slice(&scalar_h_vec);
746        scalars.push(scalar_G);
747        // scalars.push(scalar_H);
748        // scalars.push(scalar_A);
749        scalars.push(scalar_S);
750        scalars.extend_from_slice(&scalar_L);
751        scalars.extend_from_slice(&scalar_R);
752        scalars.extend_from_slice(&scalar_coms);
753        scalars.push(scalar_T1);
754        scalars.push(scalar_T2);
755
756        // compute concatenated base vector
757        let mut points: Vec<Point<Secp256k1>> = Vec::with_capacity(2 * nm + 2 * lg_nm + m + 6);
758        points.extend_from_slice(g_vec);
759        points.extend_from_slice(h_vec);
760        points.push(G.clone());
761        // points.push(*H);
762        // points.push(self.A);
763        points.push(self.S.clone());
764        points.extend_from_slice(&self.inner_product_proof.L);
765        points.extend_from_slice(&self.inner_product_proof.R);
766        points.extend_from_slice(ped_com);
767        points.push(self.T1.clone());
768        points.push(self.T2.clone());
769
770        let H_times_scalar_H = H * &Scalar::<Secp256k1>::from(&scalar_H);
771        let tot_len = points.len();
772        let lhs = (0..tot_len)
773            .map(|i| &points[i] * &Scalar::<Secp256k1>::from(&scalars[i]))
774            .fold(H_times_scalar_H, |acc, x| acc + x as Point<Secp256k1>);
775
776        // single multi-exponentiation check
777        if lhs == self.A {
778            Ok(())
779        } else {
780            Err(RangeProofError)
781        }
782    }
783}
784
785pub fn generate_random_point(bytes: &[u8]) -> Point<Secp256k1> {
786    let compressed_point_len =
787        <<Secp256k1 as Curve>::Point as ECPoint>::CompressedPointLength::USIZE;
788    let truncated = if bytes.len() > compressed_point_len - 1 {
789        &bytes[0..compressed_point_len - 1]
790    } else {
791        &bytes
792    };
793    let mut buffer = GenericArray::<
794        u8,
795        <<Secp256k1 as Curve>::Point as ECPoint>::CompressedPointLength,
796    >::default();
797    buffer.as_mut_slice()[0] = 0x2;
798    buffer.as_mut_slice()[1..1 + truncated.len()].copy_from_slice(truncated);
799    if let Ok(point) = Point::from_bytes(buffer.as_slice()) {
800        return point;
801    }
802
803    let bn = BigInt::from_bytes(bytes);
804    let two = BigInt::from(2);
805    let bn_times_two = BigInt::mod_mul(&bn, &two, Scalar::<Secp256k1>::group_order());
806    let bytes = BigInt::to_bytes(&bn_times_two);
807    generate_random_point(&bytes)
808}
809
810#[cfg(test)]
811mod tests {
812    use curv::arithmetic::traits::*;
813    use curv::cryptographic_primitives::hashing::{Digest, DigestExt};
814    use curv::elliptic::curves::{secp256_k1::Secp256k1, Point, Scalar};
815    use curv::BigInt;
816    use sha2::Sha512;
817
818    use curv::elliptic::curves::secp256_k1::hash_to_curve::generate_random_point;
819    use proofs::range_proof::RangeProof;
820
821    pub fn test_helper(seed: &BigInt, n: usize, m: usize) {
822        let nm = n * m;
823        let G = Point::<Secp256k1>::generator();
824        let label = BigInt::from(1);
825        let hash = Sha512::new().chain_bigint(&label).result_bigint();
826        let H = generate_random_point(&Converter::to_bytes(&hash));
827
828        let g_vec = (0..nm)
829            .map(|i| {
830                let kzen_label_i = BigInt::from(i as u32) + seed;
831                let hash_i = Sha512::new().chain_bigint(&kzen_label_i).result_bigint();
832                generate_random_point(&Converter::to_bytes(&hash_i))
833            })
834            .collect::<Vec<Point<Secp256k1>>>();
835
836        // can run in parallel to g_vec:
837        let h_vec = (0..nm)
838            .map(|i| {
839                let kzen_label_j = BigInt::from(n as u32) + BigInt::from(i as u32) + seed;
840                let hash_j = Sha512::new().chain_bigint(&kzen_label_j).result_bigint();
841                generate_random_point(&Converter::to_bytes(&hash_j))
842            })
843            .collect::<Vec<Point<Secp256k1>>>();
844
845        let range = BigInt::from(2).pow(n as u32);
846        let v_vec = (0..m)
847            .map(|_| Scalar::<Secp256k1>::from(&BigInt::sample_below(&range)))
848            .collect::<Vec<Scalar<Secp256k1>>>();
849
850        let r_vec = (0..m)
851            .map(|_| Scalar::<Secp256k1>::random())
852            .collect::<Vec<Scalar<Secp256k1>>>();
853
854        let ped_com_vec = (0..m)
855            .map(|i| &*G * &v_vec[i] + &H * &r_vec[i])
856            .collect::<Vec<Point<Secp256k1>>>();
857
858        let range_proof = RangeProof::prove(&g_vec, &h_vec, &G, &H, v_vec, &r_vec, n);
859        let result = RangeProof::verify(&range_proof, &g_vec, &h_vec, &G, &H, &ped_com_vec, n);
860        assert!(result.is_ok());
861    }
862
863    pub fn test_helper_aggregated(seed: &BigInt, n: usize, m: usize) {
864        let nm = n * m;
865        let G = Point::<Secp256k1>::generator();
866        let label = BigInt::from(1);
867        let hash = Sha512::new().chain_bigint(&label).result_bigint();
868        let H = generate_random_point(&Converter::to_bytes(&hash));
869
870        let g_vec = (0..nm)
871            .map(|i| {
872                let kzen_label_i = BigInt::from(i as u32) + seed;
873                let hash_i = Sha512::new().chain_bigint(&kzen_label_i).result_bigint();
874                generate_random_point(&Converter::to_bytes(&hash_i))
875            })
876            .collect::<Vec<Point<Secp256k1>>>();
877
878        // can run in parallel to g_vec:
879        let h_vec = (0..nm)
880            .map(|i| {
881                let kzen_label_j = BigInt::from(n as u32) + BigInt::from(i as u32) + seed;
882                let hash_j = Sha512::new().chain_bigint(&kzen_label_j).result_bigint();
883                generate_random_point(&Converter::to_bytes(&hash_j))
884            })
885            .collect::<Vec<Point<Secp256k1>>>();
886
887        let range = BigInt::from(2).pow(n as u32);
888        let v_vec = (0..m)
889            .map(|_| Scalar::<Secp256k1>::from(&BigInt::sample_below(&range)))
890            .collect::<Vec<Scalar<Secp256k1>>>();
891
892        let r_vec = (0..m)
893            .map(|_| Scalar::<Secp256k1>::random())
894            .collect::<Vec<Scalar<Secp256k1>>>();
895
896        let ped_com_vec = (0..m)
897            .map(|i| &*G * &v_vec[i] + &H * &r_vec[i])
898            .collect::<Vec<Point<Secp256k1>>>();
899
900        let range_proof = RangeProof::prove(&g_vec, &h_vec, &G, &H, v_vec, &r_vec, n);
901        let result =
902            RangeProof::aggregated_verify(&range_proof, &g_vec, &h_vec, &G, &H, &ped_com_vec, n);
903        assert!(result.is_ok());
904    }
905
906    #[test]
907    pub fn test_batch_4_range_proof_32() {
908        let n = 32;
909        // num of proofs
910        let m = 4;
911        let nm = n * m;
912        let KZen: &[u8] = &[75, 90, 101, 110];
913        let kzen_label = BigInt::from_bytes(KZen);
914
915        let G = Point::<Secp256k1>::generator();
916        let label = BigInt::from(1);
917        let hash = Sha512::new().chain_bigint(&label).result_bigint();
918        let H = generate_random_point(&Converter::to_bytes(&hash));
919
920        let g_vec = (0..nm)
921            .map(|i| {
922                let kzen_label_i = BigInt::from(i as u32) + &kzen_label;
923                let hash_i = Sha512::new().chain_bigint(&kzen_label_i).result_bigint();
924                generate_random_point(&Converter::to_bytes(&hash_i))
925            })
926            .collect::<Vec<Point<Secp256k1>>>();
927
928        // can run in parallel to g_vec:
929        let h_vec = (0..nm)
930            .map(|i| {
931                let kzen_label_j = BigInt::from(n as u32) + BigInt::from(i as u32) + &kzen_label;
932                let hash_j = Sha512::new().chain_bigint(&kzen_label_j).result_bigint();
933                generate_random_point(&Converter::to_bytes(&hash_j))
934            })
935            .collect::<Vec<Point<Secp256k1>>>();
936
937        let range = BigInt::from(2).pow(n as u32);
938        let v_vec = (0..m)
939            .map(|_| Scalar::<Secp256k1>::from(&BigInt::sample_below(&range)))
940            .collect::<Vec<Scalar<Secp256k1>>>();
941
942        let r_vec = (0..m)
943            .map(|_| Scalar::<Secp256k1>::random())
944            .collect::<Vec<Scalar<Secp256k1>>>();
945
946        let ped_com_vec = (0..m)
947            .map(|i| &*G * &v_vec[i] + &H * &r_vec[i])
948            .collect::<Vec<Point<Secp256k1>>>();
949
950        let range_proof = RangeProof::prove(&g_vec, &h_vec, &G, &H, v_vec, &r_vec, n);
951        let result = RangeProof::verify(&range_proof, &g_vec, &h_vec, &G, &H, &ped_com_vec, n);
952        assert!(result.is_ok());
953    }
954
955    #[test]
956    #[should_panic]
957    pub fn test_batch_4_range_proof_32_out_of_range() {
958        let n = 32;
959        // num of proofs
960        let m = 4;
961        let nm = n * m;
962        let KZen: &[u8] = &[75, 90, 101, 110];
963        let kzen_label = BigInt::from_bytes(KZen);
964
965        let G = Point::<Secp256k1>::generator();
966        let label = BigInt::from(1);
967        let hash = Sha512::new().chain_bigint(&label).result_bigint();
968        let H = generate_random_point(&Converter::to_bytes(&hash));
969
970        let g_vec = (0..nm)
971            .map(|i| {
972                let kzen_label_i = BigInt::from(i as u32) + &kzen_label;
973                let hash_i = Sha512::new().chain_bigint(&kzen_label_i).result_bigint();
974                generate_random_point(&Converter::to_bytes(&hash_i))
975            })
976            .collect::<Vec<Point<Secp256k1>>>();
977
978        // can run in parallel to g_vec:
979        let h_vec = (0..nm)
980            .map(|i| {
981                let kzen_label_j = BigInt::from(n as u32) + BigInt::from(i as u32) + &kzen_label;
982                let hash_j = Sha512::new().chain_bigint(&kzen_label_j).result_bigint();
983                generate_random_point(&Converter::to_bytes(&hash_j))
984            })
985            .collect::<Vec<Point<Secp256k1>>>();
986
987        let range = BigInt::from(2).pow(n as u32);
988        let mut v_vec = (0..m - 1)
989            .map(|_| Scalar::<Secp256k1>::from(&BigInt::sample_below(&range)))
990            .collect::<Vec<Scalar<Secp256k1>>>();
991
992        let bad_v = BigInt::from(2).pow(33);
993        v_vec.push(Scalar::<Secp256k1>::from(&bad_v));
994
995        let r_vec = (0..m)
996            .map(|_| Scalar::<Secp256k1>::random())
997            .collect::<Vec<Scalar<Secp256k1>>>();
998
999        let ped_com_vec = (0..m)
1000            .map(|i| &*G * &v_vec[i] + &H * &r_vec[i])
1001            .collect::<Vec<Point<Secp256k1>>>();
1002
1003        let range_proof = RangeProof::prove(&g_vec, &h_vec, &G, &H, v_vec, &r_vec, n);
1004        let result = RangeProof::verify(&range_proof, &g_vec, &h_vec, &G, &H, &ped_com_vec, n);
1005        assert!(result.is_ok());
1006    }
1007
1008    #[test]
1009    pub fn test_batch_2_range_proof_16() {
1010        let n = 16;
1011        // num of proofs
1012        let m = 2;
1013        let nm = n * m;
1014        let KZen: &[u8] = &[75, 90, 101, 110];
1015        let kzen_label = BigInt::from_bytes(KZen);
1016
1017        let G = Point::<Secp256k1>::generator();
1018        let label = BigInt::from(1);
1019        let hash = Sha512::new().chain_bigint(&label).result_bigint();
1020        let H = generate_random_point(&Converter::to_bytes(&hash));
1021
1022        let g_vec = (0..nm)
1023            .map(|i| {
1024                let kzen_label_i = BigInt::from(i as u32) + &kzen_label;
1025                let hash_i = Sha512::new().chain_bigint(&kzen_label_i).result_bigint();
1026                generate_random_point(&Converter::to_bytes(&hash_i))
1027            })
1028            .collect::<Vec<Point<Secp256k1>>>();
1029
1030        // can run in parallel to g_vec:
1031        let h_vec = (0..nm)
1032            .map(|i| {
1033                let kzen_label_j = BigInt::from(n as u32) + BigInt::from(i as u32) + &kzen_label;
1034                let hash_j = Sha512::new().chain_bigint(&kzen_label_j).result_bigint();
1035                generate_random_point(&Converter::to_bytes(&hash_j))
1036            })
1037            .collect::<Vec<Point<Secp256k1>>>();
1038
1039        let range = BigInt::from(2).pow(n as u32);
1040        let v_vec = (0..m)
1041            .map(|_| Scalar::<Secp256k1>::from(&BigInt::sample_below(&range)))
1042            .collect::<Vec<Scalar<Secp256k1>>>();
1043
1044        let r_vec = (0..m)
1045            .map(|_| Scalar::<Secp256k1>::random())
1046            .collect::<Vec<Scalar<Secp256k1>>>();
1047
1048        let ped_com_vec = (0..m)
1049            .map(|i| &*G * &v_vec[i] + &H * &r_vec[i])
1050            .collect::<Vec<Point<Secp256k1>>>();
1051
1052        let range_proof = RangeProof::prove(&g_vec, &h_vec, &G, &H, v_vec, &r_vec, n);
1053        let result = RangeProof::verify(&range_proof, &g_vec, &h_vec, &G, &H, &ped_com_vec, n);
1054        assert!(result.is_ok());
1055    }
1056
1057    #[test]
1058    pub fn test_batch_1_range_proof_8() {
1059        // bit range
1060        let n = 8;
1061        // batch size
1062        let m = 1;
1063        let nm = n * m;
1064        // some seed for generating g and h vectors
1065        let KZen: &[u8] = &[75, 90, 101, 110];
1066        let kzen_label = BigInt::from_bytes(KZen);
1067
1068        // G,H - points for pederson commitment: com  = vG + rH
1069        let G = Point::<Secp256k1>::generator();
1070        let label = BigInt::from(1);
1071        let hash = Sha512::new().chain_bigint(&label).result_bigint();
1072        let H = generate_random_point(&Converter::to_bytes(&hash));
1073
1074        let g_vec = (0..nm)
1075            .map(|i| {
1076                let kzen_label_i = BigInt::from(i as u32) + &kzen_label;
1077                let hash_i = Sha512::new().chain_bigint(&kzen_label_i).result_bigint();
1078                generate_random_point(&Converter::to_bytes(&hash_i))
1079            })
1080            .collect::<Vec<Point<Secp256k1>>>();
1081
1082        // can run in parallel to g_vec:
1083        let h_vec = (0..nm)
1084            .map(|i| {
1085                let kzen_label_j = BigInt::from(n as u32) + BigInt::from(i as u32) + &kzen_label;
1086                let hash_j = Sha512::new().chain_bigint(&kzen_label_j).result_bigint();
1087                generate_random_point(&Converter::to_bytes(&hash_j))
1088            })
1089            .collect::<Vec<Point<Secp256k1>>>();
1090
1091        let range = BigInt::from(2).pow(n as u32);
1092        let v_vec = (0..m)
1093            .map(|_| Scalar::<Secp256k1>::from(&BigInt::sample_below(&range)))
1094            .collect::<Vec<Scalar<Secp256k1>>>();
1095
1096        let r_vec = (0..m)
1097            .map(|_| Scalar::<Secp256k1>::random())
1098            .collect::<Vec<Scalar<Secp256k1>>>();
1099
1100        let ped_com_vec = (0..m)
1101            .map(|i| &*G * &v_vec[i] + &H * &r_vec[i])
1102            .collect::<Vec<Point<Secp256k1>>>();
1103
1104        let range_proof = RangeProof::prove(&g_vec, &h_vec, &G, &H, v_vec, &r_vec, n);
1105        let result = RangeProof::verify(&range_proof, &g_vec, &h_vec, &G, &H, &ped_com_vec, n);
1106        assert!(result.is_ok());
1107    }
1108
1109    #[test]
1110    pub fn test_batch_4_range_proof_64() {
1111        let KZen: &[u8] = &[75, 90, 101, 110];
1112        let kzen_label = BigInt::from_bytes(KZen);
1113        test_helper(&kzen_label, 64, 4);
1114    }
1115
1116    #[test]
1117    pub fn test_agg_batch_4_range_proof_64() {
1118        let KZen: &[u8] = &[75, 90, 101, 110];
1119        let kzen_label = BigInt::from_bytes(KZen);
1120        test_helper_aggregated(&kzen_label, 64, 4);
1121    }
1122}