zcashd onboarding
A graduate course on the zcashd codebase. The intent is to take a principal cryptography engineer from "I know cryptography but zcashd is a 200k-line Bitcoin fork" to "I can navigate, audit, and modify any subsystem".
The course is structured as a self-paced reading guide. Each chapter teaches one subsystem and points to the exact files, functions, ZIPs, and external documents to read. It is paired with a six-week hands-on reading plan (chapter 11) that converges on a real merged PR.
This site is generated by Claude Code and may contain errors, out-of-date file paths, or misstatements of fact. The code at zcash/zcash is the law. The Zcash Protocol Specification at zips.z.cash/protocol/protocol.pdf and the ZIPs index are the authoritative sources for consensus. The librustzcash and orchard repositories own the cryptographic primitives.
Found a mistake? Open an issue on the onboarding fork or edit the page directly via the "Edit this page" link at the bottom of each chapter.
Source pin
Live source embeds and direct links in this course point to upstream
tag v5.5.0-rc1, the most recent ECC release at the time the
course was written. Renames after that tag will leave embedded links
intact but the line ranges may drift. The pin lives in
docusaurus.config.ts as ZCASH_PIN.
For mathematical statements about the protocol, the pin should be read as "the consensus rules as of NU5 (NU5 activation: mainnet height 1687104)". When a new network upgrade activates, both the tag and the prose need to be revisited.
Reading order
| # | Chapter | Topic | Reading time |
|---|---|---|---|
| 01 | Context and history | What zcashd is, who maintains it, ecosystem | 1 hour |
| 02 | Build system and contribution loop | autotools + depends + Cargo + local dev | 2 hours |
| 03 | Code organization | Map of src/ and src/rust/ | 3 hours |
| 04 | Consensus | Validation pipeline, NU machinery, branch IDs | 4 hours |
| 05 | P2P networking | Wire protocol, peer lifecycle, mempool relay | 3 hours |
| 06 | Cryptography | Hashes, Equihash, signatures, BLAKE2 personalization | 4 hours |
| 07 | zk-SNARKs and shielded pools | Sprout, Sapling, Orchard, batch verification | 6 hours |
| 08 | Storage | Block files, chainstate, indexes, mempool, wallet, addrman | 2 hours |
| 09 | Wallet and RPC | CWallet, ZIP-32, ZIP-316, RPC dispatch | 3 hours |
| 10 | Testing | gtest, Boost.Test, RPC framework, fuzzing | 2 hours |
| 11 | Reading plan | Six-week structured study plan with exercises | reference |
| 12 | Glossary | Domain abbreviations, with code anchors | reference |
| 13 | External references | ZIPs, papers, spec, related repos | reference |
Total active reading: roughly 30 hours. Plan to spend another 60-80 hours running the node, instrumenting it, and writing patches against it before considering yourself fluent.
What this course is not
- Not a cryptography tutorial. It assumes the reader knows what a Pedersen commitment, a Groth16 proof, a Schnorr signature, an IPA commitment, and a Merkle tree are.
- Not a Bitcoin tutorial. It assumes the reader knows what a UTXO, script, P2PKH, transaction malleability, and difficulty adjustment are.
- Not a replacement for the Zcash Protocol Specification. The spec is authoritative for consensus. This course teaches how the spec is realised in code.
Threat model
The system that this codebase implements is a privacy-preserving payment system with hard real-money consensus. The table below names the adversaries the protocol claims to defend against, the formal goal, where the defence lives, and where a regression would be caught.
| Adversary capability | Formal goal | Defence in this workspace | Regression caught by |
|---|---|---|---|
| Forge a transparent signature | EUF-CMA over secp256k1 ECDSA | src/secp256k1/ (vendored libsecp256k1) | src/test/script_tests.cpp, script_P2SH_tests.cpp |
| Spend a shielded note twice | Nullifier collision resistance | Sapling/Orchard nullifier set in UTXO view; per-NU ContextualCheckTransaction in src/main.cpp | src/gtest/test_checktransaction.cpp, qa/rpc-tests/wallet_doublespend.py |
| Spend against an anchor that was never on the active chain | Anchor must be a past Merkle root of the pool's note commitment tree | CCoinsView::HaveSaplingAnchor / GetSaplingAnchorAt lookup in ContextualCheckShieldedInputs (src/main.cpp); see chapter 07 | src/gtest/test_checktransaction.cpp anchor cases; reorg paths in qa/rpc-tests/wallet_anchorfork.py |
| Forge a shielded proof (Sapling) | Groth16 knowledge soundness over BLS12-381 | src/rust/src/sapling.rs::BatchValidator -> zcash_proofs::sapling | src/gtest/test_joinsplit.cpp, Rust unit tests upstream |
| Forge a shielded proof (Orchard) | Halo 2 knowledge soundness (IPA over Pasta cycle) | src/rust/src/orchard_ffi.rs::BatchValidator -> orchard crate | upstream orchard crate tests, qa/rpc-tests/wallet_orchard.py |
| Decrypt a shielded output the adversary does not own | KA-DH on Jubjub / Pallas, KDF-binding | src/rust/src/note_encryption.rs; the zcash_note_encryption crate | upstream zcash_note_encryption tests |
| Malleate a signature to break sighash | ZIP-215 strict Ed25519 (Sprout), ZIP-216 canonical Jubjub | src/rust/src/ed25519.rs (Zebra-strict); ZIP-216 in Rust | src/gtest/test_checktransaction.cpp and upstream |
| Replay a tx across a network upgrade | Branch ID is part of the sighash post-Overwinter | nConsensusBranchId enforced in ContextualCheckTransaction | src/gtest/test_consensus.cpp, qa/rpc-tests/feature_zip244_blockcommitments.py |
| Counterfeit value (Sprout, CVE-2019-7167) | Soundness of Groth16 over patched parameters | sprout-groth16.params distributed by zcutil/fetch-params.sh, loaded by librustzcash_init_zksnark_params | No automated regression test in this workspace; caught by parameter integrity at load time |
| Equihash false solve | Generalized birthday hardness; (n,k)=(200,9) for mainnet | src/crypto/equihash.{h,cpp,tcc}, called from src/pow.cpp::CheckEquihashSolution | src/gtest/test_pow.cpp |
| Withhold turnstile balance from a pool | ZIP-209 turnstile enforcement | src/main.cpp::ConnectBlock checks the pool-balance accumulator | qa/rpc-tests/turnstile.py |
| Reveal sender via on-wire metadata | Mitigated by Tor; not formally proven | -onlynet=onion, no IP advertisement under Tor | No automated test; operator concern |
| Reveal sender via tx-relay timing (Dandelion++) | Out of scope in this workspace | None; zcashd does not implement Dandelion++ | Out of scope; rely on Tor |
| Steal funds from an encrypted wallet | Brute-force resistance of passphrase KDF | src/wallet/crypter.cpp (iterated SHA-512, then AES-256-CBC) | src/wallet/test/crypter_tests.cpp |
Rows are grouped by category:
- Rows 1 - 9: defended by cryptographic reduction or by direct consensus rule. A regression here is a security bug.
- Rows 10 - 11: defended by heuristic (turnstile is a cross-check, not a primitive proof). A regression is severe but recoverable.
- Rows 12 - 13: out of scope for the protocol layer. Operator responsibility.
When you change code that touches any cell in this table, you must also update the test in the "regression caught by" column, or explicitly document why no test applies.
Notation
Used throughout. Reuse these symbols rather than introducing new ones.
- : a prime field of order .
- , : the Jubjub (Sapling) and Pallas (Orchard) curves, both used inside zero-knowledge circuits as embedded groups.
- , : BLS12-381 and BN-254, the outer pairing-friendly curves for Sapling and Sprout.
- : scalar multiplication of point by scalar .
- : a hash with -bit output.
- : BLAKE2b with output length bytes and personalisation string .
- : a commitment to message with randomness .
- , : symmetric encryption and decryption with key . In Zcash specifically, ChaCha20-Poly1305 for Sapling note encryption.
- : a Zcash-named pseudorandom function with key .
- , : a note commitment, a note nullifier.
- , , , : Sapling incoming viewing key, outgoing viewing key, spend authorising key, nullifier deriving key.
- \stackrel{\}{\leftarrow}$: uniform random sampling.
- : byte-string concatenation.
- : the NP relations attested by the Sapling and Orchard spend / action proofs (see chapter 07).
Conventions
- File paths are given as
src/foo/bar.cppand are relative to the zcashd repo root unless absolute. - Function names are written in their on-disk form, e.g.
ContextualCheckBlock. - "Spec" without qualification means the Zcash Protocol Specification PDF.
- "ZIP-N" refers to Zcash Improvement Proposal N at zips.z.cash.
- Live source embeds (the rendered code blocks below) link to the
v5.5.0-rc1tag ofzcash/zcashon GitHub.
How to use this course
- Read chapters 01 and 02 first. Build the node end to end before anything else; nothing in this codebase makes sense until you have it running.
- Read 03 - 05 next: the code map, consensus, and P2P. These chapters lean on Bitcoin Core background; if Bitcoin is new, read "Mastering Bitcoin" chapters 5 - 9 in parallel.
- Read 06 - 08 in any order. These are the Zcash-specific parts.
- Use chapter 11 as the week-by-week to-do list.
- Use chapters 11 - 12 as reference indices.
Where to file corrections
This site is auto-generated; the course owners welcome corrections.
For factual fixes, open an issue or pull request against the
onboarding branch on the fork.
For protocol-level corrections, the canonical place is the
ZIPs repository and the spec source
under protocol/. For implementation bugs, file at
zcash/zcash issues.