11use ark_ff:: { prelude:: * , PrimeField } ;
2- use ark_std:: { borrow:: Borrow , iterable:: Iterable , ops:: AddAssign , vec:: Vec } ;
3-
4- use crate :: { AffineCurve , ProjectiveCurve } ;
2+ use ark_std:: {
3+ borrow:: Borrow ,
4+ iterable:: Iterable ,
5+ ops:: { Add , AddAssign } ,
6+ vec:: Vec ,
7+ } ;
58
69#[ cfg( feature = "parallel" ) ]
710use rayon:: prelude:: * ;
811
912pub mod stream_pippenger;
1013pub use stream_pippenger:: * ;
1114
12- pub struct VariableBase ;
15+ pub trait VariableBaseMSM :
16+ Eq
17+ + Sized
18+ + Sync
19+ + Zero
20+ + Clone
21+ + Copy
22+ + Send
23+ + AddAssign < Self >
24+ + for < ' a > AddAssign < & ' a Self >
25+ + for < ' a > Add < & ' a Self , Output = Self >
26+ {
27+ type MSMBase : Sync + Copy ;
28+
29+ type Scalar : PrimeField ;
30+
31+ #[ doc( hidden) ]
32+ fn _double_in_place ( & mut self ) -> & mut Self ;
33+
34+ #[ doc( hidden) ]
35+ fn _add_assign_mixed ( & mut self , other : & Self :: MSMBase ) ;
1336
14- impl VariableBase {
1537 /// Optimized implementation of multi-scalar multiplication.
1638 ///
17- /// Will return `None` if `bases` and `scalar` have different lengths.
39+ /// Multiply the [`PrimeField`] elements in `scalars` with the
40+ /// respective group elements in `bases` and sum the resulting set.
41+ ///
42+ /// <section class="warning">
1843 ///
19- /// Reference: [`VariableBase::msm`]
20- pub fn msm_checked_len < G : AffineCurve > (
21- bases : & [ G ] ,
22- scalars : & [ <G :: ScalarField as PrimeField >:: BigInt ] ,
23- ) -> Option < G :: Projective > {
24- ( bases. len ( ) == scalars. len ( ) ) . then ( || Self :: msm ( bases, scalars) )
44+ /// If the elements have different length, it will chop the slices to the
45+ /// shortest length between `scalars.len()` and `bases.len()`.
46+ ///
47+ /// </section>
48+ fn msm ( bases : & [ Self :: MSMBase ] , scalars : & [ Self :: Scalar ] ) -> Self {
49+ let bigints = cfg_into_iter ! ( scalars)
50+ . map ( |s| s. into_bigint ( ) )
51+ . collect :: < Vec < _ > > ( ) ;
52+ Self :: msm_bigint ( bases, & bigints)
2553 }
2654
27- /// Optimized implementation of multi-scalar multiplication.
55+ /// Optimized implementation of multi-scalar multiplication, that checks bounds .
2856 ///
29- /// Will multiply the tuples of the diagonal product of `bases × scalars`
30- /// and sum the resulting set. Will iterate only for the elements of the
31- /// smallest of the two sets, ignoring the remaining elements of the biggest
32- /// set.
57+ /// Performs `Self::msm`, checking that `bases` and `scalars` have the same length.
58+ /// If the length are not equal, returns an error containing the shortest legth over which msm can be performed.
3359 ///
34- /// ∑i (Bi · Si)
35- pub fn msm < G : AffineCurve > (
36- bases : & [ G ] ,
37- scalars : & [ <G :: ScalarField as PrimeField >:: BigInt ] ,
38- ) -> G :: Projective {
39- let size = ark_std:: cmp:: min ( bases. len ( ) , scalars. len ( ) ) ;
40- let scalars = & scalars[ ..size] ;
60+ /// Reference: [`VariableBaseMSM::msm`]
61+ fn msm_checked ( bases : & [ Self :: MSMBase ] , scalars : & [ Self :: Scalar ] ) -> Result < Self , usize > {
62+ ( bases. len ( ) == scalars. len ( ) )
63+ . then ( || Self :: msm ( bases, scalars) )
64+ . ok_or ( usize:: min ( bases. len ( ) , scalars. len ( ) ) )
65+ }
66+
67+ /// Optimized implementation of multi-scalar multiplication.
68+ fn msm_bigint (
69+ bases : & [ Self :: MSMBase ] ,
70+ bigints : & [ <Self :: Scalar as PrimeField >:: BigInt ] ,
71+ ) -> Self {
72+ let size = ark_std:: cmp:: min ( bases. len ( ) , bigints. len ( ) ) ;
73+ let scalars = & bigints[ ..size] ;
4174 let bases = & bases[ ..size] ;
4275 let scalars_and_bases_iter = scalars. iter ( ) . zip ( bases) . filter ( |( s, _) | !s. is_zero ( ) ) ;
4376
@@ -47,10 +80,10 @@ impl VariableBase {
4780 super :: ln_without_floats ( size) + 2
4881 } ;
4982
50- let num_bits = G :: ScalarField :: MODULUS_BIT_SIZE as usize ;
51- let fr_one = G :: ScalarField :: one ( ) . into_bigint ( ) ;
83+ let num_bits = Self :: Scalar :: MODULUS_BIT_SIZE as usize ;
84+ let fr_one = Self :: Scalar :: one ( ) . into_bigint ( ) ;
5285
53- let zero = G :: Projective :: zero ( ) ;
86+ let zero = Self :: zero ( ) ;
5487 let window_starts: Vec < _ > = ( 0 ..num_bits) . step_by ( c) . collect ( ) ;
5588
5689 // Each window is of size `c`.
@@ -67,7 +100,7 @@ impl VariableBase {
67100 if scalar == fr_one {
68101 // We only process unit scalars once in the first window.
69102 if w_start == 0 {
70- res. add_assign_mixed ( base) ;
103+ res. _add_assign_mixed ( base) ;
71104 }
72105 } else {
73106 let mut scalar = scalar;
@@ -83,7 +116,7 @@ impl VariableBase {
83116 // bucket.
84117 // (Recall that `buckets` doesn't have a zero bucket.)
85118 if scalar != 0 {
86- buckets[ ( scalar - 1 ) as usize ] . add_assign_mixed ( base) ;
119+ buckets[ ( scalar - 1 ) as usize ] . _add_assign_mixed ( base) ;
87120 }
88121 }
89122 } ) ;
@@ -102,7 +135,7 @@ impl VariableBase {
102135
103136 // `running_sum` = sum_{j in i..num_buckets} bucket[j],
104137 // where we iterate backward from i = num_buckets to 0.
105- let mut running_sum = G :: Projective :: zero ( ) ;
138+ let mut running_sum = Self :: zero ( ) ;
106139 buckets. into_iter ( ) . rev ( ) . for_each ( |b| {
107140 running_sum += & b;
108141 res += & running_sum;
@@ -122,21 +155,19 @@ impl VariableBase {
122155 . fold ( zero, |mut total, sum_i| {
123156 total += sum_i;
124157 for _ in 0 ..c {
125- total. double_in_place ( ) ;
158+ total. _double_in_place ( ) ;
126159 }
127160 total
128161 } )
129162 }
130163 /// Streaming multi-scalar multiplication algorithm with hard-coded chunk
131164 /// size.
132- pub fn msm_chunks < G , F , I : ?Sized , J > ( bases_stream : & J , scalars_stream : & I ) -> G :: Projective
165+ fn msm_chunks < I : ?Sized , J > ( bases_stream : & J , scalars_stream : & I ) -> Self
133166 where
134- G : AffineCurve < ScalarField = F > ,
135167 I : Iterable ,
136- F : PrimeField ,
137- I :: Item : Borrow < F > ,
168+ I :: Item : Borrow < Self :: Scalar > ,
138169 J : Iterable ,
139- J :: Item : Borrow < G > ,
170+ J :: Item : Borrow < Self :: MSMBase > ,
140171 {
141172 assert ! ( scalars_stream. len( ) <= bases_stream. len( ) ) ;
142173
@@ -149,7 +180,7 @@ impl VariableBase {
149180 // See <https://github.com/rust-lang/rust/issues/77404>
150181 let mut bases = bases_init. skip ( bases_stream. len ( ) - scalars_stream. len ( ) ) ;
151182 let step: usize = 1 << 20 ;
152- let mut result = G :: Projective :: zero ( ) ;
183+ let mut result = Self :: zero ( ) ;
153184 for _ in 0 ..( scalars_stream. len ( ) + step - 1 ) / step {
154185 let bases_step = ( & mut bases)
155186 . take ( step)
@@ -159,7 +190,7 @@ impl VariableBase {
159190 . take ( step)
160191 . map ( |s| s. borrow ( ) . into_bigint ( ) )
161192 . collect :: < Vec < _ > > ( ) ;
162- result. add_assign ( crate :: msm :: VariableBase :: msm (
193+ result. add_assign ( Self :: msm_bigint (
163194 bases_step. as_slice ( ) ,
164195 scalars_step. as_slice ( ) ,
165196 ) ) ;
0 commit comments