← board

Wire random.pas's tier 1 to the hardware-entropy intrinsics

What is available now

function __pxxCpuHasHwRandom: Boolean;            { CPUID leaf 1 ECX bit 30, cached }
function __pxxHwRandom64(var v: UInt64): Boolean; { False = no entropy this time }

Both live in the compiler's builtin unit and are pulled in automatically by a name pre-scan, so random.pas needs no uses and no {$ifdef} — which is the point: [[feature-random-library]]'s mandate is one elegant .pas with the per-arch instruction invisible to it.

The one thing the wiring must get right

__pxxHwRandom64 returning False is normal, not an error. RDRAND clears CF and leaves the destination ZERO under load or entropy exhaustion. So the library must bound its retries (Intel's guidance is ~10) and then fall to tier 2, and must never treat the value alone as entropy — a silent zero in a CSPRNG seed is the invisible catastrophic failure the Boolean exists to prevent.

Targets

x86-64 answers truthfully; every other target answers False, which routes the library to tier 2 automatically. That is the correct answer rather than a stub, so no per-target branching is needed in the library at all.

aarch64 (MRS RNDR, gated on the optional FEAT_RNG), and the ESP RNG register, are not implemented compiler-side yet — see the parent ticket for why. When they land, this library code should need no change.

Gate

Track B's: make lib-test / make demos with $(PXX_STABLE), never rebuilding the compiler. test/lib_random.pas's SEEDED stream must stay byte-identical — the deterministic path is seeded and by definition must not touch hardware entropy. (Verified unchanged against pinned when the intrinsics landed.)

Resolved 2026-08-28 (Track B, frankB)

lib/rtl/random.pas tier 1 is live. HWEntropy64 probes __pxxCpuHasHwRandom, then retries __pxxHwRandom64 up to HW_ENTROPY_RETRIES = 10 (Intel's guidance, named rather than a bare literal) and falls to tier 2. On the give-up path v is re-zeroed before returning False, because RDRAND leaves its destination zero on failure and a silent zero reaching a CSPRNG seed is exactly the failure the Boolean exists to prevent.

No per-target branching, as the ticket predicted: x86-64 answers truthfully, every other target answers False from the probe and routes itself to tier 2. RNDR/ESP land compiler-side later and need no change here.

One surface addition beyond the wiring. The unit exported its tier-2 and tier-3 probes but had no tier-1 interface section at all, so the tier could not be tested from outside. Added HWEntropyAvailable and HWEntropy64 to the interface, symmetric with OSEntropyBytes/OSEntropy64 directly below them.

Measured, not assumed

The wiring is genuinely exercised on this box rather than passing through the not-available branch: the probe answers TRUE, /proc/cpuinfo carries rdrand, and three consecutive draws returned distinct 64-bit values. Worth stating because a test that passes by taking the easy branch looks identical to one that passes for the right reason.

test/lib_random_hw_tier1.pas asserts CONTRACTS, not values — RDRAND is present here but not on every box the suite runs on — so both branches of the probe print the same lines and the expected output is machine-independent. The line with teeth is seeded-reproducible: tier 1 must not leak into the deterministic path, where the damage would look random and therefore invisible.

Negative-controlled with a stuck source (HWEntropy64 always returning a constant): contract=FAIL and randomize-varies=FAIL, exit 1.

The ticket's stated gate holds: test/lib_random.pas's seeded stream is byte-identical against test/lib_random.expected, and lib_randomstate passes.

The negative control caught a bug in my own test

The first draft printed HWTIER1 OK unconditionally. Against the stuck source it produced two FAIL lines, then HWTIER1 OK, then exit 0 — green to anything reading the last line or the status, which is the third member of the do-not-pipe family in devdocs/dev/gating-and-waiting.md appearing on the producing side rather than the consuming one. A sentinel that failure can reach is not a sentinel. The test now tracks an allok flag, prints HWTIER1 FAIL and halts 1, and the Makefile compares the whole output rather than the tail, so the FAIL lines survive as the diagnostic.

Log