Files
suaveplan/openspec/archive/2026-04-19-crypto-primitive-replaceability/specs/crypto-cipher/spec.md
2026-05-27 23:29:53 +01:00

3.5 KiB

ADDED Requirements

Requirement: Universal AEAD primitive surface

@suaveplan/crypto-cipher SHALL expose a stable public API for the AEAD primitives listed below, independent of the underlying implementation source.

Scenario: AEAD primitives available

  • WHEN a consumer imports from @suaveplan/crypto-cipher
  • THEN aes256gcm, chacha20poly1305, xchacha20poly1305 are exported
  • AND each primitive exposes encrypt(key, nonce, plaintext, aad?) and decrypt(key, nonce, ciphertext, aad?) returning / consuming Uint8Array
  • AND each primitive is also exported from the subpath @suaveplan/crypto-cipher/<id> for tree-shaking

Requirement: Per-primitive replaceability

Every AEAD in @suaveplan/crypto-cipher SHALL have both a vendor-forked noble implementation and a native implementation slot, selected per-primitive at build time via the root crypto.config.ts.

Scenario: Every AEAD has both impl files

  • WHEN the package is inspected
  • THEN every primitive id has both src/primitives/<id>/impl/<id>.noble.ts and src/primitives/<id>/impl/<id>.native.ts
  • AND the native.ts file is either a working implementation or a stub that throws PrimitiveNotImplemented('<id>')

Requirement: Vendored noble source (Phase 0.5)

From Phase 0.5 onward, the noble implementation for every AEAD SHALL come from a vendor-fork of @noble/ciphers stored inside this package, not from the @noble/ciphers npm package.

Scenario: No external runtime dependency on @noble/ciphers (post-0.5)

  • WHEN packages/universal/crypto-cipher/package.json is inspected after Phase 0.5
  • THEN @noble/ciphers does not appear in dependencies or peerDependencies
  • AND src/vendored/ contains the forked source with its original LICENSE preserved
  • AND NOBLE_UPSTREAM.md records the pinned upstream commit SHA and sync date

Requirement: Dangerous-tier CI gate

Every primitive in this package belongs to the dangerous tier. An AEAD's default SHALL NOT be changed from 'noble' to 'native' in crypto.config.ts unless the flip PR demonstrates all gates required by crypto-hash, plus a third-party cryptographic audit sign-off covering the specific native implementation being flipped.

Scenario: Audit required to flip

  • WHEN a PR modifies crypto.config.ts to change an AEAD entry from 'noble' to 'native'
  • THEN the flip PR template requires an audit report (PDF + auditor signature) attached to the PR
  • AND the audit report references the exact commit SHA of the native impl being flipped

Requirement: Constant-time block-cipher and MAC implementation

Native AES implementations SHALL be bitsliced or use hardware intrinsics — table-lookup AES is prohibited. Native Poly1305 and GHASH implementations SHALL NOT contain data-dependent branches.

Scenario: Constant-time lint enforces this

  • WHEN any impl/*.native.ts in this package is modified
  • THEN scripts/ct-lint.ts scans for prohibited patterns (secret-indexed array access, data-dependent branches, early returns on tag comparison)
  • AND any match fails CI with a line-level diagnostic

Requirement: Nonce handling is the caller's responsibility

Primitives in this package SHALL NOT generate nonces internally. All nonce inputs are supplied by the caller.

Scenario: No internal random nonce

  • WHEN encrypt(...) is invoked
  • THEN no call to a CSPRNG is made inside the primitive
  • AND the nonce parameter is required and validated for length