Skip to main content
Merkle inclusion proof
curl --request GET \
  --url http://localhost:3001/v1/trees/{tree_index}/proof/{insertion_index}
{
  "root": "1a2b3c4d5e6f7890abcdef1234567890abcdef1234567890abcdef1234567890ab",
  "tree_index": 0,
  "insertion_index": 42,
  "proof": [
    "0000000000000000000000000000000000000000000000000000000000000000",
    "2098f5fb9e239eab3ceac3f27b81e481dc3124d55ffed523a839ee8446b64864"
  ],
  "leaf": "deadbeefcafebabe1234567890abcdef1234567890abcdef1234567890abcdef12"
}
Returns an authentication path of 20 sibling hashes — one per level — ordered from the leaf level (index 0) up to the root level (index 19). All hash values are little-endian 64-character hex strings (32 bytes each).
Merkle proofs become stale when new leaves are inserted into the tree (because the root changes). Always fetch a fresh proof immediately before submitting a claim. Never cache proofs across user sessions.

Verifying a Proof

Hash the target leaf with each sibling in order and compare the final result to the tree’s current root hash (fetch the root via Tree Metadata).

Usage in the SDK

The Umbra SDK calls this endpoint automatically via getFetchClaimableUtxosFunction. The proof is passed directly to the claim functions — you do not need to call this endpoint manually when using the SDK. If you are building a custom claim flow or integrating with the protocol directly, use this endpoint to fetch fresh proofs immediately before submitting a claim transaction.

Performance

Proof generation traverses all 20 tree levels. Under normal conditions, proofs are generated in under 100 ms. Operations exceeding 500 ms emit a slow-operation warning server-side but still return a valid proof.

Path Parameters

tree_index
integer<int64>
required

Zero-based index of the Merkle tree to query.

Required range: x >= 0
insertion_index
integer<int64>
required

Zero-based leaf position for which to generate the proof. Must be strictly less than the tree's current num_leaves.

Required range: x >= 0

Response

Merkle proof generated successfully.

Protobuf ProofResponse message returned by GET /v1/trees/{tree_index}/proof/{insertion_index}.

All hash string fields are little-endian hex representations of 32-byte Poseidon hashes (matching Solana's on-chain byte order and Circom ZK circuit input conventions). Each hash is a 64-character hex string (32 bytes).

Usage: Together with leaf, root, and the 20-element proof array, a caller can verify membership and construct a Groth16 zero-knowledge proof verifiable against the on-chain Umbra Merkle root.

Depth: The Umbra mixer uses a depth-20 Indexed Merkle Tree, so proof always contains exactly 20 sibling hashes.

root
string
required

Little-endian hex-encoded Poseidon root hash at query time. 64 hex characters (32 bytes).

Example:

"1a2b3c4d5e6f7890abcdef1234567890abcdef1234567890abcdef1234567890ab"

tree_index
integer<int64>
required

Echo of the requested tree_index path parameter.

Example:

0

insertion_index
integer<int64>
required

Echo of the requested insertion_index path parameter.

Example:

42

proof
string[]
required

Ordered sibling hashes forming the authentication path from the leaf up to the root. Always exactly 20 elements (depth-20 tree), ordered from leaf level (index 0) to root level (index 19). Each element is a 64-character little-endian hex-encoded Poseidon hash.

Required array length: 20 elements
Example:
[
"0000000000000000000000000000000000000000000000000000000000000000",
"2098f5fb9e239eab3ceac3f27b81e481dc3124d55ffed523a839ee8446b64864"
]
leaf
string
required

Little-endian hex-encoded final_commitment = Poseidon(h1_hash, h2_hash) at insertion_index. 64 hex characters (32 bytes).

Example:

"deadbeefcafebabe1234567890abcdef1234567890abcdef1234567890abcdef12"