@@ -94,9 +94,62 @@ pub(crate) const fn u32_bits(n: u32) -> u32 {
9494 u32:: BITS - n. leading_zeros ( )
9595}
9696
97+ /// Return a `Choice` representing whether `a < b`.
98+ #[ allow( clippy:: cast_possible_truncation) ]
99+ #[ cfg( target_pointer_width = "32" ) ]
100+ #[ inline]
101+ pub ( crate ) const fn usize_lt ( a : usize , b : usize ) -> Choice {
102+ Choice :: from_u32_lt ( a as u32 , b as u32 )
103+ }
104+
105+ /// Return a `Choice` representing whether `a < b`.
106+ #[ allow( clippy:: cast_possible_truncation) ]
107+ #[ cfg( target_pointer_width = "64" ) ]
108+ #[ inline]
109+ pub ( crate ) const fn usize_lt ( a : usize , b : usize ) -> Choice {
110+ Choice :: from_u64_lt ( a as u64 , b as u64 )
111+ }
112+
113+ cpubits:: cpubits! {
114+ 32 => {
115+ /// Returns the multiplicative inverse of the argument modulo 2^32.
116+ ///
117+ /// For correct results, the input `value` must be odd.
118+ #[ must_use]
119+ pub ( crate ) const fn u32_invert_odd( value: u32 ) -> u32 {
120+ debug_assert!( value & 1 == 1 , "value must be odd" ) ;
121+ let x = value. wrapping_mul( 3 ) ^ 2 ;
122+ let y = 1u32 . wrapping_sub( x. wrapping_mul( value) ) ;
123+ let ( x, y) = ( x. wrapping_mul( y. wrapping_add( 1 ) ) , y. wrapping_mul( y) ) ;
124+ let ( x, y) = ( x. wrapping_mul( y. wrapping_add( 1 ) ) , y. wrapping_mul( y) ) ;
125+ x. wrapping_mul( y. wrapping_add( 1 ) )
126+ }
127+ }
128+ }
129+
130+ /// Returns the multiplicative inverse of the argument modulo 2^64. The implementation is based
131+ /// on Hurchalla's method for computing the multiplicative inverse modulo a power of two, and
132+ /// is essentially an optimized Newton iteration.
133+ ///
134+ /// For correct results, the input `value` must be odd.
135+ ///
136+ /// For better understanding the implementation, the following paper is recommended:
137+ /// J. Hurchalla, "An Improved Integer Multiplicative Inverse (modulo 2^w)",
138+ /// <https://arxiv.org/abs/2204.04342>
139+ #[ must_use]
140+ pub ( crate ) const fn u64_invert_odd ( value : u64 ) -> u64 {
141+ debug_assert ! ( value & 1 == 1 , "value must be odd" ) ;
142+ let x = value. wrapping_mul ( 3 ) ^ 2 ;
143+ let y = 1u64 . wrapping_sub ( x. wrapping_mul ( value) ) ;
144+ let ( x, y) = ( x. wrapping_mul ( y. wrapping_add ( 1 ) ) , y. wrapping_mul ( y) ) ;
145+ let ( x, y) = ( x. wrapping_mul ( y. wrapping_add ( 1 ) ) , y. wrapping_mul ( y) ) ;
146+ let ( x, y) = ( x. wrapping_mul ( y. wrapping_add ( 1 ) ) , y. wrapping_mul ( y) ) ;
147+ x. wrapping_mul ( y. wrapping_add ( 1 ) )
148+ }
149+
97150#[ cfg( test) ]
98151mod tests {
99- use super :: { u32_max, u32_min, u32_rem} ;
152+ use super :: { u32_max, u32_min, u32_rem, usize_lt } ;
100153 use crate :: Word ;
101154
102155 #[ test]
@@ -133,4 +186,25 @@ mod tests {
133186 assert_eq ! ( u32_rem( 7 , 5 ) , 2 ) ;
134187 assert_eq ! ( u32_rem( 101 , 5 ) , 1 ) ;
135188 }
189+
190+ #[ test]
191+ fn test_usize_const_lt ( ) {
192+ assert ! ( usize_lt( 0 , 5 ) . to_bool_vartime( ) ) ;
193+ assert ! ( !usize_lt( 7 , 0 ) . to_bool_vartime( ) ) ;
194+ assert ! ( !usize_lt( 7 , 5 ) . to_bool_vartime( ) ) ;
195+ assert ! ( !usize_lt( 7 , 7 ) . to_bool_vartime( ) ) ;
196+ }
197+
198+ cpubits:: cpubits! {
199+ 32 => {
200+ #[ test]
201+ fn test_u32_invert_odd( ) {
202+ use super :: u32_invert_odd;
203+
204+ assert_eq!( u32_invert_odd( 1 ) , 1 ) ;
205+ assert_eq!( u32_invert_odd( 5 ) . wrapping_mul( 5 ) , 1 ) ;
206+ assert_eq!( u32_invert_odd( u32 :: MAX ) . wrapping_mul( u32 :: MAX ) , 1 ) ;
207+ }
208+ }
209+ }
136210}
0 commit comments