ZIP: 2006
Title: Restricting Transfers into the Orchard Pool
Owners: Daira-Emma Hopwood <[email protected]>
Credits: Sean Bowe
         Schell Carl Scivally
         Jack Grigg
         Kris Nuttycombe
Status: Final
Category: Consensus
Created: 2025-06-21
License: MIT
Discussions-To: <https://github.com/zcash/zips/issues/1305>

Terminology

The key words “MUST”, “MUST NOT”, and “SHOULD” in this document are to be interpreted as described in BCP 14 1 when, and only when, they appear in all capitals.

The term “network upgrade” in this document is to be interpreted as described in ZIP 200. 2

The character § is used when referring to sections of the Zcash Protocol Specification. 3

The terms “Orchard protocol”, “Orchard pool”, “Ironwood pool”, “Orchard-pool Action”, and “Ironwood-pool Action” are to be interpreted as described in ZIP 229. 4

The expanded receiver of an Orchard-protocol shielded payment address or note is the pair \((\mathsf{g_d}, \mathsf{pk_d})\) of its diversified base and its diversified transmission key, as defined in § 4.2.3 ‘Orchard Key Components’. 5

Abstract

NU6.3 6 specifies two restrictions intended to limit economic activity within the Orchard pool:

So the Orchard pool can still be spent from, including across the turnstile into the Ironwood pool, but cannot be used to transfer value to an address whose spending key the sender does not hold.

This ZIP specifies the enableCrossAddress flag that expresses the second restriction; the corresponding condition in the Action statement; and the consensus rules that enforce both restrictions for the Orchard pool.

Motivation

The Orchard Action circuit deployed before NU6.2 had a soundness vulnerability that could have allowed value to be created in the Orchard pool. 7 NU6.3 introduces the Ironwood pool, which uses the Orchard protocol with a corrected circuit. Value moves from the Orchard pool into it subject to the “turnstile” checks on chain value pool balances specified in ZIP 209 8.

For those checks to give the desired balance integrity assurances, newly created shielded value has to be directed into the Ironwood pool, and value in the Orchard pool should only be able to leave it. If users could still pay each other within the Orchard pool, it would remain a working payment pool, and any value created through the vulnerability could circulate in it without ever being checked at the turnstile. Disallowing new value from entering the Orchard pool, and payments between users within it, prevents that, while still letting each holder move their own funds out. It does not prevent users from rebalancing note values within the Orchard pool in order to reduce the information revealed when migrating those funds to the Ironwood pool, as specified in ZIP 318 9.

Privacy Implications

Without the cross-address restriction, unrelated real spends and outputs can share Actions, so the minimum Action count is the maximum of the numbers of real spends and real outputs. Under the restriction, a real spend and a real output can share an Action only if they use the same expanded receiver. When no such pairing is possible, the minimum Action count is instead the sum of those numbers. This increases transaction size and reduces the hiding of transaction arity provided by spend/output pairing. Same-receiver pairing and additional dummy Actions remain possible, so the public Action count does not uniquely determine the numbers of real spends and real outputs. Since the restriction applies to all Orchard-pool Actions, the resulting increase in Action counts is not by itself a wallet-specific fingerprint.

By preventing payments between users within the Orchard pool, this ZIP encourages users to transfer their funds out of that pool. Such transfers reveal the net amount leaving the pool on-chain, regardless of its destination. Transferring a wallet’s entire balance at once can therefore reveal that balance, and the amounts and timing of transfers can help link them. The restrictions preserve the ability to rebalance notes within the Orchard pool without crossing the turnstile. ZIP 318 9 specifies amount-selection and timing measures for migration to the Ironwood pool, and ZIP 326 10 describes how to construct the spend and output Actions needed for rebalancing under the cross-address restriction.

Requirements

Specification

The enableCrossAddress flag

