01 - Overview and roadmap
1. Why this chapter exists
librustzcash is a Cargo workspace of about twenty crates that
together implement Zcash wallets, transaction construction, and
zero-knowledge proving. A reader who jumps straight into a specific
crate without a map will repeatedly misattribute responsibility:
sighash math lives in zcash_primitives, key derivation lives in
zcash_keys, the shielded circuits live in external crates
(sapling-crypto, orchard). This chapter fixes the dependency
layering once so every subsequent chapter can refer to it by name.
By the end of it, you will be able to read the workspace declaration
in
Cargo.toml
and explain why each member is in the layer it is in.
2. Definitions
Definition (workspace). A Cargo workspace is a set of crates
that share a single Cargo.lock, a single target/ directory, and
optionally common metadata declared under [workspace.package] and
[workspace.dependencies]. Membership is declared in the top-level
[workspace] members array.
Definition (layer). Throughout this course, a layer is a maximal set of workspace crates such that no member of layer depends on any member of layer with . Layers are determined by the directed dependency graph; the graph is acyclic by construction (Cargo rejects cycles).
Invariant (downward dependencies). For any two workspace crates
and , if depends on then layer(A) >= layer(B). This
is what allows the wallet layer to reach for protocol types but not
the reverse.
Definition (consensus boundary). librustzcash is not a
consensus node. The
README
states: "The only way to check Zcash consensus validity is to use a
Zcash consensus node." Parsing in this repo is permissive on purpose;
the libraries focus on cryptographic correctness for wallet and
transaction-construction use cases.
3. The code
3.1 The workspace declaration
The full member list is at the top of the root Cargo.toml:
loading...
Rust edition is 2024, MSRV is 1.85.1, license is
MIT OR Apache-2.0. The resolver is 2, which is required for the
feature unification semantics most chapters rely on.
3.2 Layer 0 - Standalone components (components/)
zcash_encoding: Bitcoin-style varint,Vector,Optional,Arrayserialization helpers. Pure, no protocol logic.zcash_protocol: Constants and base types:BlockHeight,BranchId,Zatoshis,ZatBalance, network upgrade enum (NetworkUpgrade), memo types. Every other crate transitively depends on this.equihash: Verifier (and optionally solver) for the Equihash PoW. No Zcash-specific transaction logic.f4jumble: 4-round unkeyed Feistel construction over BLAKE2b used by unified addresses.zcash_address: Pure parser/serialiser for Zcash addresses and unified containers. Knows nothing about keys.zip321,eip681: Payment-request URI parsers.
Zatoshis is the most important newtype in this layer; it pins the
type-level invariant that no contributor can build a transaction
with a negative or out-of-range amount:
loading...
3.3 Layer 1 - Protocol primitives
zcash_transparent: Bitcoin-derived transparent address, output, input, bundle, sighash. Houses the transparent half of PCZT.zcash_primitives: The Zcash transaction type itself (Transaction,TransactionData), the builder, sighash trees (v4/v5/v6), the Merkle-tree module.zcash_proofs: The Sprout circuit (a Groth16 SNARK encoded withbellman) and the bindings to Sapling proving parameters (sapling-spend.params,sapling-output.params,sprout-groth16.params).
External crates pulled in at this layer (separate repositories, but load-bearing):
sapling-crypto: the entire Sapling protocol (notes, commitments, value commitments, Spend, Output, the circuit). Previously a module insidezcash_primitives; extracted for separation of concerns.orchard: the entire Orchard protocol (Action description, Halo 2 circuit, PCZT-orchard).zcash_note_encryption: a generic in-band secret distribution scheme parameterised by domain (used by both Sapling and Orchard).zip32: hierarchical-deterministic derivation, shared by all pools.zcash_spec: small helpers that encode primitives from the protocol specification (e.g.PRF^{expand}).
3.4 Layer 2 - Keys and addresses
zcash_keys: Spending keys, viewing keys, unified spending / viewing keys, ZIP 32 derivation for Sapling/Orchard/transparent.pczt: The Partially Constructed Zcash Transaction format; defines the roles (Creator, Constructor, IO Finalizer, Prover, Signer, Spend Authoriser, Combiner, Transaction Extractor) and the data shape passed between them.
3.5 Layer 3 - Wallet stack
zcash_client_backend: The wallet framework: chain-scanning, fee strategies, transaction proposals, light-client (lightwalletd) protocol, ZIP 321 payment-request handling.zcash_client_memory: In-memory backend implementation, mostly for testing.zcash_client_sqlite: SQLite implementation of the wallet storage trait family. The reference downstream.
3.6 Auxiliary crates
zcash_history: ZIP 221 / Block Header Commitments tree (a recursive hash-tree of block metadata). Lives in this repo because the structure is consensus-defined but rarely touched in wallet contexts.zcash_extensions: Experimental "transaction extensions" (TZE), behind thezfuturecfg flag. Mostly of historical interest.zcash: meta-crate that re-exports the others; the most common dependency for downstream consumers.
3.7 Code conventions to remember
A short list of project-wide patterns. Each is justified in
AGENTS.md;
read that file before contributing.
#![no_std]by default. Most crates useextern crate alloc. Anything needingstdlives behind astdfeature flag.- Bundles use the authorization typestate pattern: a
Bundle<A>is parameterised by anAuthorizationassociated type so the type system distinguishes "I have spend authorisations" from "I have a partially-built bundle that still needs signing/proving". Look forMapAuthandInProgressmarkers. - Struct fields are private. Construction goes through
from_parts(...)which returnsResult<_, Error>and enforces invariants. - All error types are non-exhaustive enums.
- Newtypes are aggressively preferred over bare integers:
Zatoshis,ZatBalance,BlockHeight,TxId, etc. - Side effects (clocks, RNGs, network calls) are passed as explicit trait arguments ("capability-oriented" style).
4. Failure modes
A contributor who modifies the workspace layering without understanding it can produce three kinds of damage:
- Cycle introduction. Adding a wallet-layer dependency to a protocol-layer crate breaks compilation across every consumer. Cargo will refuse to resolve.
- Feature-flag breakage. The repo CI matrix exercises specific
feature combinations
(
ci.yml). Adding a feature that pullsstdinto ano_stdcrate will pass locally and fail in CI under--no-default-features. - Cross-crate version skew. When two workspace crates depend on
the same external crate at different versions (e.g.
saplingvssapling-crypto), the resolver may pick a single resolution that silently downgrades a security fix.cargo tree -dexposes such duplicates. The CI runscargo vetagainstsupply-chain/audits.tomlto flag this.
The test most often broken by careless layering changes is
cargo check --workspace --all-features --no-default-features,
which the CI runs in matrix form. Always run it locally before
pushing.
5. Spec pointers
- Top-level
README.md: contains the authoritative crate-graph diagram and the explicit "this is not a consensus node" disclaimer. AGENTS.md: PR compliance gate (the change must be tied to an open GitHub issue acknowledged by a team member) and the canonical local command list. Read it before opening a PR.- Zcash Protocol Specification:
sections 3 and 4 give the abstract protocol that the
zcash_protocolandzcash_primitivescrates encode. Section 5 gives the concrete protocol that drives every shielded crate. - ZIP index: every consensus rule the workspace implements is anchored to a ZIP number; the crate README files cite them directly.
6. Exercises
-
Read the workspace. Open the root
Cargo.tomland list every workspace member alongside one sentence on what it owns. Compare your list to Section 3 of this chapter and identify any crate you misclassified. -
Draw the local dependency graph. Run
cargo tree --workspace --depth 1 --no-default-featuresand confirm that no Layer 0 crate depends on a Layer 1+ crate. Identify the one workspace crate with the highest fan-in (most crates depending on it). -
Touch the code. Pick the
Zatoshisnewtype. Add a private helper methodpub fn is_dust(&self) -> boolthat returnstruewhen the value is below the relay-rule dust threshold ( and zatoshis, per ZIP 317). Build withcargo check -p zcash_protocoland add one unit test covering both branches. Do not commit; this is a scratch exercise to confirm the build loop works.
Answers in the code
- Workspace members:
Cargo.toml. - Highest-fan-in crate:
components/zcash_protocol. Zatoshisdefinition and arithmetic:components/zcash_protocol/src/value.rs.
7. Further reading
- Reading order for the rest of this course: chapter 02 covers protocol foundations; chapter 03 calibrates cryptographic notation; chapter 04 enters Sprout and Sapling; chapter 05 covers Orchard and Halo 2; chapter 10 finally re-uses every layer above inside the wallet stack. The study plan gives a week-by-week read order with associated exercises.
- For a quick file-to-purpose lookup when you forget which crate owns what:
| Question | File |
|---|---|
| What is a transaction made of? | zcash_primitives/src/transaction/mod.rs |
| How is a transaction built? | zcash_primitives/src/transaction/builder.rs |
| How is a TxId computed? | zcash_primitives/src/transaction/txid.rs |
| What is the Sprout circuit? | zcash_proofs/src/circuit/sprout/mod.rs |
| What does a Zcash address look like? | components/zcash_address/src/kind/unified.rs |
| What does F4Jumble do? | components/f4jumble/src/lib.rs |
| How does the wallet scan a block? | zcash_client_backend/src/scanning.rs |
| What does Equihash verify? | components/equihash/src/verify.rs |
| How do we derive Sapling keys? | zcash_keys/src/keys.rs plus the sapling-crypto repo |