Blog
Design decisions

The transparency log: a Merkle tree you can check

By the Let’s Seal team6 min read

A seal proves a file is authentic. An anchor on the blockchain proves when it existed. A third question remains: how do you know we keep the record honestly, adding each entry once and holding the order fixed behind the scenes?

The operator problem

A log is easy to keep honest if you trust whoever keeps it. We build ours to earn that trust the hard way. A dishonest or compromised operator could insert a backdated entry, drop an inconvenient one, or show a different history to different people. Asking you to take our word that we would refrain is exactly the kind of trust we are trying to design out.

So the log is built so that any such attempt fails in public, and anyone watching can catch it.

Every seal is a leaf

RFC 6962
the same standard as Certificate Transparency and sigstore Rekor
~20 hashes
prove one seal is in a log of a million
append-only
consistency proofs let anyone confirm the log only grew

Each seal we issue is appended as one leaf in a Merkle tree, the same append-only structure Certificate Transparency has used since 2013 and sigstore's Rekor uses today. It is defined by an open standard, RFC 6962.

A Merkle tree hashes in pairs. Each leaf is the hash of one entry. Each parent is the hash of its two children. Keep hashing upwards and you reach a single value at the top, the root, that commits to every leaf beneath it. Change any leaf, anywhere, and the root changes. We use SHA-256, with a one-byte prefix that separates leaves from interior nodes, exactly as the standard prescribes.

signed rootgivensealyour sealgivenother seals
To prove your seal (blue) is in the tree, we hand you only the hashes outlined in blue: your leaf's sibling, and the node on the far side. You recompute the root and check it against the root we publish. For a tree of a million seals, that path is about twenty hashes.

Proving your seal is in the tree

The useful property is that a handful of hashes proves a single leaf belongs to the tree. To show your seal is included, we hand you a short list: the siblings along the path from your leaf up to the root. That is an inclusion proof.

Concretely: you hash your own entry to get your leaf, combine it with the one sibling hash we hand you to get their shared parent, combine that with the next hash up, and continue to the top. A handful of SHA-256 operations later you have a root. If it equals the root we signed and anchored, your seal is in the tree, and that root could have come from only one set of entries.

The list is short because the tree is shallow. For a log of a million seals, an inclusion proof is roughly twenty hashes, a few hundred bytes, however large the log grows.

Proving the log only ever grows

Inclusion proofs show your entry is there now. A second kind of proof, a consistency proof, shows something stronger: that an older version of the tree is a prefix of the newer one. In plain terms, that we only ever appended, leaving everything already in the tree exactly as it was.

Anyone monitoring the log can ask for a consistency proof between any two points in time and confirm, mathematically, that everything behind them stands exactly as it did. Any rewrite of the append-only Merkle tree makes every watcher's consistency check fail. That is what makes the honesty something anyone can verify.

The signed tree head, anchored to the blockchain

We publish the current root as a signed tree head: the tree size, the root hash, a timestamp, and a signature from a dedicated log key whose certificate chains to the Let's Seal root. And, as covered in the companion post, we anchor that root hash to the blockchain with OpenTimestamps. So the log's whole history is pinned to a public clock everyone shares. The tree is append-only by construction, and the sequence of its roots is timestamped in a ledger beyond our reach.

Both halves are deliberately boring and reproducible. Each leaf commits to a small canonical record: a version tag, the file's SHA-256, the seal type, the issuing certificate's name, and the time. The signed tree head is a short signed line: the version, the tree size, the root hash, and a timestamp. An independent monitor can recompute either from scratch and check our signature over it.

Check it yourself

All three are public endpoints, open to anyone:

GET /api/log/sth                         the current signed tree head
GET /api/log/proof?sha256=<hash>         an inclusion proof for one seal
GET /api/log/consistency?first=&second=  proof the log only appended

The honesty is yours to check. The tree, the proofs, and the blockchain anchor let you, or anyone watching, prove it.

Every claim here is something you can check yourself, offline, with tools we do not control. That is the whole point.