Utilities
bytesconvertsUint8Arrays to and from hex, joins them, and compares them, withtimingSafeEqualfor secrets.errorsholds the error classes that every package throws, andErrors.is, which checks an error's kind even when an app has two copies of a package. The errors guide shows how to use them.randomgives unbiased random integers, strings, and shuffles fromcrypto.getRandomValues, and a seeded generator for tests.
Check a signature in constant time
Compare secrets with Bytes.timingSafeEqual. An ordinary comparison returns at the first byte that differs, and the time it takes leaks how much of the signature an attacker guessed right.
import * as Bytes from '@portable/bytes';
const expected = new Uint8Array(
await crypto.subtle.sign('HMAC', key, payload),
);
if (!Bytes.timingSafeEqual(expected, Bytes.fromHex(signature))) {
throw new Error('Bad signature');
}