Skip to main content

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.

Auto-generated content

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

#ChapterTopicReading time
01Context and historyWhat zcashd is, who maintains it, ecosystem1 hour
02Build system and contribution loopautotools + depends + Cargo + local dev2 hours
03Code organizationMap of src/ and src/rust/3 hours
04ConsensusValidation pipeline, NU machinery, branch IDs4 hours
05P2P networkingWire protocol, peer lifecycle, mempool relay3 hours
06CryptographyHashes, Equihash, signatures, BLAKE2 personalization4 hours
07zk-SNARKs and shielded poolsSprout, Sapling, Orchard, batch verification6 hours
08StorageBlock files, chainstate, indexes, mempool, wallet, addrman2 hours
09Wallet and RPCCWallet, ZIP-32, ZIP-316, RPC dispatch3 hours
10Testinggtest, Boost.Test, RPC framework, fuzzing2 hours
11Reading planSix-week structured study plan with exercisesreference
12GlossaryDomain abbreviations, with code anchorsreference
13External referencesZIPs, papers, spec, related reposreference

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 capabilityFormal goalDefence in this workspaceRegression caught by
Forge a transparent signatureEUF-CMA over secp256k1 ECDSAsrc/secp256k1/ (vendored libsecp256k1)src/test/script_tests.cpp, script_P2SH_tests.cpp
Spend a shielded note twiceNullifier collision resistanceSapling/Orchard nullifier set in UTXO view; per-NU ContextualCheckTransaction in src/main.cppsrc/gtest/test_checktransaction.cpp, qa/rpc-tests/wallet_doublespend.py
Spend against an anchor that was never on the active chainAnchor must be a past Merkle root of the pool's note commitment treeCCoinsView::HaveSaplingAnchor / GetSaplingAnchorAt lookup in ContextualCheckShieldedInputs (src/main.cpp); see chapter 07src/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-381src/rust/src/sapling.rs::BatchValidator -> zcash_proofs::saplingsrc/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 crateupstream orchard crate tests, qa/rpc-tests/wallet_orchard.py
Decrypt a shielded output the adversary does not ownKA-DH on Jubjub / Pallas, KDF-bindingsrc/rust/src/note_encryption.rs; the zcash_note_encryption crateupstream zcash_note_encryption tests
Malleate a signature to break sighashZIP-215 strict Ed25519 (Sprout), ZIP-216 canonical Jubjubsrc/rust/src/ed25519.rs (Zebra-strict); ZIP-216 in Rustsrc/gtest/test_checktransaction.cpp and upstream
Replay a tx across a network upgradeBranch ID is part of the sighash post-OverwinternConsensusBranchId enforced in ContextualCheckTransactionsrc/gtest/test_consensus.cpp, qa/rpc-tests/feature_zip244_blockcommitments.py
Counterfeit value (Sprout, CVE-2019-7167)Soundness of Groth16 over patched parameterssprout-groth16.params distributed by zcutil/fetch-params.sh, loaded by librustzcash_init_zksnark_paramsNo automated regression test in this workspace; caught by parameter integrity at load time
Equihash false solveGeneralized birthday hardness; (n,k)=(200,9) for mainnetsrc/crypto/equihash.{h,cpp,tcc}, called from src/pow.cpp::CheckEquihashSolutionsrc/gtest/test_pow.cpp
Withhold turnstile balance from a poolZIP-209 turnstile enforcementsrc/main.cpp::ConnectBlock checks the pool-balance accumulatorqa/rpc-tests/turnstile.py
Reveal sender via on-wire metadataMitigated by Tor; not formally proven-onlynet=onion, no IP advertisement under TorNo automated test; operator concern
Reveal sender via tx-relay timing (Dandelion++)Out of scope in this workspaceNone; zcashd does not implement Dandelion++Out of scope; rely on Tor
Steal funds from an encrypted walletBrute-force resistance of passphrase KDFsrc/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.

  • Fp\mathbb{F}_p: a prime field of order pp.
  • GJ\mathbb{G}_J, GP\mathbb{G}_P: the Jubjub (Sapling) and Pallas (Orchard) curves, both used inside zero-knowledge circuits as embedded groups.
  • GBLS\mathbb{G}_{BLS}, GBN\mathbb{G}_{BN}: BLS12-381 and BN-254, the outer pairing-friendly curves for Sapling and Sprout.
  • [k]P[k]P: scalar multiplication of point PP by scalar kk.
  • H()H_\ell(\cdot): a hash with \ell-bit output.
  • BLAKE2b-(pers,x)\mathsf{BLAKE2b}\text{-}\ell(\mathsf{pers}, x): BLAKE2b with output length \ell bytes and personalisation string pers\mathsf{pers}.
  • Com(m;r)\mathsf{Com}(m; r): a commitment to message mm with randomness rr.
  • Enck\mathsf{Enc}_k, Deck\mathsf{Dec}_k: symmetric encryption and decryption with key kk. In Zcash specifically, ChaCha20-Poly1305 for Sapling note encryption.
  • PRFxname()\mathsf{PRF}_x^{\mathsf{name}}(\cdot): a Zcash-named pseudorandom function with key xx.
  • cm\mathsf{cm}, nf\mathsf{nf}: a note commitment, a note nullifier.
  • ivk\mathsf{ivk}, ovk\mathsf{ovk}, ak\mathsf{ak}, nk\mathsf{nk}: Sapling incoming viewing key, outgoing viewing key, spend authorising key, nullifier deriving key.
  • \stackrel{\}{\leftarrow}$: uniform random sampling.
  • aba \mathbin{\\|} b: byte-string concatenation.
  • RSapling,ROrchardR^{\mathsf{Sapling}}, R^{\mathsf{Orchard}}: the NP relations attested by the Sapling and Orchard spend / action proofs (see chapter 07).

Conventions

  • File paths are given as src/foo/bar.cpp and 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-rc1 tag of zcash/zcash on GitHub.

How to use this course

  1. 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.
  2. 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.
  3. Read 06 - 08 in any order. These are the Zcash-specific parts.
  4. Use chapter 11 as the week-by-week to-do list.
  5. 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.