11use std:: ops:: { Add , Mul } ;
22
3- use ark_ec:: PrimeGroup ;
3+ use ark_ec:: { PrimeGroup , scalar_mul:: BatchMulPreprocessing } ;
4+ use ark_ff:: BigInteger ;
5+ use ark_ff:: PrimeField ;
46use ark_ff:: { Field , One , UniformRand , Zero } ;
57use ark_secp256k1:: { Fr , Projective } ;
68use rand:: Rng ;
79use serde:: { Deserialize , Serialize } ;
810
11+ pub struct Secp256k1 {
12+ pub generator : BatchMulPreprocessing < Projective > ,
13+ }
14+
15+ impl Default for Secp256k1 {
16+ fn default ( ) -> Self {
17+ Self :: new ( )
18+ }
19+ }
20+
21+ impl Secp256k1 {
22+ pub fn new ( ) -> Self {
23+ // 181*176*3 is roughly the number of generator multiplications we do
24+ Self {
25+ generator : BatchMulPreprocessing :: new ( Projective :: generator ( ) , 181 * 176 * 3 ) ,
26+ }
27+ }
28+
29+ // Replacement of BatchMulPreprocessing::batch_mul, which (1) uses rayon parallelization
30+ // and (2) converts the result to an affine point instead of a projective point.
31+ fn generator_batch_mul ( & self , scalars : & [ Fr ] ) -> Vec < Projective > {
32+ scalars. iter ( ) . map ( |e| self . windowed_mul ( e) ) . collect ( )
33+ }
34+
35+ // copied from ark-ec/src/scalar_mul/mod.rs because it's not public
36+ fn windowed_mul ( & self , scalar : & Fr ) -> Projective {
37+ let outerc = self
38+ . generator
39+ . max_scalar_size
40+ . div_ceil ( self . generator . window ) ;
41+ let modulus_size = Fr :: MODULUS_BIT_SIZE as usize ;
42+ let scalar_val = scalar. into_bigint ( ) . to_bits_le ( ) ;
43+
44+ let mut res = Projective :: from ( self . generator . table [ 0 ] [ 0 ] ) ;
45+ for outer in 0 ..outerc {
46+ let mut inner = 0usize ;
47+ for i in 0 ..self . generator . window {
48+ if outer * self . generator . window + i < modulus_size
49+ && scalar_val[ outer * self . generator . window + i]
50+ {
51+ inner |= 1 << i;
52+ }
53+ }
54+ res += & self . generator . table [ outer] [ inner] ;
55+ }
56+ res
57+ }
58+ }
59+
960// we use this for both polynomials over scalars and over projective points
1061#[ derive( Clone , Debug , Serialize , Deserialize ) ]
1162pub struct Polynomial < T > ( Vec < T > ) ;
@@ -34,9 +85,8 @@ impl Polynomial<Fr> {
3485 Self ( ( 0 ..degree + 1 ) . map ( |_| Fr :: rand ( & mut rand) ) . collect ( ) )
3586 }
3687
37- pub fn coefficient_commits ( & self ) -> PolynomialCommits {
38- let generator = Projective :: generator ( ) ;
39- PolynomialCommits ( Polynomial ( self . 0 . iter ( ) . map ( |x| generator * x) . collect ( ) ) )
88+ pub fn coefficient_commits ( & self , secp : & Secp256k1 ) -> PolynomialCommits {
89+ PolynomialCommits ( Polynomial ( secp. generator_batch_mul ( & self . 0 ) ) )
4090 }
4191
4292 // shares are return with 0-based index. However, we evaluate share i at
@@ -47,13 +97,14 @@ impl Polynomial<Fr> {
4797 . collect ( )
4898 }
4999
50- pub fn share_commits ( & self , num_shares : usize ) -> ShareCommits {
51- ShareCommits (
52- self . shares ( num_shares)
53- . into_iter ( )
54- . map ( |( _, share) | Projective :: generator ( ) * share)
55- . collect ( ) ,
56- )
100+ pub fn share_commits ( & self , secp : & Secp256k1 , num_shares : usize ) -> ShareCommits {
101+ let shares = self
102+ . shares ( num_shares)
103+ . into_iter ( )
104+ . map ( |( _, share) | share)
105+ . collect :: < Vec < _ > > ( ) ;
106+ let commits = secp. generator_batch_mul ( & shares) ;
107+ ShareCommits ( commits)
57108 }
58109}
59110
@@ -75,20 +126,22 @@ impl ShareCommits {
75126 Ok ( ( ) )
76127 }
77128
78- pub fn verify_shares ( & self , shares : & [ ( usize , Fr ) ] ) -> Result < ( ) , String > {
129+ pub fn verify_shares ( & self , secp : & Secp256k1 , shares : & [ ( usize , Fr ) ] ) -> Result < ( ) , String > {
79130 let mut indices = shares. iter ( ) . map ( |( i, _) | * i) . collect :: < Vec < _ > > ( ) ;
80131 indices. sort_unstable ( ) ;
81132 if indices. windows ( 2 ) . any ( |arr| arr[ 0 ] == arr[ 1 ] ) {
82133 return Err ( "Duplicate share index found" . to_owned ( ) ) ;
83134 }
84135
85- for ( i, share) in shares. iter ( ) {
136+ let ( indices, shares) : ( Vec < _ > , Vec < _ > ) = shares. iter ( ) . copied ( ) . unzip ( ) ;
137+ let recomputed_commits = secp. generator_batch_mul ( & shares) ;
138+ for ( index, recomputed_commit) in indices. iter ( ) . zip ( recomputed_commits. into_iter ( ) ) {
86139 let share_commit = self
87140 . 0
88- . get ( * i )
141+ . get ( * index )
89142 . ok_or ( "Share index out of bounds" . to_owned ( ) ) ?;
90143
91- if * share_commit != Projective :: generator ( ) * share {
144+ if * share_commit != recomputed_commit {
92145 return Err ( "Share verification failed" . to_owned ( ) ) ;
93146 }
94147 }
@@ -191,6 +244,10 @@ pub fn lagrange_interpolate_whole_polynomial(
191244
192245#[ cfg( test) ]
193246mod tests {
247+ use std:: time:: Instant ;
248+
249+ use ark_ec:: ScalarMul ;
250+
194251 use super :: * ;
195252 use rand:: { SeedableRng , seq:: index:: sample} ;
196253 use rand_chacha:: ChaCha20Rng ;
@@ -211,16 +268,48 @@ mod tests {
211268 #[ test]
212269 fn test_commit_verification ( ) {
213270 let polynomial_degree = 3 ;
271+
272+ let secp = Secp256k1 :: new ( ) ;
273+
214274 let polynomial = Polynomial :: rand ( rand:: thread_rng ( ) , polynomial_degree) ;
215275
216276 let num_shares = polynomial_degree + 1 ;
217- let poly_commits = polynomial. coefficient_commits ( ) ;
218- let share_commits = polynomial. share_commits ( num_shares) ;
277+ let poly_commits = polynomial. coefficient_commits ( & secp ) ;
278+ let share_commits = polynomial. share_commits ( & secp , num_shares) ;
219279
220280 share_commits. verify ( & poly_commits) . unwrap ( ) ;
221281
222282 let shares = polynomial. shares ( num_shares) ;
223- share_commits. verify_shares ( & shares) . unwrap ( ) ;
283+ share_commits. verify_shares ( & secp, & shares) . unwrap ( ) ;
284+ }
285+
286+ #[ test]
287+ fn test_batch_mul ( ) {
288+ let time_start = Instant :: now ( ) ;
289+ let secp = Secp256k1 :: new ( ) ;
290+ println ! (
291+ "secp256k1 precalculation time: {:?}" ,
292+ Instant :: now( ) - time_start
293+ ) ;
294+
295+ let approx_size = secp. generator . table . iter ( ) . map ( |x| x. len ( ) ) . sum :: < usize > ( )
296+ * std:: mem:: size_of :: < <Projective as ScalarMul >:: MulBase > ( ) ;
297+ println ! ( "approx_size: {:?}" , approx_size) ;
298+
299+ let coeffs = ( 0 ..174 )
300+ . map ( |_| Fr :: rand ( & mut rand:: thread_rng ( ) ) )
301+ . collect :: < Vec < _ > > ( ) ;
302+
303+ let time_start = Instant :: now ( ) ;
304+ let vals_batched = secp. generator_batch_mul ( & coeffs) ;
305+ println ! ( "batch_mul time: {:?}" , Instant :: now( ) - time_start) ;
306+
307+ let generator = Projective :: generator ( ) ;
308+ let time_start = Instant :: now ( ) ;
309+ let vals_unbatched = coeffs. iter ( ) . map ( |c| generator * c) . collect :: < Vec < _ > > ( ) ;
310+ println ! ( "unbatched time: {:?}" , Instant :: now( ) - time_start) ;
311+
312+ assert_eq ! ( vals_batched, vals_unbatched) ;
224313 }
225314
226315 #[ test]
0 commit comments