Certificate chain anchors

Every notary certificate PQCServer issues is linked to the one before it, forming an append-only chain. The end of that chain — its head — is published here every hour and committed to the Bitcoin blockchain through OpenTimestamps.

This page exists so that the claim on the notary page can be checked rather than believed. Everything below is a static file you can download, and the verification steps run on your machine with tools that are not ours.

Current chain head
Loading…

Why this makes the date verifiable

A signature proves who signed what. It carries no date, so the date has to come from somewhere — and on most services it comes from a field in the operator's database, which the operator can change.

Chaining fixes half of that. Altering a certificate changes its hash, which breaks the link in the next one and in every one after it, so anyone holding a later certificate can demonstrate the tampering. But an operator who rewrote the entire chain would restore internal consistency, which is why the head is published here — and why it is submitted to OpenTimestamps, whose calendars commit it into a Bitcoin block.

Once an anchor is in a block, back-dating a certificate covered by it would require rewriting the Bitcoin blockchain. That is not something we can do, and it is the point of doing it this way.

The limit worth knowing: anchors are hourly, so a certificate is proven to have existed by the time of the next anchor, not to the second. For establishing precedence — who held what document first, and whether it changed — that bound is what matters. If you need certified time to the second, an accredited Time-Stamping Authority under eIDAS is the right instrument, and this is not that.

Verify an anchor yourself

Nothing here requires our cooperation. Install the OpenTimestamps client, then:

pip install opentimestamps-client

# take any anchor and its proof
curl -sO https://pqcserver.com/anchors/anchor-<seq>.json
curl -sO https://pqcserver.com/anchors/anchor-<seq>.json.ots

# fetch the Bitcoin attestation once the calendars have committed it
ots upgrade anchor-<seq>.json.ots

# confirm the file existed before a specific Bitcoin block
ots verify anchor-<seq>.json.ots

ots verify reports the block height and time the anchor was committed. That is the moment the whole chain up to that position is proven to have existed — established by Bitcoin, not by us.

A freshly submitted anchor shows only a pending attestation: the digest has reached the calendars but is not yet in a block. Run ots upgrade again a few hours later.

Checking a specific certificate

A certificate carries its own chain block with seq, prev_hash and hash. Recompute the hash from the certificate's own fields:

sha256( {"document_hash":"…","id":"ts_…","issued_at":"…",
         "prev_hash":"…","seq":N,"signature":"…"} )

Keys in that exact order, no whitespace, slashes not escaped. If it matches chain.hash, the certificate is internally consistent with its position. Then find the first anchor with a sequence at or above seq: that anchor's Bitcoin attestation is the upper bound on when the certificate can have been created. The verification page does all of this in your browser, but it is deliberately reproducible by hand.

Files published here

FileWhat it is
latest.jsonThe most recent chain head. Overwritten each hour.
index.jsonEvery anchor, newest first, with its witness status. This is what the verification page reads.
log.jsonlAppend-only log of every anchor ever published, one JSON object per line. A missing per-anchor file is conspicuous against this.
anchor-<seq>.jsonA single anchor, never modified after publication.
anchor-<seq>.json.otsIts OpenTimestamps proof. Present once the anchor has been submitted to the calendars.

Anchor history

Loading…

The implementation that produces all of this is open source, so the procedure above can be checked against the code that generates it rather than taken on description.