Skip to main content

23 - The complete key catalog

1. Why this chapter exists

Every chapter of this course names keying-material symbols (ask,nsk,ak,nk,ivk,ovk,dk,esk,epk,rcm,rcv,α\mathsf{ask}, \mathsf{nsk}, \mathsf{ak}, \mathsf{nk}, \mathsf{ivk}, \mathsf{ovk}, \mathsf{dk}, \mathsf{esk}, \mathsf{epk}, \mathsf{rcm}, \mathsf{rcv}, \alpha, and so on). A reader who needs the exact derivation, type, or code location for any of these should not have to recover it from prose. This chapter is the authoritative reference: every Zcash key is listed with its domain, derivation formula, role, and the source file that defines its Rust type. It also points at the related catalog of circuit clauses in chapter 24 and at chapter 06 for HD derivation.

2. Definitions

This chapter assumes the cryptographic primitives defined in chapter 03 (groups, fields, PRFs, commitments, signatures). Specific to this chapter:

Definition 2.1 (Field notation). Let Fq\mathbb{F}_q denote the prime field of order qq. We use J\ell_J for the Jubjub prime-order subgroup order; rr for the BLS12-381 scalar field (equal to the Jubjub base field); qPq_P for the Pallas scalar field; pPp_P for the Pallas base field. The Pallas and Vesta cofactors are 11; the Jubjub cofactor is hJ=8h_J = 8. The prime-order Jubjub subgroup is GJEJubjub(Fr)\mathbb{G}_J \subset E_{\text{Jubjub}}(\mathbb{F}_r) with GJ=J|\mathbb{G}_J| = \ell_J; the Pallas prime-order group is GP=EPallas(FpP)\mathbb{G}_P = E_{\text{Pallas}}(\mathbb{F}_{p_P}) with GP=qP|\mathbb{G}_P| = q_P.

Definition 2.2 (Generator notation). A fixed generator of a prime-order subgroup G\mathbb{G}, derived deterministically from a personalisation string via a hash-to-curve construction, is denoted by GG with a superscript tag. For example, GSapakGJG^{\mathsf{ak}}_{\text{Sap}} \in \mathbb{G}_J is the Sapling spend-authority base point.

Definition 2.3 (Scalar multiplication). For PGP \in \mathbb{G} and xFGx \in \mathbb{F}_{|\mathbb{G}|} (the scalar field of G\mathbb{G}), [x]PG[x] P \in \mathbb{G} denotes the scalar multiple of PP by xx.

Definition 2.4 (Canonical encoding repr\mathsf{repr}). For a target codomain TT (either a field or a group), the symbol reprT:T\mathsf{repr}_T : \cdot \rightarrow T denotes the canonical encoding into TT. For instance, for a Jubjub point PGJP \in \mathbb{G}_J, reprFr(P)Fr\mathsf{repr}_{\mathbb{F}_r}(P) \in \mathbb{F}_r is its uu-coordinate encoded as a little-endian field element.

Definition 2.5 (To-scalar and to-base reduction). For a 64-byte string s{0,1}512s \in \{0,1\}^{512},

ToScalar:{0,1}512FJ    (Sapling),    or  FqP  (Orchard),\mathsf{ToScalar} : \{0,1\}^{512} \rightarrow \mathbb{F}_{\ell_J} \;\;\text{(Sapling)}, \;\; \text{or}\; \mathbb{F}_{q_P} \;\text{(Orchard)}, ToBase:{0,1}512FpP    (Orchard base field),\mathsf{ToBase} : \{0,1\}^{512} \rightarrow \mathbb{F}_{p_P} \;\;\text{(Orchard base field)},

both interpret ss as a little-endian integer and reduce modulo the relevant prime. The 512512-bit input width ensures the bias introduced by modular reduction is negligible (statistical distance <2256< 2^{-256}).

Definition 2.6 (Expand-from-seed PRF). Let sk{0,1}256\mathsf{sk} \in \{0,1\}^{256} and let t{0,1}t \in \{0,1\}^{\ast} be a purpose tag. Define

PRFskexpand:{0,1}{0,1}512,PRFskexpand(t)  =  BLAKE2b-512 ⁣(pers=“Zcash_ExpandSeed”,  skt).\mathsf{PRF}^{\text{expand}}_{\mathsf{sk}} : \{0,1\}^{\ast} \rightarrow \{0,1\}^{512}, \qquad \mathsf{PRF}^{\text{expand}}_{\mathsf{sk}}(t) \;=\; \mathsf{BLAKE2b\text{-}512}\!\bigl( \text{pers} = \text{``Zcash\_ExpandSeed''},\; \mathsf{sk} \,\mathbin{\|}\, t\bigr).

Used identically by Sapling and Orchard with different purpose tags.

Definition 2.7 (Catalog entry). A catalog entry below formalises a Zcash key symbol KK by recording, where applicable:

  1. The symbol KK and its short name.
  2. The type signature, i.e. the codomain DK\mathcal{D}_K (a field, a group, or a byte-string space).
  3. The derivation: an explicit function from prior keys or randomness to KK.
  4. The role: who learns KK and what capability it confers.
  5. The Rust type in this workspace (or upstream crate) that carries KK.

Each entry below is therefore a Definition fixing KK in the form KDKK \in \mathcal{D}_K with a derivation rule.

3. The code

The catalog is organised by pool. Within each pool, keys are listed in derivation order: spending key first, then derived material, then per-transaction ephemerals.

3.1 Sprout (legacy)

Sprout is closed for new outputs but historical notes still exist.

Definition 2.8 (Sprout aska_{\mathsf{sk}}). ask{0,1}252a_{\mathsf{sk}} \in \{0,1\}^{252}, sampled uniformly (a_{\mathsf{sk}} \stackrel{\}{\leftarrow} {0,1}^{252}$). The Sprout spending key. Holder can spend Sprout notes.

Definition 2.9 (Sprout apka_{\mathsf{pk}}). apk{0,1}256a_{\mathsf{pk}} \in \{0,1\}^{256}, defined by

apk  =  PRFaskaddr(0).a_{\mathsf{pk}} \;=\; \mathsf{PRF}^{\mathsf{addr}}_{a_{\mathsf{sk}}}(0).

The Sprout paying key, published as part of the Sprout address.

Definition 2.10 (Sprout skenc\mathsf{sk}_{\text{enc}}). skenc{0,1}256\mathsf{sk}_{\text{enc}} \in \{0,1\}^{256}, derived from PRFaskaddr(1)\mathsf{PRF}^{\mathsf{addr}}_{a_{\mathsf{sk}}}(1) with the Curve25519 clamping operation. Used as a Curve25519 secret for in-band note encryption.

