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 }