Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

HDPRF — High-Dimensional Polynomial Randomness Framework

A pseudorandom byte generator that treats its internal state as an N-dimensional coordinate space. Each of N axes holds a byte stream partitioned into 256-byte blocks; a keyed function selects which block each axis reads from, and a polynomial combines the N sampled bytes into one output byte, which then drives an output mixing layer.

This is not a cryptographic random number generator. Do not use it to generate keys, nonces, IVs, or anything else where an adversary is in the threat model. The reason is architectural, not a missing feature — see Security status.


Status

Research code, honestly documented. It runs, it is reproducible, its behaviour matches its design, and its statistical properties have been measured against controls rather than asserted.

Four implementation defects and one configuration defect were found in an audit during August 2026. Four are fixed; one is inherent to the architecture and will not be fixed. All are recorded in KNOWN_ISSUES.md, including what the incorrect behaviour was, how it was found, and what it invalidated. That document is worth reading before the source.


What it does

seed file
    │
    ├── SHA-512 ──► master entropy
    │                   ├── BLAKE2b (personalised per axis) ──► 2N axis keys
    │                   └── BLAKE2b + SHAKE256 ──────────────► output-layer seeds
    │
    └── SHA-512 ──► RNG seed ──► prime sampling ──► F1 ──► 2N initial values
                                                             │
                                            SplitMix64 expansion
                                                             │
                                    ┌────────────────────────┴───────┐
                              N axis streams                  N index streams
                                    └──────────► core layer ◄────────┘
                                                      │
                                    for each output byte i:
                                      b = i // 256                (block counter)
                                      s = i %  256                (offset in block)
                                      for each axis d:
                                        blk = SHAKE256(key_d ‖ d ‖ chunk)[4b:4b+4]
                                        v_d = axis_d[blk·256 + s]
                                      core_out = F_final(v_0 … v_{N-1}) + index_byte
                                                      │
                                              output mixing layer
                                          (LCG + XOR accumulator + fmix64)
                                                      │
                                                 byte stream

Block selection is counter-addressable: block b of chunk c on axis d depends only on (key_d, d, c, b). Any chunk can be produced without producing the ones before it, and axes advance independently. This is what makes the generator parallelisable and reproducible. It is also what rules out cryptographic use.

Install

git clone https://github.com/<user>/HDPRF.git
cd HDPRF
python -m venv .venv
source .venv/bin/activate          # Windows: .venv\Scripts\activate
pip install -r requirements.txt

Python 3.10–3.12. Numba pins the supported NumPy range, so install from requirements.txt rather than pulling latest.

Run

python tools/make_data.py                                   # generate data files
python src/main.py -c configs/default_config.json
python src/main.py -c configs/default_config.json --profile

data/example_prime.txt and data/example_seed.bin are not tracked in the repository — the first is reproducible, and the second is entropy material that should not be published. tools/make_data.py generates both.

Configuration

Key Meaning
dimension N — number of coordinate axes
s1_length blocks per axis; each block is 256 bytes
iteration_count number of intermediate mixing layers before output
F1, F_layers.F2… polynomial coefficients, powers, constant per layer
buffer_size width of the output-layer XOR accumulator
decimal output length in bytes
RandomnessExtractor none, sha256, sha512, or blake2b
external_entropy_source path to the seed file; omit to use os.urandom

Polynomial powers below 5 leak the input. See Diagnostic experiments — this is measured, not theoretical. Use odd powers of 5 or above, and an even constant.

Verification

python tools/verify_fixes.py    # regression checks for the fixed defects
python tools/experiments.py     # diagnostic experiments, writes plots to photo/
python tools/comparison.py A B  # byte-level identity check between two outputs

Statistical results

TestU01 BigCrush — passed

Run against a C++ implementation of this design (TestU01 1.2.3, WSL, 1330 GB consumed, ~2 h CPU):

Number of statistics:  160
All tests were passed

The pass is clean rather than marginal. Extracting all 254 reported p-values and testing them for uniformity gives Kolmogorov–Smirnov D = 0.0742, p = 0.117 — no evidence of departure from uniform. Three p-values fell below 0.01 and four above 0.99, against roughly 2.5 expected for each. The ten-bin histogram is flat.

Caveat: the exact C++ source used for this run has been lost. The implementation was a port of this design with the same output mixing layer, but it cannot currently be reproduced. It is reported here as history, not as a reproducible claim.

Ablation study

A BigCrush pass does not say which part of the generator earned it. The core layer and the output mixing layer were therefore separated by substituting the core's output, one line at a time, and re-testing.

Through the mixer — the core's output is replaced, the mixer is untouched:

Core input SmallCrush (15) Crush (186)
Real HDPRF core pass 0 failures
Single SplitMix64 call pass 0 failures
Weyl sequence i·φ >> 56 pass 2 failures
Ramp i & 0xFF 13 failures
Constant zero 13 failures

Bypassing the mixer — raw core bytes are emitted directly:

Raw output SmallCrush (15) Crush (186)
Real HDPRF core pass 0 failures, KS p = 0.309
Single SplitMix64 call pass 0 failures, KS p = 0.135
Weyl sequence 15 failures

Three findings:

