Summary
The auths-verifier WASM is moving to carry a public key's curve in-band instead of inferring it from byte length. The attestation/chain verify functions are gaining an explicit curve argument that defaults to P-256 when omitted (no more length inference). This widget calls those functions without a curve and verifies Ed25519 attestations, so once the new WASM is vendored, Ed25519 verification will fail — a 32-byte key parsed as P-256 is rejected.
Current state / blast radius
- Not broken today. The widget ships a pre-built WASM in
wasm/ that predates the change.
- It breaks the moment that bundle is rebuilt from the updated
auths-verifier and re-vendored, unless we thread the curve through first.
src/resolvers/did-utils.ts (lines ~6-7) even documents the old contract: "the WASM verifier resolves the curve from that length." That assumption is going away.
Break mechanism
- New WASM signatures:
verifyAttestationJson(json, pk, curve?), verifyChainJson(arr, pk, curve?), verifyAttestationWithResult(json, pk, curve?), verifyChainWithWitnesses(…, curve?). With curve absent → defaults to P-256, no length inference.
src/verifier-bridge.ts calls these with 2 args (≈ lines 88, 111, 141, 154). Missing curve → undefined → P-256.
- The widget's fixtures are all 32-byte Ed25519 issuer keys (
tests/fixtures/attestation.fixture.js), so try_new(P256, 32 bytes) fails → verification breaks.
Fix (curve-agnostic — no guessing)
The widget already knows each key's curve: didKeyToPublicKeyHex (src/resolvers/did-utils.ts) decodes the multicodec varint (0xED 0x01 → Ed25519, 0x80 0x24 → P-256) and currently discards the curve. Surface it and pass it through:
src/resolvers/did-utils.ts — have didKeyToPublicKeyHex (and cesrToPublicKeyHex) also return the curve (e.g. { hex, curve: 'ed25519' | 'p256' }), or add a sibling that returns it. Update the stale comment that says the WASM infers curve from length.
src/verifier-bridge.ts — thread curve into verifyAttestation / verifyChain / verifyAttestationJson / verifyChainJson and pass it as the new WASM argument. Add curve?: string | null to the WasmModule interface (≈ lines 18-20).
packages/auths-verifier-ts (in the auths repo) — mirror the same change; it also calls the verify functions with 2 args (src/index.ts ≈ 144, 189).
- Re-vendor the rebuilt WASM +
.d.ts (wasm/auths_verifier.*).
Acceptance criteria
- Ed25519 and P-256 attestations/chains verify correctly through the widget against the rebuilt WASM.
- No curve is inferred from key length anywhere in the JS path; the curve is derived from the issuer/root did:key (or CESR) and passed explicitly.
verifier-bridge tests + the regression tests cover both curves.
Context
Upstream is the auths-verifier FFI/WASM curve hardening (carry the curve in-band rather than dispatching on byte length, which is ambiguous — 32 bytes is Ed25519 vs X25519, 33 is P-256 vs secp256k1). This issue tracks the widget-side follow-through so the WASM rebuild doesn't silently break Ed25519 verification.
Summary
The
auths-verifierWASM is moving to carry a public key's curve in-band instead of inferring it from byte length. The attestation/chain verify functions are gaining an explicitcurveargument that defaults to P-256 when omitted (no more length inference). This widget calls those functions without a curve and verifies Ed25519 attestations, so once the new WASM is vendored, Ed25519 verification will fail — a 32-byte key parsed as P-256 is rejected.Current state / blast radius
wasm/that predates the change.auths-verifierand re-vendored, unless we thread the curve through first.src/resolvers/did-utils.ts(lines ~6-7) even documents the old contract: "the WASM verifier resolves the curve from that length." That assumption is going away.Break mechanism
verifyAttestationJson(json, pk, curve?),verifyChainJson(arr, pk, curve?),verifyAttestationWithResult(json, pk, curve?),verifyChainWithWitnesses(…, curve?). Withcurveabsent → defaults to P-256, no length inference.src/verifier-bridge.tscalls these with 2 args (≈ lines 88, 111, 141, 154). Missingcurve→undefined→ P-256.tests/fixtures/attestation.fixture.js), sotry_new(P256, 32 bytes)fails → verification breaks.Fix (curve-agnostic — no guessing)
The widget already knows each key's curve:
didKeyToPublicKeyHex(src/resolvers/did-utils.ts) decodes the multicodec varint (0xED 0x01→ Ed25519,0x80 0x24→ P-256) and currently discards the curve. Surface it and pass it through:src/resolvers/did-utils.ts— havedidKeyToPublicKeyHex(andcesrToPublicKeyHex) also return the curve (e.g.{ hex, curve: 'ed25519' | 'p256' }), or add a sibling that returns it. Update the stale comment that says the WASM infers curve from length.src/verifier-bridge.ts— threadcurveintoverifyAttestation/verifyChain/verifyAttestationJson/verifyChainJsonand pass it as the new WASM argument. Addcurve?: string | nullto theWasmModuleinterface (≈ lines 18-20).packages/auths-verifier-ts(in theauthsrepo) — mirror the same change; it also calls the verify functions with 2 args (src/index.ts≈ 144, 189)..d.ts(wasm/auths_verifier.*).Acceptance criteria
verifier-bridgetests + the regression tests cover both curves.Context
Upstream is the
auths-verifierFFI/WASM curve hardening (carry the curve in-band rather than dispatching on byte length, which is ambiguous — 32 bytes is Ed25519 vs X25519, 33 is P-256 vs secp256k1). This issue tracks the widget-side follow-through so the WASM rebuild doesn't silently break Ed25519 verification.