Definition 2.11 (Sprout pkenc\mathsf{pk}_{\text{enc}}). pkencEC25519\mathsf{pk}_{\text{enc}} \in E_{\text{C25519}}, defined by pkenc=[skenc]GC25519\mathsf{pk}_{\text{enc}} = [\mathsf{sk}_{\text{enc}}] G_{\text{C25519}} with GC25519G_{\text{C25519}} the standard Curve25519 base point. Public, part of the Sprout address.

Definition 2.12 (Sprout ρ\rho). ρ{0,1}256\rho \in \{0,1\}^{256}, chosen per-note to be unique within the JoinSplit. The nullifier seed stored in the note plaintext.

Definition 2.13 (Sprout rr, commitment randomness). r{0,1}256r \in \{0,1\}^{256}, r \stackrel{\}{\leftarrow} {0,1}^{256}$ per note. Used as the randomness in the Sprout note commitment.

Definition 2.14 (Sprout ϕ\phi). ϕ{0,1}252\phi \in \{0,1\}^{252}, \phi \stackrel{\}{\leftarrow} {0,1}^{252}perJoinSplit.Usedtoderivenewper JoinSplit. Used to derive new\rho$ values for the JoinSplit's output notes.

Definition 2.15 (Sprout hsigh_{\mathsf{sig}}). hsig{0,1}256h_{\mathsf{sig}} \in \{0,1\}^{256}, equal to a BLAKE2b hash of the transaction context and the JoinSplit signing public key. Binds the JoinSplit to its signature.

Definition 2.16 (Sprout nullifier). nf{0,1}256\mathsf{nf} \in \{0,1\}^{256}, defined by

nf  =  PRFasknf(ρ).\mathsf{nf} \;=\; \mathsf{PRF}^{\mathsf{nf}}_{a_{\mathsf{sk}}}(\rho).

Sprout PRFs are SHA-256 with 4-bit tag prefixes; exact tags are in protocol spec section 5.4.2.

The Sprout circuit definition lives in zcash_proofs/src/circuit/sprout/mod.rs:

zcash_proofs/src/circuit/sprout/mod.rs
loading...

3.2 Sapling

The Sapling key tree implementation lives in the external sapling-crypto crate; this workspace consumes it via zcash_keys/src/keys.rs.

Root spending key

Definition 2.17 (Sapling sk\mathsf{sk}). sk{0,1}256\mathsf{sk} \in \{0,1\}^{256}, derived along the ZIP 32 hardened path m/32/133/acctm / 32' / 133' / \mathrm{acct}' from the wallet seed. Holder can do everything: spend, view, derive. Code: sapling-crypto::keys::SpendingKey. Sometimes called the "expanded spending key" or, with a chain code, the "extended spending key" (ZIP 32, Extended).

Spend-authorisation private key

Definition 2.18 (Sapling ask\mathsf{ask}). askFJ\mathsf{ask} \in \mathbb{F}_{\ell_J}, defined by

ask  =  ToScalar ⁣(PRFskexpand(0x00)).\mathsf{ask} \;=\; \mathsf{ToScalar}\!\bigl( \mathsf{PRF}^{\text{expand}}_{\mathsf{sk}}(0\mathrm{x}00)\bigr).

Signs Sapling spend-auth signatures after re-randomisation by α\alpha. Code: sapling-crypto::keys::ExpandedSpendingKey::ask.

Nullifier private key

Definition 2.19 (Sapling nsk\mathsf{nsk}). nskFJ\mathsf{nsk} \in \mathbb{F}_{\ell_J}, defined by

nsk  =  ToScalar ⁣(PRFskexpand(0x01)).\mathsf{nsk} \;=\; \mathsf{ToScalar}\!\bigl( \mathsf{PRF}^{\text{expand}}_{\mathsf{sk}}(0\mathrm{x}01)\bigr).

Derives nk\mathsf{nk} and, inside the circuit, the nullifier. Code: sapling-crypto::keys::ExpandedSpendingKey::nsk.

Outgoing viewing key

Definition 2.20 (Sapling ovk\mathsf{ovk}). ovk{0,1}256\mathsf{ovk} \in \{0,1\}^{256}, defined by

ovk  =  truncate32 ⁣(PRFskexpand(0x02)),\mathsf{ovk} \;=\; \mathsf{truncate}_{32}\!\bigl( \mathsf{PRF}^{\text{expand}}_{\mathsf{sk}}(0\mathrm{x}02)\bigr),

where truncate32\mathsf{truncate}_{32} takes the first 32 bytes of the 64-byte BLAKE2b output. Decrypts outputs sent by the holder via CoutC^{\text{out}}. Code: sapling-crypto::keys::ExpandedSpendingKey::ovk.

Diversifier key

Definition 2.21 (Sapling dk\mathsf{dk}). dk{0,1}256\mathsf{dk} \in \{0,1\}^{256}, defined by

dk  =  truncate32 ⁣(PRFskexpand(0x10)).\mathsf{dk} \;=\; \mathsf{truncate}_{32}\!\bigl( \mathsf{PRF}^{\text{expand}}_{\mathsf{sk}}(0\mathrm{x}10)\bigr).

Used as the FF1-AES key that enumerates the account's diversifiers. Code: sapling-crypto::zip32::DiversifierKey.

Spend-authorisation public key

Definition 2.22 (Sapling ak\mathsf{ak}). akGJ\mathsf{ak} \in \mathbb{G}_J, defined by

ak  =  [ask]GSapak,\mathsf{ak} \;=\; [\mathsf{ask}]\, G^{\mathsf{ak}}_{\text{Sap}},

with GSapakGJG^{\mathsf{ak}}_{\text{Sap}} \in \mathbb{G}_J the fixed Sapling spend-authority base point (SpendAuthSig.BasePoint). Public spend-authority key, published after re-randomisation as rk\mathsf{rk}. Code: sapling-crypto::keys::ProofGenerationKey::ak.

Nullifier deriving key

Definition 2.23 (Sapling nk\mathsf{nk}). nkGJ\mathsf{nk} \in \mathbb{G}_J, defined by

nk  =  [nsk]GSapnk,\mathsf{nk} \;=\; [\mathsf{nsk}]\, G^{\mathsf{nk}}_{\text{Sap}},

with GSapnkGJG^{\mathsf{nk}}_{\text{Sap}} \in \mathbb{G}_J the fixed nullifier generator (ProvingPublicKey.BasePoint). Keys the nullifier PRF; part of the full viewing key. Code: sapling-crypto::keys::ProofGenerationKey::nk.

Incoming viewing key

Definition 2.24 (Sapling ivk\mathsf{ivk}). ivkFJ\mathsf{ivk} \in \mathbb{F}_{\ell_J}, defined by

