1use core::cmp::Ordering;
6
7use subtle::{Choice, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess};
8
9use crate::{ConstChoice, Int, Uint};
10
11impl<const LIMBS: usize> Int<LIMBS> {
12 #[inline]
14 pub(crate) const fn select(a: &Self, b: &Self, c: ConstChoice) -> Self {
15 Self(Uint::select(&a.0, &b.0, c))
16 }
17
18 #[inline]
20 pub(crate) const fn is_nonzero(&self) -> ConstChoice {
21 Uint::is_nonzero(&self.0)
22 }
23
24 #[inline]
26 pub(crate) const fn eq(lhs: &Self, rhs: &Self) -> ConstChoice {
27 Uint::eq(&lhs.0, &rhs.0)
28 }
29
30 #[inline]
32 pub(crate) const fn lt(lhs: &Self, rhs: &Self) -> ConstChoice {
33 Uint::lt(&lhs.invert_msb().0, &rhs.invert_msb().0)
34 }
35
36 #[inline]
38 pub(crate) const fn gt(lhs: &Self, rhs: &Self) -> ConstChoice {
39 Uint::gt(&lhs.invert_msb().0, &rhs.invert_msb().0)
40 }
41
42 #[inline]
48 pub(crate) const fn cmp(lhs: &Self, rhs: &Self) -> i8 {
49 Uint::cmp(&lhs.invert_msb().0, &rhs.invert_msb().0)
50 }
51
52 pub const fn cmp_vartime(&self, rhs: &Self) -> Ordering {
54 self.invert_msb().0.cmp_vartime(&rhs.invert_msb().0)
55 }
56}
57
58impl<const LIMBS: usize> ConstantTimeEq for Int<LIMBS> {
59 #[inline]
60 fn ct_eq(&self, other: &Self) -> Choice {
61 Int::eq(self, other).into()
62 }
63}
64
65impl<const LIMBS: usize> ConstantTimeGreater for Int<LIMBS> {
66 #[inline]
67 fn ct_gt(&self, other: &Self) -> Choice {
68 Int::gt(self, other).into()
69 }
70}
71
72impl<const LIMBS: usize> ConstantTimeLess for Int<LIMBS> {
73 #[inline]
74 fn ct_lt(&self, other: &Self) -> Choice {
75 Int::lt(self, other).into()
76 }
77}
78
79impl<const LIMBS: usize> Eq for Int<LIMBS> {}
80
81impl<const LIMBS: usize> Ord for Int<LIMBS> {
82 fn cmp(&self, other: &Self) -> Ordering {
83 let c = Self::cmp(self, other);
84 match c {
85 -1 => Ordering::Less,
86 0 => Ordering::Equal,
87 _ => Ordering::Greater,
88 }
89 }
90}
91
92impl<const LIMBS: usize> PartialOrd for Int<LIMBS> {
93 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
94 Some(self.cmp(other))
95 }
96}
97
98impl<const LIMBS: usize> PartialEq for Int<LIMBS> {
99 fn eq(&self, other: &Self) -> bool {
100 self.ct_eq(other).into()
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use subtle::{ConstantTimeGreater, ConstantTimeLess};
107
108 use crate::I128;
109
110 #[test]
111 fn test_is_nonzero() {
112 assert_eq!(I128::MAX.is_nonzero().to_u8(), 1u8);
113 assert_eq!(I128::ONE.is_nonzero().to_u8(), 1u8);
114 assert_eq!(I128::ZERO.is_nonzero().to_u8(), 0u8);
115 assert_eq!(I128::MINUS_ONE.is_nonzero().to_u8(), 1u8);
116 assert_eq!(I128::MAX.is_nonzero().to_u8(), 1u8);
117 }
118
119 #[test]
120 fn test_eq() {
121 assert_eq!(I128::ZERO, I128::ONE.wrapping_add(&I128::MINUS_ONE));
122 assert_eq!(I128::ONE, I128::ZERO.wrapping_add(&I128::ONE));
123 assert_ne!(I128::ONE, I128::ZERO);
124 }
125
126 #[test]
127 fn test_gt() {
128 assert!(I128::MAX > I128::ONE);
130 assert!(I128::ONE > I128::ZERO);
131 assert!(I128::ZERO > I128::MINUS_ONE);
132 assert!(I128::MINUS_ONE > I128::MIN);
133 assert!(I128::MAX > I128::MIN);
134
135 assert_ne!(true, I128::MAX > I128::MAX);
137 assert_ne!(true, I128::ONE > I128::ONE);
138 assert_ne!(true, I128::ZERO > I128::ZERO);
139 assert_ne!(true, I128::MINUS_ONE > I128::MINUS_ONE);
140 assert_ne!(true, I128::MIN > I128::MIN);
141 }
142
143 #[test]
144 fn test_lt() {
145 assert!(I128::ONE < I128::MAX);
147 assert!(I128::ZERO < I128::ONE);
148 assert!(I128::MINUS_ONE < I128::ZERO);
149 assert!(I128::MIN < I128::MINUS_ONE);
150 assert!(I128::MIN < I128::MAX);
151
152 assert_ne!(true, I128::MAX < I128::MAX);
154 assert_ne!(true, I128::ONE < I128::ONE);
155 assert_ne!(true, I128::ZERO < I128::ZERO);
156 assert_ne!(true, I128::MINUS_ONE < I128::MINUS_ONE);
157 assert_ne!(true, I128::MIN < I128::MIN);
158 }
159
160 #[test]
161 fn ct_gt() {
162 let a = I128::MIN;
163 let b = I128::ZERO;
164 let c = I128::MAX;
165
166 assert!(bool::from(b.ct_gt(&a)));
167 assert!(bool::from(c.ct_gt(&a)));
168 assert!(bool::from(c.ct_gt(&b)));
169
170 assert!(!bool::from(a.ct_gt(&a)));
171 assert!(!bool::from(b.ct_gt(&b)));
172 assert!(!bool::from(c.ct_gt(&c)));
173
174 assert!(!bool::from(a.ct_gt(&b)));
175 assert!(!bool::from(a.ct_gt(&c)));
176 assert!(!bool::from(b.ct_gt(&c)));
177 }
178
179 #[test]
180 fn ct_lt() {
181 let a = I128::ZERO;
182 let b = I128::ONE;
183 let c = I128::MAX;
184
185 assert!(bool::from(a.ct_lt(&b)));
186 assert!(bool::from(a.ct_lt(&c)));
187 assert!(bool::from(b.ct_lt(&c)));
188
189 assert!(!bool::from(a.ct_lt(&a)));
190 assert!(!bool::from(b.ct_lt(&b)));
191 assert!(!bool::from(c.ct_lt(&c)));
192
193 assert!(!bool::from(b.ct_lt(&a)));
194 assert!(!bool::from(c.ct_lt(&a)));
195 assert!(!bool::from(c.ct_lt(&b)));
196 }
197}