Zero to Zcash

A developer tutorial that takes you from "what even is a ZK proof" to building with the Zcash protocol. No fluff. No hand-waving. Every claim verified.

By Manav Gupta March 2026 ~45 min read

When I first opened the Zcash docs, I felt like someone handed me a math PhD thesis and said "here, build something." Elliptic curves, polynomial commitments, trusted ceremonies... none of it made sense.

Turns out, it's not actually that complicated once someone explains it like a normal person. That's what this tutorial does. No academic gatekeeping. No skipping the hard parts.

💡
Prerequisites: Basic programming. Some Rust helps for later chapters. If you know what a hash function is and have heard the word "encryption," you're good.

Chapter 1

WTF Is a Zero-Knowledge Proof?

You go to a bank for a loan. They ask: "Do you make more than $5,000/month?" Normally, you'd show them your entire bank statement – every transaction, every embarrassing late-night impulse buy, everything.

But what if you could just... prove you make more than $5K without showing a single number? That's a zero-knowledge proof.

📚
Definition: A zero-knowledge proof lets a Prover convince a Verifier that a statement is true, without revealing anything beyond the truth of that statement.

Three properties make it work:

1
Completeness: If the statement is true and both parties follow the protocol, the verifier will always be convinced.
2
Soundness: If the statement is false, no cheating prover can convince the verifier (except with negligible probability).
3
Zero-Knowledge: The verifier learns absolutely nothing beyond "the statement is true." Not the amount, not the account, nothing.
The classic example: The Color-Blind Friend

Your friend is color-blind. You have a red ball and a green ball. You want to prove they're different colors without telling which is which.

Your friend hides the balls behind their back. They either swap or don't, then show you. You say "swapped" or "not swapped." If the balls were the same, you'd be guessing (50%). Since they're different, you get it right every time.

After 20 rounds, the probability you're guessing is (1/2)^20 = 0.0001%. Your friend is convinced. But they still don't know which is red and which is green. Proof happened. Information didn't leak.

Why does blockchain need this?

Regular blockchains like Bitcoin and Ethereum make everything public. Your wallet, balance, every transaction. It's pseudo-anonymous at best – one slip connecting your wallet to your identity, and your entire financial history is exposed.

Zcash uses ZK proofs so the network can verify transactions are valid without anyone seeing the sender, receiver, or amount.

✅ Check yourself

In a zero-knowledge proof, what does the verifier learn?


Chapter 2

What "Shielded" Actually Means

When Zcash says a transaction is "shielded," it means the details are cryptographically hidden on-chain using zk-SNARKs, while the network can still verify everything checks out.

The blockchain proves the math is valid without knowing what the math is about.

Two worlds in one chain

t-address
Transparent
z-address
Shielded
u-address
Unified

Unified Addresses (u1...) bundle both types. Modern wallets should use these.

Transparent (t-addresses): Work like Bitcoin. Everyone sees sender, receiver, amount. Start with t.

Shielded (z-addresses): Sender, receiver, and amount are all encrypted. Only a short proof exists publicly. Start with zs.

Unified Addresses: Start with u1. Bundle multiple receiver types. Your wallet picks the most private option automatically.

zk-SNARKs: The engine behind shielding

Z
Zero-Knowledge – reveals nothing beyond validity
S
Succinct – proof is tiny (~192 bytes) and fast to verify
N
Non-Interactive – one message, no back-and-forth
A
Arguments of Knowledge – proves the prover actually knows the secret
Key distinction: "Shielded" is not just encryption. With regular encryption, you decrypt to verify. With zk-SNARKs, verification happens on the encrypted data itself. The chain never sees the plaintext.
View keys: selective transparency

Shielded doesn't mean "hidden forever from everyone." Zcash gives you view keys you can share with auditors, tax authorities, or anyone who needs to see your transactions. You control who sees what.

Privacy by default. Transparency by choice.

✅ Check yourself

How is Zcash shielding different from regular encryption?


Chapter 3

The Math

Don't panic. I'm walking you through the entire pipeline, from a computation you want to prove, all the way to a tiny proof anyone can verify.

Computation
Arithmetic Circuit
R1CS
QAP
zk-SNARK

Step 1: Arithmetic Circuits

Any computation can be broken into addition (+) and multiplication (×) gates over a finite field. Like a logic circuit, but with math.

Example: proving you know x such that x³ + x + 5 = 35
Gate 1:  a = x × x        (x²)
Gate 2:  b = a × x        (x³)
Gate 3:  c = b + x        (x³ + x)
Gate 4:  out = c + 5      (x³ + x + 5)

Constraint: out == 35

Solution: x = 3
  9 = 3 × 3    ✓
  27 = 9 × 3   ✓
  30 = 27 + 3  ✓
  35 = 30 + 5  ✓

In Zcash, the "computation" is the full transaction validity check – ownership, balance, no double-spending. Thousands of gates.

