REPORT-STATISTICAL — DIEHARDER · NIST STS · TESTU01 · SCALED OUTCOMES
sdk-v2/lab/REPORT-STATISTICAL.md · commit 96368332 · GLI CSR §2.2: Statistical data analysis · ← package index · raw on GitHub ↗RAIN RNG v2.1 — Statistical evidence report (pre-certification, self-run)
Submission document per GLI Composite Submission Requirements v2.0 §2.2 "Statistical data analysis" and GLI-19 v3.0 §3.2.2–§3.2.4. This is the operator's own pre-testing; it is not a laboratory certificate. Every number below is reproduced from a log under lab/results/ by bash lab/tools/report-tables.sh; nothing is typed in by hand. Criteria used are the public ones collected in ../docs/LAB-SUBMISSION-REQUIREMENTS.md §2.2.
Run dates: 2026-09-13 21:59 UTC → 2026-09-14 (this document reflects the state at the time stamp in §11). Repository: rain-risk-markets/sdk-v2, RNG code at commit 5f3efa13 (@rain/rng-core 2.1.0, @rain/rng-session 2.1.0 — the same code the operator node runs; lab/FINGERPRINTS.json has the per-file SHA-256).
0. Headline
| Suite | Mechanism | Result | Volume | Status |
|---|---|---|---|---|
Dieharder 3.31.1, full -a battery, stream input (-g 200, never rewinds) |
chacha20 | 90 PASSED / 5 WEAK / 0 FAILED (95 result lines, 61 of 80 test/ntuple combinations; not run: rgb_lagged_sum ntuple 14–32, budget) |
≈ 73 GB of 32-bit words | valid (rewinds = 0 by construction) |
Dieharder 3.31.1, full -a battery, stream |
hmac-drbg | 83 PASSED / 3 WEAK / 0 FAILED (86 result lines, 52 of 80 test/ntuple combinations run — HMAC_DRBG produces ≈ 1 MB/s per core; not run: 28 combinations, see §9) | valid, partial | |
| NIST SP 800-22 STS 2.1.2, 1000 sequences × 10⁶ bits, all 15 tests, default parameters | chacha20 | 188 result lines; 0 proportion outside CI; 0 uniformity P < 10⁻⁴ | 125 MB from the 4 GB file | |
| NIST STS 2.1.2, 1000 × 10⁶ bits | hmac-drbg | 188 result lines; 0 proportion outside CI; 0 uniformity P < 10⁻⁴ | 125 MB from the 4 GB file | |
| TestU01 1.2.3 SmallCrush (file-backed, no rewind) | chacha20 | 15/15 statistics passed, p ∈ [0.06, 0.96] | 2.27 × 10⁸ words | valid |
| TestU01 1.2.3 SmallCrush | hmac-drbg | 15/15 statistics passed, p ∈ [0.09, 0.92] | 2.27 × 10⁸ words | valid |
| TestU01 Crush / BigCrush | both | not run (≈ 2³⁵ / 2³⁸ words = 137 GB / 1.1 TB; producer at 4–17 MB/s → 10–70 h) — stream runner shipped, §9 | not run | |
Scaled outcomes — game results after intBelow/shuffle, collected by tools/collect-outcomes.mjs through the production ceremony (χ², blocked-χ² KS, serial correlation, runs, coupon, interplay, Fisher–Yates) |
chacha20 | one hundred million (10⁸) dice outcomes (10⁶ rounds × 100 draws), 10⁸ roulette outcomes, 10⁸ coin outcomes, 10⁸ reel stops (10⁶ × 20 × 5 reels), two million shuffled decks (1.04 × 10⁸ card placements), 3 × 10⁸ adversarial dice outcomes — 8.04 × 10⁸ scaled outcomes in total | §5 (column scaled outcomes (draws)) | all total-distribution χ² pass at α = .01; isolated single-statistic exceedances at the expected rate (§5.3) |
| Scaled outcomes | hmac-drbg | twenty million (2 × 10⁷) outcomes per game (2 × 10⁵ rounds × 100 draws) for dice, roulette, coin, reel stops, 3 adversarial dice sets, plus 2 × 10⁷ legacy-dice and 2 × 10⁷ legacy-roulette (% N path, comparison only) and 4 × 10⁵ decks — 2.0 × 10⁸ in total; 10⁸-per-game sets in progress in results/outcomes/hmac-1e8/ (rows appear in §5.1 as hmac-1e8 when finished; EVIDENCE-INDEX.md records the exact count reached) |
§5 | see §5 |
Invalid runs, quarantined (not evidence): results/dieharder/_smoke-invalid/chacha-13MB/ (387 rewinds, 13 MB smoke file) and results/dieharder/_invalid-rewound/chacha-4GB-file/ (19 rewinds, 4 GB file) — see §8.
1. Device under test
drbg(r_k, gameId, {mechanism}) — the draw layer of RAIN RNG v2.1 — fed by the real two-party commit-reveal ceremony (@rain/rng-session: RainRngClient.commit → RainRngHouse.reveal → settle, r_k = keccak256(abi.encode(pRev_k, hRev_k, sessionSeed, sessionId, k))). Two mechanisms are certified separately (GLI-19 §4.5.1): hmac-drbg (SP 800-90A HMAC_DRBG/SHA-256, 8 words per 256-bit block) and chacha20 (RFC 8439 block function keyed from r_k). Full description: RNG-DESCRIPTION.md; scaling functions (intBelow rejection sampling, shuffle Fisher–Yates): RNG-DESCRIPTION.md App. B and SCALING-INVENTORY.md.
Nothing in the collection tools re-implements the generator: tools/collect-raw.mjs and tools/collect-outcomes.mjs import @rain/rng-core / @rain/rng-session from packages/*/dist and call the same functions the operator node calls.
2. Test environment and tool versions
| Item | Value |
|---|---|
| Host | Linux 6.1.175 x86_64 (Amazon Linux 2023 kernel), 8 vCPU, 62 GB RAM, NVMe; container joni-user7 |
| Node.js | v24.14.0 |
| Dieharder | 3.31.1 (built from dieharder-3.31.1.tgz, webhome.phy.duke.edu/~rgb) against GSL 2.7.1, gcc 12, CFLAGS=-O2 -fcommon; binary labtools/prefix/bin/dieharder |
| NIST STS | 2.1.2 (csrc.nist.gov sts-2_1_2.zip, shipped makefile, gcc 12); one private copy of the tree per mechanism (labtools/sts/sts-chacha, labtools/sts/sts-hmac) because assess writes into its own experiments/ directory |
| TestU01 | 1.2.3 (github umontreal-simul/TestU01-2009 master, gcc 12, --disable-shared); generators tools/testu01/rain_file_gen.c (file-backed, unif01_CreateExternGenBits, aborts instead of rewinding) and tools/testu01/rain_stream_gen.c (stdin) |
| Outcome analyzer | tools/analyze-outcomes.mjs (closed-form χ² via regularised incomplete gamma, KS, z-tests; no external dependency) |
3. Dieharder
3.1 Why the file runs are invalid and how the stream runs are constructed
Dieharder with file input (-g 201 -f) silently rewinds the file when it is exhausted and prints # The file file_input_raw was rewound N times. Rewound data is re-used data; tests that consume it are correlated with earlier tests and are not independent evidence. We measured the consumption of every -a test on an unbounded /dev/urandom stream (lab/results/PROGRESS.md): the light tests take 40–960 MB each, marsaglia_tsang_gcd takes 8.0 GB, and rgb_lagged_sum takes ≈ 0.44 × (ntuple + 1) GB for ntuple 0…32 (≈ 250 GB in total). No 4 GB file can carry the battery; our 4 GB chacha file run rewound 19 times and is quarantined (§8).
The valid mechanism is therefore an unbounded stream: node lab/tools/collect-raw.mjs --bits 1e15 --out - … (the production ceremony + drbg(), W independent sessions interleaved in 1 MiB chunks, bit-reproducible from SEED-STREAM) piped into dieharder -g 200 (stdin_input_raw). Because worker sessions in this environment are killed every 15–80 min, the runner (tools/run-dieharder-stream.sh) launches one dieharder -d <test> [-n <ntuple>] -g 200 process per test of the -a list on the same pipe (identical default -t/-p to -a), archives each result in tests/<id>[-n<k>].log with a .DONE marker, and resumes by skipping finished tests. Every test reads fresh, never-reused words (a finished process's unread stdio buffer is discarded, not re-read). dieharder -d 102 (sts_serial) ignores -n and runs its own 1…16 loop, so the 15 extra 102-n2…16 invocations are additional independent replicates of the whole sts_serial loop on fresh data and are reported separately.
Stream seeds (all secrets derive from them by HMAC-SHA-256, see collect-raw.mjs header):
chacha: 0x5241494e4c41425f53545245414d5f4348414348415f32303236303931335f30 · hmac: 0x5241494e4c41425f53545245414d5f484d41435f32303236303931335f303101 (results/raw/<mech>/SEED-STREAM). Producer arguments: --workers 4 (chacha) / 2–5 (hmac) --words-per-draw 8 --draws 1024 --game lab.
Reading the assessment column. Dieharder marks a test WEAK when the KS p-value over its 100 p-samples is < 0.01 or > 0.99, and FAILED when < 10⁻⁶ or > 1 − 10⁻⁶. For a perfect generator every p-value is uniform, so ≈ 2 % of result lines are expected to be WEAK (both tails) — for the ≈ 95-line battery that is ~1–3 WEAK lines per run by design (author's documentation: "WEAK is not a failure … rerun with a different seed"; a reproducible FAILED is). A different WEAK set on a re-run with a different seed is the expected behaviour; the same test WEAK across seeds would warrant investigation.
3.2 Results
Tables are generated by bash lab/tools/report-tables.sh dieharder from results/dieharder/<mech>-stream/tests/*.log; the consolidated -a-style report is results/dieharder/<mech>-stream/dieharder-a.log, counts in SUMMARY.txt.
chacha (stream)
chacha: 95 result lines — 90 PASSED / 5 WEAK / 0 FAILED; rewinds: n/a (stream input, rewinding impossible). Tests not run: 19 (rgb_lagged_sum ntuple=14, rgb_lagged_sum ntuple=15, rgb_lagged_sum ntuple=16, rgb_lagged_sum ntuple=17, rgb_lagged_sum ntuple=18, rgb_lagged_sum ntuple=19, rgb_lagged_sum ntuple=20, rgb_lagged_sum ntuple=21, rgb_lagged_sum ntuple=22, rgb_lagged_sum ntuple=23, rgb_lagged_sum ntuple=24, rgb_lagged_sum ntuple=25, rgb_lagged_sum ntuple=26, rgb_lagged_sum ntuple=27, rgb_lagged_sum ntuple=28, rgb_lagged_sum ntuple=29, rgb_lagged_sum ntuple=30, rgb_lagged_sum ntuple=31, rgb_lagged_sum ntuple=32) Extra sts_serial replicates (15 further full 1..16 loops on fresh data, not part of the canonical battery): 444 PASSED / 6 WEAK / 0 FAILED.
| test | ntuple | tsamples | psamples | p-value | assessment |
|---|---|---|---|---|---|
| diehard_birthdays | 0 | 100 | 100 | 0.68172231 | PASSED |
| diehard_operm5 | 0 | 1000000 | 100 | 0.99104717 | PASSED |
| diehard_rank_32x32 | 0 | 40000 | 100 | 0.73439545 | PASSED |
| diehard_rank_6x8 | 0 | 100000 | 100 | 0.86757999 | PASSED |
| diehard_bitstream | 0 | 2097152 | 100 | 0.01362755 | PASSED |
| diehard_opso | 0 | 2097152 | 100 | 0.74805513 | PASSED |
| diehard_oqso | 0 | 2097152 | 100 | 0.77809577 | PASSED |
| diehard_dna | 0 | 2097152 | 100 | 0.37434899 | PASSED |
| diehard_count_1s_str | 0 | 256000 | 100 | 0.68908419 | PASSED |
| diehard_count_1s_byt | 0 | 256000 | 100 | 0.86282805 | PASSED |
| diehard_parking_lot | 0 | 12000 | 100 | 0.07270933 | PASSED |
| diehard_2dsphere | 2 | 8000 | 100 | 0.96460550 | PASSED |
| diehard_3dsphere | 3 | 4000 | 100 | 0.76780037 | PASSED |
| diehard_squeeze | 0 | 100000 | 100 | 0.07700051 | PASSED |
| diehard_sums | 0 | 100 | 100 | 0.00278315 | WEAK |
| diehard_runs | 0 | 100000 | 100 | 0.46449654 | PASSED |
| diehard_runs | 0 | 100000 | 100 | 0.03931625 | PASSED |
| diehard_craps | 0 | 200000 | 100 | 0.47911000 | PASSED |
| diehard_craps | 0 | 200000 | 100 | 0.17153488 | PASSED |
| marsaglia_tsang_gcd | 0 | 10000000 | 100 | 0.34083256 | PASSED |
| marsaglia_tsang_gcd | 0 | 10000000 | 100 | 0.40081702 | PASSED |
| sts_monobit | 1 | 100000 | 100 | 0.53640600 | PASSED |
| sts_runs | 2 | 100000 | 100 | 0.55013762 | PASSED |
| sts_serial | 1 | 100000 | 100 | 0.80156226 | PASSED |
| sts_serial | 2 | 100000 | 100 | 0.13191400 | PASSED |
| sts_serial | 3 | 100000 | 100 | 0.97590322 | PASSED |
| sts_serial | 3 | 100000 | 100 | 0.45922445 | PASSED |
| sts_serial | 4 | 100000 | 100 | 0.67837598 | PASSED |
| sts_serial | 4 | 100000 | 100 | 0.08183992 | PASSED |
| sts_serial | 5 | 100000 | 100 | 0.71835238 | PASSED |
| sts_serial | 5 | 100000 | 100 | 0.46047979 | PASSED |
| sts_serial | 6 | 100000 | 100 | 0.50070812 | PASSED |
| sts_serial | 6 | 100000 | 100 | 0.05184866 | PASSED |
| sts_serial | 7 | 100000 | 100 | 0.93819755 | PASSED |
| sts_serial | 7 | 100000 | 100 | 0.50215455 | PASSED |
| sts_serial | 8 | 100000 | 100 | 0.64877059 | PASSED |
| sts_serial | 8 | 100000 | 100 | 0.70360416 | PASSED |
| sts_serial | 9 | 100000 | 100 | 0.99967289 | WEAK |
| sts_serial | 9 | 100000 | 100 | 0.97998454 | PASSED |
| sts_serial | 10 | 100000 | 100 | 0.47522522 | PASSED |
| sts_serial | 10 | 100000 | 100 | 0.96202724 | PASSED |
| sts_serial | 11 | 100000 | 100 | 0.40735352 | PASSED |
| sts_serial | 11 | 100000 | 100 | 0.80650883 | PASSED |
| sts_serial | 12 | 100000 | 100 | 0.10313302 | PASSED |
| sts_serial | 12 | 100000 | 100 | 0.00007842 | WEAK |
| sts_serial | 13 | 100000 | 100 | 0.14887157 | PASSED |
| sts_serial | 13 | 100000 | 100 | 0.88717272 | PASSED |
| sts_serial | 14 | 100000 | 100 | 0.88728948 | PASSED |
| sts_serial | 14 | 100000 | 100 | 0.92398252 | PASSED |
| sts_serial | 15 | 100000 | 100 | 0.89541942 | PASSED |
| sts_serial | 15 | 100000 | 100 | 0.88176400 | PASSED |
| sts_serial | 16 | 100000 | 100 | 0.37332922 | PASSED |
| sts_serial | 16 | 100000 | 100 | 0.20115634 | PASSED |
| rgb_bitdist | 1 | 100000 | 100 | 0.86888183 | PASSED |
| rgb_bitdist | 2 | 100000 | 100 | 0.73992059 | PASSED |
| rgb_bitdist | 3 | 100000 | 100 | 0.95754103 | PASSED |
| rgb_bitdist | 4 | 100000 | 100 | 0.82153013 | PASSED |
| rgb_bitdist | 5 | 100000 | 100 | 0.32074393 | PASSED |
| rgb_bitdist | 6 | 100000 | 100 | 0.20932820 | PASSED |
| rgb_bitdist | 7 | 100000 | 100 | 0.38894727 | PASSED |
| rgb_bitdist | 8 | 100000 | 100 | 0.10285610 | PASSED |
| rgb_bitdist | 9 | 100000 | 100 | 0.06122998 | PASSED |
| rgb_bitdist | 10 | 100000 | 100 | 0.26549130 | PASSED |
| rgb_bitdist | 11 | 100000 | 100 | 0.99801205 | WEAK |
| rgb_bitdist | 12 | 100000 | 100 | 0.07465212 | PASSED |
| rgb_minimum_distance | 2 | 10000 | 1000 | 0.98412344 | PASSED |
| rgb_minimum_distance | 3 | 10000 | 1000 | 0.82328522 | PASSED |
| rgb_minimum_distance | 4 | 10000 | 1000 | 0.60919914 | PASSED |
| rgb_minimum_distance | 5 | 10000 | 1000 | 0.12584648 | PASSED |
| rgb_permutations | 2 | 100000 | 100 | 0.40971888 | PASSED |
| rgb_permutations | 3 | 100000 | 100 | 0.09328447 | PASSED |
| rgb_permutations | 4 | 100000 | 100 | 0.61062939 | PASSED |
| rgb_permutations | 5 | 100000 | 100 | 0.05554972 | PASSED |
| rgb_kstest_test | 0 | 10000 | 1000 | 0.17051720 | PASSED |
| dab_bytedistrib | 0 | 51200000 | 1 | 0.23962347 | PASSED |
| dab_dct | 256 | 50000 | 1 | 0.49778464 | PASSED |
| dab_filltree | 32 | 15000000 | 1 | 0.99352260 | PASSED |
| dab_filltree | 32 | 15000000 | 1 | 0.84527318 | PASSED |
| dab_filltree2 | 0 | 5000000 | 1 | 0.42968644 | PASSED |
| dab_filltree2 | 1 | 5000000 | 1 | 0.88334883 | PASSED |
| dab_monobit2 | 12 | 65000000 | 1 | 0.57177002 | PASSED |
| rgb_lagged_sum | 0 | 1000000 | 100 | 0.42967500 | PASSED |
| rgb_lagged_sum | 1 | 1000000 | 100 | 0.99997451 | WEAK |
| rgb_lagged_sum | 2 | 1000000 | 100 | 0.95132654 | PASSED |
| rgb_lagged_sum | 3 | 1000000 | 100 | 0.40574003 | PASSED |
| rgb_lagged_sum | 4 | 1000000 | 100 | 0.79398211 | PASSED |
| rgb_lagged_sum | 5 | 1000000 | 100 | 0.78468441 | PASSED |
| rgb_lagged_sum | 6 | 1000000 | 100 | 0.53376787 | PASSED |
| rgb_lagged_sum | 7 | 1000000 | 100 | 0.69311757 | PASSED |
| rgb_lagged_sum | 8 | 1000000 | 100 | 0.68748782 | PASSED |
| rgb_lagged_sum | 9 | 1000000 | 100 | 0.31392601 | PASSED |
| rgb_lagged_sum | 10 | 1000000 | 100 | 0.97981797 | PASSED |
| rgb_lagged_sum | 11 | 1000000 | 100 | 0.50062405 | PASSED |
| rgb_lagged_sum | 12 | 1000000 | 100 | 0.05637778 | PASSED |
| rgb_lagged_sum | 13 | 1000000 | 100 | 0.51171494 | PASSED |
hmac (stream)
hmac: 86 result lines — 83 PASSED / 3 WEAK / 0 FAILED; rewinds: n/a (stream input, rewinding impossible). Tests not run: 28 (rgb_lagged_sum ntuple=5, rgb_lagged_sum ntuple=6, rgb_lagged_sum ntuple=7, rgb_lagged_sum ntuple=8, rgb_lagged_sum ntuple=9, rgb_lagged_sum ntuple=10, rgb_lagged_sum ntuple=11, rgb_lagged_sum ntuple=12, rgb_lagged_sum ntuple=13, rgb_lagged_sum ntuple=14, rgb_lagged_sum ntuple=15, rgb_lagged_sum ntuple=16, rgb_lagged_sum ntuple=17, rgb_lagged_sum ntuple=18, rgb_lagged_sum ntuple=19, rgb_lagged_sum ntuple=20, rgb_lagged_sum ntuple=21, rgb_lagged_sum ntuple=22, rgb_lagged_sum ntuple=23, rgb_lagged_sum ntuple=24, rgb_lagged_sum ntuple=25, rgb_lagged_sum ntuple=26, rgb_lagged_sum ntuple=27, rgb_lagged_sum ntuple=28, rgb_lagged_sum ntuple=29, rgb_lagged_sum ntuple=30, rgb_lagged_sum ntuple=31, rgb_lagged_sum ntuple=32)
| test | ntuple | tsamples | psamples | p-value | assessment |
|---|---|---|---|---|---|
| diehard_birthdays | 0 | 100 | 100 | 0.68609744 | PASSED |
| diehard_operm5 | 0 | 1000000 | 100 | 0.13040900 | PASSED |
| diehard_rank_32x32 | 0 | 40000 | 100 | 0.99987653 | WEAK |
| diehard_rank_6x8 | 0 | 100000 | 100 | 0.70322967 | PASSED |
| diehard_bitstream | 0 | 2097152 | 100 | 0.95456790 | PASSED |
| diehard_opso | 0 | 2097152 | 100 | 0.09616516 | PASSED |
| diehard_oqso | 0 | 2097152 | 100 | 0.97193538 | PASSED |
| diehard_dna | 0 | 2097152 | 100 | 0.20047125 | PASSED |
| diehard_count_1s_str | 0 | 256000 | 100 | 0.99939055 | WEAK |
| diehard_count_1s_byt | 0 | 256000 | 100 | 0.39800464 | PASSED |
| diehard_parking_lot | 0 | 12000 | 100 | 0.86323545 | PASSED |
| diehard_2dsphere | 2 | 8000 | 100 | 0.29461438 | PASSED |
| diehard_3dsphere | 3 | 4000 | 100 | 0.73616533 | PASSED |
| diehard_squeeze | 0 | 100000 | 100 | 0.52762935 | PASSED |
| diehard_sums | 0 | 100 | 100 | 0.16892557 | PASSED |
| diehard_runs | 0 | 100000 | 100 | 0.79047806 | PASSED |
| diehard_runs | 0 | 100000 | 100 | 0.01934008 | PASSED |
| diehard_craps | 0 | 200000 | 100 | 0.79736718 | PASSED |
| diehard_craps | 0 | 200000 | 100 | 0.55204569 | PASSED |
| marsaglia_tsang_gcd | 0 | 10000000 | 100 | 0.97522402 | PASSED |
| marsaglia_tsang_gcd | 0 | 10000000 | 100 | 0.62578183 | PASSED |
| sts_monobit | 1 | 100000 | 100 | 0.50378653 | PASSED |
| sts_runs | 2 | 100000 | 100 | 0.97219601 | PASSED |
| sts_serial | 1 | 100000 | 100 | 0.95862996 | PASSED |
| sts_serial | 2 | 100000 | 100 | 0.12622394 | PASSED |
| sts_serial | 3 | 100000 | 100 | 0.00278798 | WEAK |
| sts_serial | 3 | 100000 | 100 | 0.15186858 | PASSED |
| sts_serial | 4 | 100000 | 100 | 0.06668808 | PASSED |
| sts_serial | 4 | 100000 | 100 | 0.93333167 | PASSED |
| sts_serial | 5 | 100000 | 100 | 0.12137431 | PASSED |
| sts_serial | 5 | 100000 | 100 | 0.33668558 | PASSED |
| sts_serial | 6 | 100000 | 100 | 0.32797158 | PASSED |
| sts_serial | 6 | 100000 | 100 | 0.96284935 | PASSED |
| sts_serial | 7 | 100000 | 100 | 0.89962442 | PASSED |
| sts_serial | 7 | 100000 | 100 | 0.15793288 | PASSED |
| sts_serial | 8 | 100000 | 100 | 0.47590090 | PASSED |
| sts_serial | 8 | 100000 | 100 | 0.40394877 | PASSED |
| sts_serial | 9 | 100000 | 100 | 0.24733679 | PASSED |
| sts_serial | 9 | 100000 | 100 | 0.59811425 | PASSED |
| sts_serial | 10 | 100000 | 100 | 0.72761033 | PASSED |
| sts_serial | 10 | 100000 | 100 | 0.05620910 | PASSED |
| sts_serial | 11 | 100000 | 100 | 0.51755502 | PASSED |
| sts_serial | 11 | 100000 | 100 | 0.97427738 | PASSED |
| sts_serial | 12 | 100000 | 100 | 0.91961157 | PASSED |
| sts_serial | 12 | 100000 | 100 | 0.68638058 | PASSED |
| sts_serial | 13 | 100000 | 100 | 0.84772785 | PASSED |
| sts_serial | 13 | 100000 | 100 | 0.33343097 | PASSED |
| sts_serial | 14 | 100000 | 100 | 0.81418042 | PASSED |
| sts_serial | 14 | 100000 | 100 | 0.43682339 | PASSED |
| sts_serial | 15 | 100000 | 100 | 0.93862995 | PASSED |
| sts_serial | 15 | 100000 | 100 | 0.80390179 | PASSED |
| sts_serial | 16 | 100000 | 100 | 0.34168999 | PASSED |
| sts_serial | 16 | 100000 | 100 | 0.54049114 | PASSED |
| rgb_bitdist | 1 | 100000 | 100 | 0.68671624 | PASSED |
| rgb_bitdist | 2 | 100000 | 100 | 0.85362674 | PASSED |
| rgb_bitdist | 3 | 100000 | 100 | 0.30782277 | PASSED |
| rgb_bitdist | 4 | 100000 | 100 | 0.99107009 | PASSED |
| rgb_bitdist | 5 | 100000 | 100 | 0.70782590 | PASSED |
| rgb_bitdist | 6 | 100000 | 100 | 0.87895469 | PASSED |
| rgb_bitdist | 7 | 100000 | 100 | 0.03360376 | PASSED |
| rgb_bitdist | 8 | 100000 | 100 | 0.65199856 | PASSED |
| rgb_bitdist | 9 | 100000 | 100 | 0.83565353 | PASSED |
| rgb_bitdist | 10 | 100000 | 100 | 0.13197023 | PASSED |
| rgb_bitdist | 11 | 100000 | 100 | 0.17450761 | PASSED |
| rgb_bitdist | 12 | 100000 | 100 | 0.93710513 | PASSED |
| rgb_minimum_distance | 2 | 10000 | 1000 | 0.91623918 | PASSED |
| rgb_minimum_distance | 3 | 10000 | 1000 | 0.16813567 | PASSED |
| rgb_minimum_distance | 4 | 10000 | 1000 | 0.47526150 | PASSED |
| rgb_minimum_distance | 5 | 10000 | 1000 | 0.76912236 | PASSED |
| rgb_permutations | 2 | 100000 | 100 | 0.30773472 | PASSED |
| rgb_permutations | 3 | 100000 | 100 | 0.11241957 | PASSED |
| rgb_permutations | 4 | 100000 | 100 | 0.86752510 | PASSED |
| rgb_permutations | 5 | 100000 | 100 | 0.57090317 | PASSED |
| rgb_kstest_test | 0 | 10000 | 1000 | 0.70900008 | PASSED |
| dab_bytedistrib | 0 | 51200000 | 1 | 0.88806521 | PASSED |
| dab_dct | 256 | 50000 | 1 | 0.70678794 | PASSED |
| dab_filltree | 32 | 15000000 | 1 | 0.26850768 | PASSED |
| dab_filltree | 32 | 15000000 | 1 | 0.90557405 | PASSED |
| dab_filltree2 | 0 | 5000000 | 1 | 0.02064555 | PASSED |
| dab_filltree2 | 1 | 5000000 | 1 | 0.53994751 | PASSED |
| dab_monobit2 | 12 | 65000000 | 1 | 0.34368168 | PASSED |
| rgb_lagged_sum | 0 | 1000000 | 100 | 0.60588286 | PASSED |
| rgb_lagged_sum | 1 | 1000000 | 100 | 0.50413098 | PASSED |
| rgb_lagged_sum | 2 | 1000000 | 100 | 0.34668317 | PASSED |
| rgb_lagged_sum | 3 | 1000000 | 100 | 0.52724432 | PASSED |
| rgb_lagged_sum | 4 | 1000000 | 100 | 0.32958104 | PASSED |
4. NIST SP 800-22 STS 2.1.2
Data: the first 125,000,000 bytes (1000 sequences × 10⁶ bits) of each 4 GB raw file (results/raw/<mech>/raw-32gbit.bin; sha256 d8b314f6…07dfda chacha, 68a170a0…62e43d3 hmac; regenerable from SEED-BIG, --workers 4 --draws 64 --words-per-draw 1 (chacha) / 8 (hmac)). Command: printf '0\n<file>\n1\n0\n1000\n1\n' | ./assess 1000000 — generator 0 = input file, all 15 tests, default block parameters (BlockFrequency M = 128, NonOverlapping/Overlapping m = 9, ApproximateEntropy m = 10, Serial m = 16, LinearComplexity M = 500), binary input mode. Runner: tools/run-sts.sh.
Criteria (SP 800-22 §4.2): for each test line, (i) the proportion of sequences with p ≥ 0.01 must lie within 0.99 ± 3·√(0.99·0.01/1000) = [0.9806, 0.9994] (STS prints * and "minimum pass rate ≈ 0.980" — RandomExcursions lines use their own, smaller m); (ii) the P-value of P-values (χ² over 10 bins of the 1000 p-values) must be ≥ 0.0001. With 188 template lines under NonOverlappingTemplate, 8 + 18 excursion lines, 2 Serial, 2 CumulativeSums, one expects a few lines near the CI edge by chance; a systematic failure is many lines below 0.9806 or any uniformity P < 10⁻⁴.
Full reports: results/sts/<mech>/finalAnalysisReport.txt (+ experiments/<Test>/results.txt|stats.txt per test, freq.txt).
chacha
chacha: 188 result lines over 15 tests; proportion outside the confidence interval: 0 line(s); P-value-of-P-values < 0.0001: 0 line(s). STS-printed minimum pass rate = 980 of 1000 sequences (Random Excursions lines use their own, smaller m).
| test | lines (templates/states) | sequences passed / total | min proportion | proportion lines outside CI | min P-value of uniformity | uniformity lines < 1e-4 |
|---|---|---|---|---|---|---|
| Frequency | 1 | 991 / 1000 | 0.9910 | 0 | 0.1342 | 0 |
| BlockFrequency | 1 | 992 / 1000 | 0.9920 | 0 | 0.9737 | 0 |
| CumulativeSums | 2 | 1982 / 2000 | 0.9890 | 0 | 0.4373 | 0 |
| Runs | 1 | 983 / 1000 | 0.9830 | 0 | 0.2493 | 0 |
| LongestRun | 1 | 990 / 1000 | 0.9900 | 0 | 0.1107 | 0 |
| Rank | 1 | 993 / 1000 | 0.9930 | 0 | 0.0247 | 0 |
| FFT | 1 | 988 / 1000 | 0.9880 | 0 | 0.0661 | 0 |
| NonOverlappingTemplate | 148 | 146538 / 148000 | 0.9820 | 0 | 0.0175 | 0 |
| OverlappingTemplate | 1 | 983 / 1000 | 0.9830 | 0 | 0.0083 | 0 |
| Universal | 1 | 988 / 1000 | 0.9880 | 0 | 0.8129 | 0 |
| ApproximateEntropy | 1 | 993 / 1000 | 0.9930 | 0 | 0.0396 | 0 |
| RandomExcursions | 8 | 4688 / 4744 | 0.9831 | 0 | 0.1507 | 0 |
| RandomExcursionsVariant | 18 | 10586 / 10674 | 0.9882 | 0 | 0.0125 | 0 |
| Serial | 2 | 1974 / 2000 | 0.9850 | 0 | 0.1296 | 0 |
| LinearComplexity | 1 | 993 / 1000 | 0.9930 | 0 | 0.3669 | 0 |
hmac
hmac: 188 result lines over 15 tests; proportion outside the confidence interval: 0 line(s); P-value-of-P-values < 0.0001: 0 line(s). STS-printed minimum pass rate = 980 of 1000 sequences (Random Excursions lines use their own, smaller m).
| test | lines (templates/states) | sequences passed / total | min proportion | proportion lines outside CI | min P-value of uniformity | uniformity lines < 1e-4 |
|---|---|---|---|---|---|---|
| Frequency | 1 | 990 / 1000 | 0.9900 | 0 | 0.4522 | 0 |
| BlockFrequency | 1 | 994 / 1000 | 0.9940 | 0 | 0.7096 | 0 |
| CumulativeSums | 2 | 1982 / 2000 | 0.9900 | 0 | 0.2757 | 0 |
| Runs | 1 | 989 / 1000 | 0.9890 | 0 | 0.5503 | 0 |
| LongestRun | 1 | 992 / 1000 | 0.9920 | 0 | 0.5062 | 0 |
| Rank | 1 | 990 / 1000 | 0.9900 | 0 | 0.0266 | 0 |
| FFT | 1 | 989 / 1000 | 0.9890 | 0 | 0.5022 | 0 |
| NonOverlappingTemplate | 148 | 146468 / 148000 | 0.9800 | 0 | 0.0034 | 0 |
| OverlappingTemplate | 1 | 986 / 1000 | 0.9860 | 0 | 0.4827 | 0 |
| Universal | 1 | 984 / 1000 | 0.9840 | 0 | 0.1990 | 0 |
| ApproximateEntropy | 1 | 993 / 1000 | 0.9930 | 0 | 0.2583 | 0 |
| RandomExcursions | 8 | 4925 / 4960 | 0.9887 | 0 | 0.0278 | 0 |
| RandomExcursionsVariant | 18 | 11060 / 11160 | 0.9823 | 0 | 0.0983 | 0 |
| Serial | 2 | 1975 / 2000 | 0.9870 | 0 | 0.4118 | 0 |
| LinearComplexity | 1 | 989 / 1000 | 0.9890 | 0 | 0.8613 | 0 |
5. Scaled outcomes (GLI-19 §3.2.2 "final outcome", §3.2.3(b), §3.2.4(b))
Collection: tools/collect-outcomes.mjs — the ceremony above, then per round k the game's certified scaling of drbg(r_k, gameId): dice = intBelow(100), roulette = intBelow(37), coin = intBelow(2), slot-reel = 5 reels × intBelow(20) from one cursor, card-shuffle = Fisher–Yates shuffle(52). 100 draws per round for the N ≤ 100 games (20 for slot-reel) — exactly what a game engine consumes through stream.cursor(). Seed 0x5241494e4c41425f4f5554434f4d45535f32303236303931335f303030303001; per-run secrets, sessions, sha256 in results/outcomes/<mech>/<set>.csv.meta.json (CSV regenerable by seed). Runner: tools/run-outcomes.sh.
Adversarial player modes (RNG-DESCRIPTION App. A; GLI-19 §3.3.2(b), AGCO 4.26 "impervious to the player"): zero — player reveals are all-zero bytes; fixed — the player uses one fixed chain secret for every session; grind — for every session the player tries 16 candidate secrets and keeps the one whose first-round dice would be highest if the house reveal were the previous session's (a grinding strategy with no information about the unrevealed house chain). If the construction is sound, all three must be indistinguishable from the honest run.
Analysis (tools/analyze-outcomes.mjs, 99 % level): (1) total-distribution χ² (N − 1 d.f.) at α = .01 and .05; (2) the stream is cut into 100 blocks of 10⁶ draws, a χ² p-value per block, KS test of the 100 p-values against U(0,1) (a single lucky p-value cannot pass this); (3) serial correlation at lags 1…8, z = ρ√n on 5 × 10⁷ consecutive pairs, |z| < 2.576; (4) Wald–Wolfowitz runs above/below the median; (5) coupon-collector mean; (6) slot-reel interplay: for each of the 10 reel pairs the χ² test of independence on the 20 × 20 joint table (expected = row·column/n, 361 d.f.), plus the joint-uniformity χ² against n/400 per cell (399 d.f.); tool note: analyzer v1.0 evaluated the joint-uniformity statistic with 361 instead of 399 d.f., which produced three spurious α = .01 exceedances (chacha 3×4, hmac 0×1 and 2×4) in the first analysis pass — fixed 2026-09-14 (analyze-outcomes.mjs), all slot-reel sets re-analysed; the split-sample re-tests that prompted the fix are in results/outcomes/hmac/slot-reel.interplay-*-check.txt; (7) card-shuffle: 52 × 52 card × position table χ² (2601 d.f.), per-position χ² (51 d.f.) KS-uniformity, adjacency table (card j follows card i, 52 × 51), first-card χ².
5.1 Summary table (bash lab/tools/report-tables.sh outcomes)
| mechanism | data set | N | rounds × draws/round | scaled outcomes (draws) | adversary | χ² total (p) | blocked χ² KS (p) | serial corr. lags 1–8 (min p / any |z|>2.576) | runs (p) | interplay / shuffle | verdict @ α=.01 | |---|---|---|---|---|---|---|---|---|---|---|---| | chacha | card-shuffle | 52 | 2,000,000 decks × 52 = 104,000,000 placements | 104,000,000 | none | — | — | — | — | 52×52 table p=0.1000; per-position KS p=0.1369; adjacency p=0.2136; first card p=0.2173 | pass | | chacha | coin | 2 | 1,000,000 × 100 | 100,000,000 | none | 0.5279 | 0.2201 | 0.1183 / 0 | 0.9225 | — | pass | | chacha | dice-adv-fixed | 100 | 1,000,000 × 100 | 100,000,000 | fixed | 0.3725 | 0.1124 | 0.0707 / 0 | 0.6810 | — | pass | | chacha | dice-adv-grind | 100 | 1,000,000 × 100 | 100,000,000 | grind | 0.7094 | 0.0054 | 0.0021 / 1 | 0.2062 | — | see note: blockedChiSquareKS, serial | | chacha | dice-adv-zero | 100 | 1,000,000 × 100 | 100,000,000 | zero | 0.2496 | 0.5761 | 0.0010 / 1 | 0.3649 | — | see note: serial | | chacha | dice | 100 | 1,000,000 × 100 | 100,000,000 | none | 0.9423 | 0.0960 | 0.0290 / 0 | 0.7735 | — | pass | | chacha | roulette | 37 | 1,000,000 × 100 | 100,000,000 | none | 0.9733 | 0.1694 | 0.0460 / 0 | 0.3495 | — | pass | | chacha | slot-reel | 20 | 1,000,000 × 20 × 5 reels | 100,000,000 | none | 0.6622 | 0.4724 | 0.0690 / 0 | 0.9127 | 10 reel pairs, min p 0.1192, 0 < .01 | pass | | hmac | card-shuffle | 52 | 400,000 decks × 52 = 20,800,000 placements | 20,800,000 | none | — | — | — | — | 52×52 table p=0.2708; per-position KS p=0.2010; adjacency p=0.5977; first card p=0.8365 | pass | | hmac | coin | 2 | 200,000 × 100 | 20,000,000 | none | 0.6467 | 0.3853 | 0.0275 / 0 | 0.9637 | — | pass | | hmac | dice-adv-fixed | 100 | 200,000 × 100 | 20,000,000 | fixed | 0.4204 | 0.2889 | 0.1027 / 0 | 0.1801 | — | pass | | hmac | dice-adv-grind | 100 | 200,000 × 100 | 20,000,000 | grind | 0.6844 | 0.9153 | 0.0333 / 0 | 0.1669 | — | pass | | hmac | dice-adv-zero | 100 | 200,000 × 100 | 20,000,000 | zero | 0.6192 | 0.7359 | 0.2120 / 0 | 0.0709 | — | pass | | hmac | dice | 100 | 200,000 × 100 | 20,000,000 | none | 0.6154 | 0.3611 | 0.1494 / 0 | 0.9334 | — | pass | | hmac | legacy-dice | 100 | 20,000,000 × 1 | 20,000,000 | none | 0.6013 | 0.4211 | 0.1479 / 0 | 0.6976 | — | pass | | hmac | legacy-roulette | 37 | 20,000,000 × 1 | 20,000,000 | none | 0.6663 | 0.0452 | 0.0096 / 1 | 0.6164 | — | see note: serial | | hmac | roulette | 37 | 200,000 × 100 | 20,000,000 | none | 0.0607 | 0.6584 | 0.0717 / 0 | 0.1988 | — | pass | | hmac | slot-reel | 20 | 200,000 × 20 × 5 reels | 20,000,000 | none | 0.4192 | 0.4219 | 0.0751 / 0 | 0.8716 | 10 reel pairs, min p 0.0400, 0 < .01 | pass |
Total scaled outcomes analysed: chacha = 804,000,000 (8.04e+08); hmac = 200,800,000 (2.01e+08) — every one of them is a game result after intBelow/shuffle (not a raw bit), produced by the same code path a game engine uses.
Reading the volume columns: rounds × draws/round is what the collector was asked for; scaled outcomes (draws) is the number of game results in the CSV (one line per round holds draws/round comma-separated outcomes; slot-reel lines hold 5 reel stops per draw; card-shuffle lines hold one 52-card permutation = 52 placements). One-screen artifact list with sizes, counts and sha256: EVIDENCE-INDEX.md.
Per-data-set detail (every lag, every reel pair, the 52 × 52 counts): results/outcomes/<mech>/<set>.analysis.md and .csv.analysis.json.
5.2 Fisher–Yates position uniformity (card-shuffle)
| mechanism | decks | 52×52 position table χ² (2601 d.f.) | p | per-position χ² (51 d.f.): positions with p < .01 / min p / KS p | adjacency χ² (2600 d.f.) p | first-card χ² (51 d.f.) p |
|---|---|---|---|---|---|---|
| chacha | 2,000,000 | 2693.87 | 0.1000 | 0 / 0.0343 / 0.1369 | 0.2136 | 0.2173 |
| hmac | 400,000 | 2644.60 | 0.2708 | 0 / 0.0221 / 0.2010 | 0.5977 | 0.8365 |
5.3 Interpretation
Every total-distribution χ² — the GLI-19 §3.2.3(b) test proper — passes at α = .01 for every game, both mechanisms and all three adversarial modes; the observed cell extremes are within ±0.3 % of expectation at 10⁶ per cell. The blocked-χ² KS test passes for every honest data set. The 100-block × 8-lag × per-pair design evaluates ≈ 15 independent statistics per data set at the 1 % level, i.e. ≈ 0.15 expected exceedances per data set and ≈ 2–3 over the whole table; the exceedances observed (listed in the "verdict" column: lag-4 |z| = 3.07 / 3.29 in the chacha grind / zero adversarial sets, blocked-KS p = .0054 in grind) are of that count and magnitude, are not shared between data sets (a real lag-4 dependence would appear in the honest dice set drawn from the same generator, where lag 4 has z = −1.27, and in the hmac adversarial sets, where every lag passes), and are of the kind GLI-19's "collectively, at a 99 % confidence level" anticipates. All 20 reel-pair independence tests pass at α = .01 (two at .04 for hmac, ≈ the expected 0.5–1 of 20 below .05). The adversarial sets are statistically indistinguishable from the honest set on every aggregate statistic, which is the property App. A claims.
6. TestU01
| mechanism | battery | result | statistics | cost |
|---|---|---|---|---|
| chacha | smallcrush | ALL PASSED | 15 statistics, p-values in [0.06, 0.96] | CPU 00:00:10.99, 226999458 words |
| chacha | crush | not run | — | — |
| chacha | bigcrush | not run | — | — |
| hmac | smallcrush | ALL PASSED | 15 statistics, p-values in [0.09, 0.92] | CPU 00:00:11.67, 226953194 words |
| hmac | crush | not run | — | — |
| hmac | bigcrush | not run | — | — |
SmallCrush was run file-backed on the 4 GB files (rain_file_gen: sequential, exits 3 instead of rewinding; consumed 2.27 × 10⁸ words = 0.9 GB each). Criteria: TestU01 flags p-values outside [10⁻³, 1 − 10⁻³] as suspicious and outside [10⁻¹⁰, 1 − 10⁻¹⁰] as failures; both runs print "All tests were passed" with no flagged statistic. Logs: results/testu01/<mech>/smallcrush.log, command lines in RUN.txt.
Crush and BigCrush were not run (see §9). The stream generator (rain_stream_gen) and runner (tools/run-testu01-crush-stream.sh <mech> crush|bigcrush [workers]) are shipped; Crush consumes ≈ 2³⁵ words ≈ 137 GB.
6a. Latency on a real network (engineering evidence, not a §2.2 statistical item)
An unmodified @rain/rng-node was deployed on a remote host (Render web service, origin GCP us-west1 Oregon behind Cloudflare) and driven from this lab host (AWS us-east-1 Virginia) by an unmodified RainRngClient — 1,000 sequential spins per run × {HTTPS, WebSocket} × {pipelining OFF, ON}; every round verified client-side. Measured application RTT (GET /healthz, keep-alive) p50 ≈ 101 ms.
| gap (animation) | transport | pipelining OFF — critical path p50 / p95 / p99 | pipelining ON — p50 / p95 / p99 | settled / errors |
|---|---|---|---|---|
| 60 ms | HTTPS | 88.5 / 101.8 / 119.3 ms | 36.0 / 49.0 / 67.5 ms | 2,000 / 0 |
| 60 ms | WebSocket | 91.1 / 100.2 / 101.5 ms | 23.3 / 39.7 / 57.9 ms | 2,000 / 0 |
| 0 ms (nothing to hide behind) | HTTPS / WS | ≈ 87 / 100 ms | ≈ 87 / 100 ms — ON ≈ OFF, as the model predicts | 4,000 / 0 |
| 1,000 ms (realistic reel) | HTTPS / WS | see results/latency-real-network/loadtest-gap1000.txt |
critical path = local settle only |
Critical path with pipelining ≈ max(0, RTT − animation). Full report, raw JSON, network probes and the exact server bundle: results/latency-real-network/{REPORT.md,results*.json,network-baseline.txt,RUN.txt,deploy-manifest.txt}.
7. Verdict against the §2.2 criteria
| Criterion (docs/LAB-SUBMISSION-REQUIREMENTS.md §2.2) | chacha20 | hmac-drbg |
|---|---|---|
| Dieharder: no reproducible FAILED; WEAK at the ≈ 2 % rate | met — 0 FAILED in 95 lines (+ 0 FAILED in 450 sts_serial replicate lines); WEAK 5/95 ≈ 5 % (all in the p > 0.99 tail except one; 3 of the 5 are sts_serial lines; the 15 replicate loops give 6/450 = 1.3 % WEAK) | met on the 86 lines run — 0 FAILED, 3 WEAK (3.5 %); 28 test/ntuple combinations not run (§9) |
| NIST STS: every proportion within CI, every uniformity P ≥ 10⁻⁴ | met — 188/188 lines inside the CI, all uniformity P ≥ 10⁻⁴ | met — 188/188 lines inside the CI, all uniformity P ≥ 10⁻⁴ |
| TestU01: no statistic outside [10⁻¹⁰, 1 − 10⁻¹⁰]; none suspicious | met (SmallCrush) | met (SmallCrush) |
| Scaled χ² at 99 % for each game; runs/serial at 99 %; shuffle 52 × 52 p ≥ .01 | met (§5) | met (§5) |
| Adversarial-player outcomes indistinguishable from honest | met (§5.1) | met (§5.1) |
8. Invalid runs — quarantined, not evidence
| Directory | What | Why invalid | Disposition |
|---|---|---|---|
results/dieharder/_smoke-invalid/chacha-13MB/ |
dieharder -a -g 201 -f on the 13 MB smoke file (raw/chacha/raw.bin) |
387 file rewinds; a diehard_craps FAILED line in it is an artefact of recycled input |
retained for transparency; retracted; runner now refuses files < 1 GB |
results/dieharder/_invalid-rewound/chacha-4GB-file/ |
dieharder -a -g 201 -f on the 4 GB chacha file (63 PASSED / 1 WEAK / 0 FAILED as printed) |
19 file rewinds (from diehard_squeeze onward, cumulative 4 rewinds by rgb_bitdist 8); a full battery needs ≈ 250 GB |
retained; retracted; superseded by the stream run (§3) |
results/sts/chacha first attempt (2026-09-14 00:01–01:24) |
STS chacha in the shared sts-2.1.2 tree |
a 5-sequence debug run was started in the same experiments/ directory and truncated the files the 1000-sequence run was writing |
deleted; re-run in a private tree (labtools/sts/sts-chacha), result in §4 |
results/dieharder/{chacha,hmac}-stream first attempts (2026-09-13 23:31–23:33 and 2026-09-14 00:01–00:25) |
single-process dieharder -a -g 200 |
producer killed together with the worker session (stdin_input_raw(): Error: EOF), no result lines survived |
deleted; replaced by the per-test resumable runner |
9. Not run, and why
| Item | Reason | How the lab can run it |
|---|---|---|
Dieharder rgb_lagged_sum ntuple 14–32 (chacha), and the tail of the battery for hmac (§3.2) |
data volume: 0.44 × (n + 1) GB per ntuple → ≈ 200 GB for 14…32; HMAC_DRBG produces ≈ 1 MB/s per core (≈ 55 µs per 256-bit block through the full ceremony path) | bash lab/tools/run-dieharder-stream.sh <mech> <workers> — resumable, finished tests are skipped |
| TestU01 Crush / BigCrush | 2³⁵ / 2³⁸ words; attempted for chacha at 00:26Z, aborted at 00:40Z (≈ 10 h projected at the 4 MB/s available under load) | bash lab/tools/run-testu01-crush-stream.sh chacha crush 8 on an idle 8-core host ≈ 2.5 h; hmac Crush ≈ 19 h |
hmac scaled outcomes at 10⁸ (main sets at 2 × 10⁷; 10⁸ sets for dice/roulette/coin/slot-reel running in results/outcomes/hmac-1e8/, exact counts in EVIDENCE-INDEX.md) |
1.5 CPU-hours per 10⁸ game | P=4 bash lab/tools/run-outcomes-hmac-1e8.sh (resumable) |
10. Reproducibility — exact commands
# 0. build + fingerprints (BUILD.md)
npm ci && npm run lab:verify-build
# 1. raw 4 GB files (SEED-BIG; sha256 must match results/raw/<mech>/raw-32gbit.bin.sha256)
node lab/tools/collect-raw.mjs --bits 32e9 --mechanism chacha --seed $(cat lab/results/raw/chacha/SEED-BIG) --workers 4 --words-per-draw 1 --draws 64 --out lab/results/raw/chacha/raw-32gbit.bin
node lab/tools/collect-raw.mjs --bits 32e9 --mechanism hmac --seed $(cat lab/results/raw/hmac/SEED-BIG) --workers 4 --words-per-draw 8 --draws 64 --out lab/results/raw/hmac/raw-32gbit.bin
# 2. Dieharder full battery, stream (resumable)
bash lab/tools/run-dieharder-stream.sh chacha 4 ; bash lab/tools/run-dieharder-stream.sh hmac 5
bash lab/tools/summarize-dieharder-stream.sh chacha
# 3. NIST STS (one private STS tree per mechanism)
bash lab/tools/run-sts.sh chacha lab/results/raw/chacha/raw-32gbit.bin 1000 1000000 /path/to/sts-2.1.2-copy-A
bash lab/tools/run-sts.sh hmac lab/results/raw/hmac/raw-32gbit.bin 1000 1000000 /path/to/sts-2.1.2-copy-B
# 4. TestU01
lab/tools/testu01/rain_file_gen lab/results/raw/chacha/raw-32gbit.bin smallcrush "RAIN chacha raw-32gbit"
bash lab/tools/run-testu01-crush-stream.sh chacha crush 8
# 5. scaled outcomes + analysis (P parallel jobs)
P=4 bash lab/tools/run-outcomes.sh
# 6. this report's tables
bash lab/tools/report-tables.sh all
11. Provenance
Report tables generated 2026-09-14T09:18Z from lab/results/. Run journal: lab/results/PROGRESS.md; raw logs: lab/logs/. Data files > 100 MB are not committed (regenerable from the seeds; sha256 recorded next to each).
← Back to the package index · Rendered 2026-09-14 09:34 UTC from the repository copy; the markdown in the zip / repo is the document of record.