Skip to content

Commit 2f626d3

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

File tree

2 files changed

+37
-2
lines changed

2 files changed

+37
-2
lines changed

doc/api/crypto.md

+15-2
Original file line numberDiff line numberDiff line change
@@ -5443,8 +5443,11 @@ 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.
5449+
5450+
It returns true if `a` is equal to `b`, without leaking timing information that
54485451
would allow an attacker to guess one of the values. This is suitable for
54495452
comparing HMAC digests or secret values like authentication cookies or
54505453
[capability urls](https://www.w3.org/TR/capability-urls/).
@@ -5453,6 +5456,15 @@ comparing HMAC digests or secret values like authentication cookies or
54535456
must have the same byte length. An error is thrown if `a` and `b` have
54545457
different byte lengths.
54555458

5459+
This function does not compare the elements of `a` and `b` directly. Instead, it
5460+
compares the bitwise representations of `a` and `b`. If `a` and `b` are
5461+
instances of the same `TypedArray` class, this is equivalent to an element-wise
5462+
[SameValue comparison][].
5463+
5464+
<strong class="critical">In particular, this function does not follow the usual
5465+
definition of equality for floating-point numbers when `a` or `b` is a
5466+
`Float32Array` or a `Float64Array`.</strong>
5467+
54565468
If at least one of `a` and `b` is a `TypedArray` with more than one byte per
54575469
entry, such as `Uint16Array`, the result will be computed using the platform
54585470
byte order.
@@ -6104,6 +6116,7 @@ See the [list of SSL OP Flags][] for details.
61046116
[RFC 4122]: https://www.rfc-editor.org/rfc/rfc4122.txt
61056117
[RFC 5208]: https://www.rfc-editor.org/rfc/rfc5208.txt
61066118
[RFC 5280]: https://www.rfc-editor.org/rfc/rfc5280.txt
6119+
[SameValue comparison]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness
61076120
[Web Crypto API documentation]: webcrypto.md
61086121
[`BN_is_prime_ex`]: https://www.openssl.org/docs/man1.1.1/man3/BN_is_prime_ex.html
61096122
[`Buffer`]: buffer.md

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

+22
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)