What the authority actually signs
When you seal a document, the signer takes the signature it just made, hashes it,
and sends only that hash to the Time-Stamp Authority (TSA). The authority signs a small statement:
“I saw this hash at this time.” That statement is the stamp. It travels inside the
.vrfy sidecar as an entry of timestampProofs, next to the signature it covers.
{
"type": "TrustDIDTimestamp2026",
"time": "2026-09-10T18:07:03.056858Z", ← the authority's clock, not the signer's
"nonce": "CGi/1znFDSF4rDCnZm+UTg==", ← chosen by the signer, echoed back: proves freshness
"messageImprint": "40a902af7e856cb1…9c3940d8", ← SHA-256 of the signature being stamped
"hashAlgorithm": "SHA-256",
"verificationMethod": "did:web:tsa.dev.trustdid.ca#ts-active",
"proofPurpose": "timestamp",
"proofValue": "cxKUccdr2IaFezxOd4fvqG0q…" ← Ed25519 over the four fields above
}
A real stamp, issued by our development authority. Production stamps name did:web:tsa.trustdid.ca.
Three things follow from this shape. The authority never sees your document, nor even your signature — only a hash of a hash. The stamp is bound to one specific signature: move it to another document and the imprint no longer matches. And it sits outside the signed envelope by necessity: it is a signature over your signature, so it cannot be inside the thing it signs. This is the same construction PAdES and CAdES use for signature timestamps.
How the verifier uses the stamp
The verifier trusts a short list of authorities — by default did:web:tsa.trustdid.ca,
plus any you configure. For each stamp from a trusted authority it:
- recomputes the imprint from the signature in the sidecar and checks it matches;
- resolves the authority's DID document over HTTPS and picks the key named in the stamp, as it was at the stamped time (authorities rotate keys too);
- verifies the Ed25519 signature over the canonical stamp;
- and then treats the authority's time — not the signer's
createdfield — as the moment of signing when deciding which of the signer's keys was valid.
With two or more trusted authorities, their times must agree within a tolerance (60 seconds by default). If they disagree, one of them is faulty or lying and there is no way to tell which — so no time is trusted at all, and a signature that depends on it fails. Taking the earliest would have let a single rogue authority back-date a signature past an honest one.
[PASS] Signature valid — Ed25519 over canonical payload, key did:web:jacqueslatour.ca#active
[PASS] Trusted timestamp — 2026-09-12T18:05:14.194429Z by did:web:tsa.trustdid.ca (the authoritative signing time)
trustdid-verify --verbose on a document sealed against the production authority.
Why you don't have to trust the authority either
A stamp proves the authority signed a time. It does not, by itself, prove the authority was honest about it. So every stamp the authority issues is also written to a public, append-only transparency log — an RFC 6962 Merkle tree, the same construction Certificate Transparency uses to keep certificate authorities honest. No entry is returned to a signer before it is durably in the log.
Each log entry, or leaf, commits to just two things: the stamped time and a hash of the stamp. Not the imprint, not the nonce, and never the document. Anyone can see when stamps were issued; only the holder of a stamp can recognise their own leaf.
The authority periodically signs the state of the whole tree — its size and Merkle root — as a tree head. Once a head covering N entries is published, nothing can be inserted before position N. A stamp that claims a time earlier than an already-published head is provably back-dated, and a log that ever changes its past will fail a consistency check against any head that was saved earlier.
{
"type": "TrustDIDTreeHead2026",
"logId": "did:web:tsa.trustdid.ca",
"treeSize": 65,
"rootHash": "9701b21d779cafcd18b691afa1277463d48fc378541af491c3615f54dcb9159c",
"timestamp": "2026-09-14T12:26:39.680614Z",
"verificationMethod": "did:web:tsa.trustdid.ca#ts-active",
"proofPurpose": "treeHead",
"proofValue": "OgSpv4oxHPfMWp+/yTeV+Ti09OhNTbasA+kre…"
}
The production authority's signed tree head as fetched while writing this page.
trustdid-verify --audit does the relying-party check: it asks the log for an inclusion proof of
the stamp, verifies the tree head's signature with the authority's key, recomputes the leaf from the stamp
it holds, walks the Merkle path to the root — and then checks that this head is consistent with the
last one your machine saw. That last step is what catches a rewritten past.
[PASS] Transparency log — did:web:tsa.trustdid.ca: leaf 3 of 3 under head 2026-09-12T18:05:14.194429Z (first head seen)
Check the authority without our software
The log's read endpoints are public and unauthenticated. These four commands reproduce what the verifier does, minus the signature maths.
# The authority's identity and public key
curl -s https://tsa.trustdid.ca/.well-known/did.json
# The latest signed tree head: size, root, time
curl -s https://tsa.trustdid.ca/log/sth
# The first three leaves — {index, time, tokenHash, leafHash} and nothing else
curl -s "https://tsa.trustdid.ca/log/entries?start=0&end=2"
# An inclusion proof for leaf 0: the sibling hashes up to the root, plus the head it is under
curl -s "https://tsa.trustdid.ca/log/proof?index=0"
Two things you can confirm by hand. First, a leaf hash is exactly SHA-256(0x00 ‖ {"time":…,"tokenHash":…})
with the two keys in that order and no whitespace — recompute it for any entry and it matches. Second,
the head returned inside the proof carries the same rootHash as /log/sth, and the
audit path from any leaf reaches that root. Any RFC 6962 implementation will verify the path.
python3 -c 'import hashlib,json,urllib.request as u
e=json.load(u.urlopen("https://tsa.trustdid.ca/log/entries?start=0&end=0"))["entries"][0]
leaf=json.dumps({"time":e["time"],"tokenHash":e["tokenHash"]},separators=(",",":")).encode()
print(hashlib.sha256(b"\x00"+leaf).hexdigest()==e["leafHash"])'
True
Who can verify, who can stamp
Verifying
The DID document, the tree heads, the entries and both kinds of proof. No account, no key, no rate beyond ordinary abuse limits. A verifier never needs anything from us but public data.
Stamping
Issuing a stamp costs the authority storage forever, so it is part of every plan that can sign, included in the price. The signer proves its entitlement with a short-lived token; the authority checks it without ever contacting us. The verify-only tools need no plan.
Run your own authority
The authority is a standalone, dependency-free service with its own did:web identity and log.
An organisation can run one internally, or publicly for its partners, and configure TrustDID verifiers
to trust it alongside ours — two independent authorities agreeing is stronger evidence than one.
What comes next: anchoring the signed tree heads outside TrustDID's own infrastructure, so that the log's honesty can be checked by people who trust nobody involved.