crypto_bigint/uint/
cmp.rs
1use super::UInt;
6use crate::{limb::HI_BIT, Limb, SignedWord, WideSignedWord, Word, Zero};
7use core::cmp::Ordering;
8use subtle::{Choice, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess};
9
10impl<const LIMBS: usize> UInt<LIMBS> {
11 #[inline]
15 pub(crate) const fn ct_select(a: UInt<LIMBS>, b: UInt<LIMBS>, c: Word) -> Self {
16 let mut limbs = [Limb::ZERO; LIMBS];
17
18 let mut i = 0;
19 while i < LIMBS {
20 limbs[i] = Limb::ct_select(a.limbs[i], b.limbs[i], c);
21 i += 1;
22 }
23
24 UInt { limbs }
25 }
26
27 #[inline]
31 pub(crate) const fn ct_is_nonzero(&self) -> Word {
32 let mut b = 0;
33 let mut i = 0;
34 while i < LIMBS {
35 b |= self.limbs[i].0;
36 i += 1;
37 }
38 Limb::is_nonzero(Limb(b))
39 }
40
41 #[inline]
47 pub(crate) const fn ct_cmp(&self, rhs: &Self) -> SignedWord {
48 let mut gt = 0;
49 let mut lt = 0;
50 let mut i = LIMBS;
51
52 while i > 0 {
53 let a = self.limbs[i - 1].0 as WideSignedWord;
54 let b = rhs.limbs[i - 1].0 as WideSignedWord;
55 gt |= ((b - a) >> Limb::BIT_SIZE) & 1 & !lt;
56 lt |= ((a - b) >> Limb::BIT_SIZE) & 1 & !gt;
57 i -= 1;
58 }
59 (gt as SignedWord) - (lt as SignedWord)
60 }
61
62 #[inline]
65 pub(crate) const fn ct_not_eq(&self, rhs: &Self) -> Word {
66 let mut acc = 0;
67 let mut i = 0;
68
69 while i < LIMBS {
70 acc |= self.limbs[i].0 ^ rhs.limbs[i].0;
71 i += 1;
72 }
73 let acc = acc as SignedWord;
74 ((acc | acc.wrapping_neg()) >> HI_BIT) as Word
75 }
76}
77
78impl<const LIMBS: usize> ConstantTimeEq for UInt<LIMBS> {
79 #[inline]
80 fn ct_eq(&self, other: &Self) -> Choice {
81 Choice::from((!self.ct_not_eq(other) as u8) & 1)
82 }
83}
84
85impl<const LIMBS: usize> ConstantTimeGreater for UInt<LIMBS> {
86 #[inline]
87 fn ct_gt(&self, other: &Self) -> Choice {
88 let underflow = other.sbb(self, Limb::ZERO).1;
89 !underflow.is_zero()
90 }
91}
92
93impl<const LIMBS: usize> ConstantTimeLess for UInt<LIMBS> {
94 #[inline]
95 fn ct_lt(&self, other: &Self) -> Choice {
96 let underflow = self.sbb(other, Limb::ZERO).1;
97 !underflow.is_zero()
98 }
99}
100
101impl<const LIMBS: usize> Eq for UInt<LIMBS> {}
102
103impl<const LIMBS: usize> Ord for UInt<LIMBS> {
104 fn cmp(&self, other: &Self) -> Ordering {
105 match self.ct_cmp(other) {
106 -1 => Ordering::Less,
107 1 => Ordering::Greater,
108 n => {
109 debug_assert_eq!(n, 0);
110 debug_assert!(bool::from(self.ct_eq(other)));
111 Ordering::Equal
112 }
113 }
114 }
115}
116
117impl<const LIMBS: usize> PartialOrd for UInt<LIMBS> {
118 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
119 Some(self.cmp(other))
120 }
121}
122
123impl<const LIMBS: usize> PartialEq for UInt<LIMBS> {
124 fn eq(&self, other: &Self) -> bool {
125 self.ct_eq(other).into()
126 }
127}
128
129#[cfg(test)]
130mod tests {
131 use crate::{Integer, Zero, U128};
132 use subtle::{ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess};
133
134 #[test]
135 fn is_zero() {
136 assert!(bool::from(U128::ZERO.is_zero()));
137 assert!(!bool::from(U128::ONE.is_zero()));
138 assert!(!bool::from(U128::MAX.is_zero()));
139 }
140
141 #[test]
142 fn is_odd() {
143 assert!(!bool::from(U128::ZERO.is_odd()));
144 assert!(bool::from(U128::ONE.is_odd()));
145 assert!(bool::from(U128::MAX.is_odd()));
146 }
147
148 #[test]
149 fn ct_eq() {
150 let a = U128::ZERO;
151 let b = U128::MAX;
152
153 assert!(bool::from(a.ct_eq(&a)));
154 assert!(!bool::from(a.ct_eq(&b)));
155 assert!(!bool::from(b.ct_eq(&a)));
156 assert!(bool::from(b.ct_eq(&b)));
157 }
158
159 #[test]
160 fn ct_gt() {
161 let a = U128::ZERO;
162 let b = U128::ONE;
163 let c = U128::MAX;
164
165 assert!(bool::from(b.ct_gt(&a)));
166 assert!(bool::from(c.ct_gt(&a)));
167 assert!(bool::from(c.ct_gt(&b)));
168
169 assert!(!bool::from(a.ct_gt(&a)));
170 assert!(!bool::from(b.ct_gt(&b)));
171 assert!(!bool::from(c.ct_gt(&c)));
172
173 assert!(!bool::from(a.ct_gt(&b)));
174 assert!(!bool::from(a.ct_gt(&c)));
175 assert!(!bool::from(b.ct_gt(&c)));
176 }
177
178 #[test]
179 fn ct_lt() {
180 let a = U128::ZERO;
181 let b = U128::ONE;
182 let c = U128::MAX;
183
184 assert!(bool::from(a.ct_lt(&b)));
185 assert!(bool::from(a.ct_lt(&c)));
186 assert!(bool::from(b.ct_lt(&c)));
187
188 assert!(!bool::from(a.ct_lt(&a)));
189 assert!(!bool::from(b.ct_lt(&b)));
190 assert!(!bool::from(c.ct_lt(&c)));
191
192 assert!(!bool::from(b.ct_lt(&a)));
193 assert!(!bool::from(c.ct_lt(&a)));
194 assert!(!bool::from(c.ct_lt(&b)));
195 }
196}