ivk  =  [BLAKE2s-256 ⁣(pers=“Zcashivk”,  reprFr(ak)reprFr(nk))]modJ,\mathsf{ivk} \;=\; \bigl[\,\mathsf{BLAKE2s\text{-}256}\!\bigl( \text{pers} = \text{``Zcashivk''},\; \mathsf{repr}_{\mathbb{F}_r}(\mathsf{ak}) \,\mathbin{\|}\, \mathsf{repr}_{\mathbb{F}_r}(\mathsf{nk})\bigr)\,\bigr] \bmod \ell_J,

extracting each point's uu-coordinate as a 255-bit little- endian field-element encoding; the top bit is cleared before reducing modulo J\ell_J to ensure uniform reduction. Decrypts outputs received by this account. Code: sapling-crypto::keys::SaplingIvk.

Full viewing key

Definition 2.25 (Sapling fvk\mathsf{fvk}). fvk=(ak,nk,ovk)GJ×GJ×{0,1}256\mathsf{fvk} = (\mathsf{ak}, \mathsf{nk}, \mathsf{ovk}) \in \mathbb{G}_J \times \mathbb{G}_J \times \{0,1\}^{256}. With the diversifier key included (per ZIP 316), the extended full viewing key is efvk=(ak,nk,ovk,dk)\mathsf{efvk} = (\mathsf{ak}, \mathsf{nk}, \mathsf{ovk}, \mathsf{dk}). The full viewing key can compute ivk\mathsf{ivk} and decrypt incoming notes; decrypt outgoing notes via ovk\mathsf{ovk}; enumerate diversified addresses via dk\mathsf{dk}. It cannot spend or authorise (no ask\mathsf{ask}). Code: sapling-crypto::keys::FullViewingKey.

Proof generation key

Definition 2.26 (Sapling pgk\mathsf{pgk}). pgk=(ak,nsk)GJ×FJ\mathsf{pgk} = (\mathsf{ak}, \mathsf{nsk}) \in \mathbb{G}_J \times \mathbb{F}_{\ell_J}. The witness the prover supplies for the Sapling Spend circuit: public ak\mathsf{ak} and private nsk\mathsf{nsk}. A hardware-wallet flow that delegates proving hands this pair (and the per-spend α\alpha) to the prover without sending ask\mathsf{ask}, which signs only. Code: sapling-crypto::keys::ProofGenerationKey.

Diversifier

Definition 2.27 (Sapling diversifier dd). For diversifier index i[0,288)i \in [0, 2^{88}),

d  =  FF1-AESdk(Encode(i)){0,1}88.d \;=\; \mathsf{FF1\text{-}AES}_{\mathsf{dk}}(\mathsf{Encode}(i)) \in \{0,1\}^{88}.

Eleven bytes. Not every dd produces a valid prime-order generator gdg_d; the probability is approximately 1/21/2 per dd, and invalid indices are skipped. Code: sapling-crypto::keys::Diversifier, DiversifierIndex.

Diversified base

Definition 2.28 (Sapling gdg_d). gdGJg_d \in \mathbb{G}_J, defined by

gd  =  DiversifyHash(d),g_d \;=\; \mathsf{DiversifyHash}(d),

where DiversifyHash\mathsf{DiversifyHash} is a try-and-increment hash-to- curve into GJ\mathbb{G}_J using BLAKE2s with personalisation "Zcash_gd". The output is multiplied by the cofactor hJ=8h_J = 8 to land in GJ\mathbb{G}_J.

Diversified transmission key

Definition 2.29 (Sapling pkd\mathsf{pk}_d). pkdGJ\mathsf{pk}_d \in \mathbb{G}_J, defined by

pkd  =  [ivk]gd.\mathsf{pk}_d \;=\; [\mathsf{ivk}]\, g_d.

Public key tied to diversifier dd; combined with dd to form a payment address.

Sapling payment address

Definition 2.30 (Sapling address addrSap\mathsf{addr}_{\text{Sap}}). addrSap=(d,pkd){0,1}88×GJ\mathsf{addr}_{\text{Sap}} = (d, \mathsf{pk}_d) \in \{0,1\}^{88} \times \mathbb{G}_J, encoded as 11+32=4311 + 32 = 43 bytes and bech32-encoded with HRP zs (mainnet) or ztestsapling (testnet).

Note plaintext

Definition 2.31 (Sapling note). A Sapling note is the tuple

note  =  (gd,pkd,v,rseed)    GJ×GJ×[0,264)×{0,1}256,\mathsf{note} \;=\; (g_d, \mathsf{pk}_d, v, \mathsf{rseed}) \;\in\; \mathbb{G}_J \times \mathbb{G}_J \times [0, 2^{64}) \times \{0,1\}^{256},

where rseed\mathsf{rseed} is a 32-byte seed (post-ZIP 212) from which rcm\mathsf{rcm} and esk\mathsf{esk} are derived. Pre-Canopy notes used rcm\mathsf{rcm} directly.

Commitment randomness

Definition 2.32 (Sapling rcm\mathsf{rcm}, post-ZIP 212). rcmFJ\mathsf{rcm} \in \mathbb{F}_{\ell_J}, defined by

rcm  =  ToScalar ⁣(PRFrseedexpand(0x04)).\mathsf{rcm} \;=\; \mathsf{ToScalar}\!\bigl( \mathsf{PRF}^{\text{expand}}_{\mathsf{rseed}}(0\mathrm{x}04) \bigr).

Hides the note in NoteCommit\mathsf{NoteCommit} (Definition 2.36).

Ephemeral secret key

Definition 2.33 (Sapling esk\mathsf{esk}, post-ZIP 212). eskFJ\mathsf{esk} \in \mathbb{F}_{\ell_J}, defined by

esk  =  ToScalar ⁣(PRFrseedexpand(0x05)).\mathsf{esk} \;=\; \mathsf{ToScalar}\!\bigl( \mathsf{PRF}^{\text{expand}}_{\mathsf{rseed}}(0\mathrm{x}05) \bigr).

Sender's secret for ECDH note encryption. Code: local to builder; not part of any persisted key type.

Ephemeral public key

Definition 2.34 (Sapling epk\mathsf{epk}). epkGJ\mathsf{epk} \in \mathbb{G}_J, defined by

epk  =  [esk]gd.\mathsf{epk} \;=\; [\mathsf{esk}]\, g_d.

Published in the OutputDescription and Action.

Note commitment

Definition 2.35 (Sapling cm\mathsf{cm}). cmGJ\mathsf{cm} \in \mathbb{G}_J, defined by

