1
1
//! Traits for arithmetic operations on elliptic curve field elements.
2
2
3
3
use 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 } ;
5
5
pub use crypto_bigint:: Invert ;
6
6
7
7
use crypto_bigint:: Integer ;
@@ -13,26 +13,24 @@ use alloc::{borrow::ToOwned, vec::Vec};
13
13
14
14
/// Perform a batched inversion on a sequence of field elements (i.e. base field elements or scalars)
15
15
/// 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 > {
17
17
/// The output of batch inversion. A container of field elements.
18
- type Output : AsRef < [ Self ] > ;
18
+ type Output ;
19
19
20
20
/// 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 ;
24
22
}
25
23
26
24
impl < const N : usize , T > BatchInvert < [ T ; N ] > for T
27
25
where
28
26
T : Field ,
29
27
{
30
- type Output = [ Self ; N ] ;
28
+ type Output = CtOption < [ Self ; N ] > ;
31
29
32
30
fn batch_invert ( mut field_elements : [ Self ; N ] ) -> CtOption < [ Self ; N ] > {
33
31
let mut field_elements_pad = [ Self :: default ( ) ; N ] ;
34
32
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 ) ;
36
34
37
35
CtOption :: new ( field_elements, inversion_succeeded)
38
36
}
@@ -43,11 +41,12 @@ impl<'this, T> BatchInvert<&'this mut [Self]> for T
43
41
where
44
42
T : Field ,
45
43
{
46
- type Output = & ' this mut [ Self ] ;
44
+ type Output = CtOption < & ' this mut [ Self ] > ;
47
45
48
46
fn batch_invert ( field_elements : & ' this mut [ Self ] ) -> CtOption < & ' this mut [ Self ] > {
49
47
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) ;
51
50
52
51
CtOption :: new ( field_elements, inversion_succeeded)
53
52
}
@@ -58,13 +57,13 @@ impl<T> BatchInvert<&[Self]> for T
58
57
where
59
58
T : Field ,
60
59
{
61
- type Output = Vec < Self > ;
60
+ type Output = CtOption < Vec < Self > > ;
62
61
63
62
fn batch_invert ( field_elements : & [ Self ] ) -> CtOption < Vec < Self > > {
64
63
let mut field_elements: Vec < Self > = field_elements. to_owned ( ) ;
65
64
let mut field_elements_pad: Vec < Self > = vec ! [ Self :: default ( ) ; field_elements. len( ) ] ;
66
65
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 ) ;
68
67
69
68
CtOption :: new ( field_elements, inversion_succeeded)
70
69
}
@@ -75,26 +74,35 @@ impl<T> BatchInvert<Vec<Self>> for T
75
74
where
76
75
T : Field ,
77
76
{
78
- type Output = Vec < Self > ;
77
+ type Output = CtOption < Vec < Self > > ;
79
78
80
79
fn batch_invert ( mut field_elements : Vec < Self > ) -> CtOption < Vec < Self > > {
81
80
let mut field_elements_pad: Vec < Self > = vec ! [ Self :: default ( ) ; field_elements. len( ) ] ;
82
81
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 ) ;
84
83
85
84
CtOption :: new ( field_elements, inversion_succeeded)
86
85
}
87
86
}
88
87
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
+
89
96
/// Implements "Montgomery's trick", a trick for computing many modular inverses at once.
90
97
///
91
98
/// "Montgomery's trick" works by reducing the problem of computing `n` inverses
92
99
/// to computing a single inversion, plus some storage and `O(n)` extra multiplications.
93
100
///
94
101
/// 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 > (
96
103
field_elements : & mut [ T ] ,
97
104
field_elements_pad : & mut [ T ] ,
105
+ invert : fn ( T ) -> ( T , Choice ) ,
98
106
) -> Choice {
99
107
let batch_size = field_elements. len ( ) ;
100
108
if batch_size != field_elements_pad. len ( ) {
@@ -117,32 +125,32 @@ fn invert_batch_internal<T: Field>(
117
125
* field_element_pad = acc;
118
126
}
119
127
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
146
154
}
147
155
148
156
/// Linear combination.
0 commit comments