Skip to content

Merkle proofs

Witness exposes two related inclusion-proof formats. They must not be confused.

Bundle batch inclusion

In a ProofBundle, batch_inclusion is either null or:

BatchInclusion {
  batch: AttestationBatch,
  merkle_proof: MerkleProof
}

AttestationBatch fields are id, network_id, merkle_root, period_start, period_end, and attestation_count. MerkleProof fields are leaf, siblings, leaf_index, tree_size, and root. The leaf is the attestation hash before Merkle leaf hashing; siblings are bottom-up; the index is zero-based; and the root and all byte arrays are lowercase hex strings in JSON.

Bundle verification requires the proof leaf to equal the signed attestation hash, the proof root to equal the batch root, the batch to belong to the home network, the index to be below attestation_count, and tree_size to equal that count. It then checks the position-aware RFC 9162 path. An invalid or missing optional proof does not invalidate a good home threshold signature, but it prevents a Batched or Federated result.

Batch proof endpoint

GET /v1/proof/{hash}

This returns MerkleProofResponse with hash, proof, index, merkle_root, and batch_id. It is a legacy batch response and is distinct from batch_inclusion in a bundle.

Transparency-log inclusion

GET /v1/log/proof?hash={hash}&tree_size={tree_size}

This returns LogInclusionProofResponse with leaf_index, tree_size, audit_path, and a SignedTreeHead. Its path is checked against the STH's committed root. The STH threshold signature must be verified separately with the network configuration; an inclusion path alone is not an authenticated checkpoint.