Metadata-Version: 2.1
Name: wj-diode-quantum
Version: 1.0.0b2
Summary: Quantum random numbers from ANU, pushed across a data diode and served on the other side
Home-page: https://github.com/WaterJuice/wj-diode-quantum
Author: WaterJuice
License: Unlicense
Requires-Python: >=3.7
Classifier: Programming Language :: Go
Description-Content-Type: text/markdown
# wj-diode-quantum

Collects quantum random numbers from the Australian National University, pushes them across a data
diode, and serves them one at a time on the protected side.

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

```sh
uv tool install wj-diode-quantum
wj-diode-quantum setup send
wj-diode-quantum collect -c config.json
```

### Machine 2 — protected side

```sh
uv tool install wj-diode-quantum
wj-diode-quantum setup recv
wj-diode-quantum serve -c config.json
```

### Check it works

```sh
curl localhost:8099/api/status    # numbers are arriving
curl localhost:8099/api/random    # take one
```

```json
{
  "value": "a3f1c8d20b74e569ff10c3a8827d4e61",
  "timestamp": "2026-08-02T04:14:58Z",
  "source": "quantumnumbers"
}
```

`value` is your 128-bit random number, `timestamp` is when it was collected. You will never be given
that number again.

Full documentation: [docs.waterjuice.org/wj-diode-quantum](https://docs.waterjuice.org/wj-diode-quantum/latest/)

## Features

- **Both ANU APIs** — the current keyed service and the older unkeyed one. Enable either or both.
- **Any diode tool** — the transfer is a configured external command. Built against `diodetool`, but
  nothing about it is hard-coded.
- **Never serves the same number twice** — guaranteed across crashes. A value is recorded as consumed
  and flushed to disk before it reaches the client.
- **Bounded, self-trimming pool** — newest served first, oldest discarded at capacity.
- **One process per machine** — the receiving side supervises the diode tool for you.
- **Rejects damaged batches whole** — a diode cannot retransmit, so anything malformed is set aside.
- **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](https://quantumnumbers.anu.edu.au/api-key), free
  with an account. Optional if you only use the legacy endpoint.

## Building

```sh
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 ──> outbox ──> [ send ] ══════> [ recv ] ──> ingest ──> spool
                                                                            │
                                                                            v
                                                         pool.json <── serve ──> GET /api/random
```

Nothing comes back, so the collector never learns whether a batch arrived. Both sides are built to
be restartable and to keep a buffer: batches wait in the outbox until the send succeeds, and the pool
holds a reserve so the server keeps working while the other side is down.

## 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.

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.

Because a diode carries nothing back, the collector cannot be told the server is running low. Watch
`/api/status` or `wj-diode-quantum stats` on the protected side.

## Licence

Released under the [Unlicense](https://unlicense.org/) — public domain.

