170 lines
23 KiB
Markdown
170 lines
23 KiB
Markdown
# Crypto completion — streaming AEAD, recovery, device keys, scrypt, blake2b, password helpers, hash-password CLI
|
||
|
||
**Packages**: `@suaveplan/crypto`, `@suaveplan/crypto-cipher`, `@suaveplan/crypto-curve`, `@suaveplan/crypto-hash`, `@suaveplan/crypto-keys`
|
||
**Status**: PROPOSED
|
||
**Type**: feature + spec-conformance
|
||
|
||
## Why
|
||
|
||
The 2026-05-02 audit of the genesis crypto stack against `../suaveplan/packages/universal/crypto/src` identified seven confirmed feature gaps that the upstream package shipped but the genesis sub-packages do not. None of these are MAJOR architecture changes — they are concrete capabilities (streaming AEAD, ECDSA recovery, device keys, scrypt KDF, blake2b hashing + password helpers, password-driven AEAD wrappers, and the `hash-password` CLI) that downstream consumers (drive, network, audit-logging, slsa) currently work around or block on. Genesis policy (CLAUDE.md §Workflow rule 5) says "preserve the full public surface during rewrites — trimming is OK ONLY when code is duplicated elsewhere in-repo or can be replaced by an existing `@suaveplan/*` library", and none of these seven features are duplicated by anything that already landed.
|
||
|
||
Closing all seven in one coordinated pass is preferable to seven small changes because (a) they share validation utilities and `crypto-utils` helpers that have to land at the same revision to avoid mid-port circular pins, (b) the streaming AEAD façade in `crypto/aead` and the engine in `crypto-cipher/primitives` are linked — adding either alone leaves the public surface incoherent, and (c) the password helpers (`encryptWithPassword`, `deriveKeyFromPassword`) sit on top of the new scrypt + blake2b primitives, so they cannot ship until those primitives exist.
|
||
|
||
The seven gaps:
|
||
|
||
1. **Streaming AEAD** (`crypto-cipher` + `crypto/aead`): `encryptStreamAead` / `decryptStreamAead` async generators (255 L), `aesGcmStreamingEngine` and `xchacha20StreamingEngine` engines (35 L each), `createEncryptionStream` / `createDecryptionStream` Web-Streams adapters, `streamEncrypt` / `streamDecrypt` legacy aliases, `collectStream`, `createStreamKey`, `createStreamEncryption` (430 L of `streaming.ts`).
|
||
2. **secp256k1 ECDSA recovery** (`crypto-curve/primitives/secp256k1`): `signWithRecovery`, `recoverPublicKey`, `verifyWithRecovery` — all three present in upstream (lines 74, 143, 243 of `signing.ts`) and absent from the genesis 5-method secp256k1 noble engine.
|
||
3. **Device-key suite** (`crypto-keys/keypair/device`): `createDeviceKey`, `deriveDeviceKeyFromMaster`, `generateDeviceUUID`, `extractDeviceMetadata`, `compareDeviceKeys`, `isValidDeviceKey`, plus `generateDerivedDeviceId` for one-release back-compat (261 L of `device.ts`).
|
||
4. **scrypt KDF** (`crypto-hash/primitives/scrypt`): N/r/p parameter set, salt + outputLength, async via `@noble/hashes/scrypt` (53 L of `hashing.ts` lines L273-L325).
|
||
5. **blake2b hashing** (`crypto-hash/primitives/blake2b`): variable output length, optional key, plus `hashPasswordBlake2b` / `verifyPasswordBlake2b` constant-time wrappers with the parameterised `$blake2b$v=1$cf=N$salt$hash` format.
|
||
6. **encryptWithPassword + deriveKeyFromPassword** (`crypto/password`): the high-level "password → encrypted blob" pattern (Argon2id-derived key + AEAD), 344 L of `password.ts`.
|
||
7. **`hash-password` CLI bin** (new `packages/crypto/crypto-bin` or `crypto/bin/hash-password.ts`): a one-shot CLI that hashes a plaintext password to a verifier and exits 0/1 on verify (98 L of `bin/hash-password.ts`).
|
||
|
||
## What changes
|
||
|
||
### `@suaveplan/crypto-cipher`
|
||
|
||
- ADDED: `streaming/streaming-aead.ts` — `encryptStreamAead` and `decryptStreamAead` async generators with chunk-level header / footer tags, `EncryptStreamAeadOptions` and `DecryptStreamAeadOptions` (chunk size, AAD, AbortSignal, optional `header` callback for chunk-tag attestation).
|
||
- ADDED: `streaming/streaming-aead-aes-gcm.ts` — `aesGcmStreamingEngine: StreamingAeadEngine` adapter built on the existing `aes-256-gcm` primitive; nonce per chunk derived from a 12-byte base nonce + 32-bit counter (RFC 5116-compatible).
|
||
- ADDED: `streaming/streaming-aead-xchacha20.ts` — `xchacha20StreamingEngine: StreamingAeadEngine` adapter built on the existing `xchacha20-poly1305` primitive; nonce per chunk derived from a 24-byte base nonce + 32-bit counter.
|
||
- ADDED: `streaming/streaming-aead.types.ts` — `StreamingAeadEngine` interface, `StreamingChunkTag` interface, `StreamingHeader` interface.
|
||
- ADDED: error codes `CRYPTO_CIPHER.STREAM_TAG_MISMATCH`, `CRYPTO_CIPHER.STREAM_OUT_OF_ORDER`, `CRYPTO_CIPHER.STREAM_ABORTED`, `CRYPTO_CIPHER.STREAM_INVALID_NONCE_BASE`.
|
||
|
||
### `@suaveplan/crypto-curve`
|
||
|
||
- ADDED: `primitives/secp256k1/impl/secp256k1.noble/secp256k1.noble.ts` exports `signWithRecovery(digest, privateKey)`, `recoverPublicKey(signatureWithRecovery, digest)`, and `verifyWithRecovery(signatureWithRecovery, digest, expectedPublicKey)`. The signature-with-recovery byte layout is the canonical 65-byte form (64-byte compact signature + 1 recovery byte).
|
||
- ADDED: `primitives/secp256k1/impl/secp256k1.native/secp256k1.native.ts` matching surface (libsodium does not ship secp256k1 — native engine throws `CRYPTO_CURVE.PRIMITIVE_NOT_IMPLEMENTED` per genesis convention).
|
||
- MODIFIED: `secp256k1.select` re-exports the three new functions.
|
||
- ADDED: error codes `CRYPTO_CURVE.RECOVERY_BYTE_MISSING`, `CRYPTO_CURVE.RECOVERY_BYTE_INVALID`, `CRYPTO_CURVE.RECOVERED_KEY_MISMATCH`.
|
||
|
||
### `@suaveplan/crypto-hash`
|
||
|
||
- ADDED: `primitives/scrypt/scrypt.ts` — `scrypt(password, salt, options)` with `N`, `r`, `p`, `dkLen` parameters; uses `@noble/hashes/scrypt`'s `scryptAsync`.
|
||
- ADDED: `primitives/scrypt/scrypt.select` and `primitives/scrypt/impl/scrypt.noble/scrypt.noble.ts` matching the existing per-primitive selector layout.
|
||
- ADDED: `primitives/blake2b/blake2b.ts` — `blake2b(message, options)` with `dkLen` (1–64 bytes), optional `key`, optional `salt`, optional `personalization`.
|
||
- ADDED: `primitives/blake2b/blake2b.select` and `primitives/blake2b/impl/blake2b.noble/blake2b.noble.ts`.
|
||
- ADDED: `mac/blake2b-password/blake2b-password.ts` — `hashPasswordBlake2b(password, options)` and `verifyPasswordBlake2b(storedHash, password)`, using the `$blake2b$v=1$cf=<costFactor>$<saltHex>$<hashHex>` MCF-style format and constant-time comparison.
|
||
- ADDED: error codes `CRYPTO_HASH.SCRYPT_INVALID_N`, `CRYPTO_HASH.BLAKE2B_OUTPUT_TOO_LONG`, `CRYPTO_HASH.BLAKE2B_KEY_TOO_LONG`, `CRYPTO_HASH.BLAKE2B_PASSWORD_FORMAT_INVALID`.
|
||
|
||
### `@suaveplan/crypto-keys`
|
||
|
||
- ADDED: `keypair/device/device.ts` — `createDeviceKey`, `deriveDeviceKeyFromMaster`, `generateDeviceUUID`, `extractDeviceMetadata`, `compareDeviceKeys`, `isValidDeviceKey`, plus the `generateDerivedDeviceId` back-compat alias.
|
||
- ADDED: `keypair/device/device.types.ts` — `DeviceKey`, `MasterKey`, `DeviceKeyOptions`, `DeviceKeyDerivationOptions`, `DeviceIdOptions`, `DeviceMetadata` interfaces.
|
||
- ADDED: error codes `CRYPTO_KEYS.DEVICE_INVALID_MASTER`, `CRYPTO_KEYS.DEVICE_INVALID_KEY`, `CRYPTO_KEYS.DEVICE_DERIVATION_FAILED`.
|
||
|
||
### `@suaveplan/crypto`
|
||
|
||
- ADDED: `aead/streaming/streaming-aead.ts` — high-level façade `encryptStreamAead` / `decryptStreamAead` that selects the engine (`xchacha20-poly1305` or `aes-256-gcm`) from the opts argument and delegates to `crypto-cipher`. Re-exports `aesGcmStreamingEngine` and `xchacha20StreamingEngine`.
|
||
- ADDED: `aead/streaming/web-streams.ts` — `createEncryptionStream(opts)` and `createDecryptionStream(opts)` returning `TransformStream<Uint8Array, Uint8Array>` Web-Streams adapters; `collectStream(stream)`, `createStreamKey(rng?)`, `createStreamEncryption(opts)` helpers; `streamEncrypt` / `streamDecrypt` aliases preserved for back-compat.
|
||
- ADDED: `password/encrypt-with-password.ts` — `encryptWithPassword(password, plaintext, options?)` and `decryptWithPassword(password, ciphertext, options?)`. Default KDF is Argon2id; opt into scrypt via `kdf: "scrypt"` in options. Default cipher is `xchacha20-poly1305`. Output is a self-describing binary header (`magic`, `kdf`, `kdfParams`, `cipher`, `salt`, `nonce`) followed by the ciphertext.
|
||
- ADDED: `password/derive-key-from-password.ts` — `deriveKeyFromPassword(password, salt, options?)` returning a 32-byte `Uint8Array` suitable for use as a symmetric key. KDF selection (`argon2id` / `scrypt` / `pbkdf2`) is via the options bundle.
|
||
- ADDED: error codes `CRYPTO.STREAM_AEAD_HEADER_INVALID`, `CRYPTO.PASSWORD_KDF_UNKNOWN`, `CRYPTO.PASSWORD_BLOB_HEADER_INVALID`, `CRYPTO.PASSWORD_BLOB_VERSION_UNSUPPORTED`.
|
||
|
||
### `@suaveplan/crypto-bin` (new package)
|
||
|
||
- ADDED: a thin CLI package `packages/crypto/crypto-bin` whose only purpose is to ship the `hash-password` bin. Per-Suaveplan policy CLI surfaces live in their own package so they do not leak `@suaveplan/cli` runtime deps into the universal-tier `@suaveplan/crypto`. Depends on `@suaveplan/cli`, `@suaveplan/crypto-hash`, `@suaveplan/error`. Bin: `suaveplan-hash-password`. Reads a password from stdin or `--password`, writes a verifier hash (Argon2id by default, `--algo blake2b` opt-in) to stdout; with `--verify <stored>` reads `--password` and exits `0` on match, `1` on mismatch.
|
||
|
||
## Out of scope
|
||
|
||
- **Post-quantum signature primitives** (Dilithium, SPHINCS+, ML-KEM key-encapsulation) — separate `crypto-pqc-*` family of sub-packages already discussed in `STATUS.md`. Adding PQC primitives requires a separate engine adapter substrate that is larger than this entire change.
|
||
- **FIDO2 / WebAuthn helpers** — already covered by browser-tier deps in the genesis app shells; no upstream parity gap here.
|
||
- **HSM / KMS adapters** (CloudHSM, AWS KMS, GCP KMS) — operational concern, not a library gap; tracked separately under the audit-logging adapter family.
|
||
- **Argon2id parameter migration helper** — upstream ships `migrateArgon2idParams(oldHash, newOptions)` for re-hashing on login. Genesis already routes Argon2id verification through `crypto-hash/primitives/argon2id` and migration belongs in a future `auth` change, not in `crypto-hash`.
|
||
- **Modifying the existing Argon2id primitive** — the new `encryptWithPassword` defers to the existing `argon2id` primitive without changing its signature.
|
||
- **`crypto-vault` integration** — `crypto-vault` already wraps Argon2id-hardened HD derivation; once `scrypt` lands in `crypto-hash`, a follow-up change can add a `kdf: "scrypt"` option to the vault. Out of scope here to keep this change focused on the seven enumerated gaps.
|
||
|
||
## Source mapping
|
||
|
||
Genesis `enterprise/crypto.md` is a generic enterprise-quality template (no per-feature requirements), so source mapping cites the upstream package source directly.
|
||
|
||
| Requirement | Source file | Source lines | Notes |
|
||
|---|---|---|---|
|
||
| `encryptStreamAead` / `decryptStreamAead` async generators | `packages/universal/crypto/src/symmetric/streaming/streaming-aead.ts` | L11-L255 | Verbatim port; thread `AbortSignal` through |
|
||
| `aesGcmStreamingEngine` adapter | `packages/universal/crypto/src/symmetric/streaming/streaming-aead-aes-gcm.ts` | L9-L35 | Verbatim |
|
||
| `xchacha20StreamingEngine` adapter | `packages/universal/crypto/src/symmetric/streaming/streaming-aead-xchacha20.ts` | L9-L35 | Verbatim |
|
||
| `createEncryptionStream` / `createDecryptionStream` / `streamEncrypt` / `streamDecrypt` / `collectStream` / `createStreamKey` / `createStreamEncryption` | `packages/universal/crypto/src/symmetric/streaming/streaming.ts` | L23-L430 | Verbatim port; preserve `ChaCha20Stream` / `AESStream` named exports |
|
||
| `signWithRecovery` (secp256k1) | `packages/universal/crypto/src/asymmetric/signing/signing.ts` | L74-L120 | Verbatim |
|
||
| `recoverPublicKey` (secp256k1) | `packages/universal/crypto/src/asymmetric/signing/signing.ts` | L143-L235 | Verbatim |
|
||
| `verifyWithRecovery` (secp256k1) | `packages/universal/crypto/src/asymmetric/signing/signing.ts` | L243-L307 | Verbatim |
|
||
| `createDeviceKey` | `packages/universal/crypto/src/keys/device/device.ts` | L32-L49 | Verbatim |
|
||
| `deriveDeviceKeyFromMaster` | `packages/universal/crypto/src/keys/device/device.ts` | L56-L89 | Verbatim |
|
||
| `generateDeviceUUID` | `packages/universal/crypto/src/keys/device/device.ts` | L96-L155 | Verbatim |
|
||
| `extractDeviceMetadata` | `packages/universal/crypto/src/keys/device/device.ts` | L157-L181 | Verbatim |
|
||
| `isValidDeviceKey`, `compareDeviceKeys` | `packages/universal/crypto/src/keys/device/device.ts` | L182-L245 | Verbatim |
|
||
| `generateDerivedDeviceId` back-compat alias | `packages/universal/crypto/src/keys/device/device.ts` | L249-L260 | Replace upstream `@deprecated` JSDoc with prose ("Backwards-compatibility alias for `generateDeviceUUID`.") per CLAUDE.md §2 |
|
||
| `scrypt` async KDF | `packages/universal/crypto/src/core/hashing/hashing.ts` | L273-L325 | Verbatim (delegates to `@noble/hashes/scrypt::scryptAsync`) |
|
||
| `blake2b` hash | `packages/universal/crypto/src/core/hashing/hashing.ts` | L1-L60 (imports + helpers used) | Re-host as a top-level primitive in `crypto-hash` |
|
||
| `hashPasswordBlake2b` | `packages/universal/crypto/src/core/hashing/hashing.ts` | L617-L666 | Verbatim |
|
||
| `verifyPasswordBlake2b` | `packages/universal/crypto/src/core/hashing/hashing.ts` | L672-L745 | Verbatim |
|
||
| `encryptWithPassword` | `packages/universal/crypto/src/symmetric/password/password.ts` | L54-L113 | Verbatim port; replace `PasswordError` plain class with `SuaveplanError` code `CRYPTO.PASSWORD_*` |
|
||
| `deriveKeyFromPassword` | `packages/universal/crypto/src/symmetric/password/password.ts` | L172-L209 | Verbatim |
|
||
| `hash-password` CLI | `packages/universal/crypto/src/bin/hash-password.ts` | L1-L98 | Verbatim port; replace direct `process.exit` with `cli.exit(code)` from `@suaveplan/cli` |
|
||
|
||
### Requirements with no source line
|
||
|
||
| Requirement | Justification |
|
||
|---|---|
|
||
| `StreamingAeadEngine` interface (formal) | Upstream uses a duck-typed object; genesis convention is a named interface in a `*.types.ts` file (see CLAUDE.md §11 "No nested object literals in interfaces"). |
|
||
| Error codes mapped to `@suaveplan/error` (`CRYPTO_CIPHER.STREAM_*`, `CRYPTO_CURVE.RECOVERY_*`, `CRYPTO_KEYS.DEVICE_*`, `CRYPTO_HASH.SCRYPT_*` / `BLAKE2B_*`, `CRYPTO.PASSWORD_*`) | Genesis-wide policy: every thrown error routes through `@suaveplan/error` with a stable code. Upstream throws plain `Error` / `PasswordError`. |
|
||
| `crypto-bin` as its own package | Universal-tier `@suaveplan/crypto` cannot depend on `@suaveplan/cli` (CLI is browser/server-tier and pulls in `@suaveplan/readline`). Splitting the CLI out keeps `crypto` zero-side-effect and tree-shakeable. |
|
||
| `encryptWithPassword` self-describing binary header | Upstream stores `salt + ciphertext` only; consumers had to know the iteration count externally. Genesis adds a versioned 16-byte header (`magic[4] \| version[1] \| kdf[1] \| cipher[1] \| reserved[1] \| saltLen[2] \| nonceLen[2] \| kdfParamsLen[4]`) so a blob is self-descriptive and rotation-safe. |
|
||
| `decryptWithPassword` companion to `encryptWithPassword` | Upstream's `decryptWithPassword` (L115-L160 of `password.ts`) is included. Listed here only because the proposal text earlier groups gap 6 as one verb; this row exists so reviewers can see both halves are covered. |
|
||
| `signWithRecovery` / `recoverPublicKey` / `verifyWithRecovery` exposed at `secp256k1.noble.ts` rather than the higher-level `signing.ts` | Upstream's `signing.ts` is a multi-key façade that pulls `BaseKeySchema` plumbing genesis hasn't ported. Putting the three functions on the curve primitive (where they belong cryptographically) avoids a circular dep with `crypto-keys`. |
|
||
|
||
## Verification approach
|
||
|
||
Each spec delta requirement carries a `**Verified by:**` line pointing at concrete `it(...)` titles. The test files that will exist after this change ships:
|
||
|
||
- `packages/crypto/crypto-cipher/src/streaming/streaming-aead/streaming-aead.test.ts` — chunk round-trip per engine; tag mismatch detection; abort propagation
|
||
- `packages/crypto/crypto-cipher/src/streaming/streaming-aead/streaming-aead.spec-conformance.test.ts` — `StreamingAeadEngine` contract pinned for both adapters; nonce-counter monotonicity; out-of-order chunks emit `STREAM_OUT_OF_ORDER`
|
||
- `packages/crypto/crypto-curve/src/primitives/secp256k1/secp256k1.test.ts` — extended with sign/recover/verify-with-recovery cases; recovery byte 0/1 round-trip
|
||
- `packages/crypto/crypto-curve/src/primitives/secp256k1/secp256k1.spec-conformance.test.ts` — invalid recovery byte emits `RECOVERY_BYTE_INVALID`; missing recovery byte emits `RECOVERY_BYTE_MISSING`; recovered key mismatch emits `RECOVERED_KEY_MISMATCH`
|
||
- `packages/crypto/crypto-hash/src/primitives/scrypt/scrypt.test.ts` — KAT round-trip vs upstream RFC 7914 vectors; `dkLen` 32 / 64 / 128
|
||
- `packages/crypto/crypto-hash/src/primitives/scrypt/scrypt.spec-conformance.test.ts` — invalid `N` (non-power-of-two, < 2) emits `SCRYPT_INVALID_N`
|
||
- `packages/crypto/crypto-hash/src/primitives/blake2b/blake2b.test.ts` — RFC 7693 KAT round-trip; output length 1..64; keyed mode
|
||
- `packages/crypto/crypto-hash/src/primitives/blake2b/blake2b.spec-conformance.test.ts` — output > 64 emits `BLAKE2B_OUTPUT_TOO_LONG`; key > 64 emits `BLAKE2B_KEY_TOO_LONG`
|
||
- `packages/crypto/crypto-hash/src/mac/blake2b-password/blake2b-password.test.ts` — round-trip hash → verify; salt freshness across calls; constant-time comparison observable via timing-side-channel test
|
||
- `packages/crypto/crypto-hash/src/mac/blake2b-password/blake2b-password.spec-conformance.test.ts` — malformed stored hash emits `BLAKE2B_PASSWORD_FORMAT_INVALID`
|
||
- `packages/crypto/crypto-keys/src/keypair/device/device.test.ts` — `createDeviceKey` round-trip; `deriveDeviceKeyFromMaster` deterministic; `generateDeviceUUID` valid v4; `extractDeviceMetadata` round-trip; `compareDeviceKeys` constant-time
|
||
- `packages/crypto/crypto-keys/src/keypair/device/device.spec-conformance.test.ts` — invalid master emits `DEVICE_INVALID_MASTER`; corrupt key emits `DEVICE_INVALID_KEY`
|
||
- `packages/crypto/crypto/src/aead/streaming/streaming-aead.test.ts` — façade selects correct engine; round-trip per `xchacha20-poly1305` and `aes-256-gcm`
|
||
- `packages/crypto/crypto/src/aead/streaming/web-streams.test.ts` — Web-Streams round-trip; `collectStream` aggregates correctly; `streamEncrypt` / `streamDecrypt` aliases match the canonical functions
|
||
- `packages/crypto/crypto/src/password/encrypt-with-password.test.ts` — round-trip `encrypt → decrypt`; KDF selection (`argon2id` vs `scrypt`); blob header self-descriptive (different KDF params produce different headers; reading a v1 blob with a v2 reader emits `PASSWORD_BLOB_VERSION_UNSUPPORTED`)
|
||
- `packages/crypto/crypto/src/password/encrypt-with-password.spec-conformance.test.ts` — `kdf: "unknown"` emits `PASSWORD_KDF_UNKNOWN`; truncated blob emits `PASSWORD_BLOB_HEADER_INVALID`
|
||
- `packages/crypto/crypto/src/password/derive-key-from-password.test.ts` — KDF selection; deterministic given fixed salt + params; output length is exactly 32 bytes
|
||
- `packages/crypto/crypto-bin/src/hash-password/hash-password.test.ts` — Argon2id mode end-to-end (hash, then verify, exit 0); blake2b mode end-to-end; bad password verify exits 1; missing `--password` arg emits non-zero exit
|
||
- `packages/crypto/crypto-bin/src/hash-password/hash-password.spec-conformance.test.ts` — error path emits `CRYPTO.HASH_PASSWORD_CLI_*` codes (one per known failure mode)
|
||
|
||
## Migration impact
|
||
|
||
This change is **additive** — it does not modify any existing public surface. Verification:
|
||
|
||
- Existing `@suaveplan/crypto` consumers (`crypto-vault`, `slsa`, `audit-logging`, `auth`, `streams`, `bitpacker-crypto`, `drive-plugin-chunks`, `data/packer`) — none use `signWithRecovery` / streaming AEAD / device keys / scrypt / blake2b / `encryptWithPassword` / hash-password CLI today (the symbols don't exist on genesis). New exports therefore have zero callers at land time.
|
||
- Existing `crypto-cipher` callers (`crypto`, `crypto-sodium`) — only consume the three primitive selectors (`aes-256-gcm`, `chacha20-poly1305`, `xchacha20-poly1305`). The new `streaming/*` subpath is an isolated subtree.
|
||
- Existing `crypto-curve` callers (`crypto`) — only consume the four primitive selectors. The three new `signWithRecovery` / `recoverPublicKey` / `verifyWithRecovery` exports do not collide with the existing `sign` / `verify`.
|
||
- Existing `crypto-hash` callers (`crypto`, `crypto-vault`, `crypto-curve`) — consume `sha256`, `sha384`, `sha512`, `hmac`, `hkdf`, `pbkdf2`, `argon2id`. The new `scrypt` and `blake2b` primitives are isolated.
|
||
- Existing `crypto-keys` callers (`crypto-vault`, `auth`) — consume `Keychain` and `keypair/{generate,validate}`. The new `keypair/device` subtree is isolated.
|
||
|
||
A `bunx turbo build typecheck test --filter=...@suaveplan/crypto*` sweep runs in §9 of `tasks.md` to verify all dependents compile and test green before archive.
|
||
|
||
## Impact
|
||
|
||
### Affected dependents
|
||
|
||
Run `bunx turbo ls --filter=...@suaveplan/crypto` to enumerate. For each dependent, check one box:
|
||
|
||
- `@suaveplan/crypto-sodium` — [ ] tests run / [ ] docs reviewed / [x] no action needed (consumes only the existing AEAD / sign / agree façade; new streaming / password helpers are additive subpaths)
|
||
- `@suaveplan/crypto-browser` — [ ] tests run / [ ] docs reviewed / [x] no action needed (same — consumes existing AEAD / sign / agree façade)
|
||
- `@suaveplan/crypto-vault` — [x] tests run / [x] docs reviewed / [ ] no action needed (vault may want to opt into `scrypt` KDF in a follow-up; verifying it still typechecks is required because it imports `crypto-hash` directly)
|
||
- `@suaveplan/crypto-keys` — [x] tests run / [x] docs reviewed / [ ] no action needed (we are *adding* `keypair/device/*` to it in this change, so its own tests must run)
|
||
- `@suaveplan/auth` — [x] tests run / [ ] docs reviewed / [ ] no action needed (consumes `crypto-keys`, depends on us not breaking the existing `keypair/{generate,validate}` exports)
|
||
- `@suaveplan/audit-logging` — [ ] tests run / [ ] docs reviewed / [x] no action needed (consumes only the AEAD façade for log encryption — new streaming subpath does not collide)
|
||
- `@suaveplan/slsa` — [ ] tests run / [ ] docs reviewed / [x] no action needed (consumes only `crypto/sign` for in-toto attestation signing — `signWithRecovery` is a new export, not a modification)
|
||
- `@suaveplan/streams` — [ ] tests run / [ ] docs reviewed / [x] no action needed (consumes only the existing primitive selectors)
|
||
- `@suaveplan/bitpacker-crypto` — [ ] tests run / [ ] docs reviewed / [x] no action needed (consumes the AEAD façade for packed-bit encryption — new exports do not collide)
|
||
- `@suaveplan/drive-plugin-chunks` — [ ] tests run / [ ] docs reviewed / [x] no action needed (consumes the AEAD façade for at-rest chunk encryption — new streaming subpath is a candidate for a follow-up port, not a regression risk here)
|
||
- `@suaveplan/data/packer` — [ ] tests run / [ ] docs reviewed / [x] no action needed (consumes the AEAD façade only)
|
||
- `@suaveplan/crypto-utils` — [x] tests run / [ ] docs reviewed / [ ] no action needed (foundation — its own coverage gate must pass after this change; `crypto-utils` is unchanged but `crypto-hash` and `crypto-cipher` consume it, so its tests must still pass)
|
||
|
||
For the four [x] dependents above (`crypto-vault`, `crypto-keys`, `auth`, `crypto-utils`), running their full test suite is part of §9 of `tasks.md`.
|