Each Action has a flag \(\mathsf{enableCrossAddress} \;{\small ⦂}\; \mathbb{B}\kern-0.05em\textsf{,}\) which is set in order to allow the expanded receiver of the Action’s output note to differ from the expanded receiver of its input note. The value of \(\mathsf{enableCrossAddress}\) is the same for all Actions of a bundle, and is encoded once per bundle in bit 2 of its flags byte:

For blocks before NU6.3 activation, cross-address transfers are always permitted: \(\mathsf{enableCrossAddress}\) is taken to be \(1\) for every Action. From NU6.3 activation, \(\mathsf{enableCrossAddress}\) is bit 2 of the flags byte for each pool, so it is \(0\) for every Orchard-pool Action.

Action statement

For a given Orchard-protocol Action description, let \(\mathsf{disableCrossAddress} = 1 - \mathsf{enableCrossAddress}\kern-0.05em\textsf{.}\)

From NU6.3 activation, the Action statement gains a primary input \(\mathsf{disableCrossAddress} \;{\small ⦂}\; \mathbb{B}\kern-0.05em\textsf{,}\) after \(\mathsf{enableOutputs}\kern-0.05em\textsf{,}\) and the following condition:

Cross-address restriction: \(\mathsf{disableCrossAddress} = 0\kern-0.05em\textsf{,}\) or \(\mathsf{g_d^{old}} = \mathsf{g_d^{new}}\) and \(\mathsf{pk_d^{old}} = \mathsf{pk_d^{new}}\kern-0.05em\textsf{.}\)

The auxiliary input of the Action statement already includes the spent note’s expanded receiver \((\mathsf{g_d^{old}}, \mathsf{pk_d^{old}})\) and the output note’s expanded receiver \((\mathsf{g_d^{new}}, \mathsf{pk_d^{new}})\kern-0.05em\textsf{.}\)

A single circuit, and a single verifying key identified as OrchardCircuitVersion::PostNu6_3, are used for the Actions of both the Orchard pool and the Ironwood pool from NU6.3 activation. The pools differ in the consensus restrictions on the value of \(\mathsf{enableCrossAddress}\kern-0.05em\textsf{,}\) not in the circuit.

Consensus rules

The following consensus rules apply from NU6.3 activation to every transaction, whatever its version:

Together with the rule that bit 2 of flagsOrchard is 0, these ensure that after NU6.3 activation no value enters the Orchard pool, and every Orchard-pool Action sends its output to the expanded receiver of the note that it spends.

Requirements on wallets

When an Action with \(\mathsf{enableCrossAddress} = 0\) needs a dummy output note, that note MUST be sent to the expanded receiver of the Action’s spent note (which may itself be a dummy note), rather than to a random address. Likewise, a dummy spent note paired with an output note that is not a dummy MUST be at the expanded receiver of the output note.

ZIP 326 specifies how wallets spend from, and rebalance notes within, the Orchard pool after NU6.3 activation. 10 In particular, an Action that creates an output note carrying value pairs it with a dummy spent note at the same expanded receiver, and the dummy output note of an Action that spends a real note has a random note ciphertext.

Changes to the Protocol Specification

This section is written as a set of changes relative to version 2026.7.0 of the protocol specification 11. They are applied in version 2026.8.0. 3 Each change applies from NU6.3 activation, and is marked as such in the specification.

§ 4.6 ‘Action Descriptions’

Add:

Let \(\mathsf{pool} \;{\small ⦂}\; \{\mathsf{OrchardPool}, \mathsf{IronwoodPool}\}\) be the pool of this Action description.

Define an expanded receiver as in ZIP 2006, i.e. \((\mathsf{g_d}, \mathsf{pk_d})\) for a shielded payment address.

Add \(\mathsf{enableCrossAddress}\) to the components of an Action description, after \(\mathsf{enableOutputs}\kern-0.05em\textsf{,}\) with the description:

\(\mathsf{enableCrossAddress} \;{\small ⦂}\; \mathbb{B}\) is a flag that is set in order to enable the expanded receiver of the output note to be different from the expanded receiver of the input note in this Action.

