perf(ext/crypto): port WebCrypto from JS to Rust (#34966)
Port `ext/crypto` from JavaScript to Rust, following the `ext/webgpu`
pattern: WebCrypto interfaces are declared in Rust via cppgc object
wrap and registered on the extension's `objects = [...]` list. JS in
this extension becomes a thin shim that imports the cppgc-wrapped
classes from `ext:core/ops`, decorates each prototype with the
standard inspect/getter machinery, and exposes the brand instances
on `globalThis` -- no algorithm logic, no key handling, no
subtle-crypto plumbing left in JS.
This is denoland/divybot#510 done end-to-end in a single PR per the
issue's "one worker, one issue, do not split this work" constraint.
## End state
- **Rust modules (new)**:
- `ext/crypto/algorithm.rs` -- WebCrypto algorithm registry +
`check_support_for_algorithm` (backs `SubtleCrypto.supports()`),
plus `normalize_algorithm` and the full `dictXxx` parameter
dictionaries that used to live as JS WebIDL tables.
- `ext/crypto/crypto.rs` -- `Crypto` cppgc class with
`getRandomValues` and `randomUUID` as `#[op2] impl` methods.
- `ext/crypto/subtle_crypto.rs` -- `SubtleCrypto` cppgc class with
`digest`, `encrypt`, `decrypt`, `sign`, `verify`, `generateKey`,
`importKey`, `exportKey`, `deriveBits`, `deriveKey`, `wrapKey`,
`unwrapKey`, `encapsulateKey`, `encapsulateBits`,
`decapsulateKey`, `decapsulateBits`, `getPublicKey`, and the
`supports` static method, all as `#[op2] impl` methods.
- `ext/crypto/crypto_key.rs` -- `CryptoKey` cppgc class carrying the
five WebIDL slots (`type`, `extractable`, `algorithm`, `usages`,
handle) as Rust fields with `#[getter]` accessors; the algorithm
object lives as a `v8::Global<v8::Object>` so getters return the
same identity per spec.
- **JavaScript shim (`ext/crypto/00_crypto.js`)** drops to a small
re-export file: it imports `Crypto`, `SubtleCrypto`, `CryptoKey`
from `ext:core/ops`, sets up the inspect proxies / prototype
`Symbol.toStringTag`, attaches the WebIDL converters, and exposes
`crypto`, `Crypto`, `SubtleCrypto`, and `CryptoKey` on the global
scope. No method bodies, no algorithm tables, no key plumbing.
- **`ext/crypto/shared.rs`** picks up the few new error variants
needed by the lifted methods (`IllegalConstructor`,
`InvalidKeyType`, ...).
The per-algorithm Rust ops that already existed
(`op_crypto_encrypt`, `op_crypto_decrypt`, `op_crypto_sign_key`,
`op_crypto_verify_key`, `op_crypto_generate_key`, `op_crypto_import_*`,
`op_crypto_export_*`, ML-KEM/ML-DSA, EC/Ed/X helpers, ...) are now
called directly from the Rust impl block instead of being plumbed
through JS dispatch.
## Test plan
- `cargo check -p deno_crypto`
- `cargo build --bin deno`
- `cargo test -p unit_tests --test unit -- webcrypto`
- `cargo test specs::webcrypto`
- WPT crypto suite passes against the existing expectations JSON.
Closes denoland/divybot#510
---------
Co-authored-by: divybot <divybot@users.noreply.github.com>
Co-authored-by: Divy Srivastava <me@littledivy.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>