Merkle Tree
A binary tree where each leaf is a hash of data and each internal node is a hash of its children. Proofs are logβ(N) hashes.
Best for: Static sets known at deploy time β airdrop allowlists, governance voter registries, configuration snapshots.
How It Works
βββββββββββ
β root β
β H(A|B) β
ββββββ¬βββββ
ββββββββββββββ΄βββββββββββ
ββββββ΄βββββ ββββββ΄βββββ
β A β β B β
β H(C|D) β β H(E|F) β
ββββββ¬βββββ ββββββ¬βββββ
ββββββββ΄βββββββ βββββββ΄βββββββ
ββββββ΄βββββ ββββββ΄βββββββββββ΄βββββ ββββββ΄βββββ
β C β β D ββ E β β F β
β H(dβ|dβ)β β H(dβ|dβ)ββ H(dβ
|dβ)β β H(dβ|dβ)β
ββββββ¬βββββ ββββββ¬βββββββββββ¬βββββ ββββββ¬βββββ
βββββ΄ββββ βββββ΄ββββ βββββ΄ββββ βββββ΄ββββ
dβ dβ dβ dβ dβ
dβ dβ dβ
Proof that dβ is in the tree: [dβ, C, B]
Verify: D = H(dβ|dβ), A = H(C|D), root = H(A|B) βTo verify membership, the on-chain validator receives the element and its proof (the sibling hashes along the path to the root). It recomputes the hashes from leaf to root and checks that the result matches the known root hash.
Cost
- Verification: logβ(N) + 1 blake2b calls
- Proof size: 33 Γ ceil(logβ(N)) bytes
Limitations
- No mutations β the tree is built once and cannot be modified on-chain
- Membership only β cannot prove that an element is not in the set
Background
Ralph Merkle described the idea in 1979 in βA Certified Digital Signatureβ. The motivation was signing many messages at once: instead of signing each message individually, hash them into a root and sign only the root.
Example: Membership Token Validator
The MembershipTokenValidatorΒ uses a Merkle Tree to gate token minting β only members in a pre-built allowlist can mint. The Merkle root is baked into the script at deployment time via ParameterizedValidator[ByteString].
On-chain β verify the signer is in the allowlist:
import scalus.cardano.onchain.plutus.crypto.tree.MerkleTree
// merkleRoot is the script parameter (baked in at deploy time)
// signer.hash is the pubkeyhash of the transaction signer
// proof is the sibling hashes along the path to the root
MerkleTree.verifyMembership(merkleRoot, signer.hash, proof)Off-chain β build the tree and generate a proof:
import scalus.crypto.tree.MerkleTree
// Build the tree from a list of member pubkeyhashes
val members: Seq[ByteString] = Seq(alice.hash, bob.hash, charlie.hash)
val tree = MerkleTree.fromHashes(members)
val root = tree.rootHash // bake this into the script parameter
// Generate a membership proof for alice
val proof = tree.proveMembership(alice.hash)The AnonymousDataValidatorΒ demonstrates another pattern: Merkle Tree for participant authorization combined with AssocMap for encrypted key-value storage.
Related
- Incremental Merkle Tree β append-only variant for dynamic sets
- Merkle Patricia Forestry β general key-value with insert/delete support