Step 2: R1CS (Rank-1 Constraint System)

Each multiplication gate becomes a constraint:

(A · s) × (B · s) = (C · s)

Where s is a vector of all wire values, and A, B, C are matrices encoding the circuit. Addition is "free" – absorbed into the matrices.

See the full R1CS for our example
s = [1, x, out, a, b, c]    // witness vector

Constraint 1 (a = x × x):
  A picks x, B picks x, C picks a
  x × x = a  ✓

Constraint 2 (b = a × x):
  A picks a, B picks x, C picks b
  a × x = b  ✓

Each multiplication = one R1CS constraint
Each addition = absorbed into the matrices

Step 3: QAP (Quadratic Arithmetic Program)

The constraint matrices get converted into polynomials via Lagrange interpolation. Why? Because polynomial divisibility is cheap to check and impossible to fake.

🔑
The trick: A valid witness means L(x) · R(x) - O(x) is perfectly divisible by a target polynomial T(x). The prover computes the quotient H(x). If they can produce it, the witness is valid. Forging H(x) without knowing the witness is computationally impossible.

Step 4: Elliptic Curve Commitment (BLS12-381)

Now we hide the polynomials using elliptic curve points. Zcash uses BLS12-381, designed by Sean Bowe in 2017.

1
128-bit security – meets current cryptographic recommendations
2
Pairing-friendly – supports bilinear pairings for Groth16 verification
3
Fast FFT – scalar field has a 2^32 root of unity for fast polynomial evaluation

The security relies on the discrete logarithm problem:

Given Q = k · G on the curve: easy to compute Q from k, practically impossible to find k from Q.

The prover commits to polynomials using curve points. Values are hidden, but verification through pairings still works.

Step 5: The final proof

In Groth16 (Zcash Sapling), the final proof is 3 elliptic curve elements – ~192 bytes. Doesn't matter if the circuit had millions of constraints. The proof is constant size and verifies in milliseconds.

✅ Check yourself

What comes right after Arithmetic Circuit in the pipeline?


Chapter 4

Inside a Shielded Transaction

Let's trace what actually happens when you send shielded ZEC. Step by step, nothing skipped.

Interactive: Transaction Lifecycle

Click "Next Step" to walk through each stage.

1. Create Note
Sender creates an output note: (amount, recipient address, randomness). Unlike Bitcoin UTXOs, notes are never visible on-chain.
2. Compute Commitment
A Pedersen commitment of the note goes on-chain and is added to the global Note Commitment Merkle Tree (depth 32). The commitment reveals nothing about the note.
3. Derive Nullifier
To spend the note, a unique nullifier is computed from the spending key + note data. Published on-chain to prevent double-spending. No one can link a nullifier back to its commitment.
4. Generate zk-SNARK Proof
Wallet proves: (a) note exists in Merkle tree, (b) prover owns the spending key, (c) nullifier is correct, (d) input amounts = output amounts. All without revealing any of those values.
5. Encrypt Outputs + Value Commit
New note commitments created for recipients. Note details encrypted with recipient's key. Value commitments (homomorphic) let the network verify balance without seeing amounts.
6. Broadcast
Transaction goes on-chain containing: nullifiers, new commitments, encrypted notes, value commitments, and proofs. No addresses. No amounts. No linkable data.
Step 1 / 6
How value commitments prove balance
ValueCommit(v) = v · [V] + rcv · [R]

V and R are generator points, v is value, rcv is randomness. These commitments are additively homomorphic: the network verifies that input commitments minus output commitments equals zero, without knowing any individual value.

✅ Check yourself

What prevents double-spending in Zcash's shielded pool?


Chapter 5

Sapling vs Orchard

Two shielded protocols coexist in Zcash today. Sapling (2018) uses Groth16. Orchard (2022) uses Halo 2. The fundamental difference: trust.

The trust problem

Groth16 needs a trusted setup ceremony. Secret parameters are generated; if anyone kept them, they could forge proofs and create fake ZEC. Zcash ran a Multi-Party Computation with 87+ participants – secure if even one was honest. But it's still a trust assumption.

Halo 2 eliminates the trusted setup entirely. It uses an Inner Product Argument for polynomial commitments. No hidden structure. No toxic waste. No ceremony.

FeatureSapling (Groth16)Orchard (Halo 2)
Trusted SetupRequiredNot needed
Proof Size~192 bytes (smallest)Larger (IPA-based)
Verification SpeedFastestSlightly slower
ArithmetizationR1CSPLONKish
CurveJubjub (on BLS12-381)Pallas / Vesta cycle
Hash FunctionBowe-Hopwood PedersenSinsemilla
Nullifier PRFBLAKE2sPoseidon
Recursive ProofsNoYes
Why Pallas/Vesta matter

Orchard uses the Pasta curves (Pallas + Vesta). Their key property: each curve's scalar field equals the other's base field. This creates a cycle enabling recursive proof composition – verify a proof inside another proof, infinitely. This is what makes Halo 2 powerful for future scalability.