cm  =  NoteCommitrcm(gd,pkd,v)  =  PedersenHashDnc ⁣(1011vLE,64reprFr(gd)reprFr(pkd))  +  [rcm]Rnc.\mathsf{cm} \;=\; \mathsf{NoteCommit}^{\mathsf{rcm}}(g_d, \mathsf{pk}_d, v) \;=\; \mathsf{PedersenHash}_{D_{\text{nc}}}\!\bigl( 1011 \,\mathbin{\|}\, v_{\text{LE},64} \,\mathbin{\|}\, \mathsf{repr}_{\mathbb{F}_r}(g_d) \,\mathbin{\|}\, \mathsf{repr}_{\mathbb{F}_r}(\mathsf{pk}_d) \bigr) \;+\; [\mathsf{rcm}]\, R_{\text{nc}}.

The published value is the uu-coordinate cmu=extract(cm)Fr\mathsf{cm}^u = \mathsf{extract}(\mathsf{cm}) \in \mathbb{F}_r. Code: sapling-crypto::primitives::NoteCommitment.

Value commitment randomness and value commitment

Definition 2.36 (Sapling rcv\mathsf{rcv}). rcvFJ\mathsf{rcv} \in \mathbb{F}_{\ell_J}, \mathsf{rcv} \stackrel{\}{\leftarrow} \mathbb{F}_{\ell_J}$ per spend or output.

Definition 2.37 (Sapling cv\mathsf{cv}). cvGJ\mathsf{cv} \in \mathbb{G}_J, defined by

cv  =  [v]VSap  +  [rcv]RSap,\mathsf{cv} \;=\; [v]\, V_{\text{Sap}} \;+\; [\mathsf{rcv}]\, R_{\text{Sap}},

with VSap,RSapGJV_{\text{Sap}}, R_{\text{Sap}} \in \mathbb{G}_J the fixed value and randomness bases (ValueCommitValueBase, ValueCommitRandomnessBase).

Position and rho

Definition 2.38 (Sapling ρ\rho). For a note at position pos[0,232)\mathsf{pos} \in [0, 2^{32}) in the commitment tree, ρGJ\rho \in \mathbb{G}_J is defined by

ρ  =  MixingPedersenHash(cm,pos)  =  cm  +  [pos]Gρ.\rho \;=\; \mathsf{MixingPedersenHash}(\mathsf{cm}, \mathsf{pos}) \;=\; \mathsf{cm} \;+\; [\mathsf{pos}]\, G_\rho.

Nullifier

Definition 2.39 (Sapling nullifier nf\mathsf{nf}). nf{0,1}256\mathsf{nf} \in \{0,1\}^{256}, defined by

nf  =  PRFnknfSapling(ρ)  =  BLAKE2s-256 ⁣(pers=“Zcash_nf”,  reprFr(nk)reprFr(ρ)).\mathsf{nf} \;=\; \mathsf{PRF}^{\mathsf{nfSapling}}_{\mathsf{nk}}(\rho) \;=\; \mathsf{BLAKE2s\text{-}256}\!\bigl( \text{pers} = \text{``Zcash\_nf''},\; \mathsf{repr}_{\mathbb{F}_r}(\mathsf{nk}) \,\mathbin{\|}\, \mathsf{repr}_{\mathbb{F}_r}(\rho)\bigr).

Published in the SpendDescription.

Re-randomisation

Definition 2.40 (Sapling α\alpha). αFJ\alpha \in \mathbb{F}_{\ell_J}, \alpha \stackrel{\}{\leftarrow} \mathbb{F}_{\ell_J}$ per spend.

Definition 2.41 (Sapling re-randomised keys rsk,rk\mathsf{rsk}, \mathsf{rk}).

rsk  =  ask+αFJ,rk  =  ak+[α]GSapakGJ.\mathsf{rsk} \;=\; \mathsf{ask} + \alpha \in \mathbb{F}_{\ell_J}, \qquad \mathsf{rk} \;=\; \mathsf{ak} + [\alpha]\, G^{\mathsf{ak}}_{\text{Sap}} \in \mathbb{G}_J.

rsk\mathsf{rsk} stays private; rk\mathsf{rk} is published.

Spend-authorisation signature

Definition 2.42 (Sapling σspendAuth\sigma_{\text{spendAuth}}). A RedJubjub signature under rsk\mathsf{rsk} over the sighash:

σspendAuth  =  RedJubjub.Signrsk(sighash).\sigma_{\text{spendAuth}} \;=\; \mathsf{RedJubjub.Sign}_{\mathsf{rsk}}(\mathsf{sighash}).

Verified under rk\mathsf{rk}.

Outgoing cipher key

Definition 2.43 (Sapling ock\mathsf{ock}). ock{0,1}256\mathsf{ock} \in \{0,1\}^{256}, defined by

ock  =  BLAKE2b-256 ⁣(pers=“Zcash_Derive_ock”,  ovkrepr(cv)repr(cmu)repr(epk)).\mathsf{ock} \;=\; \mathsf{BLAKE2b\text{-}256}\!\bigl( \text{pers} = \text{``Zcash\_Derive\_ock''},\; \mathsf{ovk} \,\mathbin{\|}\, \mathsf{repr}(\mathsf{cv}) \,\mathbin{\|}\, \mathsf{repr}(\mathsf{cm}^u) \,\mathbin{\|}\, \mathsf{repr}(\mathsf{epk})\bigr).

Also written KoutK_{\text{out}} in chapter 08. AEAD key for CoutC^{\text{out}}; recovers (pkd,esk)(\mathsf{pk}_d, \mathsf{esk}) from ovk\mathsf{ovk}.

Note encryption key

Definition 2.44 (Sapling KencK_{\text{enc}}). Kenc{0,1}256K_{\text{enc}} \in \{0,1\}^{256}, defined by

Kenc  =  BLAKE2b-256 ⁣(pers=“Zcash_SaplingKDF”,  repr(shared)repr(epk)),K_{\text{enc}} \;=\; \mathsf{BLAKE2b\text{-}256}\!\bigl( \text{pers} = \text{``Zcash\_SaplingKDF''},\; \mathsf{repr}(\mathsf{shared}) \,\mathbin{\|}\, \mathsf{repr}(\mathsf{epk})\bigr),

where shared=[esk]pkd=[ivk]epkGJ\mathsf{shared} = [\mathsf{esk}]\, \mathsf{pk}_d = [\mathsf{ivk}]\, \mathsf{epk} \in \mathbb{G}_J. AEAD key encrypting the note plaintext to the recipient.

Binding signature keys

Definition 2.45 (Sapling binding keys bsk,bvk\mathsf{bsk}, \mathsf{bvk}). For inputs ii and outputs jj in a Sapling bundle,