The core layer is a working generator. Its raw output — with the mixer removed entirely — passes all 186 Crush statistics with a uniform p-value distribution. scomp_LinearComp and smarsa_MatrixRank, which target linear structure, show nothing. The 43-axis architecture is producing randomness, not decorating it.

The mixer cannot create entropy, but it is a powerful equaliser. Feed it a constant or a period-256 ramp and it fails 13 of 15 SmallCrush statistics: its state recursion s_{n+1} = A·s_n + c_n + B is affine, so a periodic c_n produces a periodic state trajectory that fmix64 cannot rescue. But feed it a Weyl sequence — which fails 15 of 15 raw — and it launders it into something failing only 2 of 186. Both survivors are snpair_ClosePairs at t = 2, the lattice detector; that is the exact fingerprint of a Weyl lattice, and it is all that remains visible.

The core is statistically indistinguishable from a single SplitMix64 call. Across 186 statistics in both modes, no measurable difference. That is three multiplications and three shifts against 43 random-access gathers. The architecture is not producing a statistical advantage proportional to its cost.

Diagnostic experiments

tools/experiments.py writes three plots to photo/:

exp3 — with F1 powers all set to 1, the polynomial degenerates to a plain sum of six primes. Its range collapses to roughly 2^18, bits 19–63 are permanently zero, and chi-square against a uniform 256-bucket histogram is 2.55e6 against an expected 255.

exp4 — Pearson correlation between input and output is 1.000 at power 1 and 0.934 at power 3. The scatter plot at power 1 is a straight line: the output discloses the input directly. Powers of 5 and above scatter properly.

exp5 — differential uniformity is 256x the ideal at power 1 and 25x at power 2, approaching 1 only from power 3 upward.

Three independent measurements, one conclusion: powers below 5 are not usable.


Security status

The core makes one memory access per axis per output byte, at an address derived from the key:

v = axis[d][block_id * 256 + offset]      # block_id <- SHAKE256(key_d, ...)

Key-dependent table indexing is precisely the pattern cache-timing attacks target. Bernstein (2005) and Osvik–Shamir–Tromer (2006) recovered full AES keys from T-table access timing, remotely. Salsa20 and ChaCha20 were designed to avoid data-dependent memory access for this reason — they use only add, rotate and XOR, and are constant-time by construction.

Making HDPRF constant-time would mean reading every axis in full for every output byte: 43 x 262144 bytes per byte produced. That is not a tuning problem; it is a different algorithm.

HC-128 reached the eSTREAM software portfolio with key-dependent tables, so this is not categorically disqualifying — but HC-128's deployment has been minimal, and this is a substantial part of why.

Separately, the N-dimensional structure provides no cryptographic advantage. An N-tuple of indices is mathematically equivalent to one wider counter; L^N is a naming space, not a state space, and the entropy of the output is bounded by the entropy of the seed regardless of N.

On linear structure

The low bit of a sum modulo 256 is the XOR of the operands' low bits, which is affine over GF(2). The ablation study found no trace of this in any statistical test, and that is expected: the 43 operands are themselves pseudorandom and unknown, so "XOR of 43 unknown pseudorandom bits" is still pseudorandom to a test that does not know them.

This makes the affine structure a cryptanalytic property, not a statistical one. An attacker who knows the coefficients can set up linear equations over the key; a statistical battery cannot. The two should not be conflated, and a clean BigCrush result says nothing about the first.


Performance

Implementation Throughput
C++ / OpenMP, multi-threaded ~160 MB/s
Python / Numba prange ~1.1 MB/s

For scale, ChaCha20 reaches 1–3 GB/s single-threaded. The cost here is N random-access gathers per output byte, and there is no plausible path to closing that gap.

An earlier benchmark chart compared HDPRF against ChaCha20, AES-128-CTR and Mersenne Twister. It should not be relied on. The thread count for HDPRF and the reference implementations used for the comparators were not recorded, and the ChaCha20 figure (~364 MB/s) is far below what an optimised implementation achieves — suggesting an unvectorised reference build. Comparing a multi-threaded OpenMP generator against that is not a meaningful comparison.


Where this might actually be useful

  • Reproducible parallel simulation. Multi-dimensional addressing means a tuple like (particle, timestep, event_type) maps directly to a coordinate without being flattened into a counter first, and any dimension can be re-run independently. Philox and Threefry offer addressability, but with a flat counter.
  • High-dimensional box-counting. The L^N partition is a grid, and the machinery to build and query it in parallel already exists here.

Both are engineering conveniences rather than novel results. Neither is cryptography.


Layout

src/main.py                  pipeline, config handling, jump table manager
src/kernels.py               Numba kernels, in a separate module so that
                             cache=True keys them under one stable name
configs/default_config.json  reference configuration
tools/make_data.py           generates the prime and seed files
tools/verify_fixes.py        regression checks for the fixed defects
tools/experiments.py         diagnostic experiments (3, 4, 5)
tools/comparison.py          byte-level identity check between two outputs
photo/                       diagnostic plots
KNOWN_ISSUES.md              defect history and current limitations

License

MIT.

About

An N-dimensional coordinate-addressed PRNG, with an ablation study separating core randomness from output mixing. Not cryptographic.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages