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
// This function is non-inline to prevent the optimizer from looking inside it.
#[inline(never)]
fn constant_time_ne(a: &[u8], b: &[u8]) -> u8 {
	// Compares the sizes here so the optimizer knows a.len() == b.len()
	if a.len() != b.len() { return !0; }

	let mut tmp = 0;
	for i in 0..a.len() {
		tmp |= a[i] ^ b[i];
		// Ideally, should use an inline asm here:
		// asm!("" : "=r" (tmp) : "0" (tmp));
		// But asm! is not stable yet.
		// With the inline asm, this function could be inlined
		// since the asm would prevent the optimizer from doing
		// an early return.
	}
	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"));
///
/// // 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 {
	constant_time_ne(a, b) == 0
}