crypto_bigint/uint/
cmp.rs1use super::Uint;
6use crate::{CtChoice, Limb};
7use core::cmp::Ordering;
8use subtle::{Choice, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess};
9
10impl<const LIMBS: usize> Uint<LIMBS> {
11 #[inline]
13 pub(crate) const fn ct_select(a: &Self, b: &Self, c: CtChoice) -> Self {
14 let mut limbs = [Limb::ZERO; LIMBS];
15
16 let mut i = 0;
17 while i < LIMBS {
18 limbs[i] = Limb::ct_select(a.limbs[i], b.limbs[i], c);
19 i += 1;
20 }
21
22 Uint { limbs }
23 }
24
25 #[inline]
26 pub(crate) const fn ct_swap(a: &Self, b: &Self, c: CtChoice) -> (Self, Self) {
27 let new_a = Self::ct_select(a, b, c);
28 let new_b = Self::ct_select(b, a, c);
29
30 (new_a, new_b)
31 }
32
33 #[inline]
35 pub(crate) const fn ct_is_nonzero(&self) -> CtChoice {
36 let mut b = 0;
37 let mut i = 0;
38 while i < LIMBS {
39 b |= self.limbs[i].0;
40 i += 1;
41 }
42 Limb(b).ct_is_nonzero()
43 }
44
45 pub(crate) const fn ct_is_odd(&self) -> CtChoice {
47 CtChoice::from_lsb(self.limbs[0].0 & 1)
48 }
49
50 #[inline]
52 pub(crate) const fn ct_eq(lhs: &Self, rhs: &Self) -> CtChoice {
53 let mut acc = 0;
54 let mut i = 0;
55
56 while i < LIMBS {
57 acc |= lhs.limbs[i].0 ^ rhs.limbs[i].0;
58 i += 1;
59 }
60
61 Limb(acc).ct_is_nonzero().not()
63 }
64
65 #[inline]
67 pub(crate) const fn ct_lt(lhs: &Self, rhs: &Self) -> CtChoice {
68 let (_res, borrow) = lhs.sbb(rhs, Limb::ZERO);
72 CtChoice::from_mask(borrow.0)
73 }
74
75 #[inline]
77 pub(crate) const fn ct_gt(lhs: &Self, rhs: &Self) -> CtChoice {
78 let (_res, borrow) = rhs.sbb(lhs, Limb::ZERO);
79 CtChoice::from_mask(borrow.0)
80 }
81
82 #[inline]
88 pub(crate) const fn ct_cmp(lhs: &Self, rhs: &Self) -> i8 {
89 let mut i = 0;
90 let mut borrow = Limb::ZERO;
91 let mut diff = Limb::ZERO;
92
93 while i < LIMBS {
94 let (w, b) = rhs.limbs[i].sbb(lhs.limbs[i], borrow);
95 diff = diff.bitor(w);
96 borrow = b;
97 i += 1;
98 }
99 let sgn = ((borrow.0 & 2) as i8) - 1;
100 (diff.ct_is_nonzero().to_u8() as i8) * sgn
101 }
102
103 pub const fn cmp_vartime(&self, rhs: &Self) -> Ordering {
105 let mut i = LIMBS - 1;
106 loop {
107 let (val, borrow) = self.limbs[i].sbb(rhs.limbs[i], Limb::ZERO);
108 if val.0 != 0 {
109 return if borrow.0 != 0 {
110 Ordering::Less
111 } else {
112 Ordering::Greater
113 };
114 }
115 if i == 0 {
116 return Ordering::Equal;
117 }
118 i -= 1;
119 }
120 }
121}
122
123impl<const LIMBS: usize> ConstantTimeEq for Uint<LIMBS> {
124 #[inline]
125 fn ct_eq(&self, other: &Self) -> Choice {
126 Uint::ct_eq(self, other).into()
127 }
128}
129
130impl<const LIMBS: usize> ConstantTimeGreater for Uint<LIMBS> {
131 #[inline]
132 fn ct_gt(&self, other: &Self) -> Choice {
133 Uint::ct_gt(self, other).into()
134 }
135}
136
137impl<const LIMBS: usize> ConstantTimeLess for Uint<LIMBS> {
138 #[inline]
139 fn ct_lt(&self, other: &Self) -> Choice {
140 Uint::ct_lt(self, other).into()
141 }
142}
143
144impl<const LIMBS: usize> Eq for Uint<LIMBS> {}
145
146impl<const LIMBS: usize> Ord for Uint<LIMBS> {
147 fn cmp(&self, other: &Self) -> Ordering {
148 let c = Self::ct_cmp(self, other);
149 match c {
150 -1 => Ordering::Less,
151 0 => Ordering::Equal,
152 _ => Ordering::Greater,
153 }
154 }
155}
156
157impl<const LIMBS: usize> PartialOrd for Uint<LIMBS> {
158 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
159 Some(self.cmp(other))
160 }
161}
162
163impl<const LIMBS: usize> PartialEq for Uint<LIMBS> {
164 fn eq(&self, other: &Self) -> bool {
165 self.ct_eq(other).into()
166 }
167}
168
169#[cfg(test)]
170mod tests {
171 use crate::{Integer, Zero, U128};
172 use core::cmp::Ordering;
173 use subtle::{ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess};
174
175 #[test]
176 fn is_zero() {
177 assert!(bool::from(U128::ZERO.is_zero()));
178 assert!(!bool::from(U128::ONE.is_zero()));
179 assert!(!bool::from(U128::MAX.is_zero()));
180 }
181
182 #[test]
183 fn is_odd() {
184 assert!(!bool::from(U128::ZERO.is_odd()));
185 assert!(bool::from(U128::ONE.is_odd()));
186 assert!(bool::from(U128::MAX.is_odd()));
187 }
188
189 #[test]
190 fn ct_eq() {
191 let a = U128::ZERO;
192 let b = U128::MAX;
193
194 assert!(bool::from(a.ct_eq(&a)));
195 assert!(!bool::from(a.ct_eq(&b)));
196 assert!(!bool::from(b.ct_eq(&a)));
197 assert!(bool::from(b.ct_eq(&b)));
198 }
199
200 #[test]
201 fn ct_gt() {
202 let a = U128::ZERO;
203 let b = U128::ONE;
204 let c = U128::MAX;
205
206 assert!(bool::from(b.ct_gt(&a)));
207 assert!(bool::from(c.ct_gt(&a)));
208 assert!(bool::from(c.ct_gt(&b)));
209
210 assert!(!bool::from(a.ct_gt(&a)));
211 assert!(!bool::from(b.ct_gt(&b)));
212 assert!(!bool::from(c.ct_gt(&c)));
213
214 assert!(!bool::from(a.ct_gt(&b)));
215 assert!(!bool::from(a.ct_gt(&c)));
216 assert!(!bool::from(b.ct_gt(&c)));
217 }
218
219 #[test]
220 fn ct_lt() {
221 let a = U128::ZERO;
222 let b = U128::ONE;
223 let c = U128::MAX;
224
225 assert!(bool::from(a.ct_lt(&b)));
226 assert!(bool::from(a.ct_lt(&c)));
227 assert!(bool::from(b.ct_lt(&c)));
228
229 assert!(!bool::from(a.ct_lt(&a)));
230 assert!(!bool::from(b.ct_lt(&b)));
231 assert!(!bool::from(c.ct_lt(&c)));
232
233 assert!(!bool::from(b.ct_lt(&a)));
234 assert!(!bool::from(c.ct_lt(&a)));
235 assert!(!bool::from(c.ct_lt(&b)));
236 }
237
238 #[test]
239 fn cmp() {
240 let a = U128::ZERO;
241 let b = U128::ONE;
242 let c = U128::MAX;
243
244 assert_eq!(a.cmp(&b), Ordering::Less);
245 assert_eq!(a.cmp(&c), Ordering::Less);
246 assert_eq!(b.cmp(&c), Ordering::Less);
247
248 assert_eq!(a.cmp(&a), Ordering::Equal);
249 assert_eq!(b.cmp(&b), Ordering::Equal);
250 assert_eq!(c.cmp(&c), Ordering::Equal);
251
252 assert_eq!(b.cmp(&a), Ordering::Greater);
253 assert_eq!(c.cmp(&a), Ordering::Greater);
254 assert_eq!(c.cmp(&b), Ordering::Greater);
255 }
256
257 #[test]
258 fn cmp_vartime() {
259 let a = U128::ZERO;
260 let b = U128::ONE;
261 let c = U128::MAX;
262
263 assert_eq!(a.cmp_vartime(&b), Ordering::Less);
264 assert_eq!(a.cmp_vartime(&c), Ordering::Less);
265 assert_eq!(b.cmp_vartime(&c), Ordering::Less);
266
267 assert_eq!(a.cmp_vartime(&a), Ordering::Equal);
268 assert_eq!(b.cmp_vartime(&b), Ordering::Equal);
269 assert_eq!(c.cmp_vartime(&c), Ordering::Equal);
270
271 assert_eq!(b.cmp_vartime(&a), Ordering::Greater);
272 assert_eq!(c.cmp_vartime(&a), Ordering::Greater);
273 assert_eq!(c.cmp_vartime(&b), Ordering::Greater);
274 }
275}