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 and publishes .
Definition 2.2 (Shared Secret and KDF)
where is Blake2b personalised
with b"Zcash_OrchardKDF".
Definition 2.3 (AEAD)
with fixed nonce . The nonce reuse is safe because depends on the unique .
Definition 2.4 (Outgoing Ciphertext)
A separate AEAD on under a key derived from . 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, , , , and the 512-byte memo. ZIP 212 deterministically derives and from at decode time, which prevents a malleability attack.
3. The Code
3.1 The Domain
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 and the extracted
commitment 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 check. If a decoder accepts the explicit / 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 is single-use. Reusing 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
OrchardDomainconstants prevent this if used consistently.
5. Spec Pointers
- Zcash Protocol Specification, Section 4.18: Note encryption.
- ZIP 212: the deterministic randomness derivation that closes the malleability gap.
zcash_note_encryption: the shared framework.
6. Exercises
- Read the implementation of
OrchardDomain::derive_esk. Where is stored after it is sampled, and how does the trial-decryption side recover from the ciphertext metadata? - Trace a single trial-decryption call from
tests/builder.rsintozcash_note_encryptionand back. Identify the point at which the AEAD tag is verified. - Code task. Modify
tests/builder.rsto 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
- ZIP 316: Unified Addresses, which encapsulate the diversifier metadata the encryption depends on.
- Bellare-Rogaway's Authenticated Encryption with Associated Data is the formal model that ChaCha20-Poly1305 instantiates.