Skip to main content

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

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

wj_diode_quantum-1.0.0-py3-none-win_arm64.whl (2.7 MB view details)

Uploaded Python 3Windows ARM64

wj_diode_quantum-1.0.0-py3-none-win_amd64.whl (3.0 MB view details)

Uploaded Python 3Windows x86-64

wj_diode_quantum-1.0.0-py3-none-manylinux_2_17_x86_64.whl (2.9 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

wj_diode_quantum-1.0.0-py3-none-manylinux_2_17_aarch64.whl (2.6 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

wj_diode_quantum-1.0.0-py3-none-macosx_11_0_arm64.whl (2.7 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

wj_diode_quantum-1.0.0-py3-none-macosx_10_9_x86_64.whl (3.0 MB view details)

Uploaded Python 3macOS 10.9+ x86-64

File details

Details for the file wj_diode_quantum-1.0.0-py3-none-win_arm64.whl.

File metadata

File hashes

Hashes for wj_diode_quantum-1.0.0-py3-none-win_arm64.whl
Algorithm Hash digest
SHA256 29b6ae0fb88ffe86f96cf78724e82a4fe58ee8ca3b8b04691470f3cb06506fb9
MD5 2ec166f82f82a39a46e8464291e5884d
BLAKE2b-256 27418fe97ee20f86b701ad2a3b7a06b5350ddad6b2f599f86f1a1b806b633126

See more details on using hashes here.

File details

Details for the file wj_diode_quantum-1.0.0-py3-none-win_amd64.whl.

File metadata

File hashes

Hashes for wj_diode_quantum-1.0.0-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 70a81b17d8ce1b4c7378a51a3aa739339f5c62abdd1d6813d840171c00b288ae
MD5 7355f2ba3a1be0593048c891deb97a15
BLAKE2b-256 926bf31f7d354b86423f362cfa55cb39e23a82b4bc8d23fe355ac6ed00e4c319

See more details on using hashes here.

File details

Details for the file wj_diode_quantum-1.0.0-py3-none-manylinux_2_17_x86_64.whl.

File metadata

File hashes

Hashes for wj_diode_quantum-1.0.0-py3-none-manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 f3f605f98b0b1239f2e46e581a2f7f726ac3190b1f2b293bbcddcced76d4d1a4
MD5 80d406f85942f1b7df5944af7c6de641
BLAKE2b-256 9f8c3c81ff6f19ec4cd1c15f13411ca76f9386c7522f7ef80d11a31121722269

See more details on using hashes here.

File details

Details for the file wj_diode_quantum-1.0.0-py3-none-manylinux_2_17_aarch64.whl.

File metadata

File hashes

Hashes for wj_diode_quantum-1.0.0-py3-none-manylinux_2_17_aarch64.whl
Algorithm Hash digest
SHA256 1c48a14b7dbf67780a1e506ad3752a06f1f20af82be6b70548d4703d47ece8e5
MD5 5af3fac8aab9db523fe3a496980dea18
BLAKE2b-256 ef31e08d3783e40c64adb9c1cfe1b267c19f5ad9bfc5a4115283621ec5cb4842

See more details on using hashes here.

File details

Details for the file wj_diode_quantum-1.0.0-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for wj_diode_quantum-1.0.0-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 d1d551fde26c31990311d2569bf319cc8d92790c6ed9ea35ee2c270f8d1e3790
MD5 1440cbb5cc9d56ef795b5df433c52730
BLAKE2b-256 b5d9a7f81bbb97ce8be4ae18a91fd2ba6092c1a2f0444237baa2b233a637d40b

See more details on using hashes here.

File details

Details for the file wj_diode_quantum-1.0.0-py3-none-macosx_10_9_x86_64.whl.

File metadata

File hashes

Hashes for wj_diode_quantum-1.0.0-py3-none-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 10e984a3a99cc8aa02249f6f4c9d4705f377fbbe762c9ed9cb442f58f71738b1
MD5 a11b11c1c29b92f5ff91877d9456ba87
BLAKE2b-256 21d77ddf54c0edb06eec7935e5ab9db451d2deac89b5eecf6beaf3aa5d1413b1

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

1.0.0 This release

6 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page