forked from RustCrypto/utils
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathct_lt.rs
More file actions
107 lines (94 loc) · 2.59 KB
/
ct_lt.rs
File metadata and controls
107 lines (94 loc) · 2.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use crate::Choice;
use core::{
cmp,
num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize},
};
/// Constant time less than.
pub trait CtLt {
/// Compute whether `self < other` in constant time.
#[must_use]
fn ct_lt(&self, other: &Self) -> Choice;
}
// Impl `CtLt` using overflowing subtraction
macro_rules! impl_unsigned_ct_lt {
( $($uint:ty),+ ) => {
$(
impl CtLt for $uint {
#[inline]
fn ct_lt(&self, other: &Self) -> Choice {
let (_, overflow) = self.overflowing_sub(*other);
Choice(overflow.into())
}
}
)+
};
}
impl_unsigned_ct_lt!(u8, u16, u32, u64, u128, usize);
/// Impl `CtLt` for `NonZero<T>` by calling `NonZero::get`.
macro_rules! impl_ct_lt_for_nonzero_integer {
( $($ty:ty),+ ) => {
$(
impl CtLt for $ty {
#[inline]
fn ct_lt(&self, other: &Self) -> Choice {
self.get().ct_lt(&other.get())
}
}
)+
};
}
impl_ct_lt_for_nonzero_integer!(
NonZeroU8,
NonZeroU16,
NonZeroU32,
NonZeroU64,
NonZeroU128,
NonZeroUsize
);
impl CtLt for cmp::Ordering {
#[inline]
fn ct_lt(&self, other: &Self) -> Choice {
// No impl of `CtLt` for `i8`, so use `u8`
let a = (*self as i8) + 1;
let b = (*other as i8) + 1;
(a as u8).ct_lt(&(b as u8))
}
}
#[cfg(test)]
mod tests {
use super::CtLt;
use core::cmp::Ordering;
#[test]
fn ct_lt() {
let a = 42u64;
let b = 43u64;
assert!(!a.ct_lt(&a).to_bool());
assert!(a.ct_lt(&b).to_bool());
assert!(!b.ct_lt(&a).to_bool());
}
/// Test `CtLt`
macro_rules! ct_lt_tests {
( $($int:ident),+ ) => {
$(
mod $int {
use super::CtLt;
#[test]
fn ct_gt() {
let a = <$int>::MIN;
let b = <$int>::MAX;
assert!(!a.ct_lt(&a).to_bool());
assert!(a.ct_lt(&b).to_bool());
assert!(!b.ct_lt(&a).to_bool());
}
}
)+
};
}
ct_lt_tests!(u8, u16, u32, u64, u128, usize);
#[test]
fn ordering() {
assert!(!Ordering::Equal.ct_lt(&Ordering::Equal).to_bool());
assert!(Ordering::Less.ct_lt(&Ordering::Greater).to_bool());
assert!(!Ordering::Greater.ct_lt(&Ordering::Less).to_bool());
}
}