72 lines
3.8 KiB
Markdown
72 lines
3.8 KiB
Markdown
# Capability: seeded-prng
|
||
|
||
## ADDED Requirements
|
||
|
||
### Package identity
|
||
|
||
- REQ-PRNG-001: Package name `@suaveplan/pseudo-random`, `packages/universal/pseudo-random`.
|
||
- REQ-PRNG-002: Runtime deps: `@suaveplan/error`, `@suaveplan/types`, `tslib`, `zod`. Zero crypto deps, zero browser deps.
|
||
- REQ-PRNG-003: `"sideEffects": false`.
|
||
|
||
### SeededRng interface
|
||
|
||
- REQ-PRNG-010: Exports `SeededRng` interface extending `Rng` from `@suaveplan/types`: `{ readonly seed: number; readonly position: number; skip(n: number): this; reset(): this; at(offset: number): SeededRng; fork(id: number | string): SeededRng; checkpoint(): RngCheckpoint; restore(checkpoint: RngCheckpoint): this }`.
|
||
- REQ-PRNG-011: Exports `RngCheckpoint = { seed: number; position: number; state: unknown }` — serialisable to JSON.
|
||
|
||
### Seed normalisation
|
||
|
||
- REQ-PRNG-020: Exports `normalizeSeed(seed: string | number): number`.
|
||
- REQ-PRNG-021: String seeds: splitmix64 mixing over UTF-16 char codes. Produces stable 32-bit integer.
|
||
- REQ-PRNG-022: Numeric seeds: single splitmix64 round to avalanche input bias. Rejects NaN, Infinity, non-safe-integers with `PseudoRandomError("PRNG.SEED.INVALID")`.
|
||
- REQ-PRNG-023: Zero input produces a non-zero seed (avoids degenerate PRNG state).
|
||
|
||
### Mulberry32Rng
|
||
|
||
- REQ-PRNG-030: Exports `Mulberry32Rng` implementing `SeededRng`. 32-bit state.
|
||
- REQ-PRNG-031: `nextUint32()` uses the standard Mulberry32 algorithm: `a = (a + 0x6d2b79f5) >>> 0; ...`.
|
||
- REQ-PRNG-032: Byte-identical output to the inline implementation in `@suaveplan/testing/context`.
|
||
|
||
### Sfc32Rng
|
||
|
||
- REQ-PRNG-040: Exports `Sfc32Rng` implementing `SeededRng`. 128-bit state (4×uint32).
|
||
- REQ-PRNG-041: State initialised with 12 warmup rounds from `seedToSFC32State`.
|
||
- REQ-PRNG-042: Byte-identical output to `BulletproofPRNG` (SFC32 mode) in the bingo app for same seed.
|
||
|
||
### Xoshiro256Rng
|
||
|
||
- REQ-PRNG-050: Exports `Xoshiro256Rng` implementing `SeededRng`. 256-bit state (4×uint64 via BigInt or two uint32 pairs).
|
||
- REQ-PRNG-051: Uses xoshiro256++ algorithm.
|
||
- REQ-PRNG-052: `skip(2**128)` and `skip(2**192)` use the algebraic jump polynomials (O(log n)); other `skip(n)` uses linear burn.
|
||
|
||
### CounterRng
|
||
|
||
- REQ-PRNG-060: Exports `CounterRng` implementing `SeededRng`. Counter-based via splitmix64 hash.
|
||
- REQ-PRNG-061: `at(offset)` is O(1) — directly sets the counter.
|
||
- REQ-PRNG-062: `nextUint32()` = `splitmix64(seed XOR counter++)` truncated to 32 bits.
|
||
|
||
### Shared SeededRng behaviour
|
||
|
||
- REQ-PRNG-070: `fork(id)` derives child seed via `normalizeSeed(parentSeed XOR hash(id))`. Children are statistically independent.
|
||
- REQ-PRNG-071: `checkpoint()` returns a plain object that `JSON.stringify` round-trips without loss.
|
||
- REQ-PRNG-072: `restore(checkpoint)` resets the instance to the checkpointed state and returns `this`.
|
||
- REQ-PRNG-073: `at(offset)` returns a **new instance** at the given offset (does not mutate the original).
|
||
|
||
### Utilities
|
||
|
||
- REQ-PRNG-080: Exports `shuffle<T>(array: T[], rng?: Rng): T[]` — Fisher-Yates, returns new array.
|
||
- REQ-PRNG-081: Exports `shuffleInPlace<T>(array: T[], rng?: Rng): T[]` — Fisher-Yates, mutates.
|
||
- REQ-PRNG-082: Exports `sample<T>(array: T[], n: number, rng?: Rng): T[]` — n distinct elements without replacement.
|
||
- REQ-PRNG-083: Exports `weightedChoice<T>(items: T[], weights: number[], rng?: Rng): T`.
|
||
|
||
### Error surface
|
||
|
||
- REQ-PRNG-090: Exports `PseudoRandomError extends SuaveplanError<PseudoRandomCode>`.
|
||
- REQ-PRNG-091: Codes: `PRNG.SEED.INVALID`, `PRNG.OFFSET.OUT_OF_RANGE`, `PRNG.SAMPLE.INSUFFICIENT_ITEMS`, `PRNG.CHECKPOINT.INVALID`.
|
||
|
||
### Quality
|
||
|
||
- REQ-PRNG-100: 100% statement + branch coverage.
|
||
- REQ-PRNG-101: fast-check: determinism, fork independence (10k samples, correlation < 0.01), checkpoint round-trip.
|
||
- REQ-PRNG-102: mitata benchmarks: `nextUint32` throughput for each algorithm.
|
||
- REQ-PRNG-103: `Sfc32Rng` output verified against known vectors from bingo test suite.
|