Files
skills/docs/security-stack/security/srp/src/math/rng-bytes.md
2026-05-29 08:20:56 +01:00

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 Rng provides nextBytes.
  • Little-endian packing of nextUint32 for portability across deterministic seeded RNGs.
  • No allocation overhead on the nextBytes fast 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.