@@ -10,6 +10,7 @@ const MASK_8: u64 = (1 << 8) - 1;
10
10
#[ derive( Debug ) ]
11
11
pub enum QM31Error {
12
12
FeltTooBig ( Felt ) ,
13
+ InvalidInversion ,
13
14
}
14
15
15
16
#[ cfg( feature = "std" ) ]
@@ -23,6 +24,7 @@ impl fmt::Display for QM31Error {
23
24
"Number used as QM31 since it's more than 144 bits long: {}" ,
24
25
felt
25
26
) ,
27
+ QM31Error :: InvalidInversion => writeln ! ( f, "Attempt to invert a qm31 equal to zero" ) ,
26
28
}
27
29
}
28
30
}
@@ -35,7 +37,6 @@ impl QM31Felt {
35
37
/// [QM31Felt] constant that's equal to 0.
36
38
pub const ZERO : Self = Self ( [ 0 , 0 , 0 , 0 ] ) ;
37
39
38
-
39
40
pub fn as_raw ( & self ) -> [ u64 ; 4 ] {
40
41
self . 0
41
42
}
@@ -55,10 +56,10 @@ impl QM31Felt {
55
56
result_bytes[ 0 ..9 ] . copy_from_slice ( & bytes_part1[ 0 ..9 ] ) ;
56
57
result_bytes[ 9 ..18 ] . copy_from_slice ( & bytes_part2[ 0 ..9 ] ) ;
57
58
58
- let limbs = {
59
+ let limbs = {
59
60
let felt = Felt :: from_bytes_le_slice ( & result_bytes) ;
60
61
felt. to_le_digits ( )
61
- } ;
62
+ } ;
62
63
63
64
Self ( [
64
65
( limbs[ 0 ] & MASK_36 ) ,
@@ -163,8 +164,10 @@ impl QM31Felt {
163
164
/// Computes the inverse of a QM31 element in reduced form.
164
165
/// # Safety
165
166
/// If the value is zero will panic.
166
- pub fn inverse ( & self ) -> QM31Felt {
167
- assert_ne ! ( * self , Self :: ZERO , "Zero is not an invertible number" ) ;
167
+ pub fn inverse ( & self ) -> Result < QM31Felt , QM31Error > {
168
+ if * self == Self :: ZERO {
169
+ return Err ( QM31Error :: InvalidInversion ) ;
170
+ }
168
171
169
172
let coordinates = self . as_raw ( ) ;
170
173
@@ -188,7 +191,7 @@ impl QM31Felt {
188
191
let denom_inverse_r = ( denom_r * denom_norm_inverse_squared) % STWO_PRIME ;
189
192
let denom_inverse_i = ( ( STWO_PRIME - denom_i) * denom_norm_inverse_squared) % STWO_PRIME ;
190
193
191
- Self :: from_raw ( [
194
+ Ok ( Self :: from_raw ( [
192
195
coordinates[ 0 ] * denom_inverse_r + STWO_PRIME * STWO_PRIME
193
196
- coordinates[ 1 ] * denom_inverse_i,
194
197
coordinates[ 0 ] * denom_inverse_i + coordinates[ 1 ] * denom_inverse_r,
@@ -197,14 +200,13 @@ impl QM31Felt {
197
200
2 * STWO_PRIME * STWO_PRIME
198
201
- coordinates[ 2 ] * denom_inverse_i
199
202
- coordinates[ 3 ] * denom_inverse_r,
200
- ] )
203
+ ] ) )
201
204
}
202
205
203
- /// Computes the division of two QM31 elements in reduced form.
204
- /// # Safety
205
- /// Will panic if the rhs value is equal to zero.
206
+ /// Computes the division of two QM31 elements in reduced form. Returns an error
207
+ /// if the rhs value is equal to zero.
206
208
pub fn div ( & self , rhs : & QM31Felt ) -> Result < QM31Felt , QM31Error > {
207
- let rhs_inv = rhs. inverse ( ) ;
209
+ let rhs_inv = rhs. inverse ( ) ? ;
208
210
Ok ( self . mul ( & rhs_inv) )
209
211
}
210
212
@@ -357,19 +359,19 @@ mod test {
357
359
fn test_qm31_packed_reduced_inv ( ) {
358
360
let x_coordinates = [ 1259921049 , 1442249570 , 1847759065 , 2094551481 ] ;
359
361
let x = QM31Felt :: from_raw ( x_coordinates) ;
360
- let res = x. inverse ( ) ;
362
+ let res = x. inverse ( ) . unwrap ( ) ;
361
363
let expected = Felt :: from ( 1 ) . try_into ( ) . unwrap ( ) ;
362
364
assert_eq ! ( x. mul( & res) , expected) ;
363
365
364
366
let x_coordinates = [ 1 , 2 , 3 , 4 ] ;
365
367
let x = QM31Felt :: from_raw ( x_coordinates) ;
366
- let res = x. inverse ( ) ;
368
+ let res = x. inverse ( ) . unwrap ( ) ;
367
369
let expected = Felt :: from ( 1 ) . try_into ( ) . unwrap ( ) ;
368
370
assert_eq ! ( x. mul( & res) , expected) ;
369
371
370
372
let x_coordinates = [ 1749652895 , 834624081 , 1930174752 , 2063872165 ] ;
371
373
let x = QM31Felt :: from_raw ( x_coordinates) ;
372
- let res = x. inverse ( ) ;
374
+ let res = x. inverse ( ) . unwrap ( ) ;
373
375
let expected = Felt :: from ( 1 ) . try_into ( ) . unwrap ( ) ;
374
376
assert_eq ! ( x. mul( & res) , expected) ;
375
377
}
@@ -386,7 +388,7 @@ mod test {
386
388
|arr| !arr. iter( ) . all( |x| * x == 0 ) )
387
389
) {
388
390
let x = QM31Felt :: from_raw( x_coordinates) ;
389
- let res = x. inverse( ) ;
391
+ let res = x. inverse( ) . unwrap ( ) ;
390
392
// Expect 1_felt252
391
393
let expected = QM31Felt :: from_raw( [ 1 , 0 , 0 , 0 ] ) ;
392
394
assert_eq!( x. mul( & res) , expected) ;
@@ -400,7 +402,7 @@ mod test {
400
402
. no_shrink( )
401
403
) {
402
404
let x = QM31Felt :: from_raw( x_coordinates) ;
403
- let res = x. inverse( ) ;
405
+ let res = x. inverse( ) . unwrap ( ) ;
404
406
// Expect 1_felt252
405
407
let expected = QM31Felt :: from_raw( [ 1 , 0 , 0 , 0 ] ) ;
406
408
assert_eq!( x. mul( & res) , expected) ;
0 commit comments