Skip to content

Commit f5a5c48

Browse files
committed
Harden constant-time equality on arrays and slices
perf
1 parent f1f8e53 commit f5a5c48

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
@@ -289,12 +289,6 @@ pub trait ConstantTimeEq {
289289
impl<T: ConstantTimeEq> ConstantTimeEq for [T] {
290290
/// Check whether two slices of `ConstantTimeEq` types are equal.
291291
///
292-
/// # Note
293-
///
294-
/// This function short-circuits if the lengths of the input slices
295-
/// are different. Otherwise, it should execute in time independent
296-
/// of the slice contents.
297-
///
298292
/// Since arrays coerce to slices, this function works with fixed-size arrays:
299293
///
300294
/// ```
@@ -311,23 +305,17 @@ impl<T: ConstantTimeEq> ConstantTimeEq for [T] {
311305
/// ```
312306
#[inline]
313307
fn ct_eq(&self, _rhs: &[T]) -> Choice {
314-
let len = self.len();
315-
316-
// Short-circuit on the *lengths* of the slices, not their
317-
// contents.
318-
if len != _rhs.len() {
319-
return Choice::from(0);
320-
}
308+
// Determine if the lengths are equal in constant time
309+
let len_ct_eq = self.len().ct_eq(&_rhs.len());
321310

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

330-
x.into()
317+
// Now check that the length and bytes are both equal in constant time
318+
len_ct_eq & contents_ct_eq.into()
331319
}
332320
}
333321

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)