Drop signing-key.verifying-key; generate-key returns the key pair - #59
Merged
Conversation
A `signing-key` promised material a provider may not hold. Deriving the public half from a private key is not a WebCrypto operation: recovering the point from a private-only import is an unspecified spec gap (w3c/webcrypto#356) that engines answer differently, and a keystore-resident non-extractable key can sign while yielding nothing else. An infallible derive therefore makes an entire class of legitimate keys unservable — the same reasoning that keeps class D out of the in-guest provider and mandated non-approved behavior out of the WIT. Remove the method. `ed25519-sign`/`ecdsa-sign` `generate-key` now return `tuple<signing-key, verifying-key>`: every platform hands over both halves at generation, so the public key is available exactly where it is guaranteed to exist. Importers mint it from the public bytes they hold via `import-verifying-key`. A fallible per-algorithm derive stays possible additively if a seed-only-import need ever materializes. On the jco host this removes the reason signature private keys were imported platform-extractable: the WIT flag is now the `CryptoKey`'s own, so the platform enforces non-extractability and the README's claim about it becomes true for signature keys, not just HMAC/AES. `derivePublicKey` and its unattributable `error.other` lift go with it; the ECDSA private-only PKCS#8 import is documented as the best-effort path it is. The suites keep their coverage without the derive: the Ed25519 RFC 8032 known answer verifies its signature under the vector's public key (pinning that seed and key are one pair), and the round-trip probes use the pair returned by generation.
This was referenced Jul 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A
signing-keyresource promised material a provider may not hold.Deriving the public half from a private key is not a WebCrypto operation.
Recovering the point from a private-only import is a recognized spec gap
(w3c/webcrypto#356) that engines answer differently, and a keystore-resident
non-extractable key can sign while yielding nothing else. Because
signing-key.verifying-keywas infallible by contract, both of thoselegitimate key shapes were unservable — the jco host had to fail the whole
import when the derive failed. This is the same reasoning that keeps class D
algorithms out of the in-guest provider and mandated non-approved behavior out
of the WIT: the package should not require behavior a legitimate provider
cannot supply.
The change
signature.signing-key.verifying-key.ed25519-signandecdsa-signgenerate-keynow returnresult<tuple<signing-key, verifying-key>, error>— every platform handsover both halves at generation, so the public key is available exactly where
it is guaranteed to exist. Importers mint it from the public bytes they hold
via
import-verifying-key. Evolved in0.1.0in place, per the precedent ofthe
digest.computereturn-type change and the ChaCha interface split.if a seed-only-import need ever materializes; removal does not foreclose it,
while the infallible method did foreclose keystore-resident keys.
Cascading effect on the jco host
Signature private keys were imported and generated platform-
extractable: truesolely so
derivePublicKeycould do its JWK round-trip, which demoted the WITextractability gate to a JS boolean. With no derive, the WIT flag is passed
straight to
importKey/generateKey, so the platformCryptoKeyenforcesnon-extractability for signature keys exactly as it already did for HMAC/AES —
and README.md's claim about that becomes true rather than aspirational
(#28's second checklist item, resolved structurally rather than by weakening
the docs).
derivePublicKeyand its unattributableerror.otherlift are deletedoutright. The ECDSA private-only PKCS#8 import is now documented as the
best-effort path it is: it works where the platform cooperates and declines
with
invalid-keywhere it does not, which the WIT permits.Suite coverage without the derive
vector's public key, which pins that the imported seed and that key are one
pair — the property the derived-point comparison was there for.
verifying-key-export-roundtripexports the generated public half.Verification
just check(fmt, clippy, WIT, Rust tests)just transpile,just test-nodeTwo gates could not run locally and are left to CI:
jco-browser(no Chrome onthis machine) and
test-webcrypto-componentize-wpt— the WPT runner's inputlock hashes
wit/*.wit, so any WIT change invalidates it and thewpt-componentjob builds a fresh one. The componentize-sdk surface(HMAC-SHA-256 + AES-256-GCM) is untouched by this change.
Issue tracking
Addresses the second checklist item of #28 (README overclaims platform
enforcement of extractability) at its root. Deliberately does not close
#28: the third item (JWK
d-string exposure inSigningKey.exportKey) remainsopen. Note that the mint-time half of that exposure is gone with
derivePublicKey— what remains is the per-exportdstring, addressableseparately by exporting via
pkcs8and parsing the DER.