Skip to content
Launch App >

The privacy mechanism relies on Merkle trees and cryptographic commitments. This page explains these concepts at a practical level.

A commitment is a hash that “locks in” a value without revealing it. For private transfers, each deposit creates a commitment from two secrets:

commitment = poseidon(nullifier, secret)
ComponentPurpose
nullifierRandom 32-byte value. Its hash is published on withdrawal to prevent double-spending.
secretRandom 32-byte value. Keeps the commitment secure even if nullifier is guessed.
commitmentThe hash stored in the Merkle tree. Reveals nothing about nullifier or secret.

All commitments are stored in a Merkle tree - a binary tree where each node is the hash of its children:

The protocol uses depth-32 Merkle trees, supporting up to 2³² (4+ billion) deposits per token.

  1. Efficient Proofs: Prove membership with only 32 hashes (the path from leaf to root)
  2. Privacy: The proof reveals nothing about which specific commitment you’re proving
  3. Compact Storage: Only the root hash needs to be stored on-chain

The anonymity set is all deposits in the same Merkle tree. When you withdraw:

  • You prove “I know the secret for one of these deposits”
  • The verifier cannot determine which deposit

The larger the anonymity set, the stronger the privacy. Each Merkle tree is per-token and per-deposit-size.

The protocol uses Poseidon hash function instead of SHA-256 or Keccak because:

  • ZK-friendly: Much cheaper to prove in zero-knowledge circuits
  • Secure: Designed specifically for ZK applications
  • Efficient: Fewer constraints means faster proof generation

Your client code must use a Poseidon implementation compatible with the circuit. See the Deposit guide for reference implementations.

ConceptWhat It Means for You
Commitment generationMust happen client-side for privacy
Secret storageYou are responsible for backing up nullifier + secret
Anonymity setWait for more deposits to increase privacy
Single useEach commitment can only be withdrawn once