--- /dev/null
+#![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
+}