skip to content

In a Certificate Transparency log, what does an inclusion proof establish that a consistency proof does not?

level: seniorimportance: nice to knowfreq 30%

answer

  1. one entry, versus one whole history
  2. audit path proves membership
  3. consistency proves append-only
  4. both are checked against a tree head
  5. monitor reads entries, auditor checks proofs

basics

~20 s

An inclusion proof shows one entry is in the tree a given signed tree head commits to. A consistency proof shows an earlier tree head's tree is a prefix of a later one, so the log appended and rewrote nothing.

solid answer

~40 s

The two proofs answer different questions and cannot substitute for each other. An **inclusion proof** — the audit path, fetched with `get-proof-by-hash` — is the list of sibling hashes that lets you recompute the **Merkle Tree Hash** from one `MerkleTreeLeaf` hash and match it against a **Signed Tree Head**; it establishes *this entry is in that tree*. A **consistency proof** relates two signed tree heads and establishes that the smaller tree is a prefix of the larger: everything that was there is still there, unmodified, with new entries only appended. It names no certificate at all. So an inclusion proof detects a log that promised an entry and never merged it; a consistency proof detects a log that rewrote its history.

code

json · 6 lines
json
{
  "tree_size": 1487233901,
  "timestamp": 1694102400000,
  "sha256_root_hash": "<base64 Merkle Tree Hash at this size>",
  "tree_head_signature": "<base64 signature made by the log>"
}

go deeper

for a junior

Recall that the log can prove two separate things: that one entry is in it, and that it has only ever been appended to.

for a middle

Explain the mechanics: recompute a root from a leaf hash and its audit path for inclusion, and compare two tree heads for consistency.

for a senior

Say who actually performs these checks and why the connecting client does not — a round trip to the log both costs latency and reveals which site the user is visiting.

for a principal

Assess how much the accountability of the log ecosystem is worth to your risk position, given that it rests on independent auditing rather than on anything your own clients verify.

## Two proofs, two questions A Certificate Transparency log is a Merkle tree over its entries, and it periodically publishes a **Signed Tree Head** (STH): a signed statement of the tree's size and its **Merkle Tree Hash** — the root of that hash tree. Beware the noun: this root is the top of a hash tree and is unrelated to a root certificate held as a trust anchor. Everything provable about the log is proved against an STH, and the two proof types answer strictly different questions: - **Inclusion proof (audit path).** *Is this one entry in the tree this STH commits to?* Fetched with `get-proof-by-hash` given the leaf hash and a tree size. - **Consistency proof.** *Is the tree this older STH commits to a prefix of the tree this newer STH commits to?* Fetched between two tree sizes. Neither implies the other. You can hold a perfectly valid inclusion proof against an STH from a log that quietly dropped a thousand other entries last week; you can hold a perfectly valid consistency proof from a log that never merged the entry it promised you. ## How an inclusion proof works 1. Fetch an STH with `get-sth` and keep its tree size and Merkle Tree Hash. 2. Compute the `MerkleTreeLeaf` hash for the entry, from the same bytes the log was given. 3. Ask `get-proof-by-hash` for the audit path for that leaf hash at that tree size. 4. Hash upward — leaf with sibling, result with the next sibling, and so on — and compare the final value to the Merkle Tree Hash in the STH. A match means the entry is genuinely in that tree. The proof is small: its length grows with the logarithm of the tree size, which is why this stays cheap for a log holding billions of entries. ## How a consistency proof works Given an older STH at size *m* and a newer one at size *n*, the log supplies the interior node hashes that let you recompute both roots from one shared set of values. If both recomputations match their respective STHs, the first *m* entries are unchanged and the difference is purely appended. This is the proof that makes **append-only** a checkable property rather than a promise. Without it, a log could serve one history to one observer and a rewritten history to another, and no single inclusion proof would reveal it. | | inclusion proof | consistency proof | |---|---|---| | subject | one entry | two views of the whole log | | answers | is this entry in that tree? | was anything altered or removed? | | fetched with | `get-proof-by-hash` | a proof between two tree sizes | | detects | a promise the log never merged | a log that rewrote its history | | mentions a certificate | yes, by leaf hash | no | ## Who actually checks these The **auditor** does. The specification splits the watching roles: a **monitor** reads entries and cares about their content — a certificate for a name someone owns — while an **auditor** cares about the log's own behaviour and checks tree heads and proofs. The two are different jobs and are often run by different parties. Ordinary connecting clients do neither on the connection path. Fetching a proof would add a round trip to a third party and would tell the log operator which site a user is visiting, so the check that happens during a handshake is an offline signature verification on the timestamps and nothing more. That leaves a real gap, and the honest statement of the model is: the logs are accountable **because** someone independent audits them, not because every client checks. One more thing an auditor has to watch for, and the reason consistency proofs exist at all: an STH is only meaningful if everyone is being shown the same one. A log that shows one tree head to one observer and a different, incompatible one to another has **split its view**, and this is invisible to anybody who only ever talks to it alone. Detecting it requires comparing tree heads observed by different parties — which is why proposals in this area focus on circulating tree heads between observers rather than on making individual clients do more work. ## Why the portal team cares Mostly you do not check these yourself; you rely on the log ecosystem being audited. But the distinction matters the moment you are reasoning about evidence. If you hold a signed certificate timestamp for a certificate issued for one of your names and you want to prove, in a write-up, that the issuance is publicly recorded, the artefact you need is an **inclusion proof against a current tree head** — the timestamp alone is a promise, and a consistency proof says nothing about your certificate at all.

  • Could a log serve valid inclusion proofs to everyone and still be misbehaving?
    Yes, in two ways. It can withhold merging for entries it issued timestamps for, which no inclusion proof you already hold would reveal. And it can present different tree heads to different observers — a split view — so each observer gets internally consistent proofs against an incompatible history. Detecting that needs observers to compare the tree heads they were shown.
  • Why is the difference between a Merkle tree root and a trust anchor worth stating explicitly?
    Because both are called the root in the same conversation and they are unrelated objects. A trust anchor is a certificate at the top of a certification path that a verifier has chosen to trust. A Merkle Tree Hash is a hash over log entries with no signing authority and no relationship to path validation. Conflating them produces answers that sound right and mean nothing.

An inclusion proof is being shown the page and the index entry for your own name. A consistency proof is checking that every page of last month's copy of the register still reads the same in this month's — it says nothing about any particular name.

saying these in an interview costs you the question

  • Uses an inclusion proof to argue the log has not been rewritten.
  • Thinks a consistency proof names a particular certificate.
  • Assumes connecting clients fetch these proofs on every connection.
  • Confuses the Merkle tree's root hash with a trust anchor.
  • Believes a monitor and an auditor do the same job.
  • Thinks a valid proof means the certificate should have been issued.