1313#[ macro_use]
1414mod macros;
1515
16+ #[ cfg( feature = "alloc" ) ]
17+ pub ( crate ) mod boxed;
18+
1619use crate :: { ConstChoice , ConstCtOption , Inverter , Limb , Odd , Uint , Word } ;
1720use subtle:: CtOption ;
1821
@@ -80,7 +83,7 @@ impl<const SAT_LIMBS: usize, const UNSAT_LIMBS: usize>
8083 let mut matrix;
8184
8285 while !g. eq ( & Int62L :: ZERO ) {
83- ( delta, matrix) = Self :: jump ( & f, & g, delta) ;
86+ ( delta, matrix) = jump ( & f. 0 , & g. 0 , delta) ;
8487 ( f, g) = fg ( f, g, matrix) ;
8588 ( d, e) = de ( & self . modulus , self . inverse , d, e, matrix) ;
8689 }
@@ -99,7 +102,7 @@ impl<const SAT_LIMBS: usize, const UNSAT_LIMBS: usize>
99102 /// `UNSAT_LIMBS` which are computed when defining `PrecomputeInverter::Inverter` for various
100103 /// `Uint` limb sizes.
101104 pub ( crate ) const fn gcd ( f : & Uint < SAT_LIMBS > , g : & Uint < SAT_LIMBS > ) -> Uint < SAT_LIMBS > {
102- let f_0 = Int62L :: from_uint ( f) ;
105+ let f_0 = Int62L :: < UNSAT_LIMBS > :: from_uint ( f) ;
103106 let inverse = inv_mod2_62 ( f. as_words ( ) ) ;
104107
105108 let mut d = Int62L :: ZERO ;
@@ -110,7 +113,7 @@ impl<const SAT_LIMBS: usize, const UNSAT_LIMBS: usize>
110113 let mut matrix;
111114
112115 while !g. eq ( & Int62L :: ZERO ) {
113- ( delta, matrix) = Self :: jump ( & f, & g, delta) ;
116+ ( delta, matrix) = jump ( & f. 0 , & g. 0 , delta) ;
114117 ( f, g) = fg ( f, g, matrix) ;
115118 ( d, e) = de ( & f_0, inverse, d, e, matrix) ;
116119 }
@@ -122,52 +125,6 @@ impl<const SAT_LIMBS: usize, const UNSAT_LIMBS: usize>
122125 f. to_uint ( )
123126 }
124127
125- /// Returns the Bernstein-Yang transition matrix multiplied by 2^62 and the new value of the
126- /// delta variable for the 62 basic steps of the Bernstein-Yang method, which are to be
127- /// performed sequentially for specified initial values of f, g and delta
128- const fn jump (
129- f : & Int62L < UNSAT_LIMBS > ,
130- g : & Int62L < UNSAT_LIMBS > ,
131- mut delta : i64 ,
132- ) -> ( i64 , Matrix ) {
133- // This function is defined because the method "min" of the i64 type is not constant
134- const fn min ( a : i64 , b : i64 ) -> i64 {
135- if a > b {
136- b
137- } else {
138- a
139- }
140- }
141-
142- let ( mut steps, mut f, mut g) = ( 62 , f. lowest ( ) as i64 , g. lowest ( ) as i128 ) ;
143- let mut t: Matrix = [ [ 1 , 0 ] , [ 0 , 1 ] ] ;
144-
145- loop {
146- let zeros = min ( steps, g. trailing_zeros ( ) as i64 ) ;
147- ( steps, delta, g) = ( steps - zeros, delta + zeros, g >> zeros) ;
148- t[ 0 ] = [ t[ 0 ] [ 0 ] << zeros, t[ 0 ] [ 1 ] << zeros] ;
149-
150- if steps == 0 {
151- break ;
152- }
153- if delta > 0 {
154- ( delta, f, g) = ( -delta, g as i64 , -f as i128 ) ;
155- ( t[ 0 ] , t[ 1 ] ) = ( t[ 1 ] , [ -t[ 0 ] [ 0 ] , -t[ 0 ] [ 1 ] ] ) ;
156- }
157-
158- // The formula (3 * x) xor 28 = -1 / x (mod 32) for an odd integer x in the two's
159- // complement code has been derived from the formula (3 * x) xor 2 = 1 / x (mod 32)
160- // attributed to Peter Montgomery.
161- let mask = ( 1 << min ( min ( steps, 1 - delta) , 5 ) ) - 1 ;
162- let w = ( g as i64 ) . wrapping_mul ( f. wrapping_mul ( 3 ) ^ 28 ) & mask;
163-
164- t[ 1 ] = [ t[ 0 ] [ 0 ] * w + t[ 1 ] [ 0 ] , t[ 0 ] [ 1 ] * w + t[ 1 ] [ 1 ] ] ;
165- g += w as i128 * f as i128 ;
166- }
167-
168- ( delta, t)
169- }
170-
171128 /// Returns either "value (mod M)" or "-value (mod M)", where M is the modulus the inverter
172129 /// was created for, depending on "negate", which determines the presence of "-" in the used
173130 /// formula. The input integer lies in the interval (-2 * M, M).
@@ -207,8 +164,14 @@ const fn inv_mod2_62(value: &[Word]) -> i64 {
207164 let value = {
208165 #[ cfg( target_pointer_width = "32" ) ]
209166 {
210- debug_assert ! ( value. len( ) >= 2 ) ;
211- value[ 0 ] as u64 | ( value[ 1 ] as u64 ) << 32
167+ debug_assert ! ( value. len( ) >= 1 ) ;
168+ let mut ret = value[ 0 ] as u64 ;
169+
170+ if value. len ( ) >= 2 {
171+ ret |= ( value[ 1 ] as u64 ) << 32 ;
172+ }
173+
174+ ret
212175 }
213176
214177 #[ cfg( target_pointer_width = "64" ) ]
@@ -225,6 +188,48 @@ const fn inv_mod2_62(value: &[Word]) -> i64 {
225188 ( x. wrapping_mul ( y. wrapping_add ( 1 ) ) & ( u64:: MAX >> 2 ) ) as i64
226189}
227190
191+ /// Returns the Bernstein-Yang transition matrix multiplied by 2^62 and the new value of the
192+ /// delta variable for the 62 basic steps of the Bernstein-Yang method, which are to be
193+ /// performed sequentially for specified initial values of f, g and delta
194+ const fn jump ( f : & [ u64 ] , g : & [ u64 ] , mut delta : i64 ) -> ( i64 , Matrix ) {
195+ // This function is defined because the method "min" of the i64 type is not constant
196+ const fn min ( a : i64 , b : i64 ) -> i64 {
197+ if a > b {
198+ b
199+ } else {
200+ a
201+ }
202+ }
203+
204+ let ( mut steps, mut f, mut g) = ( 62 , f[ 0 ] as i64 , g[ 0 ] as i128 ) ;
205+ let mut t: Matrix = [ [ 1 , 0 ] , [ 0 , 1 ] ] ;
206+
207+ loop {
208+ let zeros = min ( steps, g. trailing_zeros ( ) as i64 ) ;
209+ ( steps, delta, g) = ( steps - zeros, delta + zeros, g >> zeros) ;
210+ t[ 0 ] = [ t[ 0 ] [ 0 ] << zeros, t[ 0 ] [ 1 ] << zeros] ;
211+
212+ if steps == 0 {
213+ break ;
214+ }
215+ if delta > 0 {
216+ ( delta, f, g) = ( -delta, g as i64 , -f as i128 ) ;
217+ ( t[ 0 ] , t[ 1 ] ) = ( t[ 1 ] , [ -t[ 0 ] [ 0 ] , -t[ 0 ] [ 1 ] ] ) ;
218+ }
219+
220+ // The formula (3 * x) xor 28 = -1 / x (mod 32) for an odd integer x in the two's
221+ // complement code has been derived from the formula (3 * x) xor 2 = 1 / x (mod 32)
222+ // attributed to Peter Montgomery.
223+ let mask = ( 1 << min ( min ( steps, 1 - delta) , 5 ) ) - 1 ;
224+ let w = ( g as i64 ) . wrapping_mul ( f. wrapping_mul ( 3 ) ^ 28 ) & mask;
225+
226+ t[ 1 ] = [ t[ 0 ] [ 0 ] * w + t[ 1 ] [ 0 ] , t[ 0 ] [ 1 ] * w + t[ 1 ] [ 1 ] ] ;
227+ g += w as i128 * f as i128 ;
228+ }
229+
230+ ( delta, t)
231+ }
232+
228233/// Returns the updated values of the variables f and g for specified initial ones and
229234/// Bernstein-Yang transition matrix multiplied by 2^62. The returned vector is
230235/// "matrix * (f, g)' / 2^62", where "'" is the transpose operator.
@@ -329,14 +334,12 @@ impl<const LIMBS: usize> Int62L<LIMBS> {
329334 /// The ordering of the chunks in these arrays is little-endian
330335 #[ allow( trivial_numeric_casts, clippy:: wrong_self_convention) ]
331336 pub const fn to_uint < const SAT_LIMBS : usize > ( & self ) -> Uint < SAT_LIMBS > {
337+ debug_assert ! ( !self . is_negative( ) , "can't convert negative number to Uint" ) ;
338+
332339 if LIMBS != bernstein_yang_nlimbs ! ( SAT_LIMBS * Limb :: BITS as usize ) {
333340 panic ! ( "incorrect number of limbs" ) ;
334341 }
335342
336- if self . is_negative ( ) {
337- panic ! ( "can't convert negative number to Uint" ) ;
338- }
339-
340343 let mut ret = [ 0 as Word ; SAT_LIMBS ] ;
341344 impl_limb_convert ! ( u64 , 62 , & self . 0 , Word , Word :: BITS as usize , ret) ;
342345 Uint :: from_words ( ret)
@@ -366,8 +369,9 @@ impl<const LIMBS: usize> Int62L<LIMBS> {
366369 //
367370 // Since for the two's complement code the additive negation is the result of adding 1 to
368371 // the bitwise inverted argument's representation, for any encoded integers x and y we have
369- // x * y = (-x) * (-y) = (!x + 1) * (-y) = !x * (-y) + (-y), where "!" is the bitwise
372+ // x * y = (-x) * (-y) = (!x + 1) * (-y) = !x * (-y) + (-y), where "!" is the bitwise
370373 // inversion and arithmetic operations are performed according to the rules of the code.
374+ //
371375 // If the short multiplicand is negative, the algorithm below uses this formula by
372376 // substituting the short multiplicand for y and turns into the modified standard
373377 // multiplication algorithm, where the carry flag is initialized with the additively
@@ -454,8 +458,26 @@ impl<const LIMBS: usize> PartialEq for Int62L<LIMBS> {
454458
455459#[ cfg( test) ]
456460mod tests {
461+ use crate :: { Inverter , PrecomputeInverter , U256 } ;
462+
457463 type Int62L = super :: Int62L < 4 > ;
458464
465+ #[ test]
466+ fn invert ( ) {
467+ let g =
468+ U256 :: from_be_hex ( "00000000CBF9350842F498CE441FC2DC23C7BF47D3DE91C327B2157C5E4EED77" ) ;
469+ let modulus =
470+ U256 :: from_be_hex ( "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551" )
471+ . to_odd ( )
472+ . unwrap ( ) ;
473+ let inverter = modulus. precompute_inverter ( ) ;
474+ let result = inverter. invert ( & g) . unwrap ( ) ;
475+ assert_eq ! (
476+ U256 :: from_be_hex( "FB668F8F509790BC549B077098918604283D42901C92981062EB48BC723F617B" ) ,
477+ result
478+ ) ;
479+ }
480+
459481 #[ test]
460482 fn int62l_add ( ) {
461483 assert_eq ! ( Int62L :: ZERO , Int62L :: ZERO . add( & Int62L :: ZERO ) ) ;
@@ -486,4 +508,28 @@ mod tests {
486508 assert ! ( !Int62L :: ONE . is_negative( ) ) ;
487509 assert ! ( Int62L :: MINUS_ONE . is_negative( ) ) ;
488510 }
511+
512+ #[ test]
513+ fn int62l_shr ( ) {
514+ let n = super :: Int62L ( [
515+ 0 ,
516+ 1211048314408256470 ,
517+ 1344008336933394898 ,
518+ 3913497193346473913 ,
519+ 2764114971089162538 ,
520+ 4 ,
521+ ] ) ;
522+
523+ assert_eq ! (
524+ & n. shr( ) . 0 ,
525+ & [
526+ 1211048314408256470 ,
527+ 1344008336933394898 ,
528+ 3913497193346473913 ,
529+ 2764114971089162538 ,
530+ 4 ,
531+ 0
532+ ]
533+ ) ;
534+ }
489535}
0 commit comments