A
no_stdRust Cargo Workspace for streaming statistical randomness testing.
Runs natively as a CLI binary (randstat) and compiles to WebAssembly for web dashboards.
Evolved from Stochast/entropy β old project untouched, this is the clean rewrite.
| Suite | Tests | Standard | Status | Description |
|---|---|---|---|---|
| randstat-suite-ent | 5 tests | Fourmilab ENT | β Complete | Fast baseline β entropy, chi-square, arithmetic mean, Monte Carlo Ο, serial correlation |
| randstat-suite-nist | 15 tests | NIST SP 800-22 Rev 1a | π§ In Progress | Cryptographic randomness battery (Β§2.1βΒ§2.15) β monobit active, structured stubs |
| randstat-suite-sp800-90b | 10 tests | NIST SP 800-90B | π Planned | Min-entropy estimation on physical noise sources (TRNG/QRNG) |
| randstat-suite-ais31 | 9 tests | BSI AIS 20 / AIS 31 | π Planned | German BSI physical TRNG evaluation battery (Tests T0βT8) |
| randstat-suite-dieharder | 12 tests | DIEHARD / Dieharder | π Planned | Classical PRNG verification battery (Birthday spacings, Craps, Squeeze, etc.) |
| randstat-suite-testu01 | 10+ tests | TestU01 | π Planned | Academic benchmark batteries (SmallCrush / Crush / BigCrush) |
| randstat-suite-practrand | 6 tests | PractRand | π Planned | Dynamic multi-terabyte stream testing filters (BCFN, Gap-16, FPFT, etc.) |
| randstat-suite-gjrand | 4 tests | gjrand | π Planned | Lightweight generator benchmarking battery |
| randstat-suite-full | Master | Unified meta-suite | π§ In Progress | Comprehensive aggregator combining all test batteries |
All suites run in both native (CLI/embedded) and WebAssembly environments
no_stdcompatible β runs on embedded systems, compiles to WASM- Streaming API β process unlimited data with constant memory
- Implement once, reuse everywhere β shared tests defined once in
randstat-tests, reused across suites - Modular suites β link only the batteries you need (precise WASM binary control)
- Zero heap allocation β all tests are
Copy + const-constructible - Multi-format output β terminal tables, Markdown reports, JSON (CI/CD)
- Explicit TestStatus β real evaluated tests vs
NOT IMPLEMENTEDstubs clearly distinguished
# Evaluate with standard ENT suite (default)
randstat data.bin
# Evaluate with NIST SP 800-22 battery
randstat data.bin --suite nist
# Generate Markdown report
randstat data.bin --suite nist --md
# JSON output for scripts / CI
randstat data.bin --suite nist --json
# Read from stdin
cat /dev/urandom | head -c 1M | randstat --suite nist
# ASCII mode (one number per line)
randstat numbers.txt --ascii
# Custom significance level (99% confidence)
randstat data.bin --alpha 0.01randstat-core #![no_std] libm
β
β algorithms/ β pure stateless evaluation functions
β bitstream/ β streaming byte accumulators (SHA-256, MC, SCC, freq)
β math/ β chi2 PDF/CDF, critical values, plot generators
β stats/ β EntResult, GuardrailEvaluation #[repr(C)] structs
β traits.rs β StreamTest trait + TestResult + TestStatus
β
β
randstat-tests #![no_std] thin StreamTest wrappers (one file per test)
β
ββββββββββββββββββββ¬βββββββββββββββββββ¬βββββββββββββββββββ¬βββββββββββββββββββ
β β β β β
randstat-suite-ent randstat-suite-nist randstat-suite-sp800-90b randstat-suite-ais31 (dieharder, testu01, etc.)
β β β β β
ββββββββββββββββββββ΄βββββββββββββββββββ΄βββββββββββββββββββ΄βββββββββββββββββββ
β
randstat-suite-full (meta-suite aggregating all)
β
ββββββββββ΄βββββββββ
β β
randstat-cli randstat-wasm
(std) (#![no_std], modular feature flags)
| Principle | Implementation |
|---|---|
| One test = one file | Every StreamTest struct lives in its own .rs file in randstat-tests
|
| Implement once | Common tests (Monobit, Runs, Rank, |
| Algorithms in core | Pure evaluation functions in randstat_core::algorithms β no state, just math |
| Suites as separate crates | Each suite is independently linkable β precise WASM binary size control |
| Zero heap allocation | All suites are Copy + const-constructible; static mut in WASM is safe |
no_std boundary |
core + libm only; std exists only in randstat-cli
|
| Zero heap allocation | All suites are Copy + const-constructible; static mut in WASM is safe |
no_std boundary |
core + libm only; std exists only in randstat-cli
|
Comprehensive catalog of all implemented and planned tests, organized by functional category.
| Test | Standard | Suites | Status |
|---|---|---|---|
| Shannon Entropy | Fourmilab ENT | ENT, Full, AIS 31 | β Real |
| Frequency (Monobit) | NIST SP800-22 Β§2.1 | NIST, Full, AIS 31 | β Real |
| Chi-Square Uniformity | ENT / Pearson | ENT, NIST, Full, AIS 31, gjrand | β Real |
| Arithmetic Mean | Fourmilab ENT | ENT, NIST, Full | β Real |
| Block Frequency | NIST SP800-22 Β§2.2 | NIST, Full | π§ Stub |
| Cumulative Sums (CUSUM) | NIST SP800-22 Β§2.13 | NIST, Full | π§ Stub |
| Serial Test (m-bit patterns) | NIST SP800-22 Β§2.11 | NIST, Full | π§ Stub |
| Count Ones in Stream | Dieharder | Dieharder | π§ Stub |
| Test | Standard | Suites | Status |
|---|---|---|---|
| Runs Test | NIST SP800-22 Β§2.3 | NIST, Full | π§ Stub |
| Longest Run of Ones | NIST SP800-22 Β§2.4 | NIST, Full | π§ Stub |
| Runs Up/Down | Dieharder | Dieharder | π§ Stub |
| OPERM5 (Overlapping Permutations) | Dieharder | Dieharder | π§ Stub |
| Test | Standard | Suites | Status |
|---|---|---|---|
| DFT / FFT Spectral | NIST SP800-22 Β§2.6 | NIST, Full | π§ Stub |
| Test | Standard | Suites | Status |
|---|---|---|---|
| Non-overlapping Template | NIST SP800-22 Β§2.7 | NIST, Full | π§ Stub |
| Overlapping Template | NIST SP800-22 Β§2.8 | NIST, Full | π§ Stub |
| OQSO | Dieharder | Dieharder | π§ Stub |
| DNA | Dieharder | Dieharder | π§ Stub |
| Test | Standard | Suites | Status |
|---|---|---|---|
| Maurer's Universal | NIST SP800-22 Β§2.9 | NIST, Full | π§ Stub |
| Berlekamp-Massey (Linear Complexity) | NIST SP800-22 Β§2.10 | NIST, Full | π§ Stub |
| Approximate Entropy | NIST SP800-22 Β§2.12 | NIST, Full | π§ Stub |
| Squeeze | Dieharder | Dieharder | π§ Stub |
| Test | Standard | Suites | Status |
|---|---|---|---|
| Monte Carlo Ο Estimation | Fourmilab ENT | ENT, Full | β Real |
| Serial Correlation | Fourmilab ENT | ENT, Full | β Real |
| Birthday Spacings | Dieharder | Dieharder | π§ Stub |
| Parking Lot | Dieharder | Dieharder | π§ Stub |
| Minimum Distance 2D | Dieharder | Dieharder | π§ Stub |
| 3D Spheres | Dieharder | Dieharder | π§ Stub |
| Test | Standard | Suites | Status |
|---|---|---|---|
| Binary Matrix Rank | NIST SP800-22 Β§2.5 | NIST, Full | π§ Stub |
| Test | Standard | Suites | Status |
|---|---|---|---|
| Random Excursions | NIST SP800-22 Β§2.14 | NIST, Full | π§ Stub |
| Random Excursions Variant | NIST SP800-22 Β§2.15 | NIST, Full | π§ Stub |
| Test | Standard | Suites | Status |
|---|---|---|---|
| Overlapping Sums | Dieharder | Dieharder | π§ Stub |
| Craps | Dieharder | Dieharder | π§ Stub |
Note: NIST Serial Test (Β§2.11) is an m-bit pattern frequency test, distinct from the ENT Serial Correlation test (Pearson correlation coefficient).
SHA-256 Note: SHA-256 is used for file identity fingerprinting, not as a statistical test. It's implemented in
randstat-core::bitstream::sha256and exposed as standalone WASM exports (sha256_reset/update/finalize) available in every build, including math-only.
randstat/
βββ Cargo.toml Workspace root
βββ justfile Build recipes
βββ crates/
β βββ randstat-core/ Core primitives (#![no_std])
β β βββ src/
β β βββ algorithms/ Pure stateless evaluation functions
β β βββ bitstream/ Streaming accumulators (SHA-256, MC, SCC, freq)
β β βββ math/ Chi-square PDF/CDF, critical values, plotting
β β βββ stats/ Result structs (#[repr(C)] for WASM)
β β βββ traits.rs StreamTest trait + TestResult
β βββ randstat-tests/ Individual test implementations (#![no_std])
β β βββ src/
β β βββ frequency/ Bit/byte frequency tests
β β βββ runs/ Run-structure tests
β β βββ spectral/ Fourier/spectral tests
β β βββ template/ Pattern occupancy tests
β β βββ complexity/ Compressibility tests
β β βββ spatial/ Geometric tests
β β βββ matrix/ Matrix rank tests
β β βββ excursions/ Random walk tests
β β βββ distribution/ Derived-distribution tests
β βββ randstat-suite-ent/ ENT suite
β βββ randstat-suite-nist/ NIST SP800-22 suite
β βββ randstat-suite-quick/ Quick screening suite
β βββ randstat-suite-full/ Full suite (ENT + NIST)
β βββ randstat-suite-dieharder/ Dieharder suite (planned)
βββ apps/
β βββ randstat-cli/ CLI binary
β βββ randstat-wasm/ WASM library (6 feature-gated builds)
βββ ui/ JavaScript SDK
-
Implement the algorithm in
randstat-core/src/algorithms/your_test.rs:pub fn your_test(count: u64, total: u64) -> TestResult { ... }
Register in
algorithms/mod.rs. -
Create the accumulator in
randstat-tests/src/category/your_test.rs:pub struct YourTest { /* raw counts */ } impl StreamTest for YourTest { fn evaluate(&self) -> TestResult { randstat_core::algorithms::your_test::your_test(self.count, self.total) } }
Register in
category/mod.rs. -
Add to suite: Edit the suite crate (e.g.,
randstat-suite-nist/src/lib.rs) to add the field and update/reset calls. -
Verify:
cargo check --workspace && cargo test --workspace
# Development
just check # Check workspace
just test # Run tests
just check-wasm # Check no_std crates for wasm32 target
just ci # Full CI gate (check + check-wasm + test)
# CLI
just build # Build CLI
just run -- FILE # Run CLI on file
just install # Install to ~/.cargo/bin/randstat
# WebAssembly (5 size-optimized variants)
just build-wasm-all # Build all variants
just build-wasm-math # ~3β5 KB β PDF/CDF calculators only
just build-wasm-ent # ~15β18 KB β ENT suite
just build-wasm-quick # ~12β15 KB β Quick suite
just build-wasm-nist # ~30 KB β NIST suite
just build-wasm-full # ~35 KB β Full suite (ENT + NIST)
# Manual WASM build
cargo build -p randstat-wasm \
--no-default-features --features ent \
--target wasm32-unknown-unknown --releaseBinary: randstat
Modes: Binary stream (default) | ASCII line mode (--ascii)
Output formats: Terminal table | Markdown (--md) | JSON (--json)
==========================================================================================
RANDSTAT RANDOMNESS EVALUATION REPORT
==========================================================================================
File / Input Source : data.bin
Input Data Mode : Binary (Raw Byte Stream)
Evaluated Stream : 3,563,365 bytes (3.40 MB)
SHA-256 Hash : 004a5176923d5fa689405c1b573a44313fc1ed7f1f1713c95c76583650d4bdf6
Significance Alpha : Ξ± = 0.0500 (95.0% Confidence)
+------------------------+---------------------+-----------------------+--------------------+--------+
| Test Metric | Calculated Value | Ideal Range (Ξ±=5%) | Deviation / Exceed | Status |
+------------------------+---------------------+-----------------------+--------------------+--------+
| Shannon Entropy | 7.999943 b/B | ~ 8.000000 bits/byte | Compress: 0.00% | PASS |
| Chi-Square (df=255) | 281.47 | [212.65 - 301.14] | Exceed: 12.24% | PASS |
| Arithmetic Mean | 127.5564 | ~ 127.500000 | Diff: +0.0564 | PASS |
| Monte Carlo Pi | 3.138647637 | ~ 3.141592654 | Error: 0.09% | PASS |
| Serial Correlation | -0.000100 | [-0.010000, 0.010000] | Uncorrelated | PASS |
+------------------------+---------------------+-----------------------+--------------------+--------+
OVERALL VERDICT: [β LIKELY RANDOM]
| Verdict | Meaning |
|---|---|
β LIKELY RANDOM |
All metrics within statistical bounds |
β NON-UNIFORM |
Chi-square exceedance too low β biased or patterned byte distribution |
β TOO UNIFORM |
Chi-square exceedance too high β artificially forced uniformity |
| Export | Description |
|---|---|
chi2_pdf_export(x, df) |
Chi-square PDF at x |
normal_pdf_export(x, df) |
Normal approximation PDF |
chi2_critical_value_export(alpha, df) |
Wilson-Hilferty critical value |
chi2_pochisq(x, df) |
Upper-tail exceedance probability |
get_buffer_ptr() |
Pointer to 1000-element f64 plot buffer |
wasm_generate_chi2_points(df, xmin, xmax, steps) |
Fill buffer with Chi-square curve points |
wasm_generate_normal_points(df, xmin, xmax, steps) |
Fill buffer with Normal curve points |
sha256_reset() |
Reset SHA-256 accumulator |
sha256_update(ptr, len) |
Feed bytes into SHA-256 accumulator |
sha256_finalize(out_ptr) |
Write 32-byte digest to out_ptr |
| Export | Description |
|---|---|
ent_reset() |
Reset all ENT accumulators |
ent_update(ptr, len) |
Feed len bytes at ptr into the suite |
ent_finalize(out_result*) |
Write EntResult struct to out_result |
ent_validate(alpha, out_guardrail*) |
Write GuardrailEvaluation to out_guardrail |
Note:
ent_finalizesetsEntResult.sha256to zero. Callsha256_finalizeseparately for the digest.
| Feature | Exports |
|---|---|
nist |
nist_reset(), nist_update(ptr, len) |
quick |
quick_reset(), quick_update(ptr, len) |
full |
full_reset(), full_update(ptr, len) |
const wasm = await WebAssembly.instantiateStreaming(fetch('randstat_wasm.wasm'));
const exports = wasm.instance.exports;
const { memory, sha256_reset, sha256_update, sha256_finalize,
ent_reset, ent_update, ent_finalize } = exports;
// SHA-256 and the suite are independent β both receive the same bytes.
const INPUT_OFFSET = 65536;
const RESULT_OFFSET = INPUT_OFFSET + data.length;
const DIGEST_OFFSET = RESULT_OFFSET + 128; // after EntResult struct
sha256_reset();
ent_reset();
new Uint8Array(memory.buffer, INPUT_OFFSET, data.length).set(data);
sha256_update(INPUT_OFFSET, data.length);
ent_update(INPUT_OFFSET, data.length);
// Two separate outputs:
sha256_finalize(DIGEST_OFFSET); // 32 bytes β file identity
ent_finalize(RESULT_OFFSET); // EntResult struct β statistical metrics
// Read the 32-byte digest
const digest = new Uint8Array(memory.buffer, DIGEST_OFFSET, 32);
const hex = Array.from(digest).map(b => b.toString(16).padStart(2,'0')).join('');Contributions are welcome! Before submitting a pull request, please read and agree to the Contributor License Agreement (CLA).
In brief: Your contributions will be publicly available under EUPL-1.2, but you grant the project maintainer additional rights to use contributions in proprietary projects. See CLA.md for full details.
Licensed under the European Union Public Licence v1.2 (EUPL-1.2).
Note for Contributors: By contributing to this project, you agree to the Contributor License Agreement (CLA), which grants the project maintainer broader rights including use in proprietary projects.