crypto_bigint/limb/
cmp.rs1use crate::{ConstChoice, Limb};
4use core::cmp::Ordering;
5use subtle::{
6 Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess,
7};
8
9impl Limb {
10 #[inline]
12 pub fn is_odd(&self) -> Choice {
13 Choice::from(self.0 as u8 & 1)
14 }
15
16 pub fn cmp_vartime(&self, other: &Self) -> Ordering {
21 self.0.cmp(&other.0)
22 }
23
24 pub const fn eq_vartime(&self, other: &Self) -> bool {
26 self.0 == other.0
27 }
28
29 #[inline]
31 pub(crate) const fn select(a: Self, b: Self, c: ConstChoice) -> Self {
32 Self(c.select_word(a.0, b.0))
33 }
34
35 #[inline]
37 pub(crate) const fn is_nonzero(&self) -> ConstChoice {
38 ConstChoice::from_word_nonzero(self.0)
39 }
40}
41
42impl ConstantTimeEq for Limb {
43 #[inline]
44 fn ct_eq(&self, other: &Self) -> Choice {
45 self.0.ct_eq(&other.0)
46 }
47
48 #[inline]
49 fn ct_ne(&self, other: &Self) -> Choice {
50 self.0.ct_ne(&other.0)
51 }
52}
53
54impl ConstantTimeGreater for Limb {
55 #[inline]
56 fn ct_gt(&self, other: &Self) -> Choice {
57 ConstChoice::from_word_gt(self.0, other.0).into()
58 }
59}
60
61impl ConstantTimeLess for Limb {
62 #[inline]
63 fn ct_lt(&self, other: &Self) -> Choice {
64 ConstChoice::from_word_lt(self.0, other.0).into()
65 }
66}
67
68impl Eq for Limb {}
69
70impl Ord for Limb {
71 fn cmp(&self, other: &Self) -> Ordering {
72 let mut ret = Ordering::Less;
73 ret.conditional_assign(&Ordering::Equal, self.ct_eq(other));
74 ret.conditional_assign(&Ordering::Greater, self.ct_gt(other));
75 debug_assert_eq!(ret == Ordering::Less, bool::from(self.ct_lt(other)));
76 ret
77 }
78}
79
80impl PartialOrd for Limb {
81 #[inline]
82 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
83 Some(self.cmp(other))
84 }
85}
86
87impl PartialEq for Limb {
88 #[inline]
89 fn eq(&self, other: &Self) -> bool {
90 self.ct_eq(other).into()
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use crate::{Limb, Zero};
97 use core::cmp::Ordering;
98 use subtle::{ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess};
99
100 #[test]
101 fn is_zero() {
102 assert!(bool::from(Limb::ZERO.is_zero()));
103 assert!(!bool::from(Limb::ONE.is_zero()));
104 assert!(!bool::from(Limb::MAX.is_zero()));
105 }
106
107 #[test]
108 fn is_odd() {
109 assert!(!bool::from(Limb::ZERO.is_odd()));
110 assert!(bool::from(Limb::ONE.is_odd()));
111 assert!(bool::from(Limb::MAX.is_odd()));
112 }
113
114 #[test]
115 fn ct_eq() {
116 let a = Limb::ZERO;
117 let b = Limb::MAX;
118
119 assert!(bool::from(a.ct_eq(&a)));
120 assert!(!bool::from(a.ct_eq(&b)));
121 assert!(!bool::from(b.ct_eq(&a)));
122 assert!(bool::from(b.ct_eq(&b)));
123 }
124
125 #[test]
126 fn ct_gt() {
127 let a = Limb::ZERO;
128 let b = Limb::ONE;
129 let c = Limb::MAX;
130
131 assert!(bool::from(b.ct_gt(&a)));
132 assert!(bool::from(c.ct_gt(&a)));
133 assert!(bool::from(c.ct_gt(&b)));
134
135 assert!(!bool::from(a.ct_gt(&a)));
136 assert!(!bool::from(b.ct_gt(&b)));
137 assert!(!bool::from(c.ct_gt(&c)));
138
139 assert!(!bool::from(a.ct_gt(&b)));
140 assert!(!bool::from(a.ct_gt(&c)));
141 assert!(!bool::from(b.ct_gt(&c)));
142 }
143
144 #[test]
145 fn ct_lt() {
146 let a = Limb::ZERO;
147 let b = Limb::ONE;
148 let c = Limb::MAX;
149
150 assert!(bool::from(a.ct_lt(&b)));
151 assert!(bool::from(a.ct_lt(&c)));
152 assert!(bool::from(b.ct_lt(&c)));
153
154 assert!(!bool::from(a.ct_lt(&a)));
155 assert!(!bool::from(b.ct_lt(&b)));
156 assert!(!bool::from(c.ct_lt(&c)));
157
158 assert!(!bool::from(b.ct_lt(&a)));
159 assert!(!bool::from(c.ct_lt(&a)));
160 assert!(!bool::from(c.ct_lt(&b)));
161 }
162
163 #[test]
164 fn cmp() {
165 assert_eq!(Limb::ZERO.cmp(&Limb::ONE), Ordering::Less);
166 assert_eq!(Limb::ONE.cmp(&Limb::ONE), Ordering::Equal);
167 assert_eq!(Limb::MAX.cmp(&Limb::ONE), Ordering::Greater);
168 }
169}