wj-diode-quantum
Collects quantum random numbers from the Australian National University, streams them across a data diode, and serves them one at a time on the protected side. Each value is 1024 bits.
A data diode only carries data one way, so a machine behind one cannot ask ANU for random numbers itself. This program splits the job in two: one side collects and pushes, the other stockpiles what arrives and hands it out on request.
Quick start
Two machines, one command each.
Machine 1 — internet side
uv tool install wj-diode-quantum
wj-diode-quantum setup send
wj-diode-quantum collect -c config.json
Machine 2 — protected side
uv tool install wj-diode-quantum
wj-diode-quantum setup recv
wj-diode-quantum serve -c config.json
Check it works
curl localhost:8099/api/status # numbers are arriving
curl localhost:8099/api/random # take one
{
"value": "74b033a4332c7112cf0c3ff5...67f6b30ee",
"timestamp": "2026-08-02T04:14:58Z",
"source": "quantumnumbers",
"bits": 1024
}
value is your 1024-bit random number, 256 lowercase hex characters. timestamp is when it was
collected. You will never be given that number again.
Or without the JSON around it — each of these carries the same metadata in X-Quantum-* headers:
curl localhost:8099/api/random/hex # 256 hex characters
curl localhost:8099/api/random/base64 # the same value, base64
curl -o key.bin localhost:8099/api/random/binary # exactly 128 raw bytes
Open http://localhost:8099/ in a browser for the same thing with live pool figures, or
curl localhost:8099/api/help for it as plain text. There is an OpenAPI description at
/api/spec.
Full documentation: docs.waterjuice.org/wj-diode-quantum
Features
- The numbers are never written in the clear. The collecting side writes nothing at all. The serving side can keep its pool across restarts, but only encrypted, under a passphrase held in the environment and never stored beside the file.
- Both ANU APIs — the current keyed service and the older unkeyed one, each on its own schedule sized to its rate limit. Enable either or both.
- Any diode tool — the transfer is a configured external command reading and writing a stream.
Built against
diodetool, but nothing about it is hard-coded. - Never serves the same number twice — including across a restart, when the pool is persisted. A value is recorded as served on disk before it reaches the client, so a crash mid-request can only lose it, never hand it out again.
- Four output formats — JSON, hex, base64 and raw bytes, with the metadata in response headers.
- Bounded, self-trimming pool — newest served first, oldest discarded at capacity.
- One process per machine — the receiving side runs the diode tool for you.
- Damage is contained — a diode cannot retransmit, so a corrupted value is dropped and the stream resynchronises rather than losing everything behind it.
- Zero dependencies — a single static binary, Go standard library only.
Requirements
- A tool that can move a file across your diode, on both sides.
- An ANU API key from quantumnumbers.anu.edu.au, free with an account. Optional if you only use the legacy endpoint.
Building
make build # wheels for all platforms, plus documentation
make check # tests, format check, and vet
make dev # run from source via a .venv launcher
How it fits together
internet side diode protected side
───────────── ───── ──────────────
ANU ──> collect ──> [ stream-send ] ══════> [ stream-recv ] ──> serve ──> GET /api/random
stdin stdout │
v
pool (encrypted on
disk, or memory)
Nothing comes back, so the collector never learns whether anything arrived. On the sending side nothing is stored at all: a transfer the diode will not take is retried and then discarded. On the serving side the pool may be kept across restarts, encrypted; without that it is lost on restart and refills from the far side's next cycle.
Security
There is no authentication on the API. Anyone who can reach the port can drain the pool. The
default binds to 127.0.0.1 — keep it on loopback or a trusted network, or put a reverse proxy in
front of it. Supply is finite, so a rate limit matters as much as authentication.
Diode passwords are written to a file with mode 0600 and passed with --password-file rather than
on a command line, where ps would expose them.
The pool file is AES-256-GCM under a key stretched from $WJ_POOL_KEY with PBKDF2-HMAC-SHA256, and
is written mode 0600. That protects it where it travels without the key — backups, volume
snapshots, a disk pulled out of a machine — not against something that can already read both the
file and the process environment. Lose the key and the pool is gone: there is no escrow, and a
diode carries nothing back to ask for the numbers again.
Because a diode carries nothing back, the collector cannot be told the server is running low. Watch
/api/status, the root page, or wj-diode-quantum stats on the protected side.
Licence
Released under the Unlicense — public domain.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file wj_diode_quantum-1.0.0-py3-none-win_arm64.whl.
File metadata
- Download URL: wj_diode_quantum-1.0.0-py3-none-win_arm64.whl
- Upload date:
- Size: 2.7 MB
- Tags: Python 3, Windows ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
29b6ae0fb88ffe86f96cf78724e82a4fe58ee8ca3b8b04691470f3cb06506fb9
|
|
| MD5 |
2ec166f82f82a39a46e8464291e5884d
|
|
| BLAKE2b-256 |
27418fe97ee20f86b701ad2a3b7a06b5350ddad6b2f599f86f1a1b806b633126
|
File details
Details for the file wj_diode_quantum-1.0.0-py3-none-win_amd64.whl.
File metadata
- Download URL: wj_diode_quantum-1.0.0-py3-none-win_amd64.whl
- Upload date:
- Size: 3.0 MB
- Tags: Python 3, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
70a81b17d8ce1b4c7378a51a3aa739339f5c62abdd1d6813d840171c00b288ae
|
|
| MD5 |
7355f2ba3a1be0593048c891deb97a15
|
|
| BLAKE2b-256 |
926bf31f7d354b86423f362cfa55cb39e23a82b4bc8d23fe355ac6ed00e4c319
|
File details
Details for the file wj_diode_quantum-1.0.0-py3-none-manylinux_2_17_x86_64.whl.
File metadata
- Download URL: wj_diode_quantum-1.0.0-py3-none-manylinux_2_17_x86_64.whl
- Upload date:
- Size: 2.9 MB
- Tags: Python 3, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f3f605f98b0b1239f2e46e581a2f7f726ac3190b1f2b293bbcddcced76d4d1a4
|
|
| MD5 |
80d406f85942f1b7df5944af7c6de641
|
|
| BLAKE2b-256 |
9f8c3c81ff6f19ec4cd1c15f13411ca76f9386c7522f7ef80d11a31121722269
|
File details
Details for the file wj_diode_quantum-1.0.0-py3-none-manylinux_2_17_aarch64.whl.
File metadata
- Download URL: wj_diode_quantum-1.0.0-py3-none-manylinux_2_17_aarch64.whl
- Upload date:
- Size: 2.6 MB
- Tags: Python 3, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1c48a14b7dbf67780a1e506ad3752a06f1f20af82be6b70548d4703d47ece8e5
|
|
| MD5 |
5af3fac8aab9db523fe3a496980dea18
|
|
| BLAKE2b-256 |
ef31e08d3783e40c64adb9c1cfe1b267c19f5ad9bfc5a4115283621ec5cb4842
|
File details
Details for the file wj_diode_quantum-1.0.0-py3-none-macosx_11_0_arm64.whl.
File metadata
- Download URL: wj_diode_quantum-1.0.0-py3-none-macosx_11_0_arm64.whl
- Upload date:
- Size: 2.7 MB
- Tags: Python 3, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d1d551fde26c31990311d2569bf319cc8d92790c6ed9ea35ee2c270f8d1e3790
|
|
| MD5 |
1440cbb5cc9d56ef795b5df433c52730
|
|
| BLAKE2b-256 |
b5d9a7f81bbb97ce8be4ae18a91fd2ba6092c1a2f0444237baa2b233a637d40b
|
File details
Details for the file wj_diode_quantum-1.0.0-py3-none-macosx_10_9_x86_64.whl.
File metadata
- Download URL: wj_diode_quantum-1.0.0-py3-none-macosx_10_9_x86_64.whl
- Upload date:
- Size: 3.0 MB
- Tags: Python 3, macOS 10.9+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
10e984a3a99cc8aa02249f6f4c9d4705f377fbbe762c9ed9cb442f58f71738b1
|
|
| MD5 |
a11b11c1c29b92f5ff91877d9456ba87
|
|
| BLAKE2b-256 |
21d77ddf54c0edb06eec7935e5ab9db451d2deac89b5eecf6beaf3aa5d1413b1
|