bsk  =  iinrcvijoutrcvjFJ,\mathsf{bsk} \;=\; \sum_{i \in \text{in}} \mathsf{rcv}_i - \sum_{j \in \text{out}} \mathsf{rcv}_j \in \mathbb{F}_{\ell_J}, bvk  =  iincviinjoutcvjout[vbalanceSap]VSapGJ.\mathsf{bvk} \;=\; \sum_{i \in \text{in}} \mathsf{cv}_i^{\text{in}} - \sum_{j \in \text{out}} \mathsf{cv}_j^{\text{out}} - [v_{\text{balance}}^{\text{Sap}}]\, V_{\text{Sap}} \in \mathbb{G}_J.

If the bundle balances, bvk=[bsk]RSap\mathsf{bvk} = [\mathsf{bsk}]\, R_{\text{Sap}}; the spender holds bsk\mathsf{bsk} and signs the sighash under it. Code: sapling-crypto::bundle::Bundle::binding_signature.

Internal vs external addresses

Definition 2.46 (Sapling internal sub-tree). ZIP 316 specifies an internal full-viewing-key sub-tree for change addresses, distinct from the user-facing external one. The internal sub-tree has its own ovkint{0,1}256\mathsf{ovk}^{\text{int}} \in \{0,1\}^{256}, dkint{0,1}256\mathsf{dk}^{\text{int}} \in \{0,1\}^{256}, and diversifier index space. An external observer cannot link change outputs to user-visible addresses. The internal keys derive from the external ones via further hardened ZIP-32 children with index 11.

3.3 Orchard

The Orchard key tree is implemented in the external orchard crate; this workspace consumes it via zcash_keys/src/keys.rs. Structurally parallel to Sapling with several simplifications.

Root spending key

Definition 2.47 (Orchard skO\mathsf{sk}_O). skO{0,1}256\mathsf{sk}_O \in \{0,1\}^{256}, derived via ZIP 32 from the wallet seed analogously to Sapling. Code: orchard::keys::SpendingKey.

Spend-authorisation private key

Definition 2.48 (Orchard ask\mathsf{ask}). askFqP\mathsf{ask} \in \mathbb{F}_{q_P}, defined by

ask  =  ToScalar ⁣(PRFskOexpand(0x06)).\mathsf{ask} \;=\; \mathsf{ToScalar}\!\bigl( \mathsf{PRF}^{\text{expand}}_{\mathsf{sk}_O}(0\mathrm{x}06)\bigr).

Nullifier deriving key

Definition 2.49 (Orchard nk\mathsf{nk}). nkFpP\mathsf{nk} \in \mathbb{F}_{p_P}, defined by

nk  =  ToBase ⁣(PRFskOexpand(0x07)).\mathsf{nk} \;=\; \mathsf{ToBase}\!\bigl( \mathsf{PRF}^{\text{expand}}_{\mathsf{sk}_O}(0\mathrm{x}07)\bigr).

Unlike Sapling, Orchard's nk\mathsf{nk} is a field element, not a curve point. This is a key Orchard simplification: the nullifier PRF feeds nk\mathsf{nk} directly into a Poseidon hash inside the circuit, avoiding the cost of decoding a point.

Randomiser for ivk commitment

Definition 2.50 (Orchard rivk\mathsf{rivk}). rivkFqP\mathsf{rivk} \in \mathbb{F}_{q_P}, defined by

rivk  =  ToScalar ⁣(PRFskOexpand(0x08)).\mathsf{rivk} \;=\; \mathsf{ToScalar}\!\bigl( \mathsf{PRF}^{\text{expand}}_{\mathsf{sk}_O}(0\mathrm{x}08)\bigr).

Used as the randomness in the Sinsemilla-based CommitIvk\mathsf{CommitIvk}.

Outgoing viewing key and diversifier key

Definition 2.51 (Orchard ovk,dk\mathsf{ovk}, \mathsf{dk}). ovk{0,1}256\mathsf{ovk} \in \{0,1\}^{256} and dk{0,1}256\mathsf{dk} \in \{0,1\}^{256}, jointly defined by the concatenation

ovkdk  =  PRFskOexpand ⁣(0x82,  reprFpP(ak),  reprFpP(nk)).\mathsf{ovk} \,\mathbin{\|}\, \mathsf{dk} \;=\; \mathsf{PRF}^{\text{expand}}_{\mathsf{sk}_O}\!\bigl( 0\mathrm{x}82,\; \mathsf{repr}_{\mathbb{F}_{p_P}}(\mathsf{ak}),\; \mathsf{repr}_{\mathbb{F}_{p_P}}(\mathsf{nk})\bigr).

The 64-byte output is split: the first 32 bytes are ovk\mathsf{ovk}, the next 32 are dk\mathsf{dk}. The dependence on ak\mathsf{ak} and nk\mathsf{nk} binds these to the rest of the tree.

Spend-authorisation public key

Definition 2.52 (Orchard ak\mathsf{ak}). akGP\mathsf{ak} \in \mathbb{G}_P, defined by

ak  =  [ask]GOrchak.\mathsf{ak} \;=\; [\mathsf{ask}]\, G^{\mathsf{ak}}_{\text{Orch}}.

Incoming viewing key

Definition 2.53 (Orchard ivk\mathsf{ivk}). ivkFqP\mathsf{ivk} \in \mathbb{F}_{q_P}, defined by

ivk  =  ExtractFqP ⁣(SinsemillaCommitDcvrivk ⁣(repr(ak)repr(nk))),\mathsf{ivk} \;=\; \mathsf{Extract}_{\mathbb{F}_{q_P}}\!\bigl( \mathsf{SinsemillaCommit}^{\mathsf{rivk}}_{D_{\text{cv}}}\!\bigl( \mathsf{repr}(\mathsf{ak}) \,\mathbin{\|}\, \mathsf{repr}(\mathsf{nk})\bigr)\bigr),

with Dcv=D_{\text{cv}} = "z.cash:Orchard-CommitIvk". SinsemillaCommit\mathsf{SinsemillaCommit} is a randomised commitment, Sinsemilla hash plus a randomness term. Sapling's ivk\mathsf{ivk} is a hash; Orchard's is a randomised commitment. The commitment form lets the circuit prove derivation more efficiently.

Full viewing key

Definition 2.54 (Orchard fvkO\mathsf{fvk}_O). fvkO=(ak,nk,rivk)GP×FpP×FqP\mathsf{fvk}_O = (\mathsf{ak}, \mathsf{nk}, \mathsf{rivk}) \in \mathbb{G}_P \times \mathbb{F}_{p_P} \times \mathbb{F}_{q_P}. ovk\mathsf{ovk} and dk\mathsf{dk} are derived from fvkO\mathsf{fvk}_O deterministically.

