NotBefore
Commit the decision. Randomize later. Verify the result.
New here? How the beacon works — the hourly cycle, why nobody can steer the number, and how to check it yourself, in plain language.
Register the input digest, the decision rule and its parameters before the randomness you will use
exists. NotBefore then derives the result deterministically from a public, hourly, host-attested randomness log
and packages the evidence an auditor needs to check the registration, the selection, the randomness and the
execution — without trusting this site.
What is fixed, and when. Each hour the operator publishes a commitment
C = SHA-256(E) to 32 bytes of hardware entropy E it already holds, bound to a
drand round about one minute in the future (five minutes before 2026-09-13 18:00 UTC); after the round it reveals
E. A consumer's value is V* = SHA-256(domain ‖ C ‖ ρR ‖ chain ‖ R):
fixed the instant round R exists, by data committed before it. The producer knows E; nobody
knows ρR before drand releases it, under drand's threshold assumptions. A withheld reveal
changes nothing about V* — it only removes the QRNG provenance for that hour. Publication before the
round is evidenced by two RFC 3161 tokens and a Rekor entry, never by a git date.
The registered decision, end to end
pip install notbefore
notbefore keygen # once: your Ed25519 identity
notbefore plan --after 2026-10-01T00:00Z --purpose chart-audit-2026-q4 \
--decision-id NCT01234567/protocol-3/randomization-1 --sample 50 eligible.txt
# ... wait for the hour ...
notbefore execute notbefore-plan-chart-audit-2026-q4.json # no choices; halts rather than rerolls
notbefore receipt notbefore-plan-chart-audit-2026-q4.json # one page, every line re-verified
notbefore bundle notbefore-plan-chart-audit-2026-q4.json --out r1.zip # attach to the paper or workpaper
notbefore check-bundle r1.zip # what the reviewer runs, offline
plan signs the contract with your key, timestamps its bytes with FreeTSA and DigiCert, and registers
the signed statement in the write-once decision log: the first statement per
key and decision id is the authoritative preregistration. execute selects the first eligible commit
released at or after your instant — eligible means verified, both tokens and its Rekor anchor before its round —
and refuses if the log did not confirm your registration, if a superseded contract is presented, or if a
candidate's eligibility cannot be established. It never silently moves to another value. Verdicts are
VERIFIED, DEGRADED (a dry run) or INVALID. One page for the person
who has to defend the randomization: WORKFLOW.md. Every command: USAGE.md.
Direct derivations — notbefore split 45 --purpose … --frac 0.8 roster.txt — reproduce a
result from an already published pulse. They demonstrate reproducibility; on their own they do not establish
preregistration. Legacy reveal-based contracts (versions 1–2) still execute, labelled.
The timing record
Every pulse carries signed measurements from the clocks that anchor it. The primary time base is an Intel i210
hardware clock on the p550 host, disciplined to a u-blox ZED-F9T PPS captured in hardware; that same i210
continuously measures a BMC grandmaster disciplined by a separate LEA-6T receiver, and a third host (k3)
disciplined by that grandmaster signs its own observations. Two GNSS-disciplined paths, one measured relationship —
both start at GPS, so they corroborate clock operation; they are not independent against a GNSS-common failure.
F9T TP1 PPS ──> i210 SDP0 (hardware capture) ──> ts2phc ──> i210 PHC ──── measures ────┐
▼
LEA-6T PPS ──> P550-BMC grandmaster (trimmed via ptptgt) ──> PTP domain 44 ──> k3 PHC BMC PHC
One dated record, pulse 0112 (2026-09-13 23:00 UTC), as signed
by each host: F9T→i210 discipline 8.9 ns RMS, −20 to +20 ns, 60 samples over 59 s, servo locked;
i210's observation of the BMC grandmaster 27.1 ns RMS, −31 to +66 ns, 30 samples over 58 s, path delay
445 ns (an estimate, not a symmetry proof); BMC→k3 discipline 37.9 ns RMS over 120 samples; F9T qErr for the
anchoring epoch +1.9 ns, logged and not applied; PHC epoch guard intact on both hosts. The hour itself: k3 started
19.5 µs after the instant on its own PTP-disciplined clock, and p550's i210 stamped its hardware second event
27 µs after the same instant and delivered its signed statement to k3 1.3 ms later, bound into the commit
(latency_chain.md). These are windowed precision figures. They are not absolute UTC
accuracy: the antenna delay (69 ns) is measured, the rest of the absolute budget is not, and the receiver is
L1-only today. Every v0.5 pulse from 0018 carries these signed statements; the verifier authenticates them
(host signatures, pulse binding) and, since notbefore 0.13.0, checks them against a versioned
timing profile: v1 (clock health) for every v0.5 pulse, and from 0.15.0 v2, which also
requires the two-clock cadence provenance above for pulses from 0098. Details and every correction:
HARDWARE.md, CLAIMS.md, ERRATA.md.
Log checkpoint
The log is an RFC 6962 Merkle tree over every pulse, published as a
C2SP checkpoint in
signed-note form:
/checkpoint current signed head
/checkpoints/NNNNNN per-size history
/decisions the decision log (origin notbefore.net/decisions)
Origin notbefore.net/log. Anyone can recompute the root from the published pulses and
check consistency with any earlier head. Checkpoints are cosigned by notbefore.net/witness/ryzen — a
witness we operate ourselves (same sponsor, second system), which proves the witness path works, not independence;
independent witnessing is requested and not yet in place. A split view is detected by consistency proofs against a
head a client already holds, by comparing observers' copies, and by the Rekor and OpenTimestamps anchors of every
checkpoint — not by any single client alone. See TLOG.md.
Verify it yourself
pip install notbefore
notbefore verify 113 # host signatures, drand BLS offline, RFC 3161, Rekor anchors, checkpoint inclusion
notbefore checkpoint # the current signed head against the vendored identity and your cached head
The verifier, every key, the drand group key and both RFC 3161 trust chains are inside the
package, pinned to a named log commit. Needs git and openssl on PATH. Without the BLS
library the CLI fails closed. Timestamp tokens: every v0.5 commit since pulse 0018 carries two,
taken at mint; skip pulses carry them when a TSA answered; pulses 0001–0009 predate them. Publication anchors: live
from pulse 0042; 0001–0041 were anchored retroactively and their Rekor times are not commit times.
Published data
/chain/pulse-NNNN.json — every pulse record, signed; full listing on
GitHub. The signed index is the
checkpoint (TLOG.md); an unsigned directory listing would carry no guarantee, so there isn't one.
- How the beacon works — a plain-language description in Simplified Technical English; informative
- PROTOCOL.md — pulse format, verification, the commit-bound value; normative
- NOTBEFORE.md — the product contract (draft 0.9): what the guarantee is, and is not
- DECISION-LOG.md · FALLBACK.md — the write-once log and why the operator cannot steer
- CLAIMS.md · ERRATA.md · reviews/ —
what is claimed, every correction, and the external reviews verbatim
- HARDWARE.md · THESIS.md — the attesting hosts, their clocks, and what exact timing does and does not prove
Source
github.com/docdailey/qrng-beacon-log
· notbefore on PyPI · MIT; log data CC BY 4.0