4.1 KiB
Capability Spec Delta: crypto-core (crypto-core)
Package: @suaveplan/crypto-core
Status: PROPOSED
Every requirement below carries a
**Verified by:**line at authoring time. No exceptions.
MODIFIED Requirements
Requirement: ByteSource and Rng are distinct contracts
@suaveplan/crypto-core SHALL declare ByteSource as the package's callable byte producer (type ByteSource = (n: number) => Uint8Array), exported from src/primitives/random-bytes/random-bytes.ts. The package SHALL NOT alias Rng to ByteSource or to any callable shape — the canonical Rng (from @suaveplan/types) is an object with nextUint32 / nextFloat, fundamentally different from a callable byte producer. The previous type Rng = ByteSource alias and the defaultRng: ByteSource = defaultByteSource constant SHALL both be removed.
@suaveplan/crypto-core MAY re-export the canonical Rng from @suaveplan/types under the name Rng as a back-compat forwarder for one release cycle, with a prose comment naming the canonical import path and the removal change ID (remove-deprecated-rng-aliases). The forwarder MUST live at src/primitives/random-bytes/random-bytes.ts and be re-surfaced through the three barrels (src/primitives/random-bytes/index.ts, src/primitives/index.ts, src/index.ts). The defaultRng re-export SHALL NOT survive in any barrel — consumers use defaultByteSource directly.
The RandomBytesOptions shape SHALL drop the legacy rng?: ByteSource field; only byteSource?: ByteSource remains. The internal selector simplifies from options.byteSource ?? options.rng ?? defaultByteSource to options.byteSource ?? defaultByteSource. Repo-internal grep confirms zero callsites pass { rng: ... } to randomBytes today.
@suaveplan/crypto-core SHALL preserve every other ByteSource-typed surface verbatim — engine constructors (AeadEngine, SignEngine, AgreeEngine, SealedBoxEngine, AuthBoxEngine), the byteSource injection on generateKeypair (ed25519, ecdsaP256, x25519), and the defaultByteSource constant. None of these reference Rng; they reference ByteSource by its real name.
Verified by: packages/crypto/crypto-core/src/primitives/random-bytes/random-bytes.ts (no type Rng = ByteSource; no defaultRng; presence of export type { Rng } from "@suaveplan/types" back-compat re-export) AND packages/crypto/crypto-core/src/primitives/random-bytes/random-bytes.test.ts::"randomBytes accepts byteSource option" AND packages/crypto/crypto-core/src/primitives/random-bytes/random-bytes.test.ts::"randomBytes rejects negative or non-integer n" AND bunx turbo typecheck test --filter=@suaveplan/crypto-core (green with zero assertion edits) AND bunx turbo test --filter=...@suaveplan/crypto-core (every consumer green) AND repo-internal grep grep -rn "defaultRng\b\|\.rng:\|, rng:" packages/crypto/crypto-core/src/ --include="*.ts" returns zero results outside the documented back-compat re-export comment.
Scenario: Rng re-export forwards canonical
- WHEN a consumer writes
import type { Rng } from "@suaveplan/crypto-core" - THEN the imported type is structurally identical to
import type { Rng } from "@suaveplan/types"(an object, NOT a callable)
Scenario: ByteSource remains the callable contract
- WHEN a consumer writes
import type { ByteSource } from "@suaveplan/crypto-core" - THEN the imported type is
(n: number) => Uint8Array
Scenario: defaultRng is removed
- WHEN a consumer writes
import { defaultRng } from "@suaveplan/crypto-core" - THEN
tscrejects with "has no exported memberdefaultRng"
Scenario: RandomBytesOptions.rng field is removed
- WHEN a consumer calls
randomBytes(32, { rng: customSource }) - THEN
tscrejects with "Object literal may only specify known properties, andrngdoes not exist in typeRandomBytesOptions"
Scenario: engines preserve ByteSource injection
- WHEN a consumer calls
ed25519.generateKeypair({ byteSource: customSource }) - THEN the keypair is generated using
customSource(32)(behavior unchanged)