Diversifier, diversified base, transmission key

Definition 2.55 (Orchard d,gd,pkdd, g_d, \mathsf{pk}_d). d{0,1}88d \in \{0,1\}^{88} is derived from dk\mathsf{dk} as in Sapling. Then

gd  =  DiversifyHash(d)GP,pkd  =  [ivk]gdGP.g_d \;=\; \mathsf{DiversifyHash}(d) \in \mathbb{G}_P, \qquad \mathsf{pk}_d \;=\; [\mathsf{ivk}]\, g_d \in \mathbb{G}_P.

Orchard payment address

Definition 2.56 (Orchard address addrO\mathsf{addr}_O). addrO=(d,pkd){0,1}88×GP\mathsf{addr}_O = (d, \mathsf{pk}_d) \in \{0,1\}^{88} \times \mathbb{G}_P, encoded in 43 bytes and packaged inside a Unified Address (no standalone bech32 form).

Note plaintext

Definition 2.57 (Orchard note). An Orchard note is the tuple

noteO  =  (ρ,ψ,gd,pkd,v,rseed)    FpP×FpP×GP×GP×[0,264)×{0,1}256.\mathsf{note}_O \;=\; (\rho, \psi, g_d, \mathsf{pk}_d, v, \mathsf{rseed}) \;\in\; \mathbb{F}_{p_P} \times \mathbb{F}_{p_P} \times \mathbb{G}_P \times \mathbb{G}_P \times [0, 2^{64}) \times \{0,1\}^{256}.

The additional fields ρ\rho and ψ\psi are uniqueness nonces that chain across the bundle: each new note's ρ\rho equals the nullifier of the spent note in the same Action. ψ\psi is derived from rseed\mathsf{rseed} and ρ\rho:

ψ  =  ToBase ⁣(PRFrseedexpand(0x09,ρ)).\psi \;=\; \mathsf{ToBase}\!\bigl( \mathsf{PRF}^{\text{expand}}_{\mathsf{rseed}}(0\mathrm{x}09, \rho) \bigr).

Commitment randomness

Definition 2.58 (Orchard rcm\mathsf{rcm}). rcmFqP\mathsf{rcm} \in \mathbb{F}_{q_P}, defined by

rcm  =  ToScalar ⁣(PRFrseedexpand(0x05,ρ)).\mathsf{rcm} \;=\; \mathsf{ToScalar}\!\bigl( \mathsf{PRF}^{\text{expand}}_{\mathsf{rseed}}(0\mathrm{x}05, \rho) \bigr).

Note commitment

Definition 2.59 (Orchard cm\mathsf{cm}). cmGP\mathsf{cm} \in \mathbb{G}_P, defined by

cm  =  SinsemillaDncrcm ⁣(repr(gd)repr(pkd)vLE,64repr(ρ)repr(ψ)).\mathsf{cm} \;=\; \mathsf{Sinsemilla}^{\mathsf{rcm}}_{D_{\text{nc}}}\!\bigl( \mathsf{repr}(g_d) \,\mathbin{\|}\, \mathsf{repr}(\mathsf{pk}_d) \,\mathbin{\|}\, v_{\text{LE}, 64} \,\mathbin{\|}\, \mathsf{repr}(\rho) \,\mathbin{\|}\, \mathsf{repr}(\psi)\bigr).

The published value is the xx-coordinate cmx=extract(cm)FpP\mathsf{cmx} = \mathsf{extract}(\mathsf{cm}) \in \mathbb{F}_{p_P}.

Ephemeral keys for note encryption

Definition 2.60 (Orchard esk,epk\mathsf{esk}, \mathsf{epk}). eskFqP\mathsf{esk} \in \mathbb{F}_{q_P} and epkGP\mathsf{epk} \in \mathbb{G}_P, defined by

esk  =  ToScalar ⁣(PRFrseedexpand(0x04,ρ)),epk  =  [esk]gd.\mathsf{esk} \;=\; \mathsf{ToScalar}\!\bigl( \mathsf{PRF}^{\text{expand}}_{\mathsf{rseed}}(0\mathrm{x}04, \rho) \bigr), \qquad \mathsf{epk} \;=\; [\mathsf{esk}]\, g_d.

Value commitment

Definition 2.61 (Orchard cvnet\mathsf{cv}^{\text{net}}). cvnetGP\mathsf{cv}^{\text{net}} \in \mathbb{G}_P, defined by

cvnet  =  [vnet]VOrch  +  [rcv]ROrch,\mathsf{cv}^{\text{net}} \;=\; [v^{\text{net}}]\, V_{\text{Orch}} \;+\; [\mathsf{rcv}]\, R_{\text{Orch}},

where vnet=voldvnewv^{\text{net}} = v_{\text{old}} - v_{\text{new}} is the net value of the Action (positive when the old note was larger than the new one). The bundle balance equation aggregates these commitments.

Nullifier

Definition 2.62 (Orchard nullifier nf\mathsf{nf}). nfFpP\mathsf{nf} \in \mathbb{F}_{p_P}, defined by

nf  =  ExtractFpP ⁣([PRFnknfOrchard(ρ)+ψ]KOrch  +  cm),\mathsf{nf} \;=\; \mathsf{Extract}_{\mathbb{F}_{p_P}}\!\bigl( [\mathsf{PRF}^{\mathsf{nfOrchard}}_{\mathsf{nk}}(\rho) + \psi]\, K_{\text{Orch}} \;+\; \mathsf{cm}\bigr),

with KOrchGPK_{\text{Orch}} \in \mathbb{G}_P a fixed Pallas generator and PRFnknfOrchard\mathsf{PRF}^{\mathsf{nfOrchard}}_{\mathsf{nk}} a Poseidon-based PRF keyed by nk\mathsf{nk}.

Re-randomisation, binding sig, OCK, K_enc

Definition 2.63 (Orchard re-randomisation rsk,rk\mathsf{rsk}, \mathsf{rk}). For \alpha \stackrel{\}{\leftarrow} \mathbb{F}_{q_P}$,

rsk  =  ask+αFqP,rk  =  ak+[α]GOrchakGP.\mathsf{rsk} \;=\; \mathsf{ask} + \alpha \in \mathbb{F}_{q_P}, \qquad \mathsf{rk} \;=\; \mathsf{ak} + [\alpha]\, G^{\mathsf{ak}}_{\text{Orch}} \in \mathbb{G}_P.

Definition 2.64 (Orchard ock\mathsf{ock}). ock{0,1}256\mathsf{ock} \in \{0,1\}^{256}, defined by

