Files
skills/docs/security-stack/security/jws/src/algorithms/registry.md
2026-05-29 08:20:56 +01:00

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 throws JWS.ALG_UNSUPPORTED.
  • lookup(alg) — returns the impl or undefined.
  • lookupOrThrow(alg) — returns the impl or throws JWS.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 AlgorithmRegistry
    • register<K>(alg: string, impl: AlgorithmImpl<K>): void
    • lookup(alg: string): AlgorithmImpl<unknown> | undefined
    • lookupOrThrow(alg: string): AlgorithmImpl<unknown>
    • has(alg: string): boolean
    • algorithms(): readonly string[]
  • const defaultRegistry: AlgorithmRegistry
  • interface 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.