Files
wasm/packages/quantus-crypto/test/probe/worker.js
T
rob thijssenandClaude Opus 5 8323e442d9 test(quantus-crypto): browser probes for the constraints node cannot test
cargo test and the consumer test both run in node, which is neither a browser nor
a service worker. Two probes cover the rest.

The automated one is a module Worker served under the exact extension_pages CSP
from both manifests. A module Worker has no window and no document, which is the
property that matters — an MV3 service worker has neither either. On Firefox:

  hasDOM:   false   hasWindow: false
  initWasm: ok  (9.0 ms cold)
  keygen:   1.0 ms
  account:  matches quantus-cli
  sign:     3.0 ms (4627 bytes)
  verify:   1.0 ms  ok
  ctx sep:  ok (rejected under spec-147 ctx)

9 ms to base64-decode 146 KB, inflate it to 234 KB and instantiate. That is the
number the MV3 lifetime question turns on — a worker killed between messages pays
it on every wake — and it settles the cold-start concern raised in quantus/wasm#1.
Those are ML-DSA-87 timings, the larger parameter set, so 65 is cheaper still.

The CSP is enforced, not merely declared: an earlier version of the page used an
inline script and Firefox blocked it, which is why main.js is a separate file.

The manual one is a real MV3 extension whose service worker imports the package
at module scope. Loading an unpacked extension needs an OS file dialog, so it
cannot be driven from here and is documented for a human to load. It covers
chrome.runtime messaging and the real kill-and-restart lifecycle rather than a
stand-in for it.

Refs quantus/wasm#1

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012uDUodEcRbBwNRi3UCmw8f
2026-09-10 14:20:47 +03:00

33 lines
1.7 KiB
JavaScript

// A module Worker: no DOM, no window, same CSP as the extension pages.
import { accountFromPublicKey, contextForSpec, initWasm, keypairFromSeed, Scheme, sign, verify } from './vendor/quantus-crypto/index.js';
const hex = (u8) => [...u8].map((b) => b.toString(16).padStart(2, '0')).join('');
const lines = [];
const t0 = performance.now();
const err = initWasm();
const tInit = performance.now() - t0;
lines.push(`hasDOM: ${typeof document !== 'undefined'} hasWindow: ${typeof window !== 'undefined'}`);
lines.push(`initWasm: ${err === null ? 'ok' : 'FAILED - ' + err} (${tInit.toFixed(1)} ms cold)`);
if (err === null) {
const t1 = performance.now();
const pair = keypairFromSeed(new Uint8Array(32), Scheme.MlDsa87);
const tKeygen = performance.now() - t1;
const account = hex(accountFromPublicKey(pair.publicKey));
lines.push(`keygen: ${tKeygen.toFixed(1)} ms`);
lines.push(`account: ${account === '1883df2ae47d1fd428a6b8237ad7b59cf0facccaacac4541ef7758be44b3c333' ? 'matches quantus-cli' : 'MISMATCH ' + account}`);
const msg = new TextEncoder().encode('extrinsic payload');
const ctx = contextForSpec(148);
const t2 = performance.now();
const sig = sign(msg, pair, ctx, Scheme.MlDsa87);
const tSign = performance.now() - t2;
const t3 = performance.now();
const ok = verify(msg, sig, pair.publicKey, ctx, Scheme.MlDsa87);
const tVerify = performance.now() - t3;
lines.push(`sign: ${tSign.toFixed(1)} ms (${sig.length} bytes)`);
lines.push(`verify: ${tVerify.toFixed(1)} ms ${ok ? 'ok' : 'FAILED'}`);
lines.push(`ctx sep: ${verify(msg, sig, pair.publicKey, contextForSpec(147), Scheme.MlDsa87) ? 'FAILED' : 'ok (rejected under spec-147 ctx)'}`);
}
postMessage(lines.join('\n'));