Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,108 @@
# Tasks — crypto-keys
> Every checkbox MUST reflect work actually done in this change.
## 1. Spec authoring
- [x] 1.1 Read `openspec/AGENTS.md` §0, §0a, §0b, §0c, §6a, §7, §13, §14 end-to-end
- [x] 1.2 Read `../suaveplan/packages/universal/keys/src/lib/chain-signer.ts` in full
- [x] 1.3 Read `../suaveplan/packages/universal/keys/src/lib/keys-common.ts` (factory section)
- [x] 1.4 Read `../suaveplan/enterprise/keys.md` to confirm scope boundary
- [x] 1.5 Read genesis `packages/crypto/crypto/src/keychain/keychain.ts` and `keychain/index.ts` (public surface)
- [x] 1.6 Skim every `packages/crypto/crypto-curve/src/primitives/*/impl/*.noble/*.ts` and confirm sign/verify signature
- [x] 1.7 Draft `proposal.md` with scope, divergence table, source mapping, affected dependents
- [x] 1.8 Draft `design.md` covering file layout, three codecs, three hashers, algorithm dispatch, error-code map, factory layer
- [x] 1.9 Draft `specs/crypto-keys/spec.md` with `### Requirement: / #### Scenario: / **Verified by:**` form
- [x] 1.10 Run `openspec validate add-crypto-keys` and fix any structural failures
## 2. Scaffolding
- [x] 2.1 Create `packages/crypto/crypto-keys/` mirroring `packages/database/seed/` layout
- [x] 2.2 Write `package.json` v0.0.0, `sideEffects: false`, subpath exports for every feature module (error-codes/error-codes, types/{chain-level,hasher,codec}, hashers/{raw,domain,merkle}/<name>, codecs/{tlv,recursive-ed25519,cbor}/<name>, signer/signer, factory/factory)
- [x] 2.3 Wire deps: `@suaveplan/crypto: workspace:^`, `@suaveplan/crypto-curve: workspace:^`, `@suaveplan/crypto-hash: workspace:^`, `@suaveplan/cbor: workspace:^`, `@suaveplan/error: workspace:^`, `@suaveplan/types: workspace:^`, `tslib: catalog:build`
- [x] 2.4 Wire devDeps: `@suaveplan/testing: workspace:^`, `@types/node: catalog:`, `@vitest/coverage-istanbul: catalog:testing`, `fast-check: catalog:testing`, `typescript: catalog:`, `vite: catalog:build`, `vite-plugin-dts: catalog:build`, `vitest: catalog:testing`
- [x] 2.5 Write `tsconfig.json`, `tsconfig.lib.json` extending the genesis base
- [x] 2.6 Write `vite.config.ts` (multi-entry, ES-only, preserveModules)
- [x] 2.7 Write `vitest.config.ts` using a project-local config with `pool: 'forks'` + 100% Istanbul thresholds
- [x] 2.8 Write `tests/setup/polyfills.ts` (universal tier, no polyfills needed — same pattern as seed)
- [x] 2.9 Write `README.md` (≥ 200 words, all 6 required sections per CLAUDE.md docs gate)
## 3. Implementation — errors & shared types
- [x] 3.1 `src/error-codes/error-codes.ts` — `defineCodes("CHAIN_KEYS", [...])` with 7 codes; `ChainKeysError extends SuaveplanError<ChainKeysErrorCode>` with `depth?` / `algorithm?` discriminants
- [x] 3.2 `src/error-codes/error-codes.test.ts` — every code reachable from a `ChainKeysError` construction; `cause` chain preservation; discriminants populate
- [x] 3.3 `src/error-codes/error-codes.md` — full doc with required sections
- [x] 3.4 `src/error-codes/index.ts` — explicit named re-exports
- [x] 3.5 `src/types/chain-level.ts` — `ChainLevel`, `VerificationResult`, `ParsedChainLevel` interfaces; `chain-level.md` sibling
- [x] 3.6 `src/types/hasher.ts` — `ChainHasher` interface (`hash`, `name`); `hasher.md` sibling
- [x] 3.7 `src/types/codec.ts` — `ChainCodec` interface (`encode`, `decode`, `name`); `codec.md` sibling
## 4. Implementation — hashers (3)
- [x] 4.1 `src/hashers/raw/raw.ts` — `RawHasher implements ChainHasher` (identity hash)
- [x] 4.2 `src/hashers/raw/raw.test.ts` — identity property; ignores parent; name is "raw"
- [x] 4.3 `src/hashers/raw/raw.md` + `index.ts`
- [x] 4.4 `src/hashers/domain/domain.ts` — `DomainHasher implements ChainHasher` with constructor-supplied `domainTag` (1–64 ASCII bytes); raises `CHAIN_KEYS.INVALID_DOMAIN_TAG`
- [x] 4.5 `src/hashers/domain/domain.test.ts` — `sha256(utf8(tag) || encodedKeys)`; constructor validation (empty / oversize); ignores parent; name is "domain"
- [x] 4.6 `src/hashers/domain/domain.md` + `index.ts`
- [x] 4.7 `src/hashers/merkle/merkle.ts` — `MerkleHasher implements ChainHasher`; root hash without parent, parent root hash for non-root
- [x] 4.8 `src/hashers/merkle/merkle.test.ts` — root path; non-root commits to parent; tampering with parent invalidates child
- [x] 4.9 `src/hashers/merkle/merkle.md` + `index.ts`
## 5. Implementation — codecs (3)
- [x] 5.1 `src/codecs/tlv/tlv.ts` — `TlvChainCodec implements ChainCodec`; `[version=1][hasher][per level: algorithm + keys_len:u16 + keys + sig_len:u16 + sig]`; algorithm-id ↔ enum byte table; hasher-name ↔ enum byte table; raises `CHAIN_KEYS.INVALID_FORMAT` on bad version/truncation/length overrun
- [x] 5.2 `src/codecs/tlv/tlv.test.ts` — encode/decode round-trip for every algorithm; truncated buffer; bad version byte; length overrun; multi-level chain
- [x] 5.3 `src/codecs/tlv/tlv.md` + `index.ts`
- [x] 5.4 `src/codecs/recursive-ed25519/recursive-ed25519.ts` — `RecursiveEd25519Codec implements ChainCodec`; fixed `keys_size = 8 * KEY_SLOT_PUBLIC_BYTE_SIZE`; rejects non-Ed25519 at encode (`CHAIN_KEYS.UNSUPPORTED_ALGORITHM`)
- [x] 5.5 `src/codecs/recursive-ed25519/recursive-ed25519.test.ts` — Ed25519 round-trip; non-Ed25519 rejection; multi-level recursion; bad version
- [x] 5.6 `src/codecs/recursive-ed25519/recursive-ed25519.md` + `index.ts`
- [x] 5.7 `src/codecs/cbor/cbor.ts` — `CborChainCodec implements ChainCodec`; CBOR map `{ v, h, levels: [{ a, k, s }] }`; deterministic encoder; rejects unknown `h`/`a` strings
- [x] 5.8 `src/codecs/cbor/cbor.test.ts` — encode/decode round-trip; deterministic byte equality; bad CBOR; missing fields
- [x] 5.9 `src/codecs/cbor/cbor.md` + `index.ts`
## 6. Implementation — ChainedKeySigner
- [x] 6.1 `src/signer/signer.types.ts` — `ISigner` / `SignerOptions` / `SignerSignOptions` interfaces
- [x] 6.2 `src/signer/signer.ts` — `ChainedKeySigner` class:
- constructor `{ hasher?, codec? }` defaults `RawHasher` + `TlvChainCodec`
- `sign(publicKeys, signSlot, parent?)` — encodes public keychain, computes bytes-to-sign via hasher (passing parsed parent's leaf level if applicable), dispatches to `@suaveplan/crypto-curve` sign by `signSlot.algorithm`, prepends new level via codec
- `verify(chainBytes, trustedRoot)` — decodes via codec, walks every level computing the same bytes-to-sign, dispatches to `crypto-curve` verify, checks deepest signer matches `trustedRoot.public` via constant-time compare, returns `{ valid, depth, levels, errors }`
- `parse(chainBytes)` — decode-only
- `stripToDepth(chainBytes, depth)` — re-encode the leaf-most `depth` levels via codec
- Wraps any crypto-curve exception as `ChainKeysError` with `cause` preserved
- [x] 6.3 `src/signer/signer.test.ts` — every public method × every (hasher, codec) combination × every algorithm; tampering tests at every byte boundary; abort signal future-proofing (omitted intentionally; sign is in-memory)
- [x] 6.4 `src/signer/signer.md` + `index.ts`
## 7. Implementation — hierarchical factory
- [x] 7.1 `src/factory/factory.ts` — `createRootKeysWithChain`, `createServerKeysWithChain`, `rollServerKeysWithChain`; all default to `new ChainedKeySigner()` when omitted; raise `CHAIN_KEYS.INVALID_KEYCHAIN` when `rootKeys.master`/`rootKeys.sign` lacks private material
- [x] 7.2 `src/factory/factory.test.ts` — 3-level chain (root → server → user); verify against root; tamper at server level → fails; missing root.master / root.sign → INVALID_KEYCHAIN; injected signer with non-default hasher works end-to-end
- [x] 7.3 `src/factory/factory.md` + `index.ts`
## 8. Root barrel & public surface
- [x] 8.1 `src/index.ts` — re-export every public symbol via explicit named exports (no `export *` — rule §6a)
- [x] 8.2 Verify `bunx turbo build --filter=@suaveplan/crypto-keys` succeeds and dist contains every advertised subpath
## 9. Pre-archive gates
- [x] 9.1 `bunx turbo lint --filter=@suaveplan/crypto-keys` green; zero biome suppressions
- [x] 9.2 `bunx turbo typecheck --filter=@suaveplan/crypto-keys` green
- [x] 9.3 `bunx turbo test --filter=@suaveplan/crypto-keys` green; zero `.skip` / `.only` / `it.todo`
- [x] 9.4 `bunx turbo test:coverage --filter=@suaveplan/crypto-keys` green at 100% statement/branch/function/line (Istanbul)
- [x] 9.5 `bun run docs:check --filter=@suaveplan/crypto-keys` green
- [x] 9.6 `grep -rnE "from ['\"](vitest|bun:test)['\"]" packages/crypto/crypto-keys/src/` → zero matches (rule §7)
- [x] 9.7 `grep -rnE "^export \*" packages/crypto/crypto-keys/src/` → only the root barrel and exempt forms (rule §6a)
- [x] 9.8 `grep -rnE "from ['\"](node:|bun:|fs|path|stream|net|http)['\"]" packages/crypto/crypto-keys/src/` → zero matches (universal tier)
- [x] 9.9 `grep -rn "@deprecated\|TODO\|FIXME\|ts-ignore\|ts-expect-error\|\\.skip\|\\.only\|\\bany\\b\|console\\.log" packages/crypto/crypto-keys/src/ --include="*.ts"` → zero matches
- [x] 9.10 Every `### Requirement` in `specs/crypto-keys/spec.md` checked off against the implementation
- [x] 9.11 `bun scripts/folder-reorg/generate-manifest.ts`; `MANIFEST.md` includes `@suaveplan/crypto-keys`
- [x] 9.12 `STATUS.md` row added or updated — entry under crypto plugin, status `✅`
## 10. Fold + archive
- [x] 10.1 Fold `specs/crypto-keys/spec.md` into `openspec/specs/crypto-keys/spec.md` (new canonical capability; convert `## ADDED Requirements` → `## Requirements` and prepend `## Purpose`)
- [x] 10.2 `openspec validate crypto-keys` clean
- [x] 10.3 Move `openspec/changes/add-crypto-keys/` → `openspec/archive/$(date +%Y-%m-%d)-add-crypto-keys/`
- [x] 10.4 Commit per CLAUDE.md commit-style; do not push without user approval