first commit
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
# `range/constant-time-compare.ts`
|
||||
|
||||
## Purpose
|
||||
|
||||
`constantTimeEqualsHex` compares two hex suffixes without early-exit on
|
||||
the first mismatching character. It is used by the range-API client to
|
||||
verify whether any line in the response matches the input password's
|
||||
35-char suffix, so a timing-side-channel attacker cannot infer which
|
||||
slot the real suffix lands in. The instrumented variant
|
||||
(`constantTimeEqualsHexInstrumented`) returns the byte-XOR count for
|
||||
test assertions.
|
||||
|
||||
## Features
|
||||
|
||||
- Branch-free byte loop using OR-accumulator over XOR pairs.
|
||||
- Touches every byte of the input — no length-based shortcut beyond the
|
||||
initial length-mismatch check.
|
||||
- ASCII-only (uppercase hex) inputs guarantee `charCodeAt` is
|
||||
single-byte, keeping per-character cost predictable.
|
||||
- Test instrumentation exposed without changing the hot path.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import { constantTimeEqualsHex } from "@suaveplan/hibp";
|
||||
|
||||
if (constantTimeEqualsHex(line.suffix, target)) {
|
||||
/* matched */
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { constantTimeEqualsHexInstrumented } from "@suaveplan/hibp";
|
||||
|
||||
const { equal, bytesTouched } = constantTimeEqualsHexInstrumented(a, b);
|
||||
if (!equal && bytesTouched !== a.length) {
|
||||
throw new Error("comparator regressed to early-exit");
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `constantTimeEqualsHex(a: string, b: string): boolean`.
|
||||
- `constantTimeEqualsHexInstrumented(a, b): { equal, bytesTouched }`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
JavaScript does not expose a true constant-time string compare, but the
|
||||
loop pattern above is the canonical approximation. The OR-accumulator
|
||||
trick converts every byte XOR into a single boolean test at the end,
|
||||
eliminating the data-dependent branch that an `if (a[i] !== b[i])
|
||||
return false` would introduce. The length-mismatch check leaks only the
|
||||
public fact that the two strings differ in length, which is never
|
||||
secret in this protocol. The test suite asserts the wall-clock mean
|
||||
delta between equal and unequal pairs stays within tolerance over
|
||||
10 000 samples; the more rigorous proof is the bytes-touched
|
||||
invariant.
|
||||
Reference in New Issue
Block a user