Nerzen NTP Loading status TR
Transparency logMerkle tree · SHA-256Ed25519every minute

Time proof

So that we cannot make up the answer to "was your clock right at 03:14 last night?" after the fact, we write the server's clock state to a signed log once a minute. Once written, a record cannot be changed or removed without breaking the signature. Query a past moment below; verification happens in your browser.

Query a moment

the log starts on — · times are in your device's local time

Loading the log…

How it works

  1. Record: every minute the clock-discipline software's current measurements are written as a one-line JSON record: state, stratum, offset, error bound, source counts and any events.
  2. Tree: the records of one UTC day are the leaves of a Merkle tree. The tree root is a single 32-byte digest of all of that day's records; change one character in one record and the root changes.
  3. Signature: with every new record the day's head — the day, the record count, the root and the previous day's root — is signed with the log key.
  4. Chain: because each day carries the previous day's root, the days are linked; altering a past day breaks the signatures of every day after it.
  5. Verification: the query above downloads the day's records, recomputes the root in your browser and checks the signature. You do not need to trust the server; knowing the public key is enough.

Log public key (Ed25519, base64) — click to copy:

—

Record fields

FieldMeaning
tThe moment the record was written (UTC, ISO 8601)
seqThe record's sequence number within the day; its leaf index in the tree
statelocked locked to sources · holdover no source, running on its own oscillator · unsynchronised not synchronised
stratumStratum at that moment
referenceThe source steering the clock: country / type / protection / position
offsetInstantaneous offset of the system clock from the selected source (seconds)
rms_offsetLong-term average of the offset (seconds)
root_delay · root_dispersionRound trip to the primary clock and accumulated uncertainty (seconds)
error_boundPublished error bound: root delay ÷ 2 + root dispersion (seconds)
frequency_ppm · skew_ppmOscillator correction and its uncertainty
leapLeap second status
sourcesTotal, usable and NTS-protected source counts
eventslogger_start, state_change, reference_change, stratum_change

Files

/timelog/index.jsonFirst and last day of the log, public key
/timelog/latest.jsonLatest record and latest signed head
/timelog/YYYY/MM/DD.jsonlThat day's records, one per line
/timelog/YYYY/MM/DD.head.jsonThat day's signed head
/timelog/pubkey.pem · pubkey.txtLog public key
/timelog/verify.pyProof bundle verifier

The signed body of a head has five lines: log name, day, record count, root (base64) and the previous day's root. A leaf hash is SHA-256(0x00 ‖ line) and a node hash is SHA-256(0x01 ‖ left ‖ right) (RFC 6962).

Verifying from the command line

The proof bundle you download is self-contained: it holds the record, the path linking the record to the root, the signed head and the public key. The verifier does not contact any server.

Verify a bundle
curl -O https://ntp.nerzen.com/timelog/verify.py
python3 verify.py nerzen-timeproof-*.json \
  --key "$(curl -s https://ntp.nerzen.com/timelog/pubkey.txt)"
Inspect a whole day by hand
curl -s https://ntp.nerzen.com/timelog/latest.json   # latest record + signed head
curl -s https://ntp.nerzen.com/timelog/2026/10/01.jsonl | wc -l   # must equal the record count in the head

Limits

  • It is self-attested. The log records what the server itself measured; it proves what we reported at that moment and that we did not change it later, not that the clock was truly correct.
  • The signing key is on the server. Someone who compromises the server could sign new records. They cannot, however, alter a past day unnoticed while anyone holds a previously saved head for that day.
  • No independent witness. For now heads are signed only with our key. To strengthen the guarantee, save latest.json yourself at regular intervals; we cannot present a history that contradicts a head you hold.
  • Resolution is one minute. A brief event between two records may not appear in the log.
  • Not a calibration certificate or a legal timestamp.
  • If logging stops, those minutes have no record; the gap is plainly visible from the record times and cannot be filled in later.

Frequently asked questions

What is this log for?

When you later investigate an incident in which your systems took time from us, you can see our server's state at that moment — was it locked, what was the error bound, did the source change — based on a record signed at the time rather than on our word.

What is a proof bundle?

A small JSON file containing one record, the hash path that links it to the day's root, the signed head and the public key. You can attach it to an incident report and verify it offline even years later.

Does it also prove the time I received over NTS?

No. The log records the server's state, not the individual replies given to clients. For a signed individual reply use Roughtime.

Why known structures instead of your own format?

The Merkle tree and hashing rules are the same as those used in certificate transparency logs (RFC 6962); the signature is Ed25519. Verification therefore needs tools everyone already has, not our software.