Skip to content

Commit 96180fa

Browse files
committed
Harden constant-time equality on arrays and slices
1 parent 22606eb commit 96180fa

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
@@ -287,12 +287,6 @@ pub trait ConstantTimeEq {
287287
impl<T: ConstantTimeEq> ConstantTimeEq for [T] {
288288
/// Check whether two slices of `ConstantTimeEq` types are equal.
289289
///
290-
/// # Note
291-
///
292-
/// This function short-circuits if the lengths of the input slices
293-
/// are different. Otherwise, it should execute in time independent
294-
/// of the slice contents.
295-
///
296290
/// Since arrays coerce to slices, this function works with fixed-size arrays:
297291
///
298292
/// ```
@@ -309,23 +303,17 @@ impl<T: ConstantTimeEq> ConstantTimeEq for [T] {
309303
/// ```
310304
#[inline]
311305
fn ct_eq(&self, _rhs: &[T]) -> Choice {
312-
let len = self.len();
313-
314-
// Short-circuit on the *lengths* of the slices, not their
315-
// contents.
316-
if len != _rhs.len() {
317-
return Choice::from(0);
318-
}
306+
// Determine if the lengths are equal in constant time
307+
let len_ct_eq = self.len().ct_eq(&_rhs.len());
319308

320-
// This loop shouldn't be shortcircuitable, since the compiler
321-
// shouldn't be able to reason about the value of the `u8`
322-
// unwrapped from the `ct_eq` result.
323-
let mut x = 1u8;
309+
// Check each byte for equality in constant time
310+
let mut contents_ct_eq = Choice::from(1u8);
324311
for (ai, bi) in self.iter().zip(_rhs.iter()) {
325-
x &= ai.ct_eq(bi).unwrap_u8();
312+
contents_ct_eq &= ai.ct_eq(bi);
326313
}
327314

328-
x.into()
315+
// Now check that the length and bytes are both equal in constant time
316+
len_ct_eq & contents_ct_eq
329317
}
330318
}
331319

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)