NotBefore

Commit the decision. Randomize later. Verify the result.

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 five minutes in the future; 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 0067 (2026-09-13 01:05 UTC), as signed by each host: F9T→i210 discipline 9.95 ns RMS, −16 to +17 ns, 12 samples over 12 s, servo locked; i210's observation of the BMC grandmaster 7.9 ns RMS, −13 to +4 ns, 4 samples over 20 s, path delay 442 ns (an estimate, not a symmetry proof); BMC→k3 discipline 41.4 ns RMS over 60 samples; F9T qErr for the anchoring epoch −2.166 ns, logged and not applied; PHC epoch guard intact on both hosts. 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. The verifier authenticates these statements (host signatures, pulse binding); a versioned quality policy over them is being added (timing profile). Details and every correction: HARDWARE.md, CLAIMS.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 67        # 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

Source

github.com/docdailey/qrng-beacon-log · notbefore on PyPI · MIT; log data CC BY 4.0