2.7 KiB
AlgorithmRegistry
Purpose
In-package mapping from alg identifier to the concrete AlgorithmImpl that knows how to verify and (optionally) sign. The registry is seeded at module load with the 13 built-in algorithms required by RFC 7518 §3 and RFC 8037 (HS256/384/512, RS256/384/512, PS256/384/512, ES256/384/512, EdDSA, none). Downstream packages register experimental algorithms (e.g. ML-DSA, secp256k1) via AlgorithmRegistry.register without forking this package.
Features
defaultRegistry— the package-wide seeded registry consumed by the verify/sign pipelines.register(alg, impl)— add an algorithm; duplicate registration throwsJWS.ALG_UNSUPPORTED.lookup(alg)— returns the impl orundefined.lookupOrThrow(alg)— returns the impl or throwsJWS.ALG_UNSUPPORTED.has(alg)/algorithms()— introspection helpers.
Usage: Basic Example
import { defaultRegistry } from "@suaveplan/jws";
defaultRegistry.has("RS256"); // true
defaultRegistry.has("ML-DSA-44"); // false
Usage: Advanced Example
import {
AlgorithmRegistry,
type AlgorithmImpl,
defaultRegistry,
} from "@suaveplan/jws";
const mlDsa44: AlgorithmImpl<Uint8Array> = {
alg: "ML-DSA-44",
verify: async (signingInput, sig, pub) => myMlDsaImpl.verify(pub, sig, signingInput),
sign: async (signingInput, priv) => myMlDsaImpl.sign(priv, signingInput),
};
defaultRegistry.register("ML-DSA-44", mlDsa44);
// Or build an isolated registry for an integration test:
const isolated = new AlgorithmRegistry();
isolated.register("HS256", myHsImpl);
API Reference
class AlgorithmRegistryregister<K>(alg: string, impl: AlgorithmImpl<K>): voidlookup(alg: string): AlgorithmImpl<unknown> | undefinedlookupOrThrow(alg: string): AlgorithmImpl<unknown>has(alg: string): booleanalgorithms(): readonly string[]
const defaultRegistry: AlgorithmRegistryinterface AlgorithmImpl<K = unknown> { alg: string; verify(signingInput, signature, key: K): Promise<boolean>; sign?(signingInput, key: K): Promise<Uint8Array> }seedBuiltinAlgorithms(): void— idempotent seeding (already invoked at module load).
Implementation Notes
Built-ins are seeded by the side-effect import import "./builtin.js" at the root of algorithms/index.ts AND src/index.ts. Idempotent via a module-scoped boolean so the registry survives test reload cycles. Registering an algorithm twice throws rather than silently overwriting, because silent overwrite would be an algorithm-confusion vector — a malicious downstream package could redefine RS256 to delegate to an attacker-controlled impl. The registry is mutable but only via register; there is no unregister for the same reason.