11//! Traits for arithmetic operations on elliptic curve field elements.
22
33use core:: iter;
4- pub use core:: ops:: { Add , AddAssign , Mul , Neg , Shr , ShrAssign , Sub , SubAssign } ;
4+ pub use core:: ops:: { Add , AddAssign , Mul , MulAssign , Neg , Shr , ShrAssign , Sub , SubAssign } ;
55pub use crypto_bigint:: Invert ;
66
77use crypto_bigint:: Integer ;
@@ -13,26 +13,24 @@ use alloc::{borrow::ToOwned, vec::Vec};
1313
1414/// Perform a batched inversion on a sequence of field elements (i.e. base field elements or scalars)
1515/// at an amortized cost that should be practically as efficient as a single inversion.
16- pub trait BatchInvert < FieldElements : ?Sized > : Field + Sized {
16+ pub trait BatchInvert < FieldElements : ?Sized > {
1717 /// The output of batch inversion. A container of field elements.
18- type Output : AsRef < [ Self ] > ;
18+ type Output ;
1919
2020 /// Invert a batch of field elements.
21- fn batch_invert (
22- field_elements : FieldElements ,
23- ) -> CtOption < <Self as BatchInvert < FieldElements > >:: Output > ;
21+ fn batch_invert ( field_elements : FieldElements ) -> <Self as BatchInvert < FieldElements > >:: Output ;
2422}
2523
2624impl < const N : usize , T > BatchInvert < [ T ; N ] > for T
2725where
2826 T : Field ,
2927{
30- type Output = [ Self ; N ] ;
28+ type Output = CtOption < [ Self ; N ] > ;
3129
3230 fn batch_invert ( mut field_elements : [ Self ; N ] ) -> CtOption < [ Self ; N ] > {
3331 let mut field_elements_pad = [ Self :: default ( ) ; N ] ;
3432 let inversion_succeeded =
35- invert_batch_internal ( & mut field_elements, & mut field_elements_pad) ;
33+ invert_batch_internal ( & mut field_elements, & mut field_elements_pad, invert ) ;
3634
3735 CtOption :: new ( field_elements, inversion_succeeded)
3836 }
@@ -43,11 +41,12 @@ impl<'this, T> BatchInvert<&'this mut [Self]> for T
4341where
4442 T : Field ,
4543{
46- type Output = & ' this mut [ Self ] ;
44+ type Output = CtOption < & ' this mut [ Self ] > ;
4745
4846 fn batch_invert ( field_elements : & ' this mut [ Self ] ) -> CtOption < & ' this mut [ Self ] > {
4947 let mut field_elements_pad: Vec < Self > = vec ! [ Self :: default ( ) ; field_elements. len( ) ] ;
50- let inversion_succeeded = invert_batch_internal ( field_elements, & mut field_elements_pad) ;
48+ let inversion_succeeded =
49+ invert_batch_internal ( field_elements, & mut field_elements_pad, invert) ;
5150
5251 CtOption :: new ( field_elements, inversion_succeeded)
5352 }
@@ -58,13 +57,13 @@ impl<T> BatchInvert<&[Self]> for T
5857where
5958 T : Field ,
6059{
61- type Output = Vec < Self > ;
60+ type Output = CtOption < Vec < Self > > ;
6261
6362 fn batch_invert ( field_elements : & [ Self ] ) -> CtOption < Vec < Self > > {
6463 let mut field_elements: Vec < Self > = field_elements. to_owned ( ) ;
6564 let mut field_elements_pad: Vec < Self > = vec ! [ Self :: default ( ) ; field_elements. len( ) ] ;
6665 let inversion_succeeded =
67- invert_batch_internal ( & mut field_elements, & mut field_elements_pad) ;
66+ invert_batch_internal ( & mut field_elements, & mut field_elements_pad, invert ) ;
6867
6968 CtOption :: new ( field_elements, inversion_succeeded)
7069 }
@@ -75,26 +74,35 @@ impl<T> BatchInvert<Vec<Self>> for T
7574where
7675 T : Field ,
7776{
78- type Output = Vec < Self > ;
77+ type Output = CtOption < Vec < Self > > ;
7978
8079 fn batch_invert ( mut field_elements : Vec < Self > ) -> CtOption < Vec < Self > > {
8180 let mut field_elements_pad: Vec < Self > = vec ! [ Self :: default ( ) ; field_elements. len( ) ] ;
8281 let inversion_succeeded =
83- invert_batch_internal ( & mut field_elements, & mut field_elements_pad) ;
82+ invert_batch_internal ( & mut field_elements, & mut field_elements_pad, invert ) ;
8483
8584 CtOption :: new ( field_elements, inversion_succeeded)
8685 }
8786}
8887
88+ fn invert < T : Field > ( scalar : T ) -> ( T , Choice ) {
89+ let scalar = scalar. invert ( ) ;
90+ let choice = scalar. is_some ( ) ;
91+ let scalar = scalar. unwrap_or ( T :: default ( ) ) ;
92+
93+ ( scalar, choice)
94+ }
95+
8996/// Implements "Montgomery's trick", a trick for computing many modular inverses at once.
9097///
9198/// "Montgomery's trick" works by reducing the problem of computing `n` inverses
9299/// to computing a single inversion, plus some storage and `O(n)` extra multiplications.
93100///
94101/// See: https://iacr.org/archive/pkc2004/29470042/29470042.pdf section 2.2.
95- fn invert_batch_internal < T : Field > (
102+ pub ( crate ) fn invert_batch_internal < T : Copy + Mul < Output = T > + MulAssign > (
96103 field_elements : & mut [ T ] ,
97104 field_elements_pad : & mut [ T ] ,
105+ invert : fn ( T ) -> ( T , Choice ) ,
98106) -> Choice {
99107 let batch_size = field_elements. len ( ) ;
100108 if batch_size != field_elements_pad. len ( ) {
@@ -117,32 +125,32 @@ fn invert_batch_internal<T: Field>(
117125 * field_element_pad = acc;
118126 }
119127
120- acc. invert ( )
121- . map ( | mut acc| {
122- // Shift the iterator by one element back. The one we are skipping is served in `acc`.
123- let field_elements_pad = field_elements_pad
124- . iter ( )
125- . rev ( )
126- . skip ( 1 )
127- . map ( Some )
128- . chain ( iter:: once ( None ) ) ;
129-
130- for ( field_element, field_element_pad) in
131- field_elements. iter_mut ( ) . rev ( ) . zip ( field_elements_pad)
132- {
133- if let Some ( field_element_pad) = field_element_pad {
134- // Store in a temporary so we can overwrite `field_element`.
135- // $ a_{n-1} = {a_n}^{-1}*x_n $
136- let tmp = acc * * field_element;
137- // $ {x_n}^{-1} = a_{n}^{-1}*a_{n-1} $
138- * field_element = acc * * field_element_pad;
139- acc = tmp;
140- } else {
141- * field_element = acc;
142- }
143- }
144- } )
145- . is_some ( )
128+ let ( mut acc, choice ) = invert ( acc ) ;
129+
130+ // Shift the iterator by one element back. The one we are skipping is served in `acc`.
131+ let field_elements_pad = field_elements_pad
132+ . iter ( )
133+ . rev ( )
134+ . skip ( 1 )
135+ . map ( Some )
136+ . chain ( iter:: once ( None ) ) ;
137+
138+ for ( field_element, field_element_pad) in
139+ field_elements. iter_mut ( ) . rev ( ) . zip ( field_elements_pad)
140+ {
141+ if let Some ( field_element_pad) = field_element_pad {
142+ // Store in a temporary so we can overwrite `field_element`.
143+ // $ a_{n-1} = {a_n}^{-1}*x_n $
144+ let tmp = acc * * field_element;
145+ // $ {x_n}^{-1} = a_{n}^{-1}*a_{n-1} $
146+ * field_element = acc * * field_element_pad;
147+ acc = tmp;
148+ } else {
149+ * field_element = acc;
150+ }
151+ }
152+
153+ choice
146154}
147155
148156/// Linear combination.
0 commit comments