1
1
use core:: fmt;
2
2
3
3
use crate :: felt:: Felt ;
4
- use lambdaworks_math:: field:: {
5
- element:: FieldElement , fields:: fft_friendly:: stark_252_prime_field:: Stark252PrimeField ,
6
- } ;
7
4
8
5
pub const STWO_PRIME : u64 = ( 1 << 31 ) - 1 ;
9
6
const STWO_PRIME_U128 : u128 = STWO_PRIME as u128 ;
@@ -12,7 +9,7 @@ const MASK_8: u64 = (1 << 8) - 1;
12
9
13
10
#[ derive( Debug ) ]
14
11
pub enum QM31Error {
15
- InvalidQM31 ( Felt ) ,
12
+ FeltTooBig ( Felt ) ,
16
13
}
17
14
18
15
#[ cfg( feature = "std" ) ]
@@ -21,7 +18,7 @@ impl std::error::Error for QM31Error {}
21
18
impl fmt:: Display for QM31Error {
22
19
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
23
20
match self {
24
- QM31Error :: InvalidQM31 ( felt) => writeln ! (
21
+ QM31Error :: FeltTooBig ( felt) => writeln ! (
25
22
f,
26
23
"Number used as QM31 since it's more than 144 bits long: {}" ,
27
24
felt
@@ -32,23 +29,15 @@ impl fmt::Display for QM31Error {
32
29
33
30
#[ repr( transparent) ]
34
31
#[ derive( Debug , Clone , Copy , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
35
- pub struct QM31Felt ( pub ( crate ) FieldElement < Stark252PrimeField > ) ;
32
+ pub struct QM31Felt ( [ u64 ; 4 ] ) ;
36
33
37
34
impl QM31Felt {
38
35
/// [QM31Felt] constant that's equal to 0.
39
- pub const ZERO : Self = Self ( FieldElement :: < Stark252PrimeField > :: from_hex_unchecked ( "0" ) ) ;
36
+ pub const ZERO : Self = Self ( [ 0 , 0 , 0 , 0 ] ) ;
40
37
41
- /// Reads four u64 coordinates from a single Felt. STWO_PRIME fits in 36 bits, hence each coordinate
42
- /// can be represented by 36 bits and a QM31 element can be stored in the first 144 bits of a Felt.
38
+
43
39
pub fn as_raw ( & self ) -> [ u64 ; 4 ] {
44
- let limbs = self . as_le_digits ( ) ;
45
-
46
- [
47
- ( limbs[ 0 ] & MASK_36 ) ,
48
- ( ( limbs[ 0 ] >> 36 ) + ( ( limbs[ 1 ] & MASK_8 ) << 28 ) ) ,
49
- ( ( limbs[ 1 ] >> 8 ) & MASK_36 ) ,
50
- ( ( limbs[ 1 ] >> 44 ) + ( limbs[ 2 ] << 20 ) ) ,
51
- ]
40
+ self . 0
52
41
}
53
42
54
43
/// Create a [QM31Felt] from the raw internal representation. Reduces four u64 coordinates and packs them
@@ -61,17 +50,25 @@ impl QM31Felt {
61
50
let bytes_part2 = ( ( coordinates[ 2 ] % STWO_PRIME ) as u128
62
51
+ ( ( ( coordinates[ 3 ] % STWO_PRIME ) as u128 ) << 36 ) )
63
52
. to_le_bytes ( ) ;
64
- let mut result_bytes = [ 0u8 ; 32 ] ;
53
+ let mut result_bytes = [ 0 ; 32 ] ;
54
+
65
55
result_bytes[ 0 ..9 ] . copy_from_slice ( & bytes_part1[ 0 ..9 ] ) ;
66
56
result_bytes[ 9 ..18 ] . copy_from_slice ( & bytes_part2[ 0 ..9 ] ) ;
67
57
68
- let value = Felt :: from_bytes_le ( & result_bytes) ;
58
+ let limbs = {
59
+ let felt = Felt :: from_bytes_le_slice ( & result_bytes) ;
60
+ felt. to_le_digits ( )
61
+ } ;
69
62
70
- Self ( value. 0 )
63
+ Self ( [
64
+ ( limbs[ 0 ] & MASK_36 ) ,
65
+ ( ( limbs[ 0 ] >> 36 ) + ( ( limbs[ 1 ] & MASK_8 ) << 28 ) ) ,
66
+ ( ( limbs[ 1 ] >> 8 ) & MASK_36 ) ,
67
+ ( ( limbs[ 1 ] >> 44 ) + ( limbs[ 2 ] << 20 ) ) ,
68
+ ] )
71
69
}
72
70
73
71
/// Computes the addition of two QM31 elements in reduced form.
74
- /// Returns an error if either operand is not reduced.
75
72
pub fn add ( & self , rhs : & QM31Felt ) -> QM31Felt {
76
73
let coordinates1 = self . as_raw ( ) ;
77
74
let coordinates2 = rhs. as_raw ( ) ;
@@ -85,7 +82,6 @@ impl QM31Felt {
85
82
}
86
83
87
84
/// Computes the negative of a QM31 element in reduced form.
88
- /// Returns an error if the input is not reduced.
89
85
pub fn neg ( & self ) -> QM31Felt {
90
86
let coordinates = self . as_raw ( ) ;
91
87
Self :: from_raw ( [
@@ -97,7 +93,6 @@ impl QM31Felt {
97
93
}
98
94
99
95
/// Computes the subtraction of two QM31 elements in reduced form.
100
- /// Returns an error if either operand is not reduced.
101
96
pub fn sub ( & self , rhs : & QM31Felt ) -> QM31Felt {
102
97
let coordinates1 = self . as_raw ( ) ;
103
98
let coordinates2 = rhs. as_raw ( ) ;
@@ -111,7 +106,6 @@ impl QM31Felt {
111
106
}
112
107
113
108
/// Computes the multiplication of two QM31 elements in reduced form.
114
- /// Returns an error if either operand is not reduced.
115
109
pub fn mul ( & self , rhs : & QM31Felt ) -> QM31Felt {
116
110
let coordinates1_u64 = self . as_raw ( ) ;
117
111
let coordinates2_u64 = rhs. as_raw ( ) ;
@@ -147,7 +141,7 @@ impl QM31Felt {
147
141
148
142
/// Computes the inverse in the M31 field using Fermat's little theorem, i.e., returns
149
143
/// `v^(STWO_PRIME-2) modulo STWO_PRIME`, which is the inverse of v unless v % STWO_PRIME == 0.
150
- fn pow2147483645 ( v : u64 ) -> u64 {
144
+ fn m31_inverse ( v : u64 ) -> u64 {
151
145
let t0 = ( Self :: sqn ( v, 2 ) * v) % STWO_PRIME ;
152
146
let t1 = ( Self :: sqn ( t0, 1 ) * t0) % STWO_PRIME ;
153
147
let t2 = ( Self :: sqn ( t1, 3 ) * t0) % STWO_PRIME ;
@@ -167,7 +161,6 @@ impl QM31Felt {
167
161
}
168
162
169
163
/// Computes the inverse of a QM31 element in reduced form.
170
- /// Returns an error if the denominator is zero or either operand is not reduced.
171
164
/// # Safety
172
165
/// If the value is zero will panic.
173
166
pub fn inverse ( & self ) -> QM31Felt {
@@ -190,7 +183,7 @@ impl QM31Felt {
190
183
( 2 * coordinates[ 0 ] * coordinates[ 1 ] + 3 * STWO_PRIME - 2 * b2_i - b2_r) % STWO_PRIME ;
191
184
192
185
let denom_norm_squared = ( denom_r * denom_r + denom_i * denom_i) % STWO_PRIME ;
193
- let denom_norm_inverse_squared = Self :: pow2147483645 ( denom_norm_squared) ;
186
+ let denom_norm_inverse_squared = Self :: m31_inverse ( denom_norm_squared) ;
194
187
195
188
let denom_inverse_r = ( denom_r * denom_norm_inverse_squared) % STWO_PRIME ;
196
189
let denom_inverse_i = ( ( STWO_PRIME - denom_i) * denom_norm_inverse_squared) % STWO_PRIME ;
@@ -208,7 +201,6 @@ impl QM31Felt {
208
201
}
209
202
210
203
/// Computes the division of two QM31 elements in reduced form.
211
- /// Returns an error if the input is zero.
212
204
/// # Safety
213
205
/// Will panic if the rhs value is equal to zero.
214
206
pub fn div ( & self , rhs : & QM31Felt ) -> Result < QM31Felt , QM31Error > {
@@ -219,31 +211,17 @@ impl QM31Felt {
219
211
pub fn is_zero ( & self ) -> bool {
220
212
* self == Self :: ZERO
221
213
}
222
-
223
- /// Convert `self`'s representative into an array of `u64` digits,
224
- /// least significant digits first.
225
- pub fn as_le_digits ( & self ) -> [ u64 ; 4 ] {
226
- let mut limbs = self . 0 . representative ( ) . limbs ;
227
- limbs. reverse ( ) ;
228
- limbs
229
- }
230
-
231
- /// Convert `self`'s representative into an array of `u64` digits,
232
- /// most significant digits first.
233
- pub fn as_be_digits ( & self ) -> [ u64 ; 4 ] {
234
- self . 0 . representative ( ) . limbs
235
- }
236
214
}
237
215
238
216
impl From < & QM31Felt > for Felt {
239
217
fn from ( value : & QM31Felt ) -> Self {
240
- Felt ( value. 0 )
218
+ Felt :: from_raw ( value. 0 )
241
219
}
242
220
}
243
221
244
222
impl From < QM31Felt > for Felt {
245
223
fn from ( value : QM31Felt ) -> Self {
246
- Felt ( value. 0 )
224
+ Felt :: from_raw ( value. 0 )
247
225
}
248
226
}
249
227
@@ -257,10 +235,10 @@ impl TryFrom<Felt> for QM31Felt {
257
235
// because we are trying to convert a Felt into a QM31Felt. This
258
236
// Felt should represent a packed QM31 which is at most 144 bits long.
259
237
if limbs[ 3 ] != 0 || limbs[ 2 ] >= 1 << 16 {
260
- return Err ( QM31Error :: InvalidQM31 ( value) ) ;
238
+ return Err ( QM31Error :: FeltTooBig ( value) ) ;
261
239
}
262
240
263
- Ok ( Self ( value . 0 ) )
241
+ Ok ( Self ( limbs ) )
264
242
}
265
243
}
266
244
@@ -274,10 +252,10 @@ impl TryFrom<&Felt> for QM31Felt {
274
252
// because we are trying to convert a Felt into a QM31Felt. This
275
253
// Felt should represent a packed QM31 which is at most 144 bits long.
276
254
if limbs[ 3 ] != 0 || limbs[ 2 ] >= 1 << 16 {
277
- return Err ( QM31Error :: InvalidQM31 ( * value) ) ;
255
+ return Err ( QM31Error :: FeltTooBig ( * value) ) ;
278
256
}
279
257
280
- Ok ( Self ( value . 0 ) )
258
+ Ok ( Self ( limbs ) )
281
259
}
282
260
}
283
261
@@ -302,7 +280,7 @@ mod test {
302
280
let qm31: Result < QM31Felt , QM31Error > = felt. try_into ( ) ;
303
281
assert ! ( matches!(
304
282
qm31,
305
- Err ( QM31Error :: InvalidQM31 ( bx) ) if bx == felt
283
+ Err ( QM31Error :: FeltTooBig ( bx) ) if bx == felt
306
284
) ) ;
307
285
}
308
286
0 commit comments