ock  =  BLAKE2b-256 ⁣(pers=“Zcash_Orchardock”,  ovkrepr(cvnet)repr(cmx)repr(epk)).\mathsf{ock} \;=\; \mathsf{BLAKE2b\text{-}256}\!\bigl( \text{pers} = \text{``Zcash\_Orchardock''},\; \mathsf{ovk} \,\mathbin{\|}\, \mathsf{repr}(\mathsf{cv}^{\text{net}}) \,\mathbin{\|}\, \mathsf{repr}(\mathsf{cmx}) \,\mathbin{\|}\, \mathsf{repr}(\mathsf{epk})\bigr).

Definition 2.65 (Orchard bvk\mathsf{bvk}). bvkGP\mathsf{bvk} \in \mathbb{G}_P, defined by

bvk  =  icvinet[vbalanceOrch]VOrch.\mathsf{bvk} \;=\; \sum_i \mathsf{cv}_i^{\text{net}} - [v_{\text{balance}}^{\text{Orch}}]\, V_{\text{Orch}}.

The binding signature is RedPallas; ZIP 224 spells out the constants.

Issuance keys (ZSA, NU7-track)

Definition 2.66 (ZSA IssuanceKey\mathsf{IssuanceKey}). IssuanceKey{0,1}256\mathsf{IssuanceKey} \in \{0,1\}^{256}. The issuer's spending- authority root for issuance. Future-only.

Definition 2.67 (ZSA ik\mathsf{ik}). ikGP\mathsf{ik} \in \mathbb{G}_P, the public issuance key derived from IssuanceKey\mathsf{IssuanceKey} analogously to ak\mathsf{ak}.

Definition 2.68 (ZSA AssetId\mathsf{AssetId}). AssetId{0,1}512\mathsf{AssetId} \in \{0,1\}^{512}, a 64-byte digest binding an asset to its issuer. See chapter 21 for ZSA context.

3.4 Transparent

Standard BIP-32 / SLIP-10 over secp256k1. Path m/44/133/acct/change/indexm / 44' / 133' / \mathrm{acct}' / \mathrm{change} / \mathrm{index}.

Definition 2.69 (Transparent xprv\mathsf{xprv}). xprv{0,1}256×{0,1}256\mathsf{xprv} \in \{0,1\}^{256} \times \{0,1\}^{256}, the BIP-32 extended private key, consisting of a 32-byte private scalar and a 32-byte chain code.

Definition 2.70 (Transparent xpub\mathsf{xpub}). xpubGsecp256k1×{0,1}256\mathsf{xpub} \in \mathbb{G}_{\text{secp256k1}} \times \{0,1\}^{256}, the BIP-32 extended public key, consisting of a secp256k1 point and the chain code.

Definition 2.71 (Transparent skT\mathsf{sk}_T). skTFnsecp256k1\mathsf{sk}_T \in \mathbb{F}_{n_{\text{secp256k1}}}, the secp256k1 scalar private key extracted from a non-hardened xprv\mathsf{xprv}.

Definition 2.72 (Transparent pkT\mathsf{pk}_T). pkTGsecp256k1\mathsf{pk}_T \in \mathbb{G}_{\text{secp256k1}}, defined by pkT=[skT]Gsecp256k1\mathsf{pk}_T = [\mathsf{sk}_T] G_{\text{secp256k1}}.

Definition 2.73 (Transparent hash160\mathsf{hash160}). hash160{0,1}160\mathsf{hash160} \in \{0,1\}^{160}, defined by

hash160  =  RIPEMD-160 ⁣(SHA-256(enc(pkT))),\mathsf{hash160} \;=\; \mathsf{RIPEMD\text{-}160}\!\bigl( \mathsf{SHA\text{-}256}(\mathsf{enc}(\mathsf{pk}_T))\bigr),

the address payload of P2PKH outputs.

The transparent key implementation:

zcash_transparent/src/keys.rs
loading...

ZIP 48 account-level keys live alongside in zcash_transparent/src/zip48.rs.

3.5 Unified

Defined by ZIP 316. Encoded via F4Jumble in components/f4jumble/src/lib.rs and bech32m in components/zcash_address/src.

Unified spending key

Definition 2.74 (Unified spending key USK\mathsf{USK}). USK=(xprvT,eskSap,skO)\mathsf{USK} = (\mathsf{xprv}_T, \mathsf{esk}_{\text{Sap}}, \mathsf{sk}_O) where each component is optional and present per the account's policy. Code: zcash_keys::keys::UnifiedSpendingKey.

zcash_keys/src/keys.rs
loading...

Unified full viewing key

Definition 2.75 (Unified full viewing key UFVK\mathsf{UFVK}). UFVK=(xpubT,efvkSap,fvkO)\mathsf{UFVK} = (\mathsf{xpub}_T, \mathsf{efvk}_{\text{Sap}}, \mathsf{fvk}_O). The Sapling component efvkSap\mathsf{efvk}_{\text{Sap}} includes the diversifier key dkSap\mathsf{dk}_{\text{Sap}}.

Unified incoming viewing key

Definition 2.76 (Unified incoming viewing key UIVK\mathsf{UIVK}). UIVK=(xpubTexternal,ivkSap,ivkO)\mathsf{UIVK} = (\mathsf{xpub}_T^{\text{external}}, \mathsf{ivk}_{\text{Sap}}, \mathsf{ivk}_O). Decrypts incoming but not outgoing notes; a weaker capability than UFVK\mathsf{UFVK}, suitable for read-only services.

Unified address

Definition 2.77 (Unified address UA\mathsf{UA}). UA\mathsf{UA} is a bundle of receivers indexed by typecodes:

UA  =  {TypecodeiReceiveri}i,\mathsf{UA} \;=\; \{\text{Typecode}_i \mapsto \mathsf{Receiver}_i\}_i,

with typecodes per ZIP 316. Encoded as F4Jumble(TLV-concatHMAC)\mathsf{F4Jumble}(\mathsf{TLV}\text{-concat} \,\mathbin{\|}\, \mathsf{HMAC}) and then bech32m with HRP u.

3.6 Note encryption keys at a glance

For both Sapling and Orchard:

KeySender knowsRecipient knowsPurpose
esk\mathsf{esk}yesnoECDH secret
epk\mathsf{epk}yes (publishes)yes (sees on-chain)ECDH public
shared\mathsf{shared}[esk]pkd[\mathsf{esk}]\,\mathsf{pk}_d[ivk]epk[\mathsf{ivk}]\,\mathsf{epk}DH output
KencK_{\text{enc}}yesyesAEAD key (recipient side)
ock\mathsf{ock}yes (via ovk\mathsf{ovk})noAEAD key (sender side)

3.7 Cross-pool relationships

Every Zcash account in this codebase has:

  • One transparent extended key per account (ZIP 48).
  • One Sapling extended spending key per account.
  • One Orchard spending key per account.

