ZeraLabs logo
WALLET

Quick Start

Integrate private payments with the ZERA SDK

The @zera-labs/sdk TypeScript package provides everything you need: Poseidon hashing, Merkle tree management, Groth16 proof generation, Solana transaction builders, and note storage backends.

Architecture Overview

The SDK is organized into four layers, each buildable independently:

Layer 1 — zera-core (Rust)
Portable crypto primitives: Poseidon X5 hashing (BN254),
incremental Merkle tree, note types, PDA derivation,
Groth16 proof formatting. Zero Solana dependency.
Layer 2 — zera-neon (Rust → Node.js via napi-rs)
Native bindings for high-performance Poseidon hashing
and Merkle operations in JavaScript environments.
Layer 3 — @zera-labs/sdk (TypeScript)
Primary integration surface. Proof generators, tx builders,
tree state client, note storage, voucher system.
Layer 4 — @zera-labs/mcp-server
Model Context Protocol server exposing SDK operations
as tools for AI agents (Claude, GPT, etc.)

Shielded Deposit

A complete deposit flow in ~15 lines:

import { createNote, computeCommitment } from '@zera-labs/sdk'
import { generateDepositProof } from '@zera-labs/sdk/prover'
import { buildDepositTransaction } from '@zera-labs/sdk/tx'
// 1. Create a shielded note (random secret + blinding)
const note = createNote(amount, assetMint, memo)
// 2. Compute Poseidon commitment (Merkle leaf)
const commitment = computeCommitment(note)
// commitment = Poseidon(amount, secret, blinding, asset, memo[0..3])
// 3. Generate Groth16 proof
const { proof } = await generateDepositProof(
note, wasmPath, zkeyPath
)
// 4. Build and send Solana transaction
const tx = await buildDepositTransaction({
commitment, proof, mint, payer, amount
})
// On-chain: verify proof → insert leaf → update Merkle root

Shielded Withdrawal

Withdraw from the shielded pool by proving Merkle membership and revealing a nullifier:

import { computeNullifier } from '@zera-labs/sdk'
import { generateWithdrawProof } from '@zera-labs/sdk/prover'
import { buildWithdrawTransaction } from '@zera-labs/sdk/tx'
import { MerkleTree } from '@zera-labs/sdk/merkle-tree'
// 1. Sync Merkle tree from chain
const tree = MerkleTree.create(24) // height=24, 16M capacity
// ... insert on-chain leaves
// 2. Compute nullifier (single-spend tag)
const nullifier = computeNullifier(note.secret, commitment)
// nullifier = Poseidon(secret, commitment)
// 3. Generate Groth16 proof
const { proof, nullifierHash } = await generateWithdrawProof(
note, leafIndex, tree, recipientHash, wasmPath, zkeyPath
)
// 4. Build transaction
const tx = await buildWithdrawTransaction({
proof, nullifierHash, recipientHash, mint, payer
})
// On-chain: verify proof → check nullifier PDA doesn't exist
// → create nullifier PDA → transfer tokens

Shielded Transfer (Note Splitting)

Split one note into two output notes — the 1-input 2-output circuit enforces value conservation:

import { generateTransferProof } from '@zera-labs/sdk/prover'
import { buildTransferTransaction } from '@zera-labs/sdk/tx'
// Split a $100 note into $30 + $70
const outputNote1 = createNote(30_000_000n, usdcMint)
const outputNote2 = createNote(70_000_000n, usdcMint)
const { proof, nullifierHash, outputCommitment1, outputCommitment2 }
= await generateTransferProof(
inputNote, inputLeafIndex, tree,
outputNote1, outputNote2, wasmPath, zkeyPath
)
const tx = await buildTransferTransaction({
proof, nullifierHash,
outputCommitment1, outputCommitment2,
mint, payer
})
// On-chain: verify proof → nullify input → insert 2 new leaves

Key Primitives

// Poseidon hashing (BN254 scalar field)
import { poseidonHash, poseidonHash2 } from '@zera-labs/sdk/crypto'
const hash = poseidonHash([a, b, c]) // arbitrary-length
const node = poseidonHash2(left, right) // Merkle node
// PDA derivation
import { derivePoolConfig, deriveVault, deriveNullifier }
from '@zera-labs/sdk/pda'
const poolConfig = derivePoolConfig(mint, programId)
const vault = deriveVault(mint, programId)
const nullifierPDA = deriveNullifier(nullifierHash, programId)
// Note storage
import { MemoryNoteStore, FileNoteStore } from '@zera-labs/sdk'
const store = new FileNoteStore('./notes.enc')
await store.save(note, leafIndex)
// Tree state sync (on-chain → local)
import { TreeStateClient } from '@zera-labs/sdk'
const client = new TreeStateClient({ rpcUrl, cacheEndpoint })
const leaves = await client.fetchAllLeaves()

On-Chain Programs

Two Solana programs are deployed:

// Shielded Pool (full Groth16 ZK)
// Deposit, withdraw, relayed withdraw, shielded transfer
Program ID: B83jSQx1CT1hPRBupinaJaEkCjrfeo6Ktncu31q3ZNeX
// Private Cash (lightweight Keccak-256 vouchers)
// Commitment-based voucher system for simpler use cases
Program ID: ESQxpH9XkBQT6EVeWwAzTZD1e9NrLMrY8RPQ9SidYsgF

Source & Contribution

The SDK is open source. Follow progress and contribute:

https://github.com/zera-labs

More Developer Resources

SDK Reference

Complete function signatures, types, constants

Architecture & Performance

Stack diagram, proof gen times, deployment

Testing & Security

144 tests, invariants, OFAC screening