88
99#![ allow( clippy:: needless_range_loop) ]  
1010
11+ use  crate :: Word ; 
12+ 
1113/// Type of the modular multiplicative inverter based on the Bernstein-Yang method. 
1214/// The inverter can be created for a specified modulus M and adjusting parameter A 
1315/// to compute the adjusted multiplicative inverses of positive integers, i.e. for 
@@ -48,19 +50,20 @@ type Matrix = [[i64; 2]; 2];
4850
4951impl < const  L :  usize >  BernsteinYangInverter < L >  { 
5052    /// Creates the inverter for specified modulus and adjusting parameter 
51- pub  const  fn  new ( modulus :  & [ u64 ] ,  adjuster :  & [ u64 ] )  -> Self  { 
53+ #[ allow( trivial_numeric_casts) ]  
54+     pub  const  fn  new ( modulus :  & [ Word ] ,  adjuster :  & [ Word ] )  -> Self  { 
5255        Self  { 
53-             modulus :  CInt :: < 62 ,  L > ( Self :: convert :: < 64 ,  62 ,  L > ( modulus) ) , 
54-             adjuster :  CInt :: < 62 ,  L > ( Self :: convert :: < 64 ,  62 ,  L > ( adjuster) ) , 
55-             inverse :  Self :: inv ( modulus[ 0 ] ) , 
56+             modulus :  CInt :: < 62 ,  L > ( convert_in :: < {   Word :: BITS   as   usize   } ,  62 ,  L > ( modulus) ) , 
57+             adjuster :  CInt :: < 62 ,  L > ( convert_in :: < {   Word :: BITS   as   usize   } ,  62 ,  L > ( adjuster) ) , 
58+             inverse :  inv_mod62 ( modulus) , 
5659        } 
5760    } 
5861
5962    /// Returns either the adjusted modular multiplicative inverse for the argument or None 
6063/// depending on invertibility of the argument, i.e. its coprimality with the modulus 
61- pub  const  fn  invert < const  S :  usize > ( & self ,  value :  & [ u64 ] )  -> Option < [ u64 ;  S ] >  { 
64+ pub  const  fn  invert < const  S :  usize > ( & self ,  value :  & [ Word ] )  -> Option < [ Word ;  S ] >  { 
6265        let  ( mut  d,  mut  e)  = ( CInt :: ZERO ,  self . adjuster ) ; 
63-         let  mut  g = CInt :: < 62 ,  L > ( Self :: convert :: < 64 ,  62 ,  L > ( value) ) ; 
66+         let  mut  g = CInt :: < 62 ,  L > ( convert_in :: < {   Word :: BITS   as   usize   } ,  62 ,  L > ( value) ) ; 
6467        let  ( mut  delta,  mut  f)  = ( 1 ,  self . modulus ) ; 
6568        let  mut  matrix; 
6669
@@ -76,7 +79,9 @@ impl<const L: usize> BernsteinYangInverter<L> {
7679        if  !f. eq ( & CInt :: ONE )  && !antiunit { 
7780            return  None ; 
7881        } 
79-         Some ( Self :: convert :: < 62 ,  64 ,  S > ( & self . norm ( d,  antiunit) . 0 ) ) 
82+         Some ( convert_out :: < 62 ,  {  Word :: BITS  as  usize  } ,  S > ( 
83+             & self . norm ( d,  antiunit) . 0 , 
84+         ) ) 
8085    } 
8186
8287    /// Returns the Bernstein-Yang transition matrix multiplied by 2^62 and the new value 
@@ -181,11 +186,40 @@ impl<const L: usize> BernsteinYangInverter<L> {
181186
182187        value
183188    } 
189+ } 
190+ 
191+ /// Returns the multiplicative inverse of the argument modulo 2^62. The implementation is based 
192+ /// on the Hurchalla's method for computing the multiplicative inverse modulo a power of two. 
193+ /// For better understanding the implementation, the following paper is recommended: 
194+ /// J. Hurchalla, "An Improved Integer Multiplicative Inverse (modulo 2^w)", 
195+ /// https://arxiv.org/pdf/2204.04342.pdf 
196+ const  fn  inv_mod62 ( value :  & [ Word ] )  -> i64  { 
197+     let  value = { 
198+         #[ cfg( target_pointer_width = "32" ) ]  
199+         { 
200+             debug_assert ! ( value. len( )  >= 2 ) ; 
201+             value[ 0 ]  as  u64  | ( value[ 1 ]  as  u64 )  << 32 
202+         } 
184203
185-     /// Returns a big unsigned integer as an array of O-bit chunks, which is equal modulo 
186- /// 2 ^ (O * S) to the input big unsigned integer stored as an array of I-bit chunks. 
187- /// The ordering of the chunks in these arrays is little-endian 
188- const  fn  convert < const  I :  usize ,  const  O :  usize ,  const  S :  usize > ( input :  & [ u64 ] )  -> [ u64 ;  S ]  { 
204+         #[ cfg( target_pointer_width = "64" ) ]  
205+         { 
206+             value[ 0 ] 
207+         } 
208+     } ; 
209+ 
210+     let  x = value. wrapping_mul ( 3 )  ^ 2 ; 
211+     let  y = 1u64 . wrapping_sub ( x. wrapping_mul ( value) ) ; 
212+     let  ( x,  y)  = ( x. wrapping_mul ( y. wrapping_add ( 1 ) ) ,  y. wrapping_mul ( y) ) ; 
213+     let  ( x,  y)  = ( x. wrapping_mul ( y. wrapping_add ( 1 ) ) ,  y. wrapping_mul ( y) ) ; 
214+     let  ( x,  y)  = ( x. wrapping_mul ( y. wrapping_add ( 1 ) ) ,  y. wrapping_mul ( y) ) ; 
215+     ( x. wrapping_mul ( y. wrapping_add ( 1 ) )  &  ( u64:: MAX  >> 2 ) )  as  i64 
216+ } 
217+ 
218+ /// Write an impl of a `convert_*` function. 
219+ /// 
220+ /// Workaround for making this function generic while still allowing it to be `const fn`. 
221+ macro_rules!  impl_convert { 
222+     ( $input_type: ty,  $output_type: ty,  $input: expr)  => { { 
189223        // This function is defined because the method "min" of the usize type is not constant 
190224        const  fn  min( a:  usize ,  b:  usize )  -> usize  { 
191225            if  a > b { 
@@ -195,15 +229,17 @@ impl<const L: usize> BernsteinYangInverter<L> {
195229            } 
196230        } 
197231
198-         let  ( total,  mut  output,  mut  bits)  = ( min ( input. len ( )  *  I ,  S  *  O ) ,  [ 0 ;  S ] ,  0 ) ; 
232+         let  total = min( $input. len( )  *  I ,  S  *  O ) ; 
233+         let  mut  output = [ 0  as  $output_type;  S ] ; 
234+         let  mut  bits = 0 ; 
199235
200236        while  bits < total { 
201237            let  ( i,  o)  = ( bits % I ,  bits % O ) ; 
202-             output[ bits / O ]  |= ( input[ bits / I ]  >> i)  << o; 
238+             output[ bits / O ]  |= ( $ input[ bits / I ]  >> i)   as  $output_type  << o; 
203239            bits += min( I  - i,  O  - o) ; 
204240        } 
205241
206-         let  mask = u64 :: MAX  >> ( 64  - O ) ; 
242+         let  mask = ( <$output_type> :: MAX  as  $output_type )   >> ( <$output_type> :: BITS   as   usize  - O ) ; 
207243        let  mut  filled = total / O  + if  total % O  > 0  {  1  }  else {  0  } ; 
208244
209245        while  filled > 0  { 
@@ -212,21 +248,23 @@ impl<const L: usize> BernsteinYangInverter<L> {
212248        } 
213249
214250        output
215-     } 
251+     } } ; 
252+ } 
216253
217-     /// Returns the multiplicative inverse of the argument modulo 2^62. The implementation is based 
218- /// on the Hurchalla's method for computing the multiplicative inverse modulo a power of two. 
219- /// For better understanding the implementation, the following paper is recommended: 
220- /// J. Hurchalla, "An Improved Integer Multiplicative Inverse (modulo 2^w)", 
221- /// https://arxiv.org/pdf/2204.04342.pdf 
222- const  fn  inv ( value :  u64 )  -> i64  { 
223-         let  x = value. wrapping_mul ( 3 )  ^ 2 ; 
224-         let  y = 1u64 . wrapping_sub ( x. wrapping_mul ( value) ) ; 
225-         let  ( x,  y)  = ( x. wrapping_mul ( y. wrapping_add ( 1 ) ) ,  y. wrapping_mul ( y) ) ; 
226-         let  ( x,  y)  = ( x. wrapping_mul ( y. wrapping_add ( 1 ) ) ,  y. wrapping_mul ( y) ) ; 
227-         let  ( x,  y)  = ( x. wrapping_mul ( y. wrapping_add ( 1 ) ) ,  y. wrapping_mul ( y) ) ; 
228-         ( x. wrapping_mul ( y. wrapping_add ( 1 ) )  &  CInt :: < 62 ,  L > :: MASK )  as  i64 
229-     } 
254+ /// Returns a big unsigned integer as an array of O-bit chunks, which is equal modulo 
255+ /// 2 ^ (O * S) to the input big unsigned integer stored as an array of I-bit chunks. 
256+ /// The ordering of the chunks in these arrays is little-endian 
257+ #[ allow( trivial_numeric_casts) ]  
258+ const  fn  convert_in < const  I :  usize ,  const  O :  usize ,  const  S :  usize > ( input :  & [ Word ] )  -> [ u64 ;  S ]  { 
259+     impl_convert ! ( Word ,  u64 ,  input) 
260+ } 
261+ 
262+ /// Returns a big unsigned integer as an array of O-bit chunks, which is equal modulo 
263+ /// 2 ^ (O * S) to the input big unsigned integer stored as an array of I-bit chunks. 
264+ /// The ordering of the chunks in these arrays is little-endian 
265+ #[ allow( trivial_numeric_casts) ]  
266+ const  fn  convert_out < const  I :  usize ,  const  O :  usize ,  const  S :  usize > ( input :  & [ u64 ] )  -> [ Word ;  S ]  { 
267+     impl_convert ! ( u64 ,  Word ,  input) 
230268} 
231269
232270/// Big signed (B * L)-bit integer type, whose variables store 
0 commit comments