Verify this record
This record’s word is not the evidence for its own integrity. Each command below is either executed against the live artifacts on every build — a command that fails stops the build rather than appearing on this page — or carries a note beneath it saying this build does not run it. All of them are for a reader to run, on the reader’s own machine.
At a glance
The shell reproduction
The root above is recomputed from the published leaves with a
shell, and the published token is checked against root.txt. Each command runs in the directory holding
the files it names, and is executed there against the live artifacts on
every build.
The root
The root is a SHA-256 Merkle tree over sorted
id|date|content_hash lines. An odd node at the end of a level
is promoted, never paired with itself. The command reads
leaves.txt.
python3 - <<'EOF'
import hashlib
L = [l.strip() for l in open('leaves.txt') if l.strip()]
h = [hashlib.sha256(x.encode()).hexdigest() for x in L]
while len(h) > 1:
n = [hashlib.sha256((h[i] + h[i+1]).encode()).hexdigest()
for i in range(0, len(h) - 1, 2)]
if len(h) % 2:
n.append(h[-1])
h = n
print(h[0])
EOFIt prints the root above, or one of us is wrong — and the published data is the evidence for which, not this sentence. What the lines are, and what they leave out, is under section (i).
The timestamp
The command reads root.txt,
the token root.tsr, and
its chain, tsa-cacert.pem and tsa.crt.
openssl ts -verify -data root.txt -in root.tsr \
-CAfile tsa-cacert.pem -untrusted tsa.crt
It prints Verification: OK where the token binds the file.
It prints no time: the authority’s instant stays inside the token,
where its signature covers it. What the token proves, and what it does
not, is under section (ii).
The observation bundle and its offline check
Each tracked row has one observation bundle, served at
/api/v1/observation-bundle/<id>.json (for example, anvisa-ai.json).
It carries every addressed observation of the row under the key its citation
carries, the path from each digest to the daily root, the root file and the
row’s four rights fields. Over the root file, the bundles of this build
carry the time-stamp authority’s token over that file, and an OpenTimestamps proof that is a calendar’s promise and not yet a timestamp. The root fixes three values of an
observation: its row id, its day and its digest. The rest of a record is
carried as published and is not fixed by the root, and a record with no
digest has nothing fixed.
No bundle is signed by this record: no record key has been made. The token in a bundle is the time-stamp authority’s signature over the root file, not this record’s.
The lines below read every bundle in the directory they run in, with
Python 3 and, for the token, openssl. They check that each leaf names
its record and that each path reaches the root, and they refuse a record that
carries a digest with no leaf, a leaf on a record with no digest, a leaf in a
bundle that no observation in it names, and a file of the directory that
cannot be read as JSON or names a bundle in another shape. The
token is verified over the root file against one authority certificate only:
the one whose SHA-256 fingerprint the lines carry, beginning
A6:37:9E:7C:EC:C0:5F:AA… and printed in full in
them, which is the fingerprint of the certificate served at
/integrity/tsa-cacert.pem, in the form
openssl x509 -noout -fingerprint -sha256 prints.
A certificate inside a bundle is never taken as the anchor, because a bundle
could carry an authority it made itself.
The run ends with status 1 on any failure; with status 2, and no failure,
where a bundle’s root is not under a verified token; and with status 0
only where every root is. A verified token fixes that a root existed by the
token’s time. It does not fix whose root it is: a token names a
file’s digest and a time, not who asked for it, and this record asks
for its own with a request that carries no credential. So a bundle made
elsewhere, over a root of its own with a token over that root, can also end
with status 0. The comparison that ties a bundle to this record is with the
root this record served: where the file served at
/integrity/root.txt is saved
as root.txt beside the bundles, the lines compare every root
with it and refuse one that differs, and where it is not, they print that no
root was compared. Each build replaces that file, so it ties only bundles of
the build serving it; the lines print every root and the day its bundles
were built, either way. A signature of this record would tie a bundle on any
day, and no bundle carries one.
A carried OpenTimestamps proof is compared with the root file’s digest
at its opening bytes, which anyone can write: that comparison is not a
timestamp, and an absent proof is not a failure. Taking a proof to a Bitcoin
block needs a block header and the stock client, whose command is in the
anchored section of /verify;
these lines do not do it. A record with no digest and a record whose digest
was removed together with its leaf read the same offline, and so do a row
with an observation and the same row with that observation and its leaf
removed: the root still folds from every other path. This build runs the
lines over every bundle it writes.
python3 - <<'EOF'
import base64, glob, hashlib, json, os, shutil, ssl, subprocess, tempfile
CA = 'A6:37:9E:7C:EC:C0:5F:AA:3C:BF:07:60:13:D7:45:E3:27:BB:BA:A3:8C:0B:9A:F2:24:69:D4:70:1D:18:AA:BC'
H = lambda s: hashlib.sha256(s.encode()).hexdigest()
OTS = b'\x00OpenTimestamps\x00\x00Proof\x00\xbf\x89\xe2\xe8\x84\xe8\x92\x94\x01\x08'
fail, files, reached, nodigest, otsok, roots, tokens, sig, other = 0, 0, 0, 0, 0, [], {}, {}, 0
def bad(*m):
global fail
fail += 1; print(*m)
for f in sorted(glob.glob('*.json')):
try:
b = json.load(open(f, encoding='utf-8'))
except ValueError:
bad(f, 'is not readable as JSON'); continue
if not isinstance(b, dict) or b.get('collection') != 'observation-bundle':
if isinstance(b, dict) and 'bundle_of' in b:
bad(f, 'not in the published bundle shape')
else:
other += 1
continue
files += 1
try:
root, rt = b['root']['value'], b['root']['file_text']
if rt != root + '\n':
bad(f, 'the root file is not the root'); continue
roots.append((f, rt, b['root'].get('built_on')))
named = set()
for o in b['observations']:
r, leaf = o['record'], o['leaf']
if not r.get('content_hash'):
nodigest += 1
if leaf is not None:
bad(f, o['key'], 'a leaf on a record with no digest')
continue
if leaf is None:
bad(f, o['key'], 'a digest with no leaf, so nothing fixes it'); continue
if leaf != '|'.join((b['bundle_of'], r['observed_date'], r['content_hash'])):
bad(f, o['key'], 'the leaf does not name its record'); continue
named.add(leaf)
h = H(leaf)
for side, sib in b['leaves'][leaf]['path']:
h = H(sib + h) if side == 'L' else H(h + sib)
if h != root:
bad(f, o['key'], 'the path does not reach the root'); continue
reached += 1
for leaf in sorted(set(b['leaves']) - named):
bad(f, leaf, 'a leaf no observation in the bundle names')
t = b['proofs']['rfc3161']
if t.get('state') == 'covers-this-root':
tokens[(rt, t['token_base64'])] = [c['pem'] for c in t['chain'] if c.get('pem')]
p = b['proofs']['opentimestamps']
if p.get('proof_base64'):
if base64.b64decode(p['proof_base64'])[:65] != OTS + hashlib.sha256(rt.encode()).digest():
bad(f, 'the proof does not open with the root file digest')
else:
otsok += 1
s = b['signature']['state']
sig[s] = sig.get(s, 0) + 1
except (KeyError, TypeError, ValueError, AttributeError, IndexError):
bad(f, 'not in the published bundle shape')
anchored, exe = set(), shutil.which('openssl')
for (rt, tok), chain in tokens.items():
if not exe:
print('no token verified: openssl is not on PATH'); break
fp = lambda c: hashlib.sha256(ssl.PEM_cert_to_DER_cert(c)).hexdigest()
try:
ca = [c for c in chain if fp(c) == CA.replace(':', '').lower()]
except ValueError:
ca = []
if not ca:
bad('token over root', rt[:16], 'carries no certificate with the pinned fingerprint'); continue
d = tempfile.mkdtemp()
open(os.path.join(d, 'root.txt'), 'wb').write(rt.encode())
open(os.path.join(d, 'root.tsr'), 'wb').write(base64.b64decode(tok))
open(os.path.join(d, 'ca.pem'), 'w').write(ca[0])
args = [exe, 'ts', '-verify', '-data', 'root.txt', '-in', 'root.tsr', '-CAfile', 'ca.pem']
rest = [c for c in chain if c != ca[0]]
if rest:
open(os.path.join(d, 'more.pem'), 'w').write(''.join(rest))
args += ['-untrusted', 'more.pem']
out = subprocess.run(args, cwd=d, capture_output=True, text=True).stdout
shutil.rmtree(d)
if 'Verification: OK' in out:
anchored.add(rt); print('token over root', rt[:16], 'Verification: OK')
else:
bad('token over root', rt[:16], 'Verification: FAILED')
if not files:
bad('no observation bundle in this directory')
if os.path.exists('root.txt'):
served = open('root.txt', 'rb').read().decode('utf-8', 'replace')
for f, rt, day in roots:
if rt != served:
bad(f, 'the root is not the one in root.txt beside it; the bundle was built on', day)
print('root.txt beside the bundles: every root compared with it')
else:
print('no root.txt beside the bundles: no root is compared with one this record served, '
'and a verified token does not tell whose root it is')
for rt in sorted(set(rt for f, rt, day in roots)):
print('root', rt.strip(), 'built on', sorted(set(str(d) for f, r, d in roots if r == rt)))
if other:
print('files that are not bundles, skipped:', other)
loose = sum(1 for f, rt, day in roots if rt not in anchored)
print('bundles %d; paths reaching the root %d; observations with no digest %d; '
'roots under a verified token %d; bundles with no verified token %d; '
'proofs opening with the root file digest %d; signature %s; failures %d'
% (files, reached, nodigest, len(anchored), loose, otsok, sig, fail))
raise SystemExit(1 if fail else 2 if loose else 0)
EOFA different question, on its own page: the integrity board runs five families of test over this record’s own data — dates against the years their documents are numbered for, referents against what an address serves, verifications against the acts behind them — and publishes each test’s question, the population it was asked over, and what it found.
The three sections below cover (i) what a reader can run against the manifest’s files alone, (ii) what someone who is not us has anchored, and (iii) what is our word.
(i) Checks a reader can run alone
These need nothing from this site except the files, and nothing from a
reader except a shell. The recompute is in the shell reproduction above;
it runs in the directory holding
leaves.txt, and its output
is compared with root.txt.
The inputs, and what reads them
| File | What it is | Read by |
|---|---|---|
root.txt | the Merkle root, one line | the timestamp check and the OpenTimestamps check; the recompute’s output is compared with it |
leaves.txt | one line per distinct observation digest | the recompute |
head.txt | the commit this root was built at | a reader checking the root against this repository |
root.tsr | an RFC 3161 timestamp token over the root | the timestamp check |
tsa.crt | the timestamp authority’s certificate | the timestamp check |
tsa-cacert.pem | its issuing certificate | the timestamp check |
root.txt.ots | a Bitcoin-anchored attestation over the root | the OpenTimestamps check |
head.txt.ots | the same over the commit | the OpenTimestamps check |
These are the files this page publishes for checking. Whether any of them checks out is what the commands on this page answer, on the machine that runs them — this page does not answer it.
The lines the root is built from
The command that recomputes the root from these lines is in the shell reproduction, with the line format it reads.
The lines are distinct: 16434 records in
the series carry both a hash and a date, and they reduce to 9686 lines,
because 6748 of them repeat an
id|date|content_hash a line already covers. A source
re-fetched on a day it has already been fetched, returning the same
bytes, adds no line — there is no further state to fix in time.
What is in the file, and what is not. The first field is the id an observation was recorded under. Of the 132 instrument rows this record publishes, 126 contribute at least one line and 6 contribute none: a line stands for retained bytes. All 6 have been observed, and no observation of them has retained content.
A further 5 ids in the file account for 365 lines: sources this record observes without publishing an instrument row. The file is a record of observations that retained content, so it is neither a list of this site’s pages nor a census of the rows it publishes.
131 distinct ids appear across the 9686 lines. Every figure in this box is derived from the published file when this page is built; none of them is written by hand.
Check a document against its recorded hash
Every instrument page shows the SHA-256 of the normalised text observed that
day, and observations.json
carries the whole series. Checking a hash means fetching the source and
comparing.
(ii) Anchored by someone who is not us
A root this site publishes and this site alone vouches for fixes nothing: we could publish any number. What makes a date checkable is a third party saying it saw that value then.
Every proof over an anchored root that this repository holds, in a committed version or in the tree, is listed on the release history, where no row is removed. A proof replaced before any commit held it is not listed.
The root above is timestamped by freetsa.org, a public RFC 3161 timestamp authority. We sent a hash; the authority returned it signed with its key, not ours. That is the only claim on this page whose forgery would require compromising someone else.
- Authority
- freetsa.org
- Its stated date
The token records the authority's exact instant, to the second. This page shows the date; the instant is in the token, and anyone verifying the proof reads it there. Nothing is withheld — the artifact is published unchanged. The check in the shell reproduction prints a verdict and no time; the instant stays inside the token, where the authority’s signature covers it.
Token: root.tsr ·
chain: tsa-cacert.pem, tsa.crt · the command
that checks them is in the shell reproduction.
What the token proves, and only this: that this exact root existed by the authority's stated time. It says nothing about who assembled it, nothing about whether the observations behind it were read correctly, and nothing about whether this record is accurate. Existence by a date is the whole claim.
Second anchor: this page is held by the Internet Archive at 20260810005227 (opens in new tab). That copy carries the token above.
An anchor that rests on nobody
The token above is one authority's signature. If that authority's key is lost, retired or compromised, every token it issued becomes a file nobody can check. So the same digests are also anchored with OpenTimestamps (opens in new tab), which writes them into the Bitcoin blockchain. Nobody operates that, which is the point: the proof outlives the calendar servers that built it, the OpenTimestamps project, and this site.
| What is anchored | Proof | State |
|---|---|---|
/integrity/root.txt 42337ae3567aae8138fcb45e… | root.txt.ots | Pending. A calendar has promised to anchor this; the Bitcoin transaction is not confirmed yet. It is a receipt for a request, not a timestamp. |
/integrity/head.txt 6b1616e77c0b2c7963b0ed69… | head.txt.ots | Pending. A calendar has promised to anchor this; the Bitcoin transaction is not confirmed yet. It is a receipt for a request, not a timestamp. |
How a stranger checks it, with the stock client and nothing of ours:
pip install opentimestamps-client==0.7.2
curl -O https://gxplex.com/integrity/root.txt
curl -O https://gxplex.com/integrity/root.txt.ots
ots verify root.txt.ots This build does not run these lines. They install a client from PyPI, fetch this site over the network, and ask a Bitcoin block explorer for a block header — none of which a build of this site does.
There is deliberately no verifier of ours to download. The client that wrote these proofs is the client that reads them, and it comes from somewhere else — a tool of ours vouching for evidence of ours would prove nothing.
/integrity/head.txt carries the commit the proof covers,
which is the parent of the commit that carries the proof: stamping the
repository and then committing the result necessarily moves it on by
one.
Granularity. One stamp per daily cycle, taken by the scheduled daily job and by nothing else — never per commit, never per working session. A completed proof names a Bitcoin block, and block times are public, so a proof discloses roughly when its stamp was taken. What that discloses here is the schedule, which is published on this site anyway. Everything this record states about its own activity is day-granular by rule.
Anchoring proves WHEN, not WHO. Both anchors on this page fix digests at times. Neither says who assembled them, whether the documents behind them were read correctly, or whether any person checked anything. The named-person verification this record describes elsewhere is a separate act, and it is still owed — no quantity of cryptography here discharges it.
(iii) Procedure — our word, and a reader cannot check it
No signing key exists yet. When one does, its generation is offline and its custody is a person's, and this page will carry the fingerprint and the verification command.
Both facts — that a key was generated offline and that it has stayed in one person's custody — are claims by this site that no reader can verify. A signature proves that a file came from the holder of a key and has not changed since it was signed. It cannot prove who has held that key. That limit belongs on this page rather than in a footnote, and nothing in this section is ever presented as a check a reader can run.
The rotation and compromise procedure is written before the first signature rather than after the first incident: how a key would be rotated.
If a key is rotated or believed compromised, the record treats it as a correction rather than as an upgrade: the old fingerprint stays published with the dates it was valid for, the new one is published with its own start date, a corrections entry states what happened and when it was noticed, and the feed carries it. Signatures made with the old key are not deleted — they remain exactly as strong as they ever were for the period before the compromise date, and exactly as weak after it. Removing them would destroy the evidence a reader needs to judge that period.
What none of this proves
A signature proves origin, and that a file has not changed since it was signed. A timestamp proves a value existed by a date. A root proves the published data is the data the root was built from.
None of it proves the record is accurate. A status read wrongly hashes exactly as well as one read correctly, and a mistake fixed at a time is still a mistake. Accuracy is not a cryptographic property; it lives in the reading, in the human check, and in the corrections log, which is additive and never silently edits. Treating a hash as evidence of correctness is the one over-claim this page exists to refuse.
What this record declines to infer from what it holds is listed at what this record refuses to infer, with the gate that refuses each line.
Method: how this record is maintained ·
the leaves and the root are at /integrity/leaves.txt and /integrity/root.txt.
Last updated: