Skip to content

Commit dc7ee98

Browse files
Update comparison methods for UintRef (#1311)
`UintRef` was deriving `PartialEq`, which simply compared the limb slices and was not constant-time. This makes the `PartialEq` implementation use `CtEq`, consistent with `Uint` and `BoxedUint`. It also adds `PartialOrd` and `Ord` implementations. Signed-off-by: Andrew Whitehead <cywolf@gmail.com>
1 parent 2021752 commit dc7ee98

2 files changed

Lines changed: 50 additions & 24 deletions

File tree

src/uint/ref_type.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ use {
3030
/// This type contains a limb slice which can be borrowed from either a [`Uint`] or [`BoxedUint`] and
3131
/// thus provides an abstraction for writing shared implementations.
3232
#[repr(transparent)]
33-
#[derive(PartialEq, Eq)]
3433
pub struct UintRef {
3534
/// Inner limb array. Stored from least significant to most significant.
3635
// TODO(tarcieri): maintain an invariant of at least one limb?

src/uint/ref_type/cmp.rs

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use core::{cmp::Ordering, mem::transmute};
66

77
use super::UintRef;
8-
use crate::{Choice, Limb, word};
8+
use crate::{Choice, CtEq, Limb, word};
99

1010
impl UintRef {
1111
/// Returns the truthy value if `self` is odd or the falsy value otherwise.
@@ -117,7 +117,7 @@ impl UintRef {
117117
Ordering::Equal
118118
}
119119

120-
/// Returns the truthy value if `self < rhs` and the falsy value otherwise.
120+
/// Returns the truthy value if `lhs < rhs` and the falsy value otherwise.
121121
#[inline(always)]
122122
pub(crate) const fn lt(lhs: &Self, rhs: &Self) -> Choice {
123123
let overlap = if lhs.nlimbs() < rhs.nlimbs() {
@@ -140,6 +140,26 @@ impl UintRef {
140140
}
141141
}
142142

143+
impl Eq for UintRef {}
144+
145+
impl Ord for UintRef {
146+
fn cmp(&self, other: &Self) -> Ordering {
147+
Self::cmp(self, other)
148+
}
149+
}
150+
151+
impl PartialOrd for UintRef {
152+
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
153+
Some(self.cmp(other))
154+
}
155+
}
156+
157+
impl PartialEq for UintRef {
158+
fn eq(&self, other: &Self) -> bool {
159+
self.ct_eq(other).into()
160+
}
161+
}
162+
143163
#[cfg(test)]
144164
mod tests {
145165
use core::cmp::Ordering;
@@ -149,40 +169,47 @@ mod tests {
149169

150170
#[test]
151171
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+
152183
let z_small = UintRef::new(&[Limb::ZERO, Limb::ZERO]);
153184
let z_big = UintRef::new(&[Limb::ZERO, Limb::ZERO, Limb::ZERO]);
154185
let a = UintRef::new(&[Limb::ZERO, Limb::ZERO, Limb::ONE]);
155186
let b = UintRef::new(&[Limb::ONE, Limb::ZERO]);
156187

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);
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);
174196
}
175197

176198
#[test]
177199
fn lt() {
200+
fn check(a: &UintRef, b: &UintRef) {
201+
assert!(UintRef::lt(a, b).to_bool_vartime());
202+
assert!(!UintRef::lt(b, a).to_bool_vartime());
203+
assert!(a < b);
204+
assert!(b > a);
205+
}
206+
178207
let lesser = UintRef::new(&[Limb::ZERO, Limb::ZERO, Limb::ZERO]);
179208
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());
209+
check(lesser, greater);
182210

183211
let smaller = UintRef::new(&[Limb::ZERO, Limb::ZERO]);
184212
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());
213+
check(smaller, bigger);
187214
}
188215
}

0 commit comments

Comments
 (0)