All articles
solanazk-compressionlight-protocolscalingtokens

ZK Compression: cheaper accounts on Solana (and why it's not cNFTs)

Light Protocol's ZK Compression stores account state as hashes with validity proofs, cutting token/PDA costs ~100×. Here's how it works, how it differs from state-compressed NFTs, and the CU cost.

ZK Compression (by Light Protocol, with indexer infra from Helius) stores account and token state as hashes in a Merkle tree, keeping the full data in the ledger rather than in rent-funded account space. A zero-knowledge validity proof proves the state is correct — so you get ~100× lower storage cost while keeping L1 security and composability.

First, the distinction everyone gets wrong

It is not the same as the state compression behind cNFTs:

  • State compression (cNFTs) — concurrent Merkle trees, essentially NFT-only, data off-chain, no general on-chain read/write of arbitrary state.
  • ZK Compression — the generalized successor: arbitrary account data (tokens, PDAs, program state) behaves like native accounts, with a ZK validity proof verified on-chain.

How it works

  • Only a hash (commitment) of each account lives on-chain, inside a state Merkle tree. The full data is emitted as calldata in the transaction.
  • A constant 128-byte Groth16 proof proves the touched accounts exist in the tree — regardless of how many accounts the tx reads/writes. Verified on-chain (~100k CU).
  • The Photon indexer (Helius) indexes Light programs so clients can read compressed state; a prover generates the proofs; forester nodes maintain the trees.

The cost win, concretely

text
                       ZK-compressed     regular SPL/account     ~saving
token account          0.000017 SOL      ~0.0029 SOL             ~100×
token mint             0.000091 SOL      ~0.0015 SOL             ~200×
100-byte PDA           ~0.000015 SOL     ~0.0016 SOL             ~100×

Reading it client-side uses the ZK Compression RPC (a superset of standard Solana RPC):

typescript
import { createRpc } from "@lightprotocol/stateless.js"

const rpc = createRpc(HELIUS_RPC_URL) // Photon-enabled endpoint

// compressed-state read methods:
await rpc.getCompressedAccount(hashOrAddress)
await rpc.getCompressedTokenAccountsByOwner(owner)
await rpc.getCompressedBalanceByOwner(owner)
await rpc.getValidityProof([accountHash])   // the 128-byte proof for a tx

The honest read

ZK Compression trades rent for compute. A compressed token transfer runs ≈292k CU (proof verification + system hashing + per- account costs), and 128 bytes of every transaction are reserved for the proof against the 1,232-byte limit. You also depend on a Photon indexer and a prover (added latency). It shines for many cheap, rarely-written accounts — airdrops to millions of wallets, long-tail token accounts, large PDA sets. Avoid it for hot accounts written every block, data >~1kB accessed frequently, or anything where the extra CU and RPC dependency outweigh the rent saved.

Live on mainnet-beta since September 2024; Photon endpoints are available from Helius, Triton, and Alchemy.

References

cNFTs proved Solana could put millions of assets on-chain for pennies. ZK Compression is the same bet, generalised to everything that isn't an NFT.