Skip to main content

Note Encryption

1. Why This Chapter Exists

Every shielded output ships an encrypted note plaintext alongside its commitment. The recipient trial-decrypts every ciphertext on chain; the sender additionally encrypts an outgoing ciphertext for their own recovery. After this chapter the reader can map each byte of an Orchard note ciphertext to its source in src/note_encryption.rs.

2. Definitions

Definition 2.1 (Ephemeral Key)

Sender samples eskRFq\mathsf{esk} \xleftarrow{R} \mathbb{F}_q^* and publishes epk=[esk]gdEp\mathsf{epk} = [\mathsf{esk}]\, g_d \in E_p.

Definition 2.2 (Shared Secret and KDF)

dhsecret=[esk]pkdEp,Kenc=KDFOrchard(dhsecret,epk),\mathsf{dhsecret} = [\mathsf{esk}]\, \mathsf{pk_d} \in E_p, \quad K^{\mathsf{enc}} = \mathsf{KDF}^{\mathsf{Orchard}}(\mathsf{dhsecret}, \mathsf{epk}),

where KDFOrchard\mathsf{KDF}^{\mathsf{Orchard}} is Blake2b personalised with b"Zcash_OrchardKDF".

Definition 2.3 (AEAD)

Cenc=ChaCha20Poly1305Kenc(P),C^{\mathsf{enc}} = \mathsf{ChaCha20Poly1305}_{K^{\mathsf{enc}}}(P),

with fixed nonce 0960^{96}. The nonce reuse is safe because KencK^{\mathsf{enc}} depends on the unique epk\mathsf{epk}.

Definition 2.4 (Outgoing Ciphertext)

A separate AEAD on (cv,cm,epk,Povk)(\mathsf{cv}, \mathsf{cm}^\star, \mathsf{epk}, P_{\mathrm{ovk}}) under a key derived from ovk\mathsf{ovk}. Allows the sender to recover the note from their own viewing key.

Definition 2.5 (Note Plaintext Encoding)

The 580-byte note plaintext encodes the lead byte, dd, vv, rseed\mathsf{rseed}, and the 512-byte memo. ZIP 212 deterministically derives ψ\psi and rcm\mathsf{rcm} from rseed\mathsf{rseed} at decode time, which prevents a malleability attack.

3. The Code

3.1 The Domain

src/note_encryption.rs
loading...

OrchardDomain carries just a single field, rho, which binds the trial-decryption attempt to the Action's nullifier seed. The implementation of the zcash_note_encryption::Domain trait further down the same file supplies the KDF, the ephemeral-key derivation, the note plaintext encoder, and the AEAD instance.

3.2 Trial Decryption

The zcash_note_encryption crate exposes a try_note_decryption function that the Orchard wallet calls per output. Success returns the note and the memo; failure is indistinguishable from random under the IK-CCA security definition.

3.3 Outgoing Encryption

OrchardDomain also supplies the outgoing-ciphertext fields. The binding to the value commitment cv\mathsf{cv} and the extracted commitment cm\mathsf{cm}^\star prevents a sender from later claiming the wrong note was sent.

3.4 Compact vs Full Ciphertexts

OrchardDomain::COMPACT_NOTE_SIZE and the related NOTE_SIZE constants distinguish the two variants. Light wallets receive only the compact prefix from a public-server scan.

4. Failure Modes

  • Skipping the rseed\mathsf{rseed} check. If a decoder accepts the explicit ψ\psi / rcm\mathsf{rcm} fields instead of re-deriving them, an adversary can re-encrypt a malicious payload that decrypts to a wrong note.
  • Fixed-nonce abuse. The fixed nonce is safe only because each KencK^{\mathsf{enc}} is single-use. Reusing esk\mathsf{esk} across two outputs breaks confidentiality (key + nonce reuse).
  • Memo length leak. The memo is padded to a fixed 512 bytes; any code path that emits a variable-length memo leaks length.
  • Ciphertext padding regression. If a future contributor truncates the ciphertext to save bytes, the AEAD tag becomes recoverable but the integrity guarantee is broken. The OrchardDomain constants prevent this if used consistently.

5. Spec Pointers

6. Exercises

  1. Read the implementation of OrchardDomain::derive_esk. Where is esk\mathsf{esk} stored after it is sampled, and how does the trial-decryption side recover epk\mathsf{epk} from the ciphertext metadata?
  2. Trace a single trial-decryption call from tests/builder.rs into zcash_note_encryption and back. Identify the point at which the AEAD tag is verified.
  3. Code task. Modify tests/builder.rs to flip one byte of the encrypted ciphertext between encryption and decryption. Run the test and verify the AEAD tag check rejects. Revert.

7. Further Reading