@@ -202,6 +202,20 @@ impl Choice {
202202 Self :: from_u64_lsb ( ( value | value. wrapping_neg ( ) ) >> ( u64:: BITS - 1 ) )
203203 }
204204
205+ /// Returns the truthy value if `x <= y` and the falsy value otherwise.
206+ #[ inline]
207+ pub const fn from_u128_le ( x : u128 , y : u128 ) -> Self {
208+ // See "Hacker's Delight" 2nd ed, section 2-12 (Comparison predicates)
209+ let bit = ( ( ( !x) | y) & ( ( x ^ y) | !( y. wrapping_sub ( x) ) ) ) >> ( u128:: BITS - 1 ) ;
210+ Self :: from_u128_lsb ( bit)
211+ }
212+
213+ /// Initialize from the least significant bit of a `u128`.
214+ #[ inline]
215+ pub const fn from_u128_lsb ( value : u128 ) -> Self {
216+ Self :: new ( ( value & 1 ) as u8 )
217+ }
218+
205219 //
206220 // `const fn` predication methods
207221 //
@@ -233,6 +247,15 @@ impl Choice {
233247 a ^ ( self . to_u64_mask ( ) & ( a ^ b) )
234248 }
235249
250+ /// `const fn` helper: return `b` if `self` is truthy, otherwise return `a`.
251+ ///
252+ /// Only use this instead of the [`CtSelect`] trait in the event you're in a `const fn` context
253+ /// and can't use the trait. The former will provide better constant-time assurances.
254+ #[ inline]
255+ pub const fn select_u128 ( self , a : u128 , b : u128 ) -> u128 {
256+ a ^ ( self . to_u128_mask ( ) & ( a ^ b) )
257+ }
258+
236259 /// Create a `u32` bitmask.
237260 ///
238261 /// # Returns
@@ -252,6 +275,16 @@ impl Choice {
252275 pub const fn to_u64_mask ( self ) -> u64 {
253276 ( self . 0 as u64 & 1 ) . wrapping_neg ( )
254277 }
278+
279+ /// Create a `u128` bitmask.
280+ ///
281+ /// # Returns
282+ /// - `0` for `Choice::FALSE`
283+ /// - `u128::MAX` for `Choice::TRUE`
284+ #[ inline]
285+ pub const fn to_u128_mask ( self ) -> u128 {
286+ ( self . 0 as u128 & 1 ) . wrapping_neg ( )
287+ }
255288}
256289
257290impl BitAnd for Choice {
@@ -501,6 +534,20 @@ mod tests {
501534 assert_eq ! ( Choice :: from_u64_nonzero( 2 ) , Choice :: TRUE ) ;
502535 }
503536
537+ #[ test]
538+ fn from_u128_le ( ) {
539+ assert_eq ! ( Choice :: from_u128_le( 0 , 0 ) , Choice :: TRUE ) ;
540+ assert_eq ! ( Choice :: from_u128_le( 1 , 0 ) , Choice :: FALSE ) ;
541+ assert_eq ! ( Choice :: from_u128_le( 1 , 1 ) , Choice :: TRUE ) ;
542+ assert_eq ! ( Choice :: from_u128_le( 1 , 2 ) , Choice :: TRUE ) ;
543+ }
544+
545+ #[ test]
546+ fn from_u128_lsb ( ) {
547+ assert_eq ! ( Choice :: from_u128_lsb( 0 ) , Choice :: FALSE ) ;
548+ assert_eq ! ( Choice :: from_u128_lsb( 1 ) , Choice :: TRUE ) ;
549+ }
550+
504551 #[ test]
505552 fn select_i64 ( ) {
506553 let a: i64 = 1 ;
@@ -524,4 +571,12 @@ mod tests {
524571 assert_eq ! ( Choice :: TRUE . select_u64( a, b) , b) ;
525572 assert_eq ! ( Choice :: FALSE . select_u64( a, b) , a) ;
526573 }
574+
575+ #[ test]
576+ fn select_u128 ( ) {
577+ let a: u128 = 1 ;
578+ let b: u128 = 2 ;
579+ assert_eq ! ( Choice :: TRUE . select_u128( a, b) , b) ;
580+ assert_eq ! ( Choice :: FALSE . select_u128( a, b) , a) ;
581+ }
527582}
0 commit comments