ExistBefore

T1 inclusion proof audit

Verify a single attestation against the daily T1 batch.

Every attestation registered through ExistBefore (free site or CertiSigma API) is bundled with thousands of others into a daily Merkle tree. The root of that tree — and only the root — is timestamped by an eIDAS-qualified TSA under Article 41 of Regulation 910/2014. This page lets you prove, in your own browser or with any RFC 6962 library, that a given attestation is one of the leaves of that signed batch.

The proof is small (a handful of 32-byte sibling hashes), the verifier is short (a few dozen lines), and the math is the same one used by Certificate Transparency to police the world's TLS certificates. No trust in ExistBefore or CertiSigma is required to perform the check.

Verify a proof in your browser.

Open the public proof page for any attestation, expand the Show batch inclusion proof panel, and copy the JSON shown below. Paste it here. The verification runs locally with WebCrypto — nothing transits to any server.

Required fields: root, leaf, leafIndex, treeSize, auditPath. All hashes are lowercase hex (64 characters).

Verify with any RFC 6962 library.

You don't need to trust the JavaScript on this page. The proof format is RFC 6962 (Certificate Transparency) audit path with leaf prefix 0x00 and internal-node prefix 0x01. Any library that implements the standard will produce the same answer. Two minimal reference implementations follow.

Python (standard library only)

import hashlib
import json

def leaf_hash(b: bytes) -> bytes:
    return hashlib.sha256(b'\x00' + b).digest()

def node_hash(left: bytes, right: bytes) -> bytes:
    return hashlib.sha256(b'\x01' + left + right).digest()

def verify_inclusion(proof: dict) -> bool:
    """RFC 6962 inclusion proof verification."""
    fn = proof['leafIndex']
    sn = proof['treeSize'] - 1
    if fn > sn or fn < 0:
        return False
    leaf_bytes = bytes.fromhex(proof['leaf'])
    # If proof['leaf'] is already the leaf hash (32B), use it directly.
    # Otherwise compute leaf_hash(leaf_bytes).
    r = leaf_bytes if len(leaf_bytes) == 32 else leaf_hash(leaf_bytes)
    for sibling_hex in proof['auditPath']:
        sibling = bytes.fromhex(sibling_hex)
        if sn == 0:
            return False  # path too long
        if (fn & 1) or (fn == sn):
            r = node_hash(sibling, r)
            while not (fn & 1):
                fn >>= 1
                sn >>= 1
        else:
            r = node_hash(r, sibling)
        fn >>= 1
        sn >>= 1
    if sn != 0:
        return False  # path too short
    return r.hex() == proof['root']

# Usage:
proof = json.loads(open('proof.json').read())
print('VALID' if verify_inclusion(proof) else 'INVALID')

JavaScript (browser, WebCrypto, no dependencies)

async function sha256(bytes) {
  return new Uint8Array(await crypto.subtle.digest('SHA-256', bytes));
}
const hex = (b) => [...b].map(x => x.toString(16).padStart(2, '0')).join('');
const unhex = (s) => new Uint8Array(s.match(/../g).map(b => parseInt(b, 16)));

async function leafHash(b)         { return sha256(Uint8Array.of(0x00, ...b)); }
async function nodeHash(left, right) { return sha256(Uint8Array.of(0x01, ...left, ...right)); }

export async function verifyInclusion(proof) {
  let fn = proof.leafIndex;
  let sn = proof.treeSize - 1;
  if (fn > sn || fn < 0) return false;
  const leafBytes = unhex(proof.leaf);
  let r = leafBytes.length === 32 ? leafBytes : await leafHash(leafBytes);
  for (const siblingHex of proof.auditPath) {
    const sibling = unhex(siblingHex);
    if (sn === 0) return false;
    if ((fn & 1) || fn === sn) {
      r = await nodeHash(sibling, r);
      while (!(fn & 1) && fn !== 0) { fn >>= 1; sn >>= 1; }
    } else {
      r = await nodeHash(r, sibling);
    }
    fn >>= 1;
    sn >>= 1;
  }
  return sn === 0 && hex(r) === proof.root;
}

Both snippets are MIT-licensed; copy them into your audit toolkit. Either implementation, run against the JSON the proof page exports, must return the same boolean as this page.

What a positive verdict actually proves.

What a positive verdict does not prove: that the original content has not been modified since the attestation was created (compare its current SHA-256 with the one in the certificate to check that), or that the file's content means what its filename suggests (semantics is out of scope; only the bytes are anchored).