Skip to content

Commit

Permalink
Harden constant-time equality on arrays and slices
Browse files Browse the repository at this point in the history
perf
  • Loading branch information
AaronFeickert committed Aug 21, 2024
1 parent f1f8e53 commit f5a5c48
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 22 deletions.
26 changes: 7 additions & 19 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,12 +289,6 @@ pub trait ConstantTimeEq {
impl<T: ConstantTimeEq> 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:
///
/// ```
Expand All @@ -311,23 +305,17 @@ impl<T: ConstantTimeEq> 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 = 1u8;
for (ai, bi) in self.iter().zip(_rhs.iter()) {
x &= ai.ct_eq(bi).unwrap_u8();
contents_ct_eq &= ai.ct_eq(bi).unwrap_u8();
}

x.into()
// Now check that the length and bytes are both equal in constant time
len_ct_eq & contents_ct_eq.into()
}
}

Expand Down
5 changes: 2 additions & 3 deletions tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down

0 comments on commit f5a5c48

Please sign in to comment.