In the description of the proof, and in the consensus rule requiring it to be valid, append \(\mathsf{disableCrossAddress}\) to the primary input, where \(\mathsf{disableCrossAddress} = 1 - \mathsf{enableCrossAddress}\kern-0.05em\textsf{.}\)

In the note on components that are encoded once for each pool, add \(\mathsf{enableCrossAddress}\) to the components listed.

Add the consensus rule:

[NU6.3 onward] \(\mathsf{vk}\) MUST be the verifying key identified by OrchardCircuitVersion::PostNu6_3.

§ 4.8.3 ‘Dummy Notes (Orchard)’

After the steps that construct the spend-related fields for a dummy Orchard-pool input note, add:

[NU6.3 onward] If \(\mathsf{enableCrossAddress} = 0\) for the Action, and its output note is not a dummy note, then the first two steps are replaced: \((\mathsf{ak}, \mathsf{nk}, \mathsf{rivk})\) and \((\mathsf{d}, \mathsf{pk_d})\) are instead the full viewing key and diversified payment address of the output note’s recipient, and the spend authorization signature for the Action is made with the corresponding spend authorizing key.

After the paragraph saying that a dummy Orchard-pool output note is sent to a random shielded payment address, add:

[NU6.3 onward] If \(\mathsf{enableCrossAddress} = 0\) for the Action, the dummy output note is instead sent to the expanded receiver of the Action’s spent note. If the spent note is not a dummy note, the transmitted note ciphertext of the dummy output note is filled with random bytes rather than being an encryption of its note plaintext. 10

§ 4.18.4 ‘Action Statement (Orchard)’

Append to the primary input:

[NU6.3 onward] \(\mathsf{disableCrossAddress} \;{\small ⦂}\; \mathbb{B}\)

In its encoding, append \(\mathsf{disableCrossAddress} \pmod{q_{\mathbb{P}}}\) to the existing nine-element sequence, giving a sequence of type \(\mathbb{F}_{q_{\mathbb{P}}}^{10}\) from NU6.3 onward. Qualify the existing nine-element encoding with “[Pre-NU6.3]”.

After the “Enable output flag” condition, add:

Cross-address restriction [NU6.3 onward]: \(\mathsf{disableCrossAddress} = 0\kern-0.05em\textsf{,}\) or \(\mathsf{g_d^{old}} = \mathsf{g_d^{new}}\) and \(\mathsf{pk_d^{old}} = \mathsf{pk_d^{new}}\kern-0.05em\textsf{.}\)

§ 7.1 ‘Transaction Encoding and Consensus’

In the combined version 5/6 transaction-format table, replace the list in the Description column for flagsOrchard:

with:

In the Description column for flagsIronwood, the version-6-only field added by ZIP 229 4, replace:

with:

§ 7.1.2 ‘Transaction Consensus Rules’

Add:

[NU6.3 onward] A coinbase transaction MUST NOT have any Orchard-pool Action descriptions.

[NU6.3 onward] \(\mathsf{v^{balanceOrchard}}\) MUST be nonnegative.

After the rule that the reserved bits \(2..7\) of the flagsOrchard field MUST be zero, add:

[NU6.3 onward] In a version 6 transaction, bit 2 of flagsOrchard encodes \(\mathsf{enableCrossAddress}\) for the Orchard-pool Actions; it is covered by the preceding rule, and so is \(0\kern-0.05em\textsf{.}\)

Changes to ZIPs

ZIP 229

In the Consensus Rules section, replace

Note that the reserved-bit rules above leave bit 2 of flagsOrchard reserved as 0 (bits 2..7), while bit 2 of flagsIronwood is the enableCrossAddress bit (reserved bits 3..7); the Orchard pool’s cross-address restriction is enforced for its Actions from NU6.3 onward as specified in [ZIP 2006].

with

