Files
suaveplan/openspec/archive/2026-05-03-restore-crypto-opinionated-layer/tasks.md
2026-05-27 23:29:53 +01:00

6.3 KiB

Tasks — restore-crypto-opinionated-layer

1. Authority concrete backend

  • 1.1 Implement InMemoryAuthority against the existing Authority interface (sign under DerivationCoordinate slot, validity-window check, revoked-slot rejection)
  • 1.2 dispose() zeroises every slot's secret material
  • 1.3 Tests: sign-success, sign-with-revoked-slot-fails, sign-with-out-of-window-key-fails, dispose-zeroises, AbortSignal cancellation
  • 1.4 Co-located .md

2. Identity hierarchy

  • 2.1 RootIdentity and ServerIdentity typed wrappers
  • 2.2 createRoot(rng, clock, options) — generates root keychain + signs its own public bundle
  • 2.3 createServer(rootAuthority, options) — generates server keychain, signed under root
  • 2.4 rollServer(rootAuthority, serverIdentity, options) — version-bump rotation; emits CRL entry for prior version; appends audit-log entry
  • 2.5 revokeServer(rootAuthority, serverRef, reason) — appends CRL + audit entries; no re-issue
  • 2.6 Tests: createRoot self-verifies; createServer parent-signed; rollServer increments version + emits CRL; revokeServer appends without re-issue
  • 2.7 Co-located .md per file

3. Three-regime Vault

  • 3.1 Vault class with three regimes: public bundle (parent-signed plaintext), private-key blob (password-AEAD), vault payload (auth-box-sealed under keypair, parent-signed under DOMAIN_VAULT_V1)
  • 3.2 pack / unpack round-trip
  • 3.3 changePassword re-encrypts the private-key blob without re-deriving the keychain
  • 3.4 rotateApplicationData re-seals payload only (keys untouched)
  • 3.5 lock() zeroises secrets
  • 3.6 BIP39 restore re-derives identical keychain
  • 3.7 Argon2id parameter floor enforced
  • 3.8 Tests: round-trip, tamper-detect, wrong-password-distinct-from-tamper, BIP39-restore, lock-zeroises, Argon2id-floor, changePassword-without-re-derive, payload-data-round-trip, rotateApplicationData-keys-untouched
  • 3.9 Delete vault/legacy-vault/ after the new Vault ships and any internal callers migrate
  • 3.10 Co-located .md (≥ 200 words) covering the three regimes

4. Packer / Unpacker

  • 4.1 Packer.pack(value, schema, recipientAuthority, senderAuthority, domainTag) — encrypt-then-sign envelope
  • 4.2 Unpacker.unpack(envelope, recipientAuthority, senderPublicBundle, domainTag, options) — verify-then-decrypt
  • 4.3 Replay-window check via issuedAt + nonce; rejects envelopes outside window or with seen nonce
  • 4.4 Tests: round-trip, recipient-verifies-sender, tamper-detect, replay-rejection, mismatched-domain-tag-fails
  • 4.5 Co-located .md

5. ChunkedPacker / ChunkedUnpacker

  • 5.1 ChunkedPacker.packFileToChunks(stream, recipient, sender, options) — per-chunk-signed fragmentation
  • 5.2 ChunkedUnpacker.reassembleFile(chunks, options) — assemble; rejects on tampered chunk
  • 5.3 Tests: 1-chunk, N-chunk, tampered-chunk-rejected, missing-chunk-rejected, out-of-order-chunks-handled
  • 5.4 Co-located .md

6. RevocationList

  • 6.1 RevocationList with append(entry, rootAuthority), verify(rootPublicBundle), check(serverRef)
  • 6.2 Append-only invariant (mutating past entries invalidates the list)
  • 6.3 Tests: append-then-verify, mutate-past-entry-fails, check-revoked-server-true, check-non-revoked-server-false
  • 6.4 Co-located .md

