crypto_bigint/uint/ref_type/
cmp.rs1use core::{cmp::Ordering, mem::transmute};
6
7use super::UintRef;
8use crate::{Choice, CtEq, Limb, word};
9
10impl UintRef {
11 #[inline]
13 #[must_use]
14 pub const fn is_odd(&self) -> Choice {
15 debug_assert!(self.nlimbs() >= 1, "should have limbs");
16 word::choice_from_lsb(self.limbs[0].0 & 1)
17 }
18
19 #[inline]
21 #[must_use]
22 pub const fn is_nonzero(&self) -> Choice {
23 let mut b = 0;
24 let mut i = 0;
25 while i < self.nlimbs() {
26 b |= self.limbs[i].0;
27 i += 1;
28 }
29 Limb(b).is_nonzero()
30 }
31
32 #[inline]
34 #[must_use]
35 pub const fn is_zero(&self) -> Choice {
36 self.is_nonzero().not()
37 }
38
39 #[inline]
41 pub(crate) const fn is_zero_vartime(&self) -> bool {
42 let mut i = 0;
43 while i < self.nlimbs() {
44 if self.limbs[i].0 != 0 {
45 return false;
46 }
47 i += 1;
48 }
49 true
50 }
51
52 #[allow(clippy::cast_possible_wrap)]
54 #[inline(always)]
55 pub(crate) const fn cmp(lhs: &Self, rhs: &Self) -> Ordering {
56 let overlap = if lhs.nlimbs() < rhs.nlimbs() {
57 lhs.nlimbs()
58 } else {
59 rhs.nlimbs()
60 };
61
62 let mut borrow = Limb::ZERO;
63 let mut diff = Limb::ZERO;
64 let mut i = 0;
65
66 while i < overlap {
67 let (w, b) = rhs.limbs[i].borrowing_sub(lhs.limbs[i], borrow);
68 diff = diff.bitor(w);
69 borrow = b;
70 i += 1;
71 }
72 let lesser = rhs.trailing(overlap).is_nonzero();
73 let greater = lhs.trailing(overlap).is_nonzero();
74
75 let sgn = borrow
77 .lsb_to_choice()
78 .and(lesser.not())
79 .or(greater)
80 .select_u8(255, 1) as i8;
81 let ord = (diff.is_nonzero().or(lesser).or(greater).to_u8() as i8) * sgn;
82
83 #[allow(unsafe_code)]
84 unsafe {
86 transmute(ord)
87 }
88 }
89
90 #[inline(always)]
92 #[must_use]
93 pub const fn cmp_vartime(&self, rhs: &Self) -> Ordering {
94 if self.nlimbs() < rhs.nlimbs() {
95 return rhs.cmp_vartime(self).reverse();
96 }
97
98 let mut i = self.nlimbs();
99 while i > rhs.nlimbs() {
100 i -= 1;
101 if self.limbs[i].0 != 0 {
102 return Ordering::Greater;
103 }
104 }
105 while i > 0 {
106 i -= 1;
107 let (val, borrow) = self.limbs[i].borrowing_sub(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 }
116
117 Ordering::Equal
118 }
119
120 #[inline(always)]
122 pub(crate) const fn lt(lhs: &Self, rhs: &Self) -> Choice {
123 let overlap = if lhs.nlimbs() < rhs.nlimbs() {
124 lhs.nlimbs()
125 } else {
126 rhs.nlimbs()
127 };
128
129 let mut i = 0;
131 let mut borrow = Limb::ZERO;
132
133 while i < overlap {
134 borrow = lhs.limbs[i].borrowing_sub(rhs.limbs[i], borrow).1;
135 i += 1;
136 }
137 let lesser = rhs.trailing(overlap).is_nonzero();
138 let greater = lhs.trailing(overlap).is_nonzero();
139 borrow.lsb_to_choice().and(greater.not()).or(lesser)
140 }
141}
142
143impl Eq for UintRef {}
144
145impl Ord for UintRef {
146 fn cmp(&self, other: &Self) -> Ordering {
147 Self::cmp(self, other)
148 }
149}
150
151impl PartialOrd for UintRef {
152 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
153 Some(self.cmp(other))
154 }
155}
156
157impl PartialEq for UintRef {
158 fn eq(&self, other: &Self) -> bool {
159 self.ct_eq(other).into()
160 }
161}
162
163#[cfg(test)]
164mod tests {
165 use core::cmp::Ordering;
166
167 use super::UintRef;
168 use crate::Limb;
169
170 #[test]
171 fn cmp() {
172 fn check(a: &UintRef, b: &UintRef, ord: Ordering) {
173 assert_eq!(UintRef::cmp(a, b), ord);
174 assert_eq!(UintRef::cmp_vartime(a, b), ord);
175 assert_eq!(a.cmp(b), ord);
176 if ord == Ordering::Equal {
177 assert_eq!(a, b);
178 } else {
179 assert_ne!(a, b);
180 }
181 }
182
183 let z_small = UintRef::new(&[Limb::ZERO, Limb::ZERO]);
184 let z_big = UintRef::new(&[Limb::ZERO, Limb::ZERO, Limb::ZERO]);
185 let a = UintRef::new(&[Limb::ZERO, Limb::ZERO, Limb::ONE]);
186 let b = UintRef::new(&[Limb::ONE, Limb::ZERO]);
187
188 check(z_small, z_big, Ordering::Equal);
189 check(z_big, z_small, Ordering::Equal);
190 check(z_small, a, Ordering::Less);
191 check(z_big, a, Ordering::Less);
192 check(a, z_small, Ordering::Greater);
193 check(a, z_big, Ordering::Greater);
194 check(a, b, Ordering::Greater);
195 check(b, a, Ordering::Less);
196 }
197
198 #[test]
199 fn lt() {
200 fn check(a: &UintRef, b: &UintRef) {
201 assert!(UintRef::lt(a, b).to_bool());
202 assert!(!UintRef::lt(b, a).to_bool());
203 assert!(a < b);
204 assert!(b > a);
205 }
206
207 let lesser = UintRef::new(&[Limb::ZERO, Limb::ZERO, Limb::ZERO]);
208 let greater = UintRef::new(&[Limb::ZERO, Limb::ONE, Limb::ZERO]);
209 check(lesser, greater);
210
211 let smaller = UintRef::new(&[Limb::ZERO, Limb::ZERO]);
212 let bigger = UintRef::new(&[Limb::ZERO, Limb::ZERO, Limb::ONE]);
213 check(smaller, bigger);
214 }
215}