@@ -5,6 +5,7 @@ use ark_std::{
55 rand:: Rng ,
66 vec:: Vec ,
77 UniformRand ,
8+ collections:: BTreeMap ,
89} ;
910
1011/// Represents a scalar multiplication check of the form `G1 * a1 + G2 * a2 + G3 * a3 + ... = T`.
@@ -18,10 +19,10 @@ use ark_std::{
1819/// The single check above is simplified by combining terms of `G1`, `H1`, etc to reduce the size of the multi-scalar multiplication
1920#[ derive( Debug , Clone ) ]
2021pub struct RandomizedMultChecker < G : AffineRepr > {
21- // map is more expensive than a vector (checked with a test)
22- // args: BTreeMap<SortableAffine<G>, G::ScalarField>,
23- /// Verification will expect the multi-scalar multiplication of first and second vector to be one.
24- args : ( Vec < G > , Vec < G :: ScalarField > ) ,
22+ /// Verification will expect the multi-scalar multiplication of key-value pairs to be one.
23+ /// x-coordinate -> (scalar, point)
24+ // This trick is taken from halo2 code (MSM) but keeping the point rather than y coordinate in value since there is no way to convert back from x, y coordinates for AffineRepr
25+ args : BTreeMap < G :: BaseField , ( G :: ScalarField , G ) > ,
2526 /// The random value chosen during creation
2627 random : G :: ScalarField ,
2728 /// The random value to be used for current check. After each check, set `current_random = current_random * random`
@@ -31,8 +32,7 @@ pub struct RandomizedMultChecker<G: AffineRepr> {
3132impl < G : AffineRepr > RandomizedMultChecker < G > {
3233 pub fn new ( random : G :: ScalarField ) -> Self {
3334 Self {
34- // args: BTreeMap::new(),
35- args : ( Vec :: new ( ) , Vec :: new ( ) ) ,
35+ args : BTreeMap :: new ( ) ,
3636 random,
3737 current_random : G :: ScalarField :: one ( ) ,
3838 }
@@ -91,60 +91,40 @@ impl<G: AffineRepr> RandomizedMultChecker<G> {
9191
9292 /// Combine all the checks into a multi-scalar multiplication and return true if the result is 0.
9393 pub fn verify ( & self ) -> bool {
94- debug_assert_eq ! ( self . args. 0 . len( ) , self . args. 1 . len( ) ) ;
95- G :: Group :: msm_unchecked ( & self . args . 0 , & self . args . 1 ) . is_zero ( )
94+ let mut points = Vec :: with_capacity ( self . len ( ) ) ;
95+ let mut scalars = Vec :: with_capacity ( self . len ( ) ) ;
96+ for ( _, ( s, point) ) in self . args . iter ( ) {
97+ points. push ( * point) ;
98+ scalars. push ( * s) ;
99+ }
100+ G :: Group :: msm_unchecked ( & points, & scalars) . is_zero ( )
96101 }
97102
98103 pub fn len ( & self ) -> usize {
99- self . args . 0 . len ( )
104+ self . args . len ( )
100105 }
101106
102107 fn add ( & mut self , p : G , s : G :: ScalarField ) {
103- // If the point already exists, update the scalar corresponding to the point
104- if let Some ( i) = self . args . 0 . iter ( ) . position ( |& p_i| p_i == p) {
105- self . args . 1 [ i] = self . args . 1 [ i] + s;
108+ if let Some ( x) = p. x ( ) {
109+ self . args
110+ . entry ( * x)
111+ . and_modify ( |( old_scalar, point) | {
112+ // If the point or its negative already exists, update the scalar accordingly
113+ if * point == p {
114+ * old_scalar += s;
115+ } else {
116+ * old_scalar -= s;
117+ debug_assert_eq ! ( point. into_group( ) , -p. into_group( ) ) ;
118+ }
119+ } )
120+ . or_insert ( ( s, p) ) ;
106121 } else {
107- self . args . 0 . push ( p ) ;
108- self . args . 1 . push ( s ) ;
122+ // If p is a point at infinity, then it doesn't impact the result
123+ debug_assert ! ( p . is_zero ( ) ) ;
109124 }
110125 }
111-
112- // fn add(&mut self, p: G, s: G::ScalarField) {
113- // let sortable_p = SortableAffine(p);
114- // let val = self.args.remove(&sortable_p);
115- // if let Some(v) = val {
116- // self.args.insert(sortable_p, v + s);
117- // } else {
118- // self.args.insert(sortable_p, s);
119- // }
120- // }
121- //
122- // pub fn verify(self) -> bool {
123- // let mut b = vec![];
124- // let mut s = vec![];
125- // for (k, v) in self.args.into_iter() {
126- // b.push(k.0);
127- // s.push(v);
128- // }
129- // G::Group::msm_unchecked(&b, &s).is_zero()
130- // }
131126}
132127
133- // #[derive(Debug, Clone, PartialEq, Eq)]
134- // pub struct SortableAffine<G: AffineRepr>(G);
135- //
136- // impl<G: AffineRepr> Ord for SortableAffine<G> {
137- // fn cmp(&self, other: &Self) -> Ordering {
138- // self.0.x().cmp(&other.0.x())
139- // }
140- // }
141- //
142- // impl<G: AffineRepr> PartialOrd for SortableAffine<G> {
143- // fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
144- // Some(self.cmp(other))
145- // }
146- // }
147-
148128#[ cfg( test) ]
149129mod test {
150130 use super :: * ;
@@ -278,6 +258,20 @@ mod test {
278258 checker. add_many ( [ g3, h3] , [ & a3, & a6] , c8) ;
279259 checker. add_many ( [ g1, g2, g3] , [ & a1, & a2, & a3] , c9) ;
280260 assert ! ( checker. verify( ) ) ;
261+
262+ let minus_g1 = -g1;
263+ let minus_g2 = -g2;
264+ let c1 = ( g1 * a1) . into_affine ( ) ;
265+ let c2 = ( minus_g1 * a2) . into_affine ( ) ;
266+ let c3 = ( g2 * a3) . into_affine ( ) ;
267+ let c4 = ( minus_g2 * a4) . into_affine ( ) ;
268+
269+ let mut checker = RandomizedMultChecker :: new_using_rng ( & mut rng) ;
270+ checker. add_1 ( g1, & a1, c1) ;
271+ checker. add_1 ( minus_g1, & a2, c2) ;
272+ checker. add_1 ( g2, & a3, c3) ;
273+ checker. add_1 ( minus_g2, & a4, c4) ;
274+ assert ! ( checker. verify( ) ) ;
281275 }
282276
283277 #[ test]
0 commit comments