7. AuditLog

  • 7.1 AuditLog append-only Merkle log; root signed by rootAuthority
  • 7.2 append(event), verify(rootPublicBundle), inclusion(eventId) proof
  • 7.3 Tampering with any past entry invalidates the root signature
  • 7.4 Tests: append-roots-correctly, tamper-past-entry-fails, inclusion-proof-verifies
  • 7.5 Co-located .md

8. Wire-format schemas + KAT fixtures

  • 8.1 Define DERIVATION_COORDINATE_SCHEMA
  • 8.2 Define KEY_SLOT_PRIVATE_SCHEMA, KEY_SLOT_PUBLIC_SCHEMA
  • 8.3 Define VAULT_PAYLOAD_SCHEMA
  • 8.4 Define PUBLIC_BUNDLE_SCHEMA (magic("SVPB") ‖ formatVersion ‖ issuerRef ‖ issuedAt ‖ nonce ‖ subjectRef ‖ slots[] ‖ parentSignature[64])
  • 8.5 Define CHAIN_BUNDLE_SCHEMA (magic("SVCB") ‖ formatVersion ‖ linkCount ‖ links[])
  • 8.6 Define CRL_ENTRY_SCHEMA, AUDIT_ENTRY_SCHEMA
  • 8.7 Commit eight golden-bytes fixtures under test-fixtures/wire-format/
  • 8.8 tests/wire-format-kat.test.ts byte-for-byte assertion
  • 8.9 Co-located .md per schema

9. Property-based round-trip

  • 9.1 tests/property-roundtrips.test.ts using fast-check
  • 9.2 Cover every pack/unpack pair: keychain, vault, public bundle, chain bundle, packer envelope, chunk, CRL entry, audit entry

10. Error codes

  • 10.1 Add PACKER.ENCRYPT_FAILED, PACKER.SIGN_FAILED, PACKER.REPLAY_REJECTED, PACKER.DOMAIN_TAG_MISMATCH
  • 10.2 Add CHUNK.TAMPERED, CHUNK.MISSING, CHUNK.OUT_OF_ORDER
  • 10.3 Add CRL.NOT_VERIFIED, CRL.MUTATED
  • 10.4 Add AUDIT.ROOT_MISMATCH, AUDIT.INCLUSION_PROOF_FAILED
  • 10.5 Add VAULT.PAYLOAD_DECRYPT_FAILED, VAULT.PAYLOAD_VERIFY_FAILED
  • 10.6 Add AUTHORITY.SLOT_REVOKED, AUTHORITY.SLOT_OUT_OF_WINDOW
  • 10.7 Each code thrown by ≥ 1 production code path (asserted by tests/codes-thrown.test.ts)

11. Verification gates

  • 11.1 bun run check — Biome 0/0/0
  • 11.2 bunx turbo lint typecheck test --filter=@suaveplan/crypto green
  • 11.3 bunx turbo test:coverage --filter=@suaveplan/crypto 100/100/100/100
  • 11.4 bunx turbo test --filter=...@suaveplan/crypto (dependent sweep) green
  • 11.5 OpenSpec conformance script clean

12. Pre-archive 7-row checklist (AGENTS.md Section 13)

  • 12.1 Generics threaded; expectTypeOf assertions on every literal-type claim
  • 12.2 Zod schemas wired at every declared boundary
  • 12.3 Every error code thrown by at least one production path
  • 12.4 Strict-mode behaviours tested both on and off
  • 12.5 OTel instruments emitted from production paths and asserted with a real MeterProvider
  • 12.6 Lifecycle dedup tested where claimed (replay-window nonces, CRL append-only)
  • 12.7 No retroactive tick

13. Archive

  • 13.1 Fold spec deltas into openspec/specs/crypto/spec.md
  • 13.2 Move openspec/changes/restore-crypto-opinionated-layer/ → openspec/archive/<yyyy-mm-dd>-restore-crypto-opinionated-layer/