Skip to main content

ctutils/
choice.rs

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