Skip to content

Commit ac6dee3

Browse files
committed
Harden constant-time equality on arrays and slices
1 parent 6b6a81a commit ac6dee3

File tree

2 files changed

+9
-22
lines changed

2 files changed

+9
-22
lines changed

src/lib.rs

+7-19
Original file line numberDiff line numberDiff line change
@@ -299,12 +299,6 @@ pub trait ConstantTimeEq {
299299
impl<T: ConstantTimeEq> ConstantTimeEq for [T] {
300300
/// Check whether two slices of `ConstantTimeEq` types are equal.
301301
///
302-
/// # Note
303-
///
304-
/// This function short-circuits if the lengths of the input slices
305-
/// are different. Otherwise, it should execute in time independent
306-
/// of the slice contents.
307-
///
308302
/// Since arrays coerce to slices, this function works with fixed-size arrays:
309303
///
310304
/// ```
@@ -321,23 +315,17 @@ impl<T: ConstantTimeEq> ConstantTimeEq for [T] {
321315
/// ```
322316
#[inline]
323317
fn ct_eq(&self, _rhs: &[T]) -> Choice {
324-
let len = self.len();
325-
326-
// Short-circuit on the *lengths* of the slices, not their
327-
// contents.
328-
if len != _rhs.len() {
329-
return Choice::from(0);
330-
}
318+
// Determine if the lengths are equal in constant time
319+
let len_ct_eq = self.len().ct_eq(&_rhs.len());
331320

332-
// This loop shouldn't be shortcircuitable, since the compiler
333-
// shouldn't be able to reason about the value of the `u8`
334-
// unwrapped from the `ct_eq` result.
335-
let mut x = 1u8;
321+
// Check each byte for equality in constant time
322+
let mut contents_ct_eq = Choice::from(1u8);
336323
for (ai, bi) in self.iter().zip(_rhs.iter()) {
337-
x &= ai.ct_eq(bi).unwrap_u8();
324+
contents_ct_eq &= ai.ct_eq(bi);
338325
}
339326

340-
x.into()
327+
// Now check that the length and bytes are both equal in constant time
328+
len_ct_eq & contents_ct_eq
341329
}
342330
}
343331

tests/mod.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,11 @@ use rand::RngCore;
66
use subtle::*;
77

88
#[test]
9-
#[should_panic]
10-
fn slices_equal_different_lengths() {
9+
fn slices_different_lengths() {
1110
let a: [u8; 3] = [0, 0, 0];
1211
let b: [u8; 4] = [0, 0, 0, 0];
1312

14-
assert_eq!((&a).ct_eq(&b).unwrap_u8(), 1);
13+
assert_eq!((&a).ct_eq(&b).unwrap_u8(), 0);
1514
}
1615

1716
#[test]

0 commit comments

Comments
 (0)