Skip to main content

ctutils/traits/
ct_gt.rs

1use crate::Choice;
2use core::{
3    cmp,
4    num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128},
5};
6
7/// Constant time greater than.
8pub trait CtGt {
9    /// Compute whether `self > other` in constant time.
10    #[must_use]
11    fn ct_gt(&self, other: &Self) -> Choice;
12}
13
14// Impl `CtGt` using overflowing subtraction
15macro_rules! impl_unsigned_ct_gt {
16    ( $($uint:ty),+ ) => {
17        $(
18            impl CtGt for $uint {
19                #[inline]
20                fn ct_gt(&self, other: &Self) -> Choice {
21                    let (_, overflow) = other.overflowing_sub(*self);
22                    Choice(overflow.into())
23                }
24            }
25        )+
26    };
27}
28
29impl_unsigned_ct_gt!(u8, u16, u32, u64, u128);
30
31/// Impl `CtGt` for `NonZero<T>` by calling `NonZero::get`.
32macro_rules! impl_ct_gt_for_nonzero_integer {
33    ( $($ty:ty),+ ) => {
34        $(
35            impl CtGt for $ty {
36                #[inline]
37                fn ct_gt(&self, other: &Self) -> Choice {
38                    self.get().ct_gt(&other.get())
39                }
40            }
41        )+
42    };
43}
44
45impl_ct_gt_for_nonzero_integer!(NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128);
46
47impl CtGt for cmp::Ordering {
48    #[inline]
49    fn ct_gt(&self, other: &Self) -> Choice {
50        // No impl of `CtGt` for `i8`, so use `u8`
51        let a = (*self as i8) + 1;
52        let b = (*other as i8) + 1;
53        (a as u8).ct_gt(&(b as u8))
54    }
55}
56
57#[cfg(test)]
58mod tests {
59    use super::CtGt;
60    use core::cmp::Ordering;
61
62    #[test]
63    fn ct_gt() {
64        let a = 42u64;
65        let b = 43u64;
66        assert!(!a.ct_gt(&a).to_bool());
67        assert!(!a.ct_gt(&b).to_bool());
68        assert!(b.ct_gt(&a).to_bool());
69    }
70
71    #[test]
72    fn ordering() {
73        assert!(!Ordering::Equal.ct_gt(&Ordering::Equal).to_bool());
74        assert!(!Ordering::Less.ct_gt(&Ordering::Greater).to_bool());
75        assert!(Ordering::Greater.ct_gt(&Ordering::Less).to_bool());
76    }
77}