Skip to main content

crypto_bigint/limb/
cmp.rs

1//! Limb comparisons
2
3use crate::{Choice, CtAssign, CtEq, CtGt, CtLt, Limb, word};
4use core::cmp::Ordering;
5
6impl Limb {
7    /// Is this limb an odd number?
8    #[inline]
9    #[must_use]
10    pub fn is_odd(self) -> Choice {
11        word::choice_from_lsb(self.0 & 1)
12    }
13
14    /// Perform a comparison of the inner value in variable-time.
15    ///
16    /// Note that the [`PartialOrd`] and [`Ord`] impls wrap constant-time
17    /// comparisons using the `subtle` crate.
18    #[must_use]
19    pub fn cmp_vartime(self, other: Self) -> Ordering {
20        self.0.cmp(&other.0)
21    }
22
23    /// Performs an equality check in variable-time.
24    #[must_use]
25    pub const fn eq_vartime(self, other: Self) -> bool {
26        self.0 == other.0
27    }
28
29    /// Returns the truthy value if `self != 0` and the falsy value otherwise.
30    #[inline]
31    pub(crate) const fn is_nonzero(self) -> Choice {
32        word::choice_from_nz(self.0)
33    }
34}
35
36impl Eq for Limb {}
37
38impl Ord for Limb {
39    fn cmp(&self, other: &Self) -> Ordering {
40        let mut ret = Ordering::Less;
41        ret.ct_assign(&Ordering::Equal, self.ct_eq(other));
42        ret.ct_assign(&Ordering::Greater, self.ct_gt(other));
43        debug_assert_eq!(ret == Ordering::Less, bool::from(self.ct_lt(other)));
44        ret
45    }
46}
47
48impl PartialOrd for Limb {
49    #[inline]
50    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
51        Some(self.cmp(other))
52    }
53}
54
55impl PartialEq for Limb {
56    #[inline]
57    fn eq(&self, other: &Self) -> bool {
58        self.ct_eq(other).into()
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use crate::{Choice, Limb};
65    use core::cmp::Ordering;
66
67    #[test]
68    fn is_zero() {
69        assert!(bool::from(Limb::ZERO.is_zero()));
70        assert!(!bool::from(Limb::ONE.is_zero()));
71        assert!(!bool::from(Limb::MAX.is_zero()));
72    }
73
74    #[test]
75    fn is_odd() {
76        assert!(!bool::from(Limb::ZERO.is_odd()));
77        assert!(bool::from(Limb::ONE.is_odd()));
78        assert!(bool::from(Limb::MAX.is_odd()));
79    }
80
81    #[test]
82    fn cmp() {
83        assert_eq!(Limb::ZERO.cmp(&Limb::ONE), Ordering::Less);
84        assert_eq!(Limb::ONE.cmp(&Limb::ONE), Ordering::Equal);
85        assert_eq!(Limb::MAX.cmp(&Limb::ONE), Ordering::Greater);
86    }
87
88    #[test]
89    fn ct_conditional_swap() {
90        let mut a = Limb::MAX;
91        let mut b = Limb::ZERO;
92
93        Limb::ct_conditional_swap(&mut a, &mut b, Choice::FALSE);
94        assert_eq!(a, Limb::MAX);
95        assert_eq!(b, Limb::ZERO);
96
97        Limb::ct_conditional_swap(&mut a, &mut b, Choice::TRUE);
98        assert_eq!(a, Limb::ZERO);
99        assert_eq!(b, Limb::MAX);
100    }
101}