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
#![no_std]
// This function is non-inline to prevent the optimizer from looking inside it.
#[inline(never)]
fn constant_time_ne(a: &[u8], b: &[u8]) -> u8 {
assert!(a.len() == b.len());
// These useless slices make the optimizer elide the bounds checks.
// See the comment in clone_from_slice() added on Rust commit 6a7bc47.
let len = a.len();
let a = &a[..len];
let b = &b[..len];
let mut tmp = 0;
for i in 0..len {
tmp |= a[i] ^ b[i];
}
tmp // The compare with 0 must happen outside this function.
}
/// Compares two equal-sized byte strings in constant time.
///
/// # Examples
///
/// ```
/// use constant_time_eq::constant_time_eq;
///
/// assert!(constant_time_eq(b"foo", b"foo"));
/// assert!(!constant_time_eq(b"foo", b"bar"));
/// assert!(!constant_time_eq(b"bar", b"baz"));
/// # assert!(constant_time_eq(b"", b""));
///
/// // Not equal-sized, so won't take constant time.
/// assert!(!constant_time_eq(b"foo", b""));
/// assert!(!constant_time_eq(b"foo", b"quux"));
/// ```
#[inline]
pub fn constant_time_eq(a: &[u8], b: &[u8]) -> bool {
a.len() == b.len() && constant_time_ne(a, b) == 0
}
// Fixed-size variants for the most common sizes.
macro_rules! constant_time_ne_n {
($ne:ident, $n:expr) => {
// This function is non-inline to prevent the optimizer from looking inside it.
#[inline(never)]
fn $ne(a: &[u8; $n], b: &[u8; $n]) -> u8 {
let mut tmp = 0;
for i in 0..$n {
tmp |= a[i] ^ b[i];
}
tmp // The compare with 0 must happen outside this function.
}
};
}
constant_time_ne_n!(constant_time_ne_16, 16);
constant_time_ne_n!(constant_time_ne_32, 32);
constant_time_ne_n!(constant_time_ne_64, 64);
/// Compares two 128-bit byte strings in constant time.
///
/// # Examples
///
/// ```
/// use constant_time_eq::constant_time_eq_16;
///
/// assert!(constant_time_eq_16(&[3; 16], &[3; 16]));
/// assert!(!constant_time_eq_16(&[3; 16], &[7; 16]));
/// ```
#[inline]
pub fn constant_time_eq_16(a: &[u8; 16], b: &[u8; 16]) -> bool {
constant_time_ne_16(a, b) == 0
}
/// Compares two 256-bit byte strings in constant time.
///
/// # Examples
///
/// ```
/// use constant_time_eq::constant_time_eq_32;
///
/// assert!(constant_time_eq_32(&[3; 32], &[3; 32]));
/// assert!(!constant_time_eq_32(&[3; 32], &[7; 32]));
/// ```
#[inline]
pub fn constant_time_eq_32(a: &[u8; 32], b: &[u8; 32]) -> bool {
constant_time_ne_32(a, b) == 0
}
/// Compares two 512-bit byte strings in constant time.
///
/// # Examples
///
/// ```
/// use constant_time_eq::constant_time_eq_64;
///
/// assert!(constant_time_eq_64(&[3; 64], &[3; 64]));
/// assert!(!constant_time_eq_64(&[3; 64], &[7; 64]));
/// ```
#[inline]
pub fn constant_time_eq_64(a: &[u8; 64], b: &[u8; 64]) -> bool {
constant_time_ne_64(a, b) == 0
}