diff --git a/src/lib.rs b/src/lib.rs index e8b6524..589ea8e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -287,12 +287,6 @@ pub trait ConstantTimeEq { impl ConstantTimeEq for [T] { /// Check whether two slices of `ConstantTimeEq` types are equal. /// - /// # Note - /// - /// This function short-circuits if the lengths of the input slices - /// are different. Otherwise, it should execute in time independent - /// of the slice contents. - /// /// Since arrays coerce to slices, this function works with fixed-size arrays: /// /// ``` @@ -309,23 +303,17 @@ impl ConstantTimeEq for [T] { /// ``` #[inline] fn ct_eq(&self, _rhs: &[T]) -> Choice { - let len = self.len(); - - // Short-circuit on the *lengths* of the slices, not their - // contents. - if len != _rhs.len() { - return Choice::from(0); - } + // Determine if the lengths are equal in constant time + let len_ct_eq = self.len().ct_eq(&_rhs.len()); - // This loop shouldn't be shortcircuitable, since the compiler - // shouldn't be able to reason about the value of the `u8` - // unwrapped from the `ct_eq` result. - let mut x = 1u8; + // Check each byte for equality in constant time + let mut contents_ct_eq = Choice::from(1u8); for (ai, bi) in self.iter().zip(_rhs.iter()) { - x &= ai.ct_eq(bi).unwrap_u8(); + contents_ct_eq &= ai.ct_eq(bi); } - x.into() + // Now check that the length and bytes are both equal in constant time + len_ct_eq & contents_ct_eq } } diff --git a/tests/mod.rs b/tests/mod.rs index 51f9fd8..3fc7f94 100644 --- a/tests/mod.rs +++ b/tests/mod.rs @@ -6,12 +6,11 @@ use rand::RngCore; use subtle::*; #[test] -#[should_panic] -fn slices_equal_different_lengths() { +fn slices_different_lengths() { let a: [u8; 3] = [0, 0, 0]; let b: [u8; 4] = [0, 0, 0, 0]; - assert_eq!((&a).ct_eq(&b).unwrap_u8(), 1); + assert_eq!((&a).ct_eq(&b).unwrap_u8(), 0); } #[test]