11use subtle:: { Choice , CtOption } ;
22
3- use crate :: { modular:: BernsteinYangInverter , Limb , NonZero , Odd , Uint , Word } ;
3+ use crate :: { modular:: BernsteinYangInverter , Limb , NonZero , Odd , Uint , WideWord , Word } ;
44
55/// A boolean value returned by constant-time `const fn`s.
66// TODO: should be replaced by `subtle::Choice` or `CtOption`
@@ -49,6 +49,14 @@ impl ConstChoice {
4949 Self ( value. wrapping_neg ( ) )
5050 }
5151
52+ /// Returns the truthy value if `value == 1`, and the falsy value if `value == 0`.
53+ /// Panics for other values.
54+ #[ inline]
55+ pub ( crate ) const fn from_wide_word_lsb ( value : WideWord ) -> Self {
56+ debug_assert ! ( value == 0 || value == 1 ) ;
57+ Self ( value. wrapping_neg ( ) as Word )
58+ }
59+
5260 #[ inline]
5361 pub ( crate ) const fn from_u32_lsb ( value : u32 ) -> Self {
5462 debug_assert ! ( value == 0 || value == 1 ) ;
@@ -129,6 +137,14 @@ impl ConstChoice {
129137 Self :: from_word_lsb ( bit)
130138 }
131139
140+ /// Returns the truthy value if `x <= y` and the falsy value otherwise.
141+ #[ inline]
142+ pub ( crate ) const fn from_wide_word_le ( x : WideWord , y : WideWord ) -> Self {
143+ // See "Hacker's Delight" 2nd ed, section 2-12 (Comparison predicates)
144+ let bit = ( ( ( !x) | y) & ( ( x ^ y) | !( y. wrapping_sub ( x) ) ) ) >> ( WideWord :: BITS - 1 ) ;
145+ Self :: from_wide_word_lsb ( bit)
146+ }
147+
132148 /// Returns the truthy value if `x <= y` and the falsy value otherwise.
133149 #[ inline]
134150 pub ( crate ) const fn from_u32_le ( x : u32 , y : u32 ) -> Self {
@@ -172,6 +188,13 @@ impl ConstChoice {
172188 a ^ ( self . 0 & ( a ^ b) )
173189 }
174190
191+ /// Return `b` if `self` is truthy, otherwise return `a`.
192+ #[ inline]
193+ pub ( crate ) const fn select_wide_word ( & self , a : WideWord , b : WideWord ) -> WideWord {
194+ let mask = ( ( self . 0 as WideWord ) << Word :: BITS ) | ( self . 0 as WideWord ) ;
195+ a ^ ( mask & ( a ^ b) )
196+ }
197+
175198 /// Return `b` if `self` is truthy, otherwise return `a`.
176199 #[ inline]
177200 pub ( crate ) const fn select_u32 ( & self , a : u32 , b : u32 ) -> u32 {
@@ -423,7 +446,7 @@ impl<const SAT_LIMBS: usize, const UNSAT_LIMBS: usize>
423446#[ cfg( test) ]
424447mod tests {
425448 use super :: ConstChoice ;
426- use crate :: Word ;
449+ use crate :: { WideWord , Word } ;
427450
428451 #[ test]
429452 fn from_u64_lsb ( ) {
@@ -445,6 +468,13 @@ mod tests {
445468 assert_eq ! ( ConstChoice :: from_word_gt( 6 , 5 ) , ConstChoice :: TRUE ) ;
446469 }
447470
471+ #[ test]
472+ fn from_wide_word_le ( ) {
473+ assert_eq ! ( ConstChoice :: from_wide_word_le( 4 , 5 ) , ConstChoice :: TRUE ) ;
474+ assert_eq ! ( ConstChoice :: from_wide_word_le( 5 , 5 ) , ConstChoice :: TRUE ) ;
475+ assert_eq ! ( ConstChoice :: from_wide_word_le( 6 , 5 ) , ConstChoice :: FALSE ) ;
476+ }
477+
448478 #[ test]
449479 fn select_u32 ( ) {
450480 let a: u32 = 1 ;
@@ -468,4 +498,12 @@ mod tests {
468498 assert_eq ! ( ConstChoice :: TRUE . select_word( a, b) , b) ;
469499 assert_eq ! ( ConstChoice :: FALSE . select_word( a, b) , a) ;
470500 }
501+
502+ #[ test]
503+ fn select_wide_word ( ) {
504+ let a: WideWord = ( 1 << Word :: BITS ) + 1 ;
505+ let b: WideWord = ( 3 << Word :: BITS ) + 4 ;
506+ assert_eq ! ( ConstChoice :: TRUE . select_wide_word( a, b) , b) ;
507+ assert_eq ! ( ConstChoice :: FALSE . select_wide_word( a, b) , a) ;
508+ }
471509}
0 commit comments