crypto_bigint/uint/ref_type/
cmp.rs1use core::{cmp::Ordering, mem::transmute};
6
7use super::UintRef;
8use crate::{Choice, 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_vartime() 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
143#[cfg(test)]
144mod tests {
145 use core::cmp::Ordering;
146
147 use super::UintRef;
148 use crate::Limb;
149
150 #[test]
151 fn cmp() {
152 let z_small = UintRef::new(&[Limb::ZERO, Limb::ZERO]);
153 let z_big = UintRef::new(&[Limb::ZERO, Limb::ZERO, Limb::ZERO]);
154 let a = UintRef::new(&[Limb::ZERO, Limb::ZERO, Limb::ONE]);
155 let b = UintRef::new(&[Limb::ONE, Limb::ZERO]);
156
157 assert_eq!(UintRef::cmp(z_small, z_big), Ordering::Equal);
158 assert_eq!(UintRef::cmp(z_big, z_small), Ordering::Equal);
159 assert_eq!(UintRef::cmp(z_small, a), Ordering::Less);
160 assert_eq!(UintRef::cmp(z_big, a), Ordering::Less);
161 assert_eq!(UintRef::cmp(a, z_small), Ordering::Greater);
162 assert_eq!(UintRef::cmp(a, z_big), Ordering::Greater);
163 assert_eq!(UintRef::cmp(a, b), Ordering::Greater);
164 assert_eq!(UintRef::cmp(b, a), Ordering::Less);
165
166 assert_eq!(UintRef::cmp_vartime(z_small, z_big), Ordering::Equal);
167 assert_eq!(UintRef::cmp_vartime(z_big, z_small), Ordering::Equal);
168 assert_eq!(UintRef::cmp_vartime(z_small, a), Ordering::Less);
169 assert_eq!(UintRef::cmp_vartime(z_big, a), Ordering::Less);
170 assert_eq!(UintRef::cmp_vartime(a, z_small), Ordering::Greater);
171 assert_eq!(UintRef::cmp_vartime(a, z_big), Ordering::Greater);
172 assert_eq!(UintRef::cmp_vartime(a, b), Ordering::Greater);
173 assert_eq!(UintRef::cmp_vartime(b, a), Ordering::Less);
174 }
175
176 #[test]
177 fn lt() {
178 let lesser = UintRef::new(&[Limb::ZERO, Limb::ZERO, Limb::ZERO]);
179 let greater = UintRef::new(&[Limb::ZERO, Limb::ONE, Limb::ZERO]);
180 assert!(UintRef::lt(lesser, greater).to_bool());
181 assert!(!UintRef::lt(greater, lesser).to_bool());
182
183 let smaller = UintRef::new(&[Limb::ZERO, Limb::ZERO]);
184 let bigger = UintRef::new(&[Limb::ZERO, Limb::ZERO, Limb::ONE]);
185 assert!(UintRef::lt(smaller, bigger).to_bool());
186 assert!(!UintRef::lt(bigger, smaller).to_bool());
187 }
188}