These are independent: knowing one does not reveal the others. The wallet stitches them together via the Unified containers. The same seed deterministically produces all three (via different ZIP 32 paths). Backing up the seed phrase backs up the full account.

3.8 Privacy hierarchy

Per pool, the capability ladder (top: most powerful):

  1. sk\mathsf{sk} - can spend.
  2. ask\mathsf{ask}, nsk\mathsf{nsk} - jointly authorise and prove a spend; cannot derive the address (need ivk\mathsf{ivk}).
  3. fvk=(ak,nk,ovk,dk)\mathsf{fvk} = (\mathsf{ak}, \mathsf{nk}, \mathsf{ovk}, \mathsf{dk}) - view incoming and outgoing; enumerate addresses; cannot spend.
  4. ivk\mathsf{ivk} - decrypt incoming; cannot view outgoing.
  5. (d,pkd)(d, \mathsf{pk}_d) - public receiver; only sendable-to.

The PCZT design respects this hierarchy: each role gets the minimum capability it needs.

3.9 Lifetime: where each key lives

PhaseStoredNotes
At restSeed (encrypted), USK and UFVK in wallet DBUSK should be encrypted in DB or held in a hardware signer
ScanningUIVK, nullifier setNo spending capability needed
Building (single key)USK, proving parameters, Merkle pathsLocal proving
PCZT constructorRead-only wallet stateNo private keys
PCZT proverpgk\mathsf{pgk} + per-spend α\alphaNo ask\mathsf{ask}
PCZT signerask\mathsf{ask} + sighashNo proving

3.10 Code reference table

TypeCrate :: Module
SpendingKey (Sapling)sapling-crypto::keys::SpendingKey
ExpandedSpendingKey (Sapling)sapling-crypto::keys::ExpandedSpendingKey
ProofGenerationKey (Sapling)sapling-crypto::keys::ProofGenerationKey
FullViewingKey (Sapling)sapling-crypto::keys::FullViewingKey
SaplingIvksapling-crypto::keys::SaplingIvk
OutgoingViewingKey (Sapling)sapling-crypto::keys::OutgoingViewingKey
DiversifierKey (Sapling)sapling-crypto::zip32::DiversifierKey
Diversifier (Sapling)sapling-crypto::keys::Diversifier
PaymentAddress (Sapling)sapling-crypto::PaymentAddress
SpendingKey (Orchard)orchard::keys::SpendingKey
FullViewingKey (Orchard)orchard::keys::FullViewingKey
IncomingViewingKey (Orchard)orchard::keys::IncomingViewingKey
DiversifierKey (Orchard)orchard::keys::DiversifierKey
Address (Orchard)orchard::Address
Transparent extended keyzcash_transparent::keys
UnifiedSpendingKeyzcash_keys::keys::UnifiedSpendingKey
UnifiedFullViewingKeyzcash_keys::keys::UnifiedFullViewingKey
UnifiedAddressRequestzcash_keys::keys
UnifiedAddresszcash_keys::address::UnifiedAddress

3.11 Derivation graphs

Sapling derivation:

seed (32 B)
| ZIP 32: m / 32' / 133' / acct'
v
sk (Sapling, 32 B)
|
|---- PRF^expand(.,0x00) -> ask (F_l)
|---- PRF^expand(.,0x01) -> nsk (F_l)
|---- PRF^expand(.,0x02) -> ovk (32 B)
|---- PRF^expand(.,0x10) -> dk (32 B)
|
v v
ak = [ask]G^ak nk = [nsk]G^nk
\_____________ ______/
\/
ivk = CRH^ivk(ak, nk) mod l
|
dk -- FF1 --> d (per index)
|
g_d = DiversifyHash(d)
|
pk_d = [ivk] g_d
|
address = (d, pk_d)

Orchard derivation:

sk_O
|
|---- PRF^expand(.,0x06) -> ask (F_q)
|---- PRF^expand(.,0x07) -> nk (F_p, field elt!)
|---- PRF^expand(.,0x08) -> rivk (F_q)
|
v v
ak = [ask]G^ak_O (nk is a scalar; no point op)
\_____________ ______/
\/
ivk = Extract(SinsemillaCommit^rivk(ak, nk))
|
ovk || dk = PRF^expand(., 0x82, ak, nk)
|
dk -- FF1 --> d
|
g_d = DiversifyHash(d)
|
pk_d = [ivk] g_d
|
receiver = (d, pk_d)

Per-transaction ephemerals (both pools):

rseed rcv alpha
| | |
v v v
rcm, esk (used in rsk = ask + alpha
| cv = [v]V |
v + [rcv]R) rk = ak + [alpha] G^ak
epk = [esk]g_d |
sigma_spendAuth =
RedSig.Sign_rsk(sighash)

5. Spec pointers

  • Zcash Protocol Specification, section 4: high-level definitions for every key in this catalog.
  • Zcash Protocol Specification, section 5: concrete formulas for PRFexpand\mathsf{PRF}^{\text{expand}}, CRHivk\mathsf{CRH}^{\mathsf{ivk}}, DiversifyHash\mathsf{DiversifyHash}, and the nullifier PRFs.
  • ZIP 32: HD derivation paths feeding the per-pool root spending key.
  • ZIP 212: the rseed-derived rcm\mathsf{rcm} and esk\mathsf{esk} that this catalog records.
  • ZIP 224: Orchard key tree.
  • ZIP 316: Unified Addresses, full viewing keys, and the internal/external split for change addresses.
  • ZIP 48: transparent account- level keys included in a UFVK.

6. Exercises

  1. Look up a symbol. A PR comments references rivk\mathsf{rivk} without context. Use this catalog to identify which pool the key belongs to, its derivation, and the line in zcash_keys/src/keys.rs or the external orchard crate where the type is defined.
  2. Diversifier count. Compute the maximum number of diversifiers a Sapling account can produce and the expected fraction of valid ones (where gdg_d lies in the prime-order subgroup). Cite the protocol spec section that gives the numbers.
  3. Trace a derivation in code. Open zcash_keys/src/keys.rs and follow the call path from a seed to a UnifiedSpendingKey to a UnifiedAddress. Cite the file and line of each intermediate type.
  4. Cross-pool capability. A user shares their UFVK with a read-only auditor. Which keys in this catalog does the auditor gain access to? Which do they not? Answer per pool.

Answers in the code

7. Further reading

  • chapter 06: the HD derivation layer that produces the root spending keys this catalog itemises.
  • chapter 24: the circuits that consume these keys as witnesses.
  • Hopwood, Bowe, Hornby, Wilcox, Sapling design notes: the original treatment of the Sapling key tree.