/**
* Deterministic `crypto.getRandomValues` for byte-exact sealing vectors.
*
* Sealer's IV epoch and AtRestCipher's per-encryption IV are random by design
* (PROTOCOL.md §3 — there is no API that accepts a caller-supplied IV, so
* nonce reuse is structurally impossible). That makes real sealing output
* unreproducible, which would leave the vectors able to prove only
* round-tripping.
*
* So the harness replaces ONLY `getRandomValues` with a seeded mulberry32
* stream and leaves `crypto.subtle` untouched and real: every derivation,
* AES-GCM tag and Ed25519 signature in the vectors is produced by the actual
* WebCrypto implementation, while the IVs become a known sequence. Both the
* TypeScript original and the ClojureScript port then emit byte-identical
* ciphertext for the same input, so the vectors pin the ciphertext itself and
* not merely "it decrypts".
*
* Cross-implementation round trips with REAL randomness are kept as well
* (TS-sealed fixtures unsealed by the port); this only adds the stronger check.
*/
const real = globalThis.crypto;
let state = 0;
/** mulberry32 — the suite's usual small deterministic PRNG. */
function next() {
state = (state + 0x6d2b79f5) | 0;
let t = state;
t = Math.imul(t ^ (t >>> 15), t | 1);
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
return ((t ^ (t >>> 14)) >>> 0) & 0xff;
}
export function resetRandom(seed = 1) {
state = seed | 0;
}
/** Install the stub. Idempotent; `crypto.subtle` stays the real one. */
export function installDetRandom() {
if (globalThis.crypto?.__det) return;
const stub = {
__det: true,
subtle: real.subtle,
randomUUID: () => real.randomUUID(),
getRandomValues(buf) {
const b = new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
for (let i = 0; i < b.length; i++) b[i] = next();
return buf;
},
};
Object.defineProperty(globalThis, "crypto", { value: stub, configurable: true, writable: true });
}
/** Restore the platform crypto (for the real-randomness round-trip cases). */
export function restoreRandom() {
Object.defineProperty(globalThis, "crypto", { value: real, configurable: true, writable: true });
}
export const hex = (u8) => [...u8].map((b) => b.toString(16).padStart(2, "0")).join("");