@@ -4,8 +4,6 @@ use crate::felt::Felt;
4
4
5
5
pub const STWO_PRIME : u64 = ( 1 << 31 ) - 1 ;
6
6
const STWO_PRIME_U128 : u128 = STWO_PRIME as u128 ;
7
- const MASK_36 : u64 = ( 1 << 36 ) - 1 ;
8
- const MASK_8 : u64 = ( 1 << 8 ) - 1 ;
9
7
10
8
#[ derive( Debug ) ]
11
9
pub enum QM31Error {
@@ -44,28 +42,24 @@ impl QM31Felt {
44
42
/// into a single Felt252. STWO_PRIME fits in 36 bits, hence each coordinate can be represented
45
43
/// by 36 bits and a QM31 element can be stored in the first 144 bits of a Felt252.
46
44
pub fn from_raw ( coordinates : [ u64 ; 4 ] ) -> QM31Felt {
47
- let bytes_part1 = ( ( coordinates [ 0 ] % STWO_PRIME ) as u128
48
- + ( ( ( coordinates[ 1 ] % STWO_PRIME ) as u128 ) << 36 ) )
49
- . to_le_bytes ( ) ;
50
- let bytes_part2 = ( ( coordinates[ 2 ] % STWO_PRIME ) as u128
51
- + ( ( ( coordinates[ 3 ] % STWO_PRIME ) as u128 ) << 36 ) )
52
- . to_le_bytes ( ) ;
53
- let mut result_bytes = [ 0 ; 32 ] ;
45
+ Self ( [
46
+ coordinates[ 0 ] % STWO_PRIME ,
47
+ coordinates [ 1 ] % STWO_PRIME ,
48
+ coordinates[ 2 ] % STWO_PRIME ,
49
+ coordinates[ 3 ] % STWO_PRIME ,
50
+ ] )
51
+ }
54
52
53
+ pub fn pack_into_felt ( & self ) -> Felt {
54
+ let coordinates = self . 0 ;
55
+
56
+ let bytes_part1 = ( coordinates[ 0 ] as u128 + ( ( coordinates[ 1 ] as u128 ) << 36 ) ) . to_le_bytes ( ) ;
57
+ let bytes_part2 = ( coordinates[ 2 ] as u128 + ( ( coordinates[ 3 ] as u128 ) << 36 ) ) . to_le_bytes ( ) ;
58
+ let mut result_bytes = [ 0u8 ; 32 ] ;
55
59
result_bytes[ 0 ..9 ] . copy_from_slice ( & bytes_part1[ 0 ..9 ] ) ;
56
60
result_bytes[ 9 ..18 ] . copy_from_slice ( & bytes_part2[ 0 ..9 ] ) ;
57
61
58
- let limbs = {
59
- let felt = Felt :: from_bytes_le_slice ( & result_bytes) ;
60
- felt. to_le_digits ( )
61
- } ;
62
-
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
- ] )
62
+ Felt :: from_bytes_le ( & result_bytes)
69
63
}
70
64
71
65
/// Computes the addition of two QM31 elements in reduced form.
@@ -215,13 +209,13 @@ impl QM31Felt {
215
209
216
210
impl From < & QM31Felt > for Felt {
217
211
fn from ( value : & QM31Felt ) -> Self {
218
- Felt :: from_raw ( value. 0 )
212
+ value. pack_into_felt ( )
219
213
}
220
214
}
221
215
222
216
impl From < QM31Felt > for Felt {
223
217
fn from ( value : QM31Felt ) -> Self {
224
- Felt :: from_raw ( value. 0 )
218
+ value. pack_into_felt ( )
225
219
}
226
220
}
227
221
@@ -261,6 +255,8 @@ impl TryFrom<&Felt> for QM31Felt {
261
255
262
256
#[ cfg( test) ]
263
257
mod test {
258
+ use core:: { u128, u16, u8} ;
259
+
264
260
use proptest:: {
265
261
array:: uniform4,
266
262
prelude:: { BoxedStrategy , Just , Strategy } ,
@@ -273,41 +269,51 @@ mod test {
273
269
} ;
274
270
275
271
#[ test]
276
- fn from_positive_felt_to_qm31_to_felt ( ) {
277
- let felt_expected = Felt :: from ( 2i128 . pow ( 126 ) ) ;
272
+ fn qm31_to_felt_packed ( ) {
273
+ let u64_max_reduced = u64:: MAX % STWO_PRIME ;
274
+
275
+ let value = u8:: MAX ;
276
+ let felt = Felt :: from ( value) ;
277
+ let qm31: QM31Felt = felt. try_into ( ) . unwrap ( ) ;
278
+ let qm31_to_felt = qm31. pack_into_felt ( ) ;
278
279
279
- let qm31: QM31Felt = felt_expected. try_into ( ) . unwrap ( ) ;
280
- let felt = qm31. into ( ) ;
280
+ assert_eq ! ( qm31_to_felt, Felt :: from( value) ) ;
281
281
282
- assert_eq ! ( qm31, felt) ;
282
+ let value = u16:: MAX ;
283
+ let felt = Felt :: from ( value) ;
284
+ let qm31: QM31Felt = felt. try_into ( ) . unwrap ( ) ;
285
+ let qm31_to_felt = qm31. pack_into_felt ( ) ;
283
286
284
- let felt_expected = Felt :: from ( 2i64 . pow ( 62 ) ) ;
285
- let qm31: QM31Felt = felt_expected. try_into ( ) . unwrap ( ) ;
286
- let felt = qm31. into ( ) ;
287
+ assert_eq ! ( qm31_to_felt, Felt :: from( value) ) ;
287
288
288
- assert_eq ! ( qm31, felt) ;
289
+ let value = u32:: MAX ;
290
+ let felt = Felt :: from ( value) ;
291
+ let qm31: QM31Felt = felt. try_into ( ) . unwrap ( ) ;
292
+ let qm31_to_felt = qm31. pack_into_felt ( ) ;
289
293
290
- let felt_expected = Felt :: from ( 2i32 . pow ( 30 ) ) ;
291
- let qm31: QM31Felt = felt_expected. try_into ( ) . unwrap ( ) ;
292
- let felt = qm31. into ( ) ;
294
+ assert_eq ! ( qm31_to_felt, Felt :: from( value as u64 % STWO_PRIME ) ) ;
293
295
294
- assert_eq ! ( qm31, felt) ;
296
+ let felt = Felt :: from ( u64:: MAX ) ;
297
+ let qm31: QM31Felt = felt. try_into ( ) . unwrap ( ) ;
298
+ let qm31_to_felt = qm31. pack_into_felt ( ) ;
299
+ dbg ! ( felt. to_le_digits( ) ) ;
295
300
296
- let felt_expected = Felt :: from ( 2i8 . pow ( 6 ) ) ;
297
- let qm31: QM31Felt = felt_expected. try_into ( ) . unwrap ( ) ;
298
- let felt = qm31. into ( ) ;
301
+ assert_eq ! ( qm31_to_felt, Felt :: from( u64_max_reduced) ) ;
299
302
300
- assert_eq ! ( qm31, felt) ;
303
+ let felt = Felt :: from ( u128:: MAX ) ;
304
+ let qm31: QM31Felt = felt. try_into ( ) . unwrap ( ) ;
305
+ let qm31_to_felt = qm31. pack_into_felt ( ) ;
301
306
302
- let felt_expected = Felt :: ZERO ;
303
- let qm31: QM31Felt = felt_expected. try_into ( ) . unwrap ( ) ;
304
- let felt = qm31. into ( ) ;
307
+ let mut bytes = [ 0u8 ; 32 ] ;
308
+ let bytes_part1 =
309
+ ( ( u64_max_reduced) as u128 + ( ( ( u64_max_reduced) as u128 ) << 36 ) ) . to_le_bytes ( ) ;
310
+ bytes[ 0 ..9 ] . copy_from_slice ( & bytes_part1[ 0 ..9 ] ) ;
305
311
306
- assert_eq ! ( qm31 , felt ) ;
312
+ assert_eq ! ( qm31_to_felt , Felt :: from_bytes_le ( & bytes ) ) ;
307
313
}
308
314
309
315
#[ test]
310
- fn qm31_packed_reduced_coordinates_over_144_bits ( ) {
316
+ fn qm31_coordinates_over_144_bits ( ) {
311
317
let mut felt_bytes = [ 0u8 ; 32 ] ;
312
318
felt_bytes[ 18 ] = 1 ;
313
319
let felt = Felt :: from_bytes_le ( & felt_bytes) ;
0 commit comments