Bottom line: Sapling is active and secure. Orchard is the future – trustless, recursive, built for scale. New wallets should prefer Orchard via Unified Addresses.

Chapter 6

Hands-On: librustzcash

Enough theory. Here's what you'd actually touch as a developer.

The protocol spec

The bible lives at zips.z.cash/protocol/protocol.pdf (400+ pages). And ZIPs at zips.z.cash:

Essential ZIPs
ZIP 0   – The ZIP process (how Zcash evolves)
ZIP 32  – HD wallets for shielded addresses
ZIP 224 – Orchard shielded protocol
ZIP 316 – Unified Addresses
ZIP 321 – Payment Request URIs

Explore the crate suite

Click any crate to see details:

zcash_primitives
Core transaction types, Merkle tree, serialization
zcash_proofs
Groth16 proving & verification
zcash_keys
Key management, ZIP-32 HD derivation
zcash_client_backend
Wallet framework, chain scanning, fees
zcash_client_sqlite
SQLite wallet storage implementation
zcash_protocol
Constants, consensus params, value types
Foundation crate. Provides Transaction, TransactionData, block headers, incremental Merkle tree, and serialization. Import this first – almost everything else depends on it.
Implements Groth16 circuits for Sapling spend/output descriptions. Handles proof generation and verification. Uses the Bellman library under the hood.
Spending keys, viewing keys, unified addresses. Implements ZIP-32 hierarchical deterministic key derivation for both Sapling and Orchard pools.
The wallet brain. Abstract interfaces for chain scanning, fee calculation, transaction proposal building, and wallet storage. Use this to build a light client.
Plug-and-play SQLite implementation of the storage interfaces from zcash_client_backend. Drop this in and you have persistent wallet state.
Low-level constants and types: network parameters, consensus branch IDs, bounded value types. Small but essential.

Architecture

zcash_client_sqlite
zcash_client_backend
zcash_primitives
zcash_proofs
zcash_keys
zcash_protocol
zcash_encoding
zcash_address

Quick start

Cargo.toml
[dependencies]
zcash_primitives = "0.17"
zcash_proofs = "0.17"
zcash_keys = { version = "0.4", features = ["orchard"] }
zcash_client_backend = "0.14"
zcash_protocol = "0.4"
Key generation (conceptual)
use zcash_keys::keys::UnifiedSpendingKey;
use zcash_protocol::consensus::Network;
use zip32::AccountId;

let seed: [u8; 32] = /* BIP-39 seed bytes */;
let account = AccountId::try_from(0).unwrap();

// Derive spending key for Sapling + Orchard
let usk = UnifiedSpendingKey::from_seed(
    &Network::MainNetwork,
    &seed,
    account,
).expect("key derivation failed");

// Get unified full viewing key
let ufvk = usk.to_unified_full_viewing_key();

// Generate a unified address (ZIP 316)
let (ua, _idx) = ufvk
    .default_address(None)
    .expect("address gen failed");
Warning: librustzcash is under active development and not fully audited. APIs change between versions. Always check docs.rs. Don't ship to production without review.

Chapter 7

Build Your Own

Three paths depending on what you want to do.

Path A: Run a node (Zebrad)

Terminal
# Install Rust
curl --proto '=https' --tlsv1.2 -sSf \
  https://sh.rustup.rs | sh

# Install Zebra
cargo install --locked \
  --git https://github.com/ZcashFoundation/zebra \
  zebrad

# Generate config + start
zebrad generate -o ~/.config/zebrad.toml
zebrad start

Path B: Light client (Zingolib)

Terminal
git clone https://github.com/zingolabs/zingolib.git
cd zingolib
cargo build --release --package zingo-cli

./target/release/zingo-cli
# Inside: help, balance, addresses, send, shield

Path C: Build a wallet from librustzcash

Development flow
// 1. Storage: WalletDb (SQLite-backed)
// 2. Keys: UnifiedSpendingKey from seed
// 3. Scan: Connect to lightwalletd, scan blocks
// 4. Build tx: Add spends + outputs, generate proofs
// 5. Broadcast: Send raw tx to the network

The Development Stack

Your App (wallet, dApp, CLI)
librustzcash
lightwalletd (gRPC)
zebrad (full node)

Where to go from here

1
Read the ZIPs – Start with ZIP 224 (Orchard) and ZIP 316 (Unified Addresses)
2
Study Halo 2 – The Halo 2 book is excellent for writing custom circuits
3
Join the communityDiscord, Forum, ZecHub Wiki
4
Contribute – librustzcash is open source. Fix a bug, improve docs, or build something. Zcash rewards contributors through grants and bounties.
🏆
You now understand ZK proofs, shielding, the math pipeline, transaction internals, Sapling vs Orchard, and how to build with the actual codebase. Go build something.