GxPlex

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

Root
42337ae3567aae8138fcb45e977dd94f9c1ade6420a88033e9503203df3fec23
Root date
The day this build fixed the root, at 00:00:00Z — the day is this record's unit, so the time is a constant, not a clock reading. The date is this record’s own statement; the date a reader can check is the third party’s, in the timestamp row.
Manifest
  • root.txt — the Merkle root, one line
  • leaves.txt — 9686 leaves in the tree, one line each
  • head.txt — the commit this root was built at
The files the timestamp checks read are listed with these under the inputs, and what reads them.
Third-party timestamp
freetsa.org, a public RFC 3161 timestamp authority — its stated date . Token: root.tsr. Blockchain anchor: pending. A calendar has promised to anchor this root and the transaction is not confirmed, so it is not a timestamp yet.
What this proves
That the published leaves are the data this root was built from, and that this exact root existed by the timestamp authority’s stated date.
What it does not prove
That the record is accurate: a status read wrongly hashes exactly as well as one read correctly. Nor who assembled the root, whether the documents behind it were read correctly, or whether any person checked anything. The limits are set out in full under what none of this proves.

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])
EOF

It 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)
EOF

A 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

FileWhat it isRead 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 anchoredProofState
/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: