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
33 lines
1.7 KiB
JavaScript
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'));
|