Skip to main content

ctutils/
choice.rs

1use crate::primitives::{bitle, bitnz};
2use crate::{CtAssign, CtAssignSlice, CtEq, CtEqSlice, CtSelectUsingCtAssign};
3use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not};
4
5#[cfg(feature = "subtle")]
6use crate::CtSelect;
7
8/// Constant-time analogue of `bool` providing a "best effort" optimization barrier.
9///
10/// This type attempts to hint to the compiler and its codegen backends that optimizations should
11/// not be applied which depend on specific values of this type.
12///
13/// This is used as a "belt-and-suspenders" defense in addition to mechanisms like
14/// constant-time predication intrinsics provided by the [`cmov`] crate, and is never expected to be
15/// the only line of defense.
16// NOTE: we deliberately do NOT impl `Eq`, `Hash`, `PartialEq`, etc. See #1315
17#[derive(Copy, Clone, Debug)]
18pub struct Choice(pub(crate) u8);
19
20impl Choice {
21    /// Equivalent of [`false`].
22    pub const FALSE: Self = Self(0);
23
24    /// Equivalent of [`true`].
25    pub const TRUE: Self = Self(1);
26
27    //
28    // `const fn` bitwise ops
29    //
30
31    /// Apply an `and` conditional to the given [`Choice`]s.
32    #[inline]
33    #[must_use]
34    pub const fn and(self, rhs: Choice) -> Choice {
35        #[cfg(all(target_arch = "arm", not(target_has_atomic = "ptr")))]
36        {
37            // Keep loop-carried predicates from becoming a short-circuiting boolean.
38            Self(self.to_u8() & rhs.to_u8())
39        }
40        #[cfg(not(all(target_arch = "arm", not(target_has_atomic = "ptr"))))]
41        {
42            Self(self.0 & rhs.0)
43        }
44    }
45
46    /// Apply an `or` conditional to the given [`Choice`]s.
47    #[inline]
48    #[must_use]
49    pub const fn or(self, rhs: Choice) -> Choice {
50        Self(self.0 | rhs.0)
51    }
52
53    /// Apply an `xor` conditional to the given [`Choice`]s.
54    #[inline]
55    #[must_use]
56    pub const fn xor(self, rhs: Choice) -> Choice {
57        Self(self.0 ^ rhs.0)
58    }
59
60    /// Compute the boolean inverse of `self`.
61    #[inline]
62    #[must_use]
63    pub const fn not(self) -> Choice {
64        // NOTE: assumes self.0 is `0` or `1` as checked in constructor
65        Self(self.0 ^ 1)
66    }
67
68    //
69    // `const fn` comparison ops
70    //
71
72    /// `const fn` equality operation.
73    #[inline]
74    #[must_use]
75    pub const fn eq(self, other: Self) -> Self {
76        Self::ne(self, other).not()
77    }
78
79    /// `const fn` not equal operation.
80    #[inline]
81    #[must_use]
82    pub const fn ne(self, other: Self) -> Self {
83        Self::xor(self, other)
84    }
85
86    //
87    // `const fn` constructor methods
88    //
89
90    // i64
91
92    /// Returns [`Choice::TRUE`] if `x == y`, and [`Choice::FALSE`] otherwise.
93    #[inline]
94    #[must_use]
95    pub const fn from_i64_eq(x: i64, y: i64) -> Self {
96        Self::from_u64_nz(x.cast_unsigned() ^ y.cast_unsigned()).not()
97    }
98
99    // u8
100
101    /// Returns [`Choice::TRUE`] if `x == y`, and [`Choice::FALSE`] otherwise.
102    #[inline]
103    #[must_use]
104    pub const fn from_u8_eq(x: u8, y: u8) -> Self {
105        Self::from_u8_nz(x ^ y).not()
106    }
107
108    /// Returns [`Choice::TRUE`] if `x <= y` and [`Choice::FALSE`] otherwise.
109    #[inline]
110    #[must_use]
111    pub const fn from_u8_le(x: u8, y: u8) -> Self {
112        Self::from_u8_lsb(bitle!(x, y, u8::BITS))
113    }
114
115    /// Initialize from the least significant bit of a `u8`.
116    #[inline]
117    #[must_use]
118    pub const fn from_u8_lsb(value: u8) -> Self {
119        Self(value & 0x1)
120    }
121
122    /// Returns [`Choice::TRUE`] if `x < y`, and [`Choice::FALSE`] otherwise.
123    #[inline]
124    #[must_use]
125    pub const fn from_u8_lt(x: u8, y: u8) -> Self {
126        // On Thumb-1, constant specialization can turn a narrow comparison into a branch.
127        #[cfg(all(target_arch = "arm", not(target_has_atomic = "ptr")))]
128        {
129            Self::from_u32_lt(x as u32, y as u32)
130        }
131        #[cfg(not(all(target_arch = "arm", not(target_has_atomic = "ptr"))))]
132        {
133            Self::from_u8_lsb(crate::primitives::bitlt!(x, y, u8::BITS))
134        }
135    }
136
137    /// Returns [`Choice::TRUE`] if `value != 0`, and [`Choice::FALSE`] otherwise.
138    #[inline]
139    #[must_use]
140    pub const fn from_u8_nz(value: u8) -> Self {
141        Self::from_u8_lsb(bitnz!(value, u8::BITS))
142    }
143
144    // u16
145
146    /// Returns [`Choice::TRUE`] if `x == y`, and [`Choice::FALSE`] otherwise.
147    #[inline]
148    #[must_use]
149    pub const fn from_u16_eq(x: u16, y: u16) -> Self {
150        Self::from_u16_nz(x ^ y).not()
151    }
152
153    /// Returns [`Choice::TRUE`] if `x <= y` and [`Choice::FALSE`] otherwise.
154    #[inline]
155    #[must_use]
156    pub const fn from_u16_le(x: u16, y: u16) -> Self {
157        Self::from_u16_lsb(bitle!(x, y, u16::BITS))
158    }
159
160    /// Initialize from the least significant bit of a `u16`.
161    #[inline]
162    #[must_use]
163    pub const fn from_u16_lsb(value: u16) -> Self {
164        Self((value & 0x1) as u8)
165    }
166
167    /// Returns [`Choice::TRUE`] if `x < y`, and [`Choice::FALSE`] otherwise.
168    #[inline]
169    #[must_use]
170    pub const fn from_u16_lt(x: u16, y: u16) -> Self {
171        // Use the same hardening as the word-sized comparison on Thumb-1.
172        #[cfg(all(target_arch = "arm", not(target_has_atomic = "ptr")))]
173        {
174            Self::from_u32_lt(x as u32, y as u32)
175        }
176        #[cfg(not(all(target_arch = "arm", not(target_has_atomic = "ptr"))))]
177        {
178            Self::from_u16_lsb(crate::primitives::bitlt!(x, y, u16::BITS))
179        }
180    }
181
182    /// Returns [`Choice::TRUE`] if `value != 0`, and [`Choice::FALSE`] otherwise.
183    #[inline]
184    #[must_use]
185    pub const fn from_u16_nz(value: u16) -> Self {
186        Self::from_u16_lsb(bitnz!(value, u16::BITS))
187    }
188
189    // u32
190
191    /// Returns [`Choice::TRUE`] if `x == y`, and [`Choice::FALSE`] otherwise.
192    #[inline]
193    #[must_use]
194    pub const fn from_u32_eq(x: u32, y: u32) -> Self {
195        Self::from_u32_nz(x ^ y).not()
196    }
197
198    /// Returns [`Choice::TRUE`] if `x <= y` and [`Choice::FALSE`] otherwise.
199    #[inline]
200    #[must_use]
201    pub const fn from_u32_le(x: u32, y: u32) -> Self {
202        crate::primitives::le_u32(x, y)
203    }
204
205    /// Initialize from the least significant bit of a `u32`.
206    #[inline]
207    #[must_use]
208    pub const fn from_u32_lsb(value: u32) -> Self {
209        Self((value & 0x1) as u8)
210    }
211
212    /// Returns [`Choice::TRUE`] if `x < y`, and [`Choice::FALSE`] otherwise.
213    #[inline]
214    #[must_use]
215    pub const fn from_u32_lt(x: u32, y: u32) -> Self {
216        crate::primitives::lt_u32(x, y)
217    }
218
219    /// Returns [`Choice::TRUE`] if `value != 0`, and [`Choice::FALSE`] otherwise.
220    #[inline]
221    #[must_use]
222    pub const fn from_u32_nz(value: u32) -> Self {
223        crate::primitives::nz_u32(value)
224    }
225
226    // u64
227
228    /// Returns [`Choice::TRUE`] if `x == y`, and [`Choice::FALSE`] otherwise.
229    #[inline]
230    #[must_use]
231    pub const fn from_u64_eq(x: u64, y: u64) -> Self {
232        Self::from_u64_nz(x ^ y).not()
233    }
234
235    /// Returns [`Choice::TRUE`] if `x <= y` and [`Choice::FALSE`] otherwise.
236    #[inline]
237    #[must_use]
238    pub const fn from_u64_le(x: u64, y: u64) -> Self {
239        crate::primitives::le_u64(x, y)
240    }
241
242    /// Initialize from the least significant bit of a `u64`.
243    #[inline]
244    #[must_use]
245    pub const fn from_u64_lsb(value: u64) -> Self {
246        Self((value & 0x1) as u8)
247    }
248
249    /// Returns [`Choice::TRUE`] if `x < y`, and [`Choice::FALSE`] otherwise.
250    #[inline]
251    #[must_use]
252    pub const fn from_u64_lt(x: u64, y: u64) -> Self {
253        crate::primitives::lt_u64(x, y)
254    }
255
256    /// Returns [`Choice::TRUE`] if `value != 0`, and [`Choice::FALSE`] otherwise.
257    #[inline]
258    #[must_use]
259    pub const fn from_u64_nz(value: u64) -> Self {
260        crate::primitives::nz_u64(value)
261    }
262
263    // u128
264
265    /// Returns [`Choice::TRUE`] if `x == y`, and [`Choice::FALSE`] otherwise.
266    #[inline]
267    #[must_use]
268    pub const fn from_u128_eq(x: u128, y: u128) -> Self {
269        Self::from_u128_nz(x ^ y).not()
270    }
271
272    /// Returns [`Choice::TRUE`] if `x <= y` and [`Choice::FALSE`] otherwise.
273    #[inline]
274    #[must_use]
275    pub const fn from_u128_le(x: u128, y: u128) -> Self {
276        #[cfg(target_pointer_width = "32")]
277        {
278            Self::from_u128_lt(y, x).not()
279        }
280        #[cfg(not(target_pointer_width = "32"))]
281        {
282            Self::from_u128_lsb(bitle!(x, y, u128::BITS))
283        }
284    }
285
286    /// Initialize from the least significant bit of a `u128`.
287    #[inline]
288    #[must_use]
289    pub const fn from_u128_lsb(value: u128) -> Self {
290        Self((value & 1) as u8)
291    }
292
293    /// Returns [`Choice::TRUE`] if `x < y`, and [`Choice::FALSE`] otherwise.
294    #[inline]
295    #[must_use]
296    pub const fn from_u128_lt(x: u128, y: u128) -> Self {
297        #[cfg(target_pointer_width = "32")]
298        {
299            Self::from_u128_lt_halves(x, y)
300        }
301        #[cfg(not(target_pointer_width = "32"))]
302        {
303            Self::from_u128_lsb(crate::primitives::bitlt!(x, y, u128::BITS))
304        }
305    }
306
307    #[cfg(any(target_pointer_width = "32", test))]
308    #[inline]
309    #[allow(clippy::cast_possible_truncation)]
310    const fn from_u128_lt_halves(x: u128, y: u128) -> Self {
311        // Full-width subtraction can introduce conditional borrow propagation.
312        // Keep the half-width predicates opaque so LLVM cannot combine them into a short-circuiting
313        // multiword comparison.
314        let x_hi = (x >> 64) as u64;
315        let y_hi = (y >> 64) as u64;
316        let hi_lt = Self::from_u64_lt(x_hi, y_hi).to_u8();
317        let hi_eq = Self::from_u64_eq(x_hi, y_hi).to_u8();
318        let lo_lt = Self::from_u64_lt(x as u64, y as u64).to_u8();
319        Self::from_u8_lsb(hi_lt | (hi_eq & lo_lt))
320    }
321
322    /// Returns [`Choice::TRUE`] if `value != 0`, and [`Choice::FALSE`] otherwise.
323    #[inline]
324    #[must_use]
325    pub const fn from_u128_nz(value: u128) -> Self {
326        Self::from_u128_lsb(bitnz!(value, u128::BITS))
327    }
328
329    //
330    // `const fn` predication methods
331    //
332
333    /// `const fn` helper: return `b` if `self` is [`Choice::TRUE`], otherwise return `a`.
334    ///
335    /// Only use this instead of the [`CtSelect`] trait in the event you're in a `const fn` context
336    /// and can't use the trait. The former will provide better constant-time assurances.
337    #[inline]
338    #[must_use]
339    pub const fn select_i64(self, a: i64, b: i64) -> i64 {
340        self.select_u64(a.cast_unsigned(), b.cast_unsigned())
341            .cast_signed()
342    }
343
344    /// `const fn` helper: return `b` if `self` is [`Choice::TRUE`], otherwise return `a`.
345    ///
346    /// Only use this instead of the [`CtSelect`] trait in the event you're in a `const fn` context
347    /// and can't use the trait. The former will provide better constant-time assurances.
348    #[inline]
349    #[must_use]
350    pub const fn select_u8(self, a: u8, b: u8) -> u8 {
351        a ^ (self.to_u8_mask() & (a ^ b))
352    }
353
354    /// `const fn` helper: return `b` if `self` is [`Choice::TRUE`], otherwise return `a`.
355    ///
356    /// Only use this instead of the [`CtSelect`] trait in the event you're in a `const fn` context
357    /// and can't use the trait. The former will provide better constant-time assurances.
358    #[inline]
359    #[must_use]
360    pub const fn select_u16(self, a: u16, b: u16) -> u16 {
361        a ^ (self.to_u16_mask() & (a ^ b))
362    }
363
364    /// `const fn` helper: return `b` if `self` is [`Choice::TRUE`], otherwise return `a`.
365    ///
366    /// Only use this instead of the [`CtSelect`] trait in the event you're in a `const fn` context
367    /// and can't use the trait. The former will provide better constant-time assurances.
368    #[inline]
369    #[must_use]
370    pub const fn select_u32(self, a: u32, b: u32) -> u32 {
371        a ^ (self.to_u32_mask() & (a ^ b))
372    }
373
374    /// `const fn` helper: return `b` if `self` is [`Choice::TRUE`], otherwise return `a`.
375    ///
376    /// Only use this instead of the [`CtSelect`] trait in the event you're in a `const fn` context
377    /// and can't use the trait. The former will provide better constant-time assurances.
378    #[inline]
379    #[must_use]
380    pub const fn select_u64(self, a: u64, b: u64) -> u64 {
381        a ^ (self.to_u64_mask() & (a ^ b))
382    }
383
384    /// `const fn` helper: return `b` if `self` is [`Choice::TRUE`], otherwise return `a`.
385    ///
386    /// Only use this instead of the [`CtSelect`] trait in the event you're in a `const fn` context
387    /// and can't use the trait. The former will provide better constant-time assurances.
388    #[inline]
389    #[must_use]
390    pub const fn select_u128(self, a: u128, b: u128) -> u128 {
391        a ^ (self.to_u128_mask() & (a ^ b))
392    }
393
394    //
395    // Output conversion methods
396    //
397
398    /// Convert `Choice` into a `bool`.
399    ///
400    /// <div class = "warning">
401    /// <b>Security Warning</b>
402    ///
403    /// Using this function will introduce timing variability, since computing this at all currently
404    /// requires a branch.
405    ///
406    /// This is intended to be used as either the one and only branch at the end of a constant-time
407    /// operation to e.g. differentiate between success and failure, or in contexts where
408    /// constant-time doesn't matter, e.g. variable-time code that operates on "maybe secret" types
409    /// which aren't secrets in a particular context.
410    ///
411    /// If you are trying to use this in the context of a constant-time operation, be warned that
412    /// the small amount of timing variability it introduces can potentially be exploited. Whenever
413    /// possible, prefer fully constant-time approaches instead.
414    /// </div>
415    #[must_use]
416    pub const fn to_bool(self) -> bool {
417        self.to_u8() != 0
418    }
419
420    /// Convert [`Choice`] to a `u8`, attempting to apply a "best effort" optimization barrier.
421    #[must_use]
422    pub const fn to_u8(self) -> u8 {
423        // `black_box` is documented as working on a "best effort" basis. That's fine, this type is
424        // likewise documented as only working on a "best effort" basis itself. The only way we
425        // rely on `black_box` for correctness is it behaving as the identity function.
426        core::hint::black_box(self.0)
427    }
428
429    /// DEPRECATED: previously a workaround to allow `const fn` boolean support on Rust 1.85.
430    ///
431    /// Use [`Choice::to_bool`] instead.
432    ///
433    /// <div class = "warning">
434    /// <b>Security Warning</b>
435    ///
436    /// See the security warnings for [`Choice::to_bool`].
437    /// </div>
438    #[deprecated(since = "0.4.3", note = "use `Choice::to_bool` instead")]
439    #[must_use]
440    pub const fn to_bool_vartime(self) -> bool {
441        self.to_bool()
442    }
443
444    /// DEPRECATED: previously a workaround to allow `const fn` boolean support on Rust 1.85.
445    ///
446    /// Use [`Choice::to_u8`] instead.
447    #[deprecated(since = "0.4.3", note = "use `Choice::to_u8` instead")]
448    #[must_use]
449    pub const fn to_u8_vartime(self) -> u8 {
450        self.to_u8()
451    }
452
453    /// Create a `u8` bitmask.
454    ///
455    /// # Returns
456    /// - `0` for `Choice::FALSE`
457    /// - `u8::MAX` for `Choice::TRUE`
458    #[inline]
459    #[must_use]
460    pub const fn to_u8_mask(self) -> u8 {
461        self.to_u8().wrapping_neg()
462    }
463
464    /// Create a `u16` bitmask.
465    ///
466    /// # Returns
467    /// - `0` for `Choice::FALSE`
468    /// - `u16::MAX` for `Choice::TRUE`
469    #[inline]
470    #[must_use]
471    pub const fn to_u16_mask(self) -> u16 {
472        (self.to_u8() as u16).wrapping_neg()
473    }
474
475    /// Create a `u32` bitmask.
476    ///
477    /// # Returns
478    /// - `0` for `Choice::FALSE`
479    /// - `u32::MAX` for `Choice::TRUE`
480    #[inline]
481    #[must_use]
482    pub const fn to_u32_mask(self) -> u32 {
483        (self.to_u8() as u32).wrapping_neg()
484    }
485
486    /// Create a `u64` bitmask.
487    ///
488    /// # Returns
489    /// - `0` for `Choice::FALSE`
490    /// - `u64::MAX` for `Choice::TRUE`
491    #[inline]
492    #[must_use]
493    pub const fn to_u64_mask(self) -> u64 {
494        (self.to_u8() as u64).wrapping_neg()
495    }
496
497    /// Create a `u128` bitmask.
498    ///
499    /// # Returns
500    /// - `0` for `Choice::FALSE`
501    /// - `u128::MAX` for `Choice::TRUE`
502    #[inline]
503    #[must_use]
504    pub const fn to_u128_mask(self) -> u128 {
505        (self.to_u8() as u128).wrapping_neg()
506    }
507}
508
509impl BitAnd for Choice {
510    type Output = Choice;
511
512    #[inline]
513    fn bitand(self, rhs: Choice) -> Choice {
514        self.and(rhs)
515    }
516}
517
518impl BitAndAssign for Choice {
519    #[inline]
520    fn bitand_assign(&mut self, rhs: Choice) {
521        *self = *self & rhs;
522    }
523}
524
525impl BitOr for Choice {
526    type Output = Choice;
527
528    #[inline]
529    fn bitor(self, rhs: Choice) -> Choice {
530        self.or(rhs)
531    }
532}
533
534impl BitOrAssign for Choice {
535    #[inline]
536    fn bitor_assign(&mut self, rhs: Choice) {
537        *self = *self | rhs;
538    }
539}
540
541impl BitXor for Choice {
542    type Output = Choice;
543
544    #[inline]
545    fn bitxor(self, rhs: Choice) -> Choice {
546        Choice(self.0 ^ rhs.0)
547    }
548}
549
550impl BitXorAssign for Choice {
551    #[inline]
552    fn bitxor_assign(&mut self, rhs: Choice) {
553        *self = *self ^ rhs;
554    }
555}
556
557impl CtAssign for Choice {
558    #[inline]
559    fn ct_assign(&mut self, other: &Self, choice: Choice) {
560        self.0.ct_assign(&other.0, choice);
561    }
562}
563impl CtAssignSlice for Choice {}
564impl CtSelectUsingCtAssign for Choice {}
565
566impl CtEq for Choice {
567    #[inline]
568    fn ct_eq(&self, other: &Self) -> Self {
569        self.0.ct_eq(&other.0)
570    }
571}
572impl CtEqSlice for Choice {}
573
574/// DEPRECATED: this exists to aid migrating code from `subtle`. Use `Choice::from_u8_lsb` instead.
575///
576/// <div class="warning">
577/// <b>Note</b>
578///
579/// Rust doesn't actually let us deprecate an impl block, however this comment is here to
580/// discourage future use and warn that this will be removed in a future release.
581/// </div>
582impl From<u8> for Choice {
583    fn from(value: u8) -> Self {
584        Choice::from_u8_lsb(value)
585    }
586}
587
588impl From<Choice> for u8 {
589    fn from(choice: Choice) -> u8 {
590        choice.to_u8()
591    }
592}
593
594/// Convert `Choice` into a `bool`.
595///
596/// <div class = "warning">
597/// <b>Security Warning</b>
598///
599/// Using this function will introduce timing variability, since computing this at all currently
600/// requires a branch.
601///
602/// See the security warnings for [`Choice::to_bool`].
603/// </div>
604impl From<Choice> for bool {
605    fn from(choice: Choice) -> bool {
606        choice.to_bool()
607    }
608}
609
610impl Not for Choice {
611    type Output = Choice;
612
613    #[inline]
614    fn not(self) -> Choice {
615        self.not()
616    }
617}
618
619#[cfg(feature = "subtle")]
620impl From<subtle::Choice> for Choice {
621    #[inline]
622    fn from(choice: subtle::Choice) -> Choice {
623        Choice(choice.unwrap_u8())
624    }
625}
626
627#[cfg(feature = "subtle")]
628impl From<Choice> for subtle::Choice {
629    #[inline]
630    fn from(choice: Choice) -> subtle::Choice {
631        subtle::Choice::from(choice.0)
632    }
633}
634
635#[cfg(feature = "subtle")]
636impl subtle::ConditionallySelectable for Choice {
637    #[inline]
638    fn conditional_select(a: &Self, b: &Self, choice: subtle::Choice) -> Self {
639        CtSelect::ct_select(a, b, choice.into())
640    }
641}
642
643#[cfg(feature = "subtle")]
644impl subtle::ConstantTimeEq for Choice {
645    #[inline]
646    fn ct_eq(&self, other: &Self) -> subtle::Choice {
647        CtEq::ct_eq(self, other).into()
648    }
649}
650
651#[cfg(test)]
652mod tests {
653    use super::Choice;
654    use crate::{CtEq, CtGt, CtLt, CtSelect};
655
656    #[test]
657    fn ct_eq() {
658        let a = Choice::TRUE;
659        let b = Choice::TRUE;
660        let c = Choice::FALSE;
661
662        assert!(a.ct_eq(&b).to_bool());
663        assert!(!a.ct_eq(&c).to_bool());
664        assert!(!b.ct_eq(&c).to_bool());
665
666        assert!(!a.ct_ne(&b).to_bool());
667        assert!(a.ct_ne(&c).to_bool());
668        assert!(b.ct_ne(&c).to_bool());
669    }
670
671    #[test]
672    fn ct_select() {
673        let a = Choice::FALSE;
674        let b = Choice::TRUE;
675        assert_eq!(a.ct_select(&b, Choice::FALSE).to_bool(), a.to_bool());
676        assert_eq!(a.ct_select(&b, Choice::TRUE).to_bool(), b.to_bool());
677    }
678
679    #[test]
680    fn and() {
681        assert_eq!((Choice::FALSE & Choice::FALSE).to_u8(), 0);
682        assert_eq!((Choice::TRUE & Choice::FALSE).to_u8(), 0);
683        assert_eq!((Choice::FALSE & Choice::TRUE).to_u8(), 0);
684        assert_eq!((Choice::TRUE & Choice::TRUE).to_u8(), 1);
685    }
686
687    #[test]
688    fn or() {
689        assert_eq!((Choice::FALSE | Choice::FALSE).to_u8(), 0);
690        assert_eq!((Choice::TRUE | Choice::FALSE).to_u8(), 1);
691        assert_eq!((Choice::FALSE | Choice::TRUE).to_u8(), 1);
692        assert_eq!((Choice::TRUE | Choice::TRUE).to_u8(), 1);
693    }
694
695    #[test]
696    fn xor() {
697        assert_eq!((Choice::FALSE ^ Choice::FALSE).to_u8(), 0);
698        assert_eq!((Choice::TRUE ^ Choice::FALSE).to_u8(), 1);
699        assert_eq!((Choice::FALSE ^ Choice::TRUE).to_u8(), 1);
700        assert_eq!((Choice::TRUE ^ Choice::TRUE).to_u8(), 0);
701    }
702
703    #[test]
704    fn not() {
705        assert_eq!(Choice::FALSE.not().to_u8(), 1);
706        assert_eq!(Choice::TRUE.not().to_u8(), 0);
707    }
708
709    #[test]
710    fn from_i64_eq() {
711        assert!(Choice::from_i64_eq(0, 1).eq(Choice::FALSE).to_bool());
712        assert!(Choice::from_i64_eq(1, 1).eq(Choice::TRUE).to_bool());
713    }
714
715    #[test]
716    fn from_u8_eq() {
717        assert!(Choice::from_u8_eq(0, 1).eq(Choice::FALSE).to_bool());
718        assert!(Choice::from_u8_eq(1, 1).eq(Choice::TRUE).to_bool());
719    }
720
721    #[test]
722    fn from_u8_le() {
723        assert!(Choice::from_u8_le(0, 0).eq(Choice::TRUE).to_bool());
724        assert!(Choice::from_u8_le(1, 0).eq(Choice::FALSE).to_bool());
725        assert!(Choice::from_u8_le(1, 1).eq(Choice::TRUE).to_bool());
726        assert!(Choice::from_u8_le(1, 2).eq(Choice::TRUE).to_bool());
727    }
728
729    #[test]
730    fn from_u8_lsb() {
731        assert!(Choice::from_u8_lsb(0).eq(Choice::FALSE).to_bool());
732        assert!(Choice::from_u8_lsb(1).eq(Choice::TRUE).to_bool());
733        assert!(Choice::from_u8_lsb(2).eq(Choice::FALSE).to_bool());
734        assert!(Choice::from_u8_lsb(3).eq(Choice::TRUE).to_bool());
735    }
736
737    #[test]
738    fn from_u8_lt() {
739        assert!(Choice::from_u8_lt(0, 0).eq(Choice::FALSE).to_bool());
740        assert!(Choice::from_u8_lt(1, 0).eq(Choice::FALSE).to_bool());
741        assert!(Choice::from_u8_lt(1, 1).eq(Choice::FALSE).to_bool());
742        assert!(Choice::from_u8_lt(1, 2).eq(Choice::TRUE).to_bool());
743    }
744
745    #[test]
746    fn from_u8_nz() {
747        assert!(Choice::from_u8_nz(0).eq(Choice::FALSE).to_bool());
748        assert!(Choice::from_u8_nz(1).eq(Choice::TRUE).to_bool());
749        assert!(Choice::from_u8_nz(2).eq(Choice::TRUE).to_bool());
750    }
751
752    #[test]
753    fn from_u16_eq() {
754        assert!(Choice::from_u16_eq(0, 1).eq(Choice::FALSE).to_bool());
755        assert!(Choice::from_u16_eq(1, 1).eq(Choice::TRUE).to_bool());
756    }
757
758    #[test]
759    fn from_u16_le() {
760        assert!(Choice::from_u16_le(0, 0).eq(Choice::TRUE).to_bool());
761        assert!(Choice::from_u16_le(1, 0).eq(Choice::FALSE).to_bool());
762        assert!(Choice::from_u16_le(1, 1).eq(Choice::TRUE).to_bool());
763        assert!(Choice::from_u16_le(1, 2).eq(Choice::TRUE).to_bool());
764    }
765
766    #[test]
767    fn from_u16_lsb() {
768        assert!(Choice::from_u16_lsb(0).eq(Choice::FALSE).to_bool());
769        assert!(Choice::from_u16_lsb(1).eq(Choice::TRUE).to_bool());
770        assert!(Choice::from_u16_lsb(2).eq(Choice::FALSE).to_bool());
771        assert!(Choice::from_u16_lsb(3).eq(Choice::TRUE).to_bool());
772    }
773
774    #[test]
775    fn from_u16_lt() {
776        assert!(Choice::from_u16_lt(0, 0).eq(Choice::FALSE).to_bool());
777        assert!(Choice::from_u16_lt(1, 0).eq(Choice::FALSE).to_bool());
778        assert!(Choice::from_u16_lt(1, 1).eq(Choice::FALSE).to_bool());
779        assert!(Choice::from_u16_lt(1, 2).eq(Choice::TRUE).to_bool());
780    }
781
782    #[test]
783    fn from_u16_nz() {
784        assert!(Choice::from_u16_nz(0).eq(Choice::FALSE).to_bool());
785        assert!(Choice::from_u16_nz(1).eq(Choice::TRUE).to_bool());
786        assert!(Choice::from_u16_nz(2).eq(Choice::TRUE).to_bool());
787    }
788
789    #[test]
790    fn from_u32_eq() {
791        assert!(Choice::from_u32_eq(0, 1).eq(Choice::FALSE).to_bool());
792        assert!(Choice::from_u32_eq(1, 1).eq(Choice::TRUE).to_bool());
793    }
794
795    #[test]
796    fn from_u32_le() {
797        assert!(Choice::from_u32_le(0, 0).eq(Choice::TRUE).to_bool());
798        assert!(Choice::from_u32_le(1, 0).eq(Choice::FALSE).to_bool());
799        assert!(Choice::from_u32_le(1, 1).eq(Choice::TRUE).to_bool());
800        assert!(Choice::from_u32_le(1, 2).eq(Choice::TRUE).to_bool());
801    }
802
803    #[test]
804    fn from_u32_lsb() {
805        assert!(Choice::from_u32_lsb(0).eq(Choice::FALSE).to_bool());
806        assert!(Choice::from_u32_lsb(1).eq(Choice::TRUE).to_bool());
807        assert!(Choice::from_u32_lsb(2).eq(Choice::FALSE).to_bool());
808        assert!(Choice::from_u32_lsb(3).eq(Choice::TRUE).to_bool());
809    }
810
811    #[test]
812    fn from_u32_lt() {
813        assert!(Choice::from_u32_lt(0, 0).eq(Choice::FALSE).to_bool());
814        assert!(Choice::from_u32_lt(1, 0).eq(Choice::FALSE).to_bool());
815        assert!(Choice::from_u32_lt(1, 1).eq(Choice::FALSE).to_bool());
816        assert!(Choice::from_u32_lt(1, 2).eq(Choice::TRUE).to_bool());
817    }
818
819    #[test]
820    fn from_u32_nz() {
821        assert!(Choice::from_u32_nz(0).eq(Choice::FALSE).to_bool());
822        assert!(Choice::from_u32_nz(1).eq(Choice::TRUE).to_bool());
823        assert!(Choice::from_u32_nz(2).eq(Choice::TRUE).to_bool());
824    }
825
826    #[test]
827    fn from_u64_eq() {
828        assert!(Choice::from_u64_eq(0, 1).eq(Choice::FALSE).to_bool());
829        assert!(Choice::from_u64_eq(1, 1).eq(Choice::TRUE).to_bool());
830    }
831
832    #[test]
833    fn from_u64_le() {
834        assert!(Choice::from_u64_le(0, 0).eq(Choice::TRUE).to_bool());
835        assert!(Choice::from_u64_le(1, 0).eq(Choice::FALSE).to_bool());
836        assert!(Choice::from_u64_le(1, 1).eq(Choice::TRUE).to_bool());
837        assert!(Choice::from_u64_le(1, 2).eq(Choice::TRUE).to_bool());
838    }
839
840    #[test]
841    fn from_u64_lsb() {
842        assert!(Choice::from_u64_lsb(0).eq(Choice::FALSE).to_bool());
843        assert!(Choice::from_u64_lsb(1).eq(Choice::TRUE).to_bool());
844    }
845
846    #[test]
847    fn from_u64_lt() {
848        assert!(Choice::from_u64_lt(0, 0).eq(Choice::FALSE).to_bool());
849        assert!(Choice::from_u64_lt(1, 0).eq(Choice::FALSE).to_bool());
850        assert!(Choice::from_u64_lt(1, 1).eq(Choice::FALSE).to_bool());
851        assert!(Choice::from_u64_lt(1, 2).eq(Choice::TRUE).to_bool());
852    }
853
854    #[test]
855    fn from_u64_nz() {
856        assert!(Choice::from_u64_nz(0).eq(Choice::FALSE).to_bool());
857        assert!(Choice::from_u64_nz(1).eq(Choice::TRUE).to_bool());
858        assert!(Choice::from_u64_nz(2).eq(Choice::TRUE).to_bool());
859    }
860
861    #[test]
862    fn from_u128_eq() {
863        assert!(Choice::from_u128_eq(0, 1).eq(Choice::FALSE).to_bool());
864        assert!(Choice::from_u128_eq(1, 1).eq(Choice::TRUE).to_bool());
865    }
866
867    #[test]
868    fn from_u128_le() {
869        assert!(Choice::from_u128_le(0, 0).eq(Choice::TRUE).to_bool());
870        assert!(Choice::from_u128_le(1, 0).eq(Choice::FALSE).to_bool());
871        assert!(Choice::from_u128_le(1, 1).eq(Choice::TRUE).to_bool());
872        assert!(Choice::from_u128_le(1, 2).eq(Choice::TRUE).to_bool());
873    }
874
875    #[test]
876    fn from_u128_lsb() {
877        assert!(Choice::from_u128_lsb(0).eq(Choice::FALSE).to_bool());
878        assert!(Choice::from_u128_lsb(1).eq(Choice::TRUE).to_bool());
879    }
880
881    #[test]
882    fn from_u128_lt() {
883        assert!(Choice::from_u128_lt(0, 0).eq(Choice::FALSE).to_bool());
884        assert!(Choice::from_u128_lt(1, 0).eq(Choice::FALSE).to_bool());
885        assert!(Choice::from_u128_lt(1, 1).eq(Choice::FALSE).to_bool());
886        assert!(Choice::from_u128_lt(1, 2).eq(Choice::TRUE).to_bool());
887    }
888
889    #[test]
890    fn from_u128_comparison_boundaries() {
891        const LT: Choice = Choice::from_u128_lt_halves((1 << 96) - 1, 1 << 96);
892        const LE: Choice = Choice::from_u128_le(1 << 64, 1 << 64);
893        assert!(LT.to_bool());
894        assert!(LE.to_bool());
895
896        let values = [
897            0,
898            1,
899            (1 << 32) - 1,
900            1 << 32,
901            (1 << 64) - 1,
902            1 << 64,
903            (1 << 64) + 1,
904            (1 << 96) - 1,
905            1 << 96,
906            u128::MAX - 1,
907            u128::MAX,
908        ];
909
910        for x in values {
911            for y in values {
912                assert_eq!(x < y, Choice::from_u128_lt_halves(x, y).to_bool());
913                assert_eq!(x < y, Choice::from_u128_lt(x, y).to_bool());
914                assert_eq!(x <= y, Choice::from_u128_le(x, y).to_bool());
915                assert_eq!(x < y, x.ct_lt(&y).to_bool());
916                assert_eq!(x > y, x.ct_gt(&y).to_bool());
917            }
918        }
919    }
920
921    #[test]
922    fn from_u128_nz() {
923        assert!(Choice::from_u128_nz(0).eq(Choice::FALSE).to_bool());
924        assert!(Choice::from_u128_nz(1).eq(Choice::TRUE).to_bool());
925        assert!(Choice::from_u128_nz(2).eq(Choice::TRUE).to_bool());
926    }
927
928    #[test]
929    fn select_i64() {
930        let a: i64 = 1;
931        let b: i64 = 2;
932        assert_eq!(Choice::TRUE.select_i64(a, b), b);
933        assert_eq!(Choice::FALSE.select_i64(a, b), a);
934    }
935
936    #[test]
937    fn select_u8() {
938        let a: u8 = 1;
939        let b: u8 = 2;
940        assert_eq!(Choice::TRUE.select_u8(a, b), b);
941        assert_eq!(Choice::FALSE.select_u8(a, b), a);
942    }
943
944    #[test]
945    fn select_u16() {
946        let a: u16 = 1;
947        let b: u16 = 2;
948        assert_eq!(Choice::TRUE.select_u16(a, b), b);
949        assert_eq!(Choice::FALSE.select_u16(a, b), a);
950    }
951
952    #[test]
953    fn select_u32() {
954        let a: u32 = 1;
955        let b: u32 = 2;
956        assert_eq!(Choice::TRUE.select_u32(a, b), b);
957        assert_eq!(Choice::FALSE.select_u32(a, b), a);
958    }
959
960    #[test]
961    fn select_u64() {
962        let a: u64 = 1;
963        let b: u64 = 2;
964        assert_eq!(Choice::TRUE.select_u64(a, b), b);
965        assert_eq!(Choice::FALSE.select_u64(a, b), a);
966    }
967
968    #[test]
969    fn select_u128() {
970        let a: u128 = 1;
971        let b: u128 = 2;
972        assert_eq!(Choice::TRUE.select_u128(a, b), b);
973        assert_eq!(Choice::FALSE.select_u128(a, b), a);
974    }
975
976    #[test]
977    fn to_bool() {
978        assert!(!Choice::FALSE.to_bool());
979        assert!(Choice::TRUE.to_bool());
980    }
981
982    #[test]
983    fn to_u8() {
984        assert_eq!(Choice::FALSE.to_u8(), 0);
985        assert_eq!(Choice::TRUE.to_u8(), 1);
986    }
987
988    #[test]
989    fn to_u8_mask() {
990        assert_eq!(Choice::FALSE.to_u8_mask(), 0);
991        assert_eq!(Choice::TRUE.to_u8_mask(), u8::MAX);
992    }
993
994    #[test]
995    fn to_u16_mask() {
996        assert_eq!(Choice::FALSE.to_u16_mask(), 0);
997        assert_eq!(Choice::TRUE.to_u16_mask(), u16::MAX);
998    }
999
1000    #[test]
1001    fn to_u32_mask() {
1002        assert_eq!(Choice::FALSE.to_u32_mask(), 0);
1003        assert_eq!(Choice::TRUE.to_u32_mask(), u32::MAX);
1004    }
1005
1006    #[test]
1007    fn to_u64_mask() {
1008        assert_eq!(Choice::FALSE.to_u64_mask(), 0);
1009        assert_eq!(Choice::TRUE.to_u64_mask(), u64::MAX);
1010    }
1011
1012    #[test]
1013    fn to_u128_mask() {
1014        assert_eq!(Choice::FALSE.to_u128_mask(), 0);
1015        assert_eq!(Choice::TRUE.to_u128_mask(), u128::MAX);
1016    }
1017}