Skip to content

Commit ad12313

Browse files
committed
doc,test: clarify timingSafeEqual semantics
1 parent 0818b52 commit ad12313

File tree

2 files changed

+29
-2
lines changed

2 files changed

+29
-2
lines changed

doc/api/crypto.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5443,8 +5443,12 @@ changes:
54435443
* `b` {ArrayBuffer|Buffer|TypedArray|DataView}
54445444
* Returns: {boolean}
54455445

5446-
This function is based on a constant-time algorithm.
5447-
Returns true if `a` is equal to `b`, without leaking timing information that
5446+
This function compares the underlying bytes that represent the given
5447+
`ArrayBuffer`, `TypedArray`, or `DataView` instances using a constant-time
5448+
algorithm. If `a` and `b` are instances of the same `TypedArray` class, this is
5449+
equivalent to an element-wise [SameValue comparison][].
5450+
5451+
This function does not leak timing information that
54485452
would allow an attacker to guess one of the values. This is suitable for
54495453
comparing HMAC digests or secret values like authentication cookies or
54505454
[capability urls](https://www.w3.org/TR/capability-urls/).
@@ -6104,6 +6108,7 @@ See the [list of SSL OP Flags][] for details.
61046108
[RFC 4122]: https://www.rfc-editor.org/rfc/rfc4122.txt
61056109
[RFC 5208]: https://www.rfc-editor.org/rfc/rfc5208.txt
61066110
[RFC 5280]: https://www.rfc-editor.org/rfc/rfc5280.txt
6111+
[SameValue comparison]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness
61076112
[Web Crypto API documentation]: webcrypto.md
61086113
[`BN_is_prime_ex`]: https://www.openssl.org/docs/man1.1.1/man3/BN_is_prime_ex.html
61096114
[`Buffer`]: buffer.md

test/sequential/test-crypto-timing-safe-equal.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,28 @@ assert.strictEqual(
3232
}
3333
}
3434

35+
{
36+
// timingSafeEqual has SameValue semantics, not equality semantics, when the
37+
// inputs are floating-point numbers.
38+
39+
const cmp = (fn) => (a, b) => a.every((x, i) => fn(x, b[i]));
40+
const eq = cmp((a, b) => a === b);
41+
const is = cmp(Object.is);
42+
43+
// NaN !== NaN, but Object.is(NaN, NaN) === true.
44+
const a = new Float32Array(10).fill(NaN);
45+
assert.strictEqual(eq(a, a), false);
46+
assert.strictEqual(is(a, a), true);
47+
assert.strictEqual(crypto.timingSafeEqual(a, a), true);
48+
49+
// 0 === -0, but Object.is(0, -0) === false.
50+
const pos0 = new Float64Array(10).fill(0);
51+
const neg0 = new Float64Array(10).fill(-0);
52+
assert.strictEqual(eq(pos0, neg0), true);
53+
assert.strictEqual(is(pos0, neg0), false);
54+
assert.strictEqual(crypto.timingSafeEqual(pos0, neg0), false);
55+
}
56+
3557
assert.throws(
3658
() => crypto.timingSafeEqual(Buffer.from([1, 2, 3]), Buffer.from([1, 2])),
3759
{

0 commit comments

Comments
 (0)