Files
suaveplan/openspec/archive/2026-05-02-crypto-spec-conformance/proposal.md
2026-05-27 23:29:53 +01:00

4.9 KiB

OpenSpec Change: crypto-spec-conformance

  • Change ID: crypto-spec-conformance
  • Package: @suaveplan/crypto
  • Status: PROPOSED
  • Date: 2026-04-26

Summary

Realign the folded openspec/specs/crypto/spec.md with the actual surface of @suaveplan/crypto (the multi-algorithm façade), add a cross-cutting src/crypto.spec-conformance.test.ts, and annotate every requirement with a **Verified by:** line so bun scripts/openspec-conformance.ts @suaveplan/crypto exits 0. Two prior archived change folders (2026-04-19-crypto-primitive-replaceability, 2026-04-19-enterprise-crypto) carry retroactively ticked markers that the conformance script downgrades to info once a *-spec-conformance rectification exists. No public-API changes.

Current state

@suaveplan/crypto is the engine-pluggable façade composing the per-primitive subpackages (crypto-utils, crypto-hash, crypto-curve, crypto-cipher). Its surface is AEAD (3 algorithms), Ed25519 / ECDSA-P256 sign-verify, X25519 agreement, sealed-box, auth-box, constantTimeEqual, zeroize, randomBytes (single CSPRNG callsite), and a CRYPTO_CODES registry. Per-feature unit tests cover the happy paths, AAD authentication, tampered-ciphertext rejection, key/nonce length validation, fast-check round-trip properties, and engine substitution. The conformance gaps are:

  • Spec drift. The folded openspec/specs/crypto/spec.md was the original enterprise-crypto proposal — it specs sha256, sha384, sha512, hmac, hkdf, pbkdf2, argon2id as exports of this façade. After the per-primitive split those primitives moved to @suaveplan/crypto-hash. The Purpose section is the literal placeholder TBD - created by archiving change enterprise-crypto. Update Purpose after archive. All 13 requirements lack **Verified by:** lines.
  • Implicit cross-cutting invariants are unpinned. Engine pluggability across all five operation namespaces, the AEAD nonce-is-caller-supplied invariant (no internal randomness in src/aead/), verify returning a boolean (never throwing) on bad signatures, the single-crypto.getRandomValues-callsite property, and the structured-error-no-leak rule for AEAD failures are all stated by the spec but not directly asserted by any test.
  • Retroactive ticking debt. Archived change folders 2026-04-19-crypto-primitive-replaceability/tasks.md and 2026-04-19-enterprise-crypto/tasks.md contain retroactively ticked, which the conformance script flags as error until a *-spec-conformance rectification folder exists.

What changes

  1. Rewrite openspec/specs/crypto/spec.md to reflect the actual façade surface:
    • Fill the ## Purpose section.
    • Replace the drifted hash / KDF / argon2id requirements (which now live in @suaveplan/crypto-hash's spec) with thirteen requirements that match the façade: engine pluggability, AEAD round-trip across three algorithms, AEAD nonce-caller-supplied invariant, AEAD authentication-failure leak rule, Ed25519 / ECDSA-P256 sign-verify with verify boolean contract, X25519 stability, sealed-box authenticity, auth-box sender authentication, constant-time-equal, zeroize, single CSPRNG callsite, structured-errors-with-stable-registry, and 100% coverage gate.
    • Add a **Verified by:** line to every ### Requirement: block pointing at concrete *.test.ts::"name" test cases.
  2. Add src/crypto.spec-conformance.test.ts covering:
    • Default-engine wiring across all five namespaces.
    • Custom-engine substitution suppresses the default for sign and agree.
    • AEAD façade source contains zero byte-source consumption (grep over src/aead/).
    • AEAD decryption-failure error context is restricted to { algorithm, ciphertextLength }.
    • Ed25519 / ECDSA-P256 verify returns false (never throws) on a wrong message.
    • X25519 agreement is byte-stable across repeated calls.
    • constantTimeEqual source contains no return / break inside its compare loop — only an XOR accumulator.
    • zeroize mutates in place (same Uint8Array reference).
    • Exactly one crypto.getRandomValues(...) callsite in src/, located in src/primitives/random-bytes.ts.
    • Every CRYPTO_CODES entry is referenced from at least one non-test source file.
    • CRYPTO_CODES is frozen.
    • Engine type exports compile.
  3. Rectify retroactive-ticking debt. Creating this crypto-spec-conformance change folder downgrades the prior retroactively ticked markers in archived task lists from error to info per the conformance-script policy.

Impact

  • Public API unchanged.
  • One new test file (~330 lines, under the 500-line budget).
  • openspec/specs/crypto/spec.md rewritten to reflect the actual façade surface; the prior text described primitives that have since moved to @suaveplan/crypto-hash.
  • Coverage stays at 100/100/100/100; the new tests exercise existing production code paths plus structural source-text invariants.
  • No new runtime dependencies.