2.6 KiB
rng-bytes
Purpose
Adapter helper that draws n bytes from any Rng implementing the @suaveplan/types contract. The Rng interface mandates nextUint32 but nextBytes is optional; SRP's client/server start functions need a ≥ 256-bit random exponent, so this helper unifies the two paths. When the supplied Rng exposes nextBytes, that path is used directly; otherwise the helper packs nextUint32 calls into a byte buffer with little-endian field extraction. Both paths produce uniform output across the full byte range.
Features
- Single entry point regardless of whether the
RngprovidesnextBytes. - Little-endian packing of
nextUint32for portability across deterministic seeded RNGs. - No allocation overhead on the
nextBytesfast path. - Pure function — no global state.
Usage: Basic Example
import { rngBytes } from "@suaveplan/srp";
import type { Rng } from "@suaveplan/types";
const rng: Rng = {
nextUint32: () => 0x12345678,
nextFloat: () => 0.5,
};
const bytes = rngBytes(rng, 32);
console.log(bytes.byteLength); // 32
Usage: Advanced Example
import { rngBytes } from "@suaveplan/srp";
import type { Rng } from "@suaveplan/types";
// Web-Crypto-backed RNG with native nextBytes — the fast path.
const cryptoRng: Rng = {
nextUint32: () => {
const buf = new Uint32Array(1);
crypto.getRandomValues(buf);
return buf[0];
},
nextFloat: () => crypto.getRandomValues(new Uint32Array(1))[0] / 2 ** 32,
nextBytes: (n: number) => crypto.getRandomValues(new Uint8Array(n)),
};
const a = rngBytes(cryptoRng, 32);
console.log(a.byteLength);
API Reference
rngBytes(rng: Rng, n: number): Uint8Array
Returns an n-byte Uint8Array of uniformly distributed bytes. When rng.nextBytes exists, delegates directly. Otherwise packs nextUint32 outputs into the buffer in little-endian byte order.
Implementation Notes
The little-endian pack order on the nextUint32 fallback is arbitrary — the resulting bytes feed straight into a bigInt decode that does NOT preserve endianness of the source 32-bit words, so any consistent order is correct. We pick little-endian because it matches the layout of Uint32Array views over ArrayBuffer on every modern platform, so an implementation that wants to optimize further can swap to a typed-array view without changing behaviour.
The helper is deliberately not memoized: each call draws fresh entropy. Callers that need a deterministic exponent for testing supply a seeded Rng instance whose nextUint32 reproduces the same word stream; rngBytes then yields a deterministic byte sequence from that stream.