Note that bit 2 of flagsOrchard is required to be 0 by the reserved-bit rule above (bits 2..7), independent of the transaction version: in a version 5 transaction it is still reserved, and in a version 6 transaction it encodes enableCrossAddress. Bit 2 of flagsIronwood is the enableCrossAddress bit (reserved bits 3..7). The Orchard pool’s cross-address restriction is enforced for its Actions from NU6.3 onward as specified in [ZIP 2006].

Rationale

Polarity of the flag

The flag is encoded in the enabled sense: bit 2 is 1 when cross-address transfers are enabled, the normal case for the Ironwood pool. With the opposite sense, a post-NU6.3 Orchard-pool spend would have to set bit 2 to 1. Signers that treat bit 2 as a reserved zero bit, such as hardware wallet firmware that has not been upgraded, would then be unable to produce valid Orchard-pool spends. In the enabled sense, the restricted state is bit 2 = 0, which is exactly what such signers already produce.

Within the circuit, the primary input is the negated value \(\mathsf{disableCrossAddress} = 1 - \mathsf{enableCrossAddress}\kern-0.05em\textsf{.}\) Then a condition of the form “\(\mathsf{disableCrossAddress} = 0\) or \(a = b\)” is enforced directly by the constraint \(\mathsf{disableCrossAddress} \cdot (a - b) = 0\kern-0.05em\textsf{.}\)

One circuit for both pools

The Orchard pool and the Ironwood pool use the same circuit and verifying key from NU6.3 activation. They are distinguished by their bundles, note commitment trees, nullifier sets, and chain value pools, and by the value of \(\mathsf{enableCrossAddress}\kern-0.05em\textsf{.}\) This avoids a separate circuit for the restricted pool. It also leaves open the option of enforcing similar restrictions on the Ironwood pool in future, should there be a reason to. This intentionally mirrors the design of the enableSpends and enableOutputs flags.

Comparing both coordinates

In the circuit, the points of the expanded receivers are witnessed in affine coordinates, and the condition is enforced coordinate-wise: for each \(\mathsf{P} \in \{\mathsf{g_d}, \mathsf{pk_d}\}\) and each coordinate \(\mathsf{c} \in \{x, y\}\kern-0.05em\textsf{,}\) \(\mathsf{disableCrossAddress} \cdot (\mathsf{c}(\mathsf{P^{old}}) - \mathsf{c}(\mathsf{P^{new}})) = 0\kern-0.05em\textsf{.}\) Both coordinates are needed.

Restricting value as well as addresses

The cross-address restriction alone does not stop new value from entering the Orchard pool, since an Action can send value to its own spent note’s address. The rule that \(\mathsf{v^{balanceOrchard}}\) is nonnegative, and the rule that coinbase transactions have no Orchard-pool Actions, close that path.

Deployment

This ZIP was deployed with NU6.3 6, which activated on Mainnet at block height 3428143.

Reference implementation

References


  1. Information on BCP 14 — “RFC 2119: Key words for use in RFCs to Indicate Requirement Levels” and “RFC 8174: Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words”  ↩︎

  2. ZIP 200: Network Upgrade Mechanism  ↩︎

  3. Zcash Protocol Specification, Version 2026.8.0 [NU6.3]  ↩︎

  4. ZIP 229: Version 6 Transaction Format  ↩︎

  5. Zcash Protocol Specification, Version 2026.8.0 [NU6.3]. Section 4.2.3: Orchard Key Components  ↩︎

  6. ZIP 258: Deployment of the NU6.3 Network Upgrade  ↩︎

  7. ZIP 257: Deployment of the Orchard Temporary Vulnerability Mitigation and NU6.2 Network Upgrade  ↩︎

  8. ZIP 209: Prohibit Out-of-Range Chain Value Pool Balances  ↩︎

  9. ZIP 318: Orchard to Ironwood Migration  ↩︎

  10. ZIP 326: NU6.3 Consequences for Wallets, section “Spending from and rebalancing within the Orchard pool”  ↩︎

  11. Zcash Protocol Specification, Version 2026.7.0 [NU6.2]  ↩︎

  12. orchard crate, version 0.16.0  ↩︎