Merkle Trees and Validity Proofs
Learn the core concepts of state trees, address trees, and validity proofs for compressed accounts.
Overview
The protocol uses two types of Merkle trees that serve different purposes:
State trees store compressed account hashes
Address trees store addresses that serve as persistent identifiers
The protocol maintains multiple Merkle trees to reduce write-lock contention. Solana's runtime locks accounts during writes, wherefore a single tree would become a bottleneck. Multiple trees allow parallel transactions.
Developers don't need to maintain or initialize Merkle trees themselves.
State trees
A state tree is a binary Merkle tree that stores data of millions of compressed Solana accounts in leaves for efficient cryptographic verification the integrity of all leaves in a tree.
Merkle Root Hash
Only this root hash is stored on chain as single value on chain to secure the integrity of all compressed state in a tree. The raw state can thus be stored as calldata in the much cheaper Solana ledger space while preserving Solana's security guarantees.

Leaf Hash Structure: Compressed Account Hashes
For compressed Solana accounts, the 32 byte leaf hashes effectively mirror the regular Solana account layout: {DataHash, StateHash; Owner, Lamports.
The data_hash represents the fingerprint of the actual account data.
The state_hash ensures that each account hash is globally unique. It includes
the public key of the state tree's respective on-chain account (i.e.,
state_tree_hash) andthe compressed account's position in the tree (i.e.,
leafIndex).
Lastly, owner_hashed determines which program owns this account and lamports show the account balance.

Merkle and Validity Proofs
In state trees, a verifies that a compressed account exists in state trees with a constant 128-byte proof size. This proof must be included in every transaction once a compressed account is created to verify the on-chain state.
Developers don't need to generate validity proofs or learn about ZK to use ZK Compression.
ZK Compression uses Groth16, a well-known pairing-based zk-SNARK, for its proof system.
The validity proof contains one or more merkle proofs:
Merkle proofs consist of sibling node hashes along the path from the account's leaf to the root.
Starting with the leaf hash, the verifier calculates up the tree using these sibling hashes. The proof path is shown with three highlighted elements in a box at the bottom right: Leaf 0, Node 1, and Node 5, representing the sibling hashes needed to verify Leaf 1.
If the calculated root matches the on-chain root, the account is verified.

For a tree with height 26, a single proof requires 26 sibling hashes (32 bytes each) plus metadata totaling 832 bytes. The proof size grows with tree height.
ZK Compression batches multiple Merkle proofs into a single zero-knowledge proof to achieve a constant 128-byte size regardless of how many accounts are verified:
1
1 merkle proof
832
1
1 merkle + 1 ZK proof
128 bytes
8
8 merkle + 1 ZK proof
128 bytes
Address trees
Address trees store addresses that serve as optional, persistent identifiers for compressed accounts.
Address Tree Structure
Address trees store derived addresses in an indexed structure. Unlike state trees that store account hashes, address trees store the actual address values along with pointers to maintain sorted order.
These addresses are used only when compressed accounts require a persistent identifier that doesn't change when the account data updates.
Merkle and Validity Proofs
In address trees, validity proofs verify when creating a compressed account with an address that the address doesn't already exist in a specified address tree. This constant 128-byte proof must be included in the transaction only when creating accounts with addresses, not for subsequent compressed account interactions.
Resources on ZK
For those interested in learning more about the fundamentals of ZK and its applications on Solana, we recommend reading the following:
Next Steps
Learn about the lifecycle of a transaction that interacts with compressed accounts.
Lifecycle of a TransactionLast updated
Was this helpful?