11use crate :: { CtEq , CtSelect } ;
22use core:: ops:: { BitAnd , BitAndAssign , BitOr , BitOrAssign , BitXor , BitXorAssign , Not } ;
33
4+ /// Bitwise less-than-or equal: returns `1` if `x <= y`, and otherwise returns `0`.
5+ ///
6+ /// See "Hacker's Delight" 2nd edition, section 2-12 (Comparison predicates)
7+ macro_rules! bitle {
8+ ( $x: expr, $y: expr, $bits: expr) => {
9+ ( ( ( !$x) | $y) & ( ( $x ^ $y) | !( $y. wrapping_sub( $x) ) ) ) >> ( $bits - 1 )
10+ } ;
11+ }
12+
13+ /// Bitwise less-than: returns `1` if `x < y`, and otherwise returns `0`.
14+ ///
15+ /// See "Hacker's Delight" 2nd edition, section 2-12 (Comparison predicates)
16+ macro_rules! bitlt {
17+ ( $x: expr, $y: expr, $bits: expr) => {
18+ ( ( ( !$x) & $y) | ( ( ( !$x) | $y) & $x. wrapping_sub( $y) ) ) >> ( $bits - 1 )
19+ } ;
20+ }
21+
22+ /// Bitwise non-zero: returns `1` if `x != 0`, and otherwise returns `0`.
23+ macro_rules! bitnz {
24+ ( $value: expr, $bits: expr) => {
25+ ( $value | $value. wrapping_neg( ) ) >> ( $bits - 1 )
26+ } ;
27+ }
28+
429/// Constant-time analogue of `bool` providing a "best effort" optimization barrier.
530///
631/// Attempts to hint to the compiler and its codegen backends that optimizations should not be
@@ -149,9 +174,7 @@ impl Choice {
149174 /// Returns the truthy value if `x <= y` and the falsy value otherwise.
150175 #[ inline]
151176 pub const fn from_u32_le ( x : u32 , y : u32 ) -> Self {
152- // See "Hacker's Delight" 2nd ed, section 2-12 (Comparison predicates)
153- let bit = ( ( ( !x) | y) & ( ( x ^ y) | !y. wrapping_sub ( x) ) ) >> ( u32:: BITS - 1 ) ;
154- Self :: from_u32_lsb ( bit)
177+ Self :: from_u32_lsb ( bitle ! ( x, y, u32 :: BITS ) )
155178 }
156179
157180 /// Initialize from the least significant bit of a `u32`.
@@ -163,15 +186,13 @@ impl Choice {
163186 /// Returns the truthy value if `x < y`, and the falsy value otherwise.
164187 #[ inline]
165188 pub const fn from_u32_lt ( x : u32 , y : u32 ) -> Self {
166- // See "Hacker's Delight" 2nd ed, section 2-12 (Comparison predicates)
167- let bit = ( ( ( !x) & y) | ( ( ( !x) | y) & x. wrapping_sub ( y) ) ) >> ( u32:: BITS - 1 ) ;
168- Self :: from_u32_lsb ( bit)
189+ Self :: from_u32_lsb ( bitlt ! ( x, y, u32 :: BITS ) )
169190 }
170191
171192 /// Returns the truthy value if `value != 0`, and the falsy value otherwise.
172193 #[ inline]
173194 pub const fn from_u32_nonzero ( value : u32 ) -> Self {
174- Self :: from_u32_lsb ( ( value | value . wrapping_neg ( ) ) >> ( u32:: BITS - 1 ) )
195+ Self :: from_u32_lsb ( bitnz ! ( value, u32 :: BITS ) )
175196 }
176197
177198 /// Returns the truthy value if `x == y`, and the falsy value otherwise.
@@ -183,9 +204,7 @@ impl Choice {
183204 /// Returns the truthy value if `x <= y` and the falsy value otherwise.
184205 #[ inline]
185206 pub const fn from_u64_le ( x : u64 , y : u64 ) -> Self {
186- // See "Hacker's Delight" 2nd ed, section 2-12 (Comparison predicates)
187- let bit = ( ( ( !x) | y) & ( ( x ^ y) | !y. wrapping_sub ( x) ) ) >> ( u64:: BITS - 1 ) ;
188- Self :: from_u64_lsb ( bit)
207+ Self :: from_u64_lsb ( bitle ! ( x, y, u64 :: BITS ) )
189208 }
190209
191210 /// Initialize from the least significant bit of a `u64`.
@@ -197,23 +216,25 @@ impl Choice {
197216 /// Returns the truthy value if `x < y`, and the falsy value otherwise.
198217 #[ inline]
199218 pub const fn from_u64_lt ( x : u64 , y : u64 ) -> Self {
200- // See "Hacker's Delight" 2nd ed, section 2-12 (Comparison predicates)
201- let bit = ( ( ( !x) & y) | ( ( ( !x) | y) & x. wrapping_sub ( y) ) ) >> ( u64:: BITS - 1 ) ;
202- Self :: from_u64_lsb ( bit)
219+ Self :: from_u64_lsb ( bitlt ! ( x, y, u64 :: BITS ) )
203220 }
204221
205222 /// Returns the truthy value if `value != 0`, and the falsy value otherwise.
206223 #[ inline]
207224 pub const fn from_u64_nonzero ( value : u64 ) -> Self {
208- Self :: from_u64_lsb ( ( value | value. wrapping_neg ( ) ) >> ( u64:: BITS - 1 ) )
225+ Self :: from_u64_lsb ( bitnz ! ( value, u64 :: BITS ) )
226+ }
227+
228+ /// Returns the truthy value if `x == y`, and the falsy value otherwise.
229+ #[ inline]
230+ pub const fn from_u128_eq ( x : u128 , y : u128 ) -> Self {
231+ Self :: from_u128_nonzero ( x ^ y) . not ( )
209232 }
210233
211234 /// Returns the truthy value if `x <= y` and the falsy value otherwise.
212235 #[ inline]
213236 pub const fn from_u128_le ( x : u128 , y : u128 ) -> Self {
214- // See "Hacker's Delight" 2nd ed, section 2-12 (Comparison predicates)
215- let bit = ( ( ( !x) | y) & ( ( x ^ y) | !( y. wrapping_sub ( x) ) ) ) >> ( u128:: BITS - 1 ) ;
216- Self :: from_u128_lsb ( bit)
237+ Self :: from_u128_lsb ( bitle ! ( x, y, u128 :: BITS ) )
217238 }
218239
219240 /// Initialize from the least significant bit of a `u128`.
@@ -222,6 +243,18 @@ impl Choice {
222243 Self :: new ( ( value & 1 ) as u8 )
223244 }
224245
246+ /// Returns the truthy value if `x < y`, and the falsy value otherwise.
247+ #[ inline]
248+ pub const fn from_u128_lt ( x : u128 , y : u128 ) -> Self {
249+ Self :: from_u128_lsb ( bitlt ! ( x, y, u128 :: BITS ) )
250+ }
251+
252+ /// Returns the truthy value if `value != 0`, and the falsy value otherwise.
253+ #[ inline]
254+ pub const fn from_u128_nonzero ( value : u128 ) -> Self {
255+ Self :: from_u128_lsb ( bitnz ! ( value, u128 :: BITS ) )
256+ }
257+
225258 //
226259 // `const fn` predication methods
227260 //
@@ -550,6 +583,12 @@ mod tests {
550583 assert_eq ! ( Choice :: from_u64_nonzero( 2 ) , Choice :: TRUE ) ;
551584 }
552585
586+ #[ test]
587+ fn from_u128_eq ( ) {
588+ assert_eq ! ( Choice :: from_u128_eq( 0 , 1 ) , Choice :: FALSE ) ;
589+ assert_eq ! ( Choice :: from_u128_eq( 1 , 1 ) , Choice :: TRUE ) ;
590+ }
591+
553592 #[ test]
554593 fn from_u128_le ( ) {
555594 assert_eq ! ( Choice :: from_u128_le( 0 , 0 ) , Choice :: TRUE ) ;
@@ -564,6 +603,21 @@ mod tests {
564603 assert_eq ! ( Choice :: from_u128_lsb( 1 ) , Choice :: TRUE ) ;
565604 }
566605
606+ #[ test]
607+ fn from_u128_lt ( ) {
608+ assert_eq ! ( Choice :: from_u128_lt( 0 , 0 ) , Choice :: FALSE ) ;
609+ assert_eq ! ( Choice :: from_u128_lt( 1 , 0 ) , Choice :: FALSE ) ;
610+ assert_eq ! ( Choice :: from_u128_lt( 1 , 1 ) , Choice :: FALSE ) ;
611+ assert_eq ! ( Choice :: from_u128_lt( 1 , 2 ) , Choice :: TRUE ) ;
612+ }
613+
614+ #[ test]
615+ fn from_u128_nonzero ( ) {
616+ assert_eq ! ( Choice :: from_u128_nonzero( 0 ) , Choice :: FALSE ) ;
617+ assert_eq ! ( Choice :: from_u128_nonzero( 1 ) , Choice :: TRUE ) ;
618+ assert_eq ! ( Choice :: from_u128_nonzero( 2 ) , Choice :: TRUE ) ;
619+ }
620+
567621 #[ test]
568622 fn select_i64 ( ) {
569623 let a: i64 = 1 ;
0 commit comments