ZIP: 318
Title: Orchard to Ironwood Migration
Owners: Schell Carl Scivally <efsubenovex@gmail.com>
        Pacu Gindre <pacu@zecdev.org>
        Kris Nuttycombe <kris@nutty.land>
Status: Draft
Category: Wallet
Created: 2026-06-16
License: MIT
Discussions-To: <https://github.com/zcash/zips/issues/1315>

Terminology

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

The terms “Orchard pool” and “Ironwood pool” are to be interpreted as described in ZIP 229 2. Following the convention in the protocol specification 3, we use slanted text to refer to pool names, in order to more clearly distinguish them from shielded protocols.

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

The terms “Mainnet” and “Testnet” are to be interpreted as defined in the Zcash protocol specification. 5

The terms “trusted TXO”, “untrusted TXO”, “known-spendable”, and “confirmed-spendable” are to be interpreted as defined in ZIP 315. 6

The terms below are to be interpreted as follows:

Migration
The process by which a wallet transfers a user’s funds from the Orchard pool to the Ironwood pool.
Pool-crossing transfer
A transaction that moves value from one shielded pool to another. The net amount crossing between the pools is revealed on-chain. 7
Note preparation
A wallet-internal send-to-self transaction (or set of such transactions) whose purpose is to restructure the wallet’s existing notes — dividing larger notes, combining smaller ones, or both — into notes that exactly fund the planned migration transactions, so that the entire migration schedule can be pre-signed and broadcast without waiting for change from earlier transactions to confirm.
Migration transaction (or part)
A single pool-crossing transfer that moves part of the user’s Orchard-pool balance to the Ironwood pool as part of a migration. In the recommended scheme each migration transaction spends exactly one Orchard-pool note and moves exactly one denomination to a single Ironwood output.
Denomination
A canonical amount of the form \(n \times 10^k\) ZEC with \(n \in \{1, 2, 5\}\) (for example 100, 50, 20, 10, 5, 2, 1, 0.5 ZEC), bounded below by the maximum residual value and above by a cap specified in Amount selection, canonical quantization.
Maximum residual value
The value below which any remainder of the balance is left unmigrated, in order to prevent small, user-identifying amounts from being leaked in pool-crossing transactions.
Anchor-height bucket (boundary)
A shared, network-wide interval of block heights delimited by boundaries: blocks whose height is \(\equiv 0 \pmod{M}\) for a network-wide modulus \(M\) (provisionally 144). The anchor height of a migration transaction is drawn at random from among past boundaries rather than derived from the wallet’s own chain tip, so that the anchor does not reveal when a particular wallet last synchronized.
Cohort
The set of all migration transactions, from all wallets, that share the same boundary anchor.
Multiplicity (\(k\kern-0.15em\) )
The number of migration transactions a single wallet contributes to one cohort.
Migration schedule
The ordered set of migration transactions, together with their scheduled broadcast heights, that a wallet plans in order to complete a migration.
Background scheduling
The use of platform mechanisms (for example, BGTaskScheduler on iOS or WorkManager on Android) to broadcast a migration transaction at an approximate future time without requiring the user to have the application in the foreground.

Abstract

This ZIP specifies best practices for wallets migrating funds from the Orchard pool to the Ironwood pool introduced by the NU6.3 network upgrade 8. It is written with light client wallets in mind, because their reliance on a light wallet server and on mobile background scheduling makes the privacy and reliability concerns most acute, but the same practices apply to desktop and full-node wallets.

Because a pool-crossing transfer reveals the migrated amount on-chain, directly sending from one pool to another can reveal the wallet balance. A naive migration risks linking transfers to a single wallet and to the user’s activity, again potentially revealing balance, and also risking that migration transactions could be linked to personally identifying information such as IP addresses. To mitigate this, wallets should decompose the balance into notes with values drawn from a fixed set of denominations, which may then be sent across the turnstile as multiple transactions submitted to the chain over time using a network anonymity layer. In order to avoid linking transactions via anchor selection, proofs are made and updated against anchors drawn from shared, network-wide boundary heights, forming cohorts that mix many wallets and de-correlate transfers from when the user opens the application.

The migration runs as a two-phase process: a note-preparation phase followed by a scheduled transaction-creation phase. Migration transactions are pre-signed, persisted, and then have their proofs updated and are broadcast by best-effort background tasks, with a fallback that prompts the user on the next application open when a scheduled window is missed. Synchronization is kept decoupled in time from broadcast. This ZIP also specifies user-consent, network-privacy, progress-reporting, and error-handling requirements.

Motivation

The Ironwood pool, introduced by the NU6.3 network upgrade 8, enables verification of the Zcash shielded supply after NU6.2 mitigated a soundness flaw in the Orchard circuit 9. To that end, NU6.3 enables a rule that disables ordinary payments within the old Orchard pool while still permitting change 10; therefore, wallets are required to add functionality to migrate Orchard funds to the Ironwood pool.

Migrating funds between shielded pools is fundamentally different from spending within a single pool. Within a pool, both balances and the relationships between transactions remain private; a pool-crossing transfer, however, necessarily reveals the net amount crossing between the pools on-chain 7, so the only privacy levers available to a wallet are the shape of the amounts it migrates and the timing of their broadcast. If a wallet migrates a user’s entire balance in a single transaction, that amount, its timing, and (via network-layer metadata) potentially the user’s IP address are all exposed at once, and the transfer can be correlated with the wallet’s other activity.

ZIP 315 6 already establishes that the user’s consent is needed to reveal amounts publicly, and that wallets should minimize pool crossing. A mass migration event is a case where many users perform pool-crossing transfers in a relatively short window. This both creates an opportunity (many simultaneous migrations form an anonymity set) and a risk, because an observer who can distinguish one user’s transfers from the crowd learns a great deal.

A precedent exists in ZIP 308 11, which defined a privacy-preserving procedure for the Sprout-to-Sapling migration by sending a bounded amount per period and hiding individual migration transactions among those of all migrating users. This ZIP adapts that idea to the light-client setting, where the wallet does not run a full validator, scheduling is constrained by mobile operating systems, and synchronization happens against a light wallet server whose operator is a potential observer. The security analysis of migration strategies is subtle, and the more obvious strategies leak significant information; this document records the analysis behind the chosen strategy, including several rejected alternatives (see Alternatives).

The goal of this ZIP is therefore to document how a light client wallet SHOULD perform the Orchard-to-Ironwood migration so that, by default, individual transfers are as hard as practical to correlate to a specific wallet or to the user’s behaviour, while still completing the migration reliably and giving the user enough information to consent to any residual information leakage. The separate NU6.3 routing change — that new payments to Orchard receivers (inside existing unified addresses) are sent via the Ironwood pool 10 — is a general send-path concern and is out of scope, although the migration destination is the same Ironwood receiver.

Requirements

Non-requirements

The following are explicitly not requirements of this flow:

Specification

Overview, two-phase architecture

A wallet performing a privacy-preserving migration SHOULD implement it as two phases:

  1. Note preparation (see Phase 1, Note preparation): quantization of the migratable balance into canonical denominations, followed by one or more wallet-internal send-to-self transactions that restructure the Orchard-pool balance into notes that exactly fund the planned migration transactions.

  2. Scheduled migration transactions (see Phase 2, Scheduled migration transactions): pre-signed pool-crossing transfers, each transferring a canonical denomination at a scheduled broadcast height with a boundary anchor, broadcast by best-effort background tasks.

A wallet MAY offer an immediate single-transfer migration in addition to the privacy-preserving flow (see Migration entry point and user consent), but it SHOULD present the privacy trade-off of doing so.

Migration entry point and user consent

When a wallet detects a non-zero confirmed-spendable Orchard-pool balance once the NU6.3 network upgrade is scheduled or has activated, it SHOULD surface a dedicated migration entry point. (Surfacing the entry point before activation allows note preparation to begin early; see Phase 1, Note preparation.)

To keep the choice tractable for users who may not know what is best, the wallet SHOULD minimize the number of privacy-tuning options exposed.

Phase 1, Note preparation

Note preparation begins with amount selection: quantization of the migratable balance into the canonical denominations that the Phase 2 migration transactions will transfer. Quantization is necessarily the first step, because the note-preparation transactions cannot be constructed without knowing the exact note values they must produce.

Amount selection, canonical quantization

The migratable Orchard-pool balance MUST be decomposed into a set of migration transactions, each transferring a single denomination. It is RECOMMENDED that the denominations be selected by canonical quantization rather than by random or arbitrary sizing. Canonical denominations collide across wallets and resist leaking information that can be used for wallet fingerprinting (see Why value collision provides privacy). A wallet MAY use a different amount-selection strategy provided it achieves the same effect, namely that migrated amounts collide across the migrating population rather than fingerprinting the wallet. Random arbitrary amounts do not achieve this and are a rejected alternative (see Alternatives).

  123.45  ZEC -> [100, 20, 2, 1, 0.2, 0.2, 0.05]
  540     ZEC -> [500, 20, 20]
  25000   ZEC -> [10000, 10000, 5000]

The fee for each part is in addition to its denomination (the visible Orchard-out value of a part is its denomination plus the canonical fee; equivalently the Ironwood output equals the denomination). Each part is funded by a single note of exactly this value, produced by note preparation.

Note preparation transactions

A migration transaction spends exactly one Orchard-pool note (see Canonical migration transaction structure). The purpose of the note-preparation transactions is to ensure that a note of exactly the right value exists for every part of the schedule, so that every part can be funded independently of the others and the entire schedule can be pre-signed at once. After NU6.3, anchors are no longer committed to by signature digests and therefore migration transactions may be signed as soon as preparation transactions that construct the notes being spent have been constructed. Only the proving step requires that the funding notes have been mined and that a candidate boundary anchor exists (see Anchor-height bucketing and cohorts). Whether preparation divides larger notes into smaller ones, combines smaller notes into larger ones, or both, is purely a function of the wallet’s existing note distribution, and the distinction is not visible on-chain (see Rationale for the canonical transaction shape).

Phase 2, Scheduled migration transactions

Canonical migration transaction structure

Each migration transaction SHOULD have:

The canonical expiry height is computed from the transaction’s scheduled broadcast height: take the most recent height at or below it that EXPIRY_MODULUS (the number of blocks corresponding to 30 days, 34560 blocks at 75-second block spacing) divides without remainder, and add 2 × EXPIRY_MODULUS (69120 blocks): a rolling window that guarantees every transaction between one and two months of validity from its scheduled broadcast. Unlike the anchor, the expiry height is committed by the transaction digest 2 and is therefore fixed when the schedule is signed; because the schedule precomputes every broadcast height (see Transfer scheduling), the expiry is nonetheless known at signing time. The bucketed rule makes the committed value identical for every migration transaction — from any wallet — whose scheduled broadcast falls within the same 30-day period, so an expiry height reveals only the coarse period in which its broadcast was scheduled, information the broadcast itself substantially makes public. (Deriving the expiry from the construction height instead would reveal the otherwise unobservable period in which the wallet’s schedule was created, and would deny the late parts of a long schedule their full validity window, forcing needless rebuilds.) For example, NU6.3 activates at Mainnet height 3428143, so every migration transaction scheduled for broadcast before height 3456000 has expiry height 3490560, and one scheduled between heights 3456000 and 3490559 has expiry height 3525120. Parts still unbroadcast when their expiry height is reached are rebuilt with a fresh anchor and expiry (see Error handling).

This strict, uniform structure serves two audiences. To an observer, it makes every migration transaction structurally identical both to every other migration transaction and to an ordinary manually created OrchardIronwood spend, and it hides whether a change output is present (see Rationale for the canonical transaction shape). To the wallet that created it, the same structure serves as a canonical migration-transaction predicate for chain-based status recovery, with disambiguation from other conforming transactions provided by viewing-key information that an observer lacks: whether the Ironwood output belongs to the wallet’s own account, and whether its value is a canonical denomination.

Anchor-height bucketing and cohorts

Transfer scheduling

The schedule is constructed in block deltas: starting from the height at which the schedule is committed (lower-bounded so that every part can anchor; see below), the wallet assigns each part a scheduled broadcast height by advancing a running height by an independently drawn delay per part, so that a wallet’s broadcasts approximate a Poisson process.

Pre-signed transaction storage

Background scheduling

Platform-specific guidance is given in Platform considerations.

Decoupling synchronization from broadcast

A background session is defined as a period of time wherein the wallet is performing computation and network interaction decoupled from any user interaction with the wallet interface. While a background session and user interaction with the wallet interface may coincide, the wallet MUST NOT permit the user’s behavior to influence the execution of the background operations.

How a wallet determines when a synchronization is needed is implementation-defined.

Fallback on application open

Destination

Network-layer privacy

Before the schedule is committed, the wallet MUST present a network-privacy step.

Platform considerations

This section is non-normative except where it restates requirements from Background scheduling and Decoupling synchronization from broadcast. The flow applies to both iOS and Android; differences are noted where they affect implementation.

iOS

Android

Status notifications

Progress visibility

The wallet SHOULD report migration progress.

User-facing copy requirements

Because background scheduling is best-effort, product copy SHOULD NOT describe the migration as automatic or guaranteed. The fallback of prompting on the next application open MUST be presented as a normal part of the flow, not as an error state.

Error handling

The wallet MUST handle at least the following conditions.

Rationale

Rationale for the scheduled background approach

The chosen approach broadcasts migration transactions from best-effort background tasks at pre-determined, randomly drawn times that are de-correlated from the user’s interaction with the application. An alternative considered was a guided “on-open” approach, in which each transfer is created at the moment the user opens the application.

The on-open approach was dismissed primarily because user-triggered sends leak too much information: the scan ranges a wallet requests from a light wallet server already link its notes to one user, and if each pool-crossing send also coincides with an application open, an observer can monitor the wallet across the entire migration. It also provides no temporal de-correlation, because every transfer is anchored to the moment of user interaction.

The scheduled approach achieves temporal de-correlation in the common case. Its worst case (when no background task ever runs and the user sends everything on a single application open) is no worse than the on-open approach, while its best case is significantly better. Pre-signed transactions can be stored using existing transaction-resubmission infrastructure.

Rationale for Poisson transfer scheduling

This subsection is non-normative.

Drawing inter-transfer delays from an exponential distribution makes the schedule memoryless: observing one of a wallet’s broadcasts gives an observer no information about when its next broadcast will occur, so there is no per-wallet timing signature to recover. Because the superposition of independent Poisson processes is itself a Poisson process, the aggregate traffic of all wallets following this schedule blends into a single pooled process from which no individual wallet’s contribution is separable by timing analysis. Shuffling the parts before scheduling extends the same property to values: the sequence of denominations a wallet emits is not a predictable function of its balance.

The mean delay must not be too short relative to the anchor-bucket interval. A schedule whose delays are much shorter than the bucket interval (for example, minutes) would compress a wallet’s entire migration into a tight, predictable window, and the burst itself would be a clustering signal. With MEAN_DELAY = 66 blocks and the bucket modulus \(M\) = 144, a wallet broadcasts about two parts per bucket on average while the exponential tail continues to spread its transfers across several cohorts. This roughly halves the expected inter-transfer latency compared with a 144-block mean. Keeping MAX_DELAY at 576 blocks, more than eight mean delays, preserves nearly all of the exponential distribution’s variance while bounding the worst-case gap so that migration completes in bounded time and canonical expiry windows remain practical.

Delays are denominated in blocks rather than wall-clock time because bucket boundaries, anchors, and expiry heights are all block-denominated, and block height is what an on-chain observer measures.

Routine background synchronization does not undermine the schedule’s de-correlation properties: a synchronization reveals to the light wallet server only that some wallet has synchronized past a given height, while a migration transaction’s anchor is the shared boundary anchor common to its entire cohort. Provided synchronization and broadcast never share a background processing window, the server learns nothing that correlates a specific synchronizing wallet with a specific migration transaction.

The same reasoning applies, at a smaller scale, to the note-preparation broadcasts. Their values and direction are fully shielded, but a burst of identically shaped padded transactions appearing at a single instant is a shape-and-timing cluster attributable to one wallet, and such a burst also telegraphs that a migration schedule will follow it. Spacing the preparation broadcasts with a smaller-mean exponential (PREP_MEAN_DELAY) prevents the cluster from forming without materially delaying the migration: preparation is unconstrained by anchor buckets — its transactions anchor at the wallet’s ordinary near-tip depth — so its spacing serves only to break up the burst, not to place transactions into shared anchor cohorts.

Rationale for the stateful design

An attractive alternative is a stateless, chain-recoverable design: persist no scheduler state at all, and instead recover migration progress from the chain using the wallet’s viewing keys (identifying migration transactions by the canonical predicate) plus a deterministic re-computation of the quantization of the remaining balance. Because the quantization is a pure function of the balance, it recomputes identically on every activation and after restore-from-seed, which makes that design robust to restart and to multi-device restore.

This unified proposal nonetheless adopts a stateful design (a persisted schedule plus pre-signed transactions) and treats statelessness and multi-device/recovery continuity as non-requirements (see Non-requirements). The reasons are:

The chain-recoverability property is not wasted: the canonical migration-transaction predicate of Canonical migration transaction structure still lets a wallet, using its viewing keys, reconstruct which denominations have confirmed, which is how the reinstall/restore case is handled as a fresh migration. The full stateless design is recorded as a rejected alternative (see Alternatives).

Rationale for canonical amount selection

Privacy for value-transparent transfers comes from value collision (many wallets emitting the same amount) and ambiguity of grouping (an observer cannot tell which amounts belong together), not from unpredictability of the amount. A high-entropy random amount collides with no other wallet and is a near-unique fingerprint; a random partition into high-entropy pieces additionally exposes the balance to subset-sum reconstruction. Canonical denominations are therefore preferred precisely because they are not distinctive: many wallets emit identical denominations, so no single transfer is identifiable by its value, and a wallet MAY safely place several transfers in one cohort. Randomizing the choice among canonical denominations (see Amount selection, canonical quantization) is categorically different from randomizing amounts: every emitted part still collides with the population, while the multiset emitted for a given balance is no longer predictable, which improves balance hiding and further weakens targeted subset-sum. The detailed privacy argument is in Why value collision provides privacy and the sections that follow it; the discarded random-amount strategies are listed in Alternatives.

Rationale for the canonical transaction shape

The canonical migration transaction spends exactly one Orchard-pool note, pads the Orchard bundle to exactly two actions, and produces exactly one Ironwood output. Under NU6.3, Orchard bundles pair every spend and every output with a fabricated counterpart, so a bundle’s action count is the sum of its spends and outputs; values and the fabricated/real distinction are hidden. The canonical two-action Orchard bundle therefore consists of one spend action and one output action, and does not reveal whether the output action carries a change output or a zero-valued dummy. This has two consequences:

The Ironwood bundle is a single action, not padded to the two-action minimum. Unlike the Orchard side, where padding hides whether a change output is present, the Ironwood side of a canonical transfer has exactly one output and nothing left to hide: its shape is already fixed by the canonical structure. A padding dummy would therefore buy no indistinguishability, while costing an extra action’s proof — a real burden when a hardware device generates the proofs, since each action’s proving data must cross the device’s bandwidth-constrained link. What matters is that one action count is pinned as canonical: if padding were left optional, conforming wallets would split into distinguishable padded and unpadded populations, partitioning the very anonymity set the canonical shape exists to unify. (The indistinguishability argument above extends to manually created OrchardIronwood spends to the extent that they are built to this same single-action shape, which wallet builders are encouraged to use for this transfer form.)

A corollary is that note preparation and pre-signing are motivated operationally rather than by privacy: the privacy properties come from the canonical shape, the canonical values, and the scheduling, while exact-value funding notes are what allow the entire schedule to be pre-signed at once and broadcast in any order.

The same hiding applies to note preparation: because fabricated components are indistinguishable from real ones, an \(N\kern-0.15em\) -action preparation transaction reveals nothing about how its actions divide between spends and outputs — whether it divides notes, combines them, or both. Only its action count and timing are observable.

Rationale for decoupling synchronization from broadcast

Linking synchronization and broadcast in the same background session would let an observer correlate the two events and thereby link the broadcast to the wallet. Keeping them separated in time preserves the de-correlation that the scheduling is designed to provide. The principal place a synchronization is unavoidable is after the note-preparation transactions confirm, since the wallet must witness the prepared notes before the first scheduled send; the exceptional case of a migration transaction that outputs change back to the Orchard pool is handled the same way, by scheduling the synchronization at a different time from the next broadcast.

Rationale for anchor-height bucketing

Drawing anchors from shared, network-wide boundaries means a transaction’s anchor reveals only that the creator had scanned beyond that boundary at some time before broadcast, not the wallet’s precise sync height or sync schedule, and allows many users' transactions to share anchors. This mirrors the goal of ZIP 308 11 (hiding individual migration transactions among those of all migrating users), adapted to anchor selection in the light-client setting, and complements the anchor-selection guidance of ZIP 315. 6

Rationale for anchor selection

This subsection is non-normative.

A “sign ahead, broadcast later” workflow can leak information through anchor selection: if the anchor were fixed at signing time — as it is under the version 5 transaction-digest rules 16, where the anchor is committed by the signature hash — then at broadcast time the gap between the anchor’s age and the broadcast height would reveal when the transaction was prepared.

Two design choices eliminate this leak. First, the version 6 transaction format 2 commits the anchor as authorizing data — a public input to the proof — rather than in the signature hash, so the prover can choose the anchor after signing, and the wallet can update a pre-signed transaction’s anchor and proof at broadcast time without re-signing (see Pre-signed transaction storage). Second, the anchor is drawn at random from the shared candidate set of boundaries rather than pinned to the most recent boundary.

Pinning to the most recent boundary would create a bottleneck at each boundary: the anonymity set for a transaction anchored at boundary \(B\) is the set of wallets that had scanned beyond \(B\) by proving time — a set that an adversary who compromises a light wallet server can approximate by observing which clients have fetched blocks past \(B\) — and shortly after each boundary that set is small. Drawing the anchor at random from all candidate boundaries means an observed anchor implies membership only in the set of wallets that scanned beyond that boundary at some time before broadcast, a set that has had time to grow. This is also why no privacy-preserving block-download mechanism is required for these invariants: the light wallet server learns which wallets have scanned past a given height, but that knowledge narrows the sender of a migration transaction no further than the anchor itself already does.

The randomized draw carries a tension: an earlier anchor requires the transaction’s funding note to have existed at that boundary, so the population able to emit early anchors is bounded by the wallets whose note preparation had confirmed by then — potentially a smaller global anonymity set. This is mitigated by the fact that note preparation can be performed before the network upgrade activates, so the funding notes of many wallets already exist at the earliest post-activation boundaries. The candidate set is nonetheless always restricted to boundaries above the NU6.3 activation height, so that wallets that prepared before the upgrade do not form a distinguishable subpopulation emitting pre-activation anchors.

The draw is recency-weighted rather than uniform over the candidate set, for four reasons. First, uniformity across wallets: under a uniform draw over each wallet’s own window, the anchor-age distribution a wallet emits is a function of when it prepared — early preparers emit anchors spread over a wide window, late preparers only recent ones — so anchor age becomes a statistical fingerprint of preparation date. Under a fixed, capped recency-weighted distribution, every wallet whose window is at least ANCHOR_AGE_CAP deep draws from the identical distribution, and wallets with shallower windows are forced toward recent anchors, where the common distribution already concentrates. Second, the cap bounds the inevitable preparation-time leak: an anchor always places the creation of the funding note before it, but no anchor can reveal more than “prepared at least ANCHOR_AGE_CAP boundaries ago” — little more than the act of broadcasting already reveals. Third, concentration: the same reasoning that prefers canonical denominations to high-entropy amounts prefers few, heavily-used anchors to many thinly-used ones; recency weighting produces large per-anchor cohorts. Fourth, alignment with manual spends: a conforming wallet making a one-off OrchardIronwood spend will naturally use a recent boundary, and keeping the migration flow’s anchor ages similar prevents anchor age from partitioning automated and manual traffic. The cap also bounds the tree states a wallet must retain for proving to the last ANCHOR_AGE_CAP boundaries.

The cost of recency weighting is a sharper posterior on proving time (a recent anchor implies proving shortly after it); this is blunted by the decoupling of proving from broadcast and by the exponential scheduling delay between them, which together turn “shortly after the anchor” into a multi-boundary window. The most recent boundary is excluded entirely because transactions anchored to it could only have been produced by wallets that synchronized within the current boundary interval — the bottleneck in miniature. In the first days after activation, every wallet’s window is shallow and all distributions collapse onto the few boundaries that exist; privacy in that regime rests on cohort size (all migrating wallets share those anchors), not on anchor diversity.

Privacy Implications

The migration necessarily reveals information; the requirements in this ZIP are intended to minimize it and to ensure the user consents to what remains. The principal sources of leakage are:

The remaining subsections of this section are non-normative; they analyze the privacy properties of the procedure specified above.

Threat model

This subsection is non-normative.

The adversary observes all on-chain migration transactions: for each, the net Orchard-out and Ironwood-in amounts and the block (hence time). The adversary does not see addresses. The adversary’s goal is clustering: partitioning the global stream of migration transactions into per-wallet sets. Successful clustering reconstructs a wallet’s migration (and hence its balance and behavior) without any address.

We additionally consider a targeted adversary who augments chain observation with off-chain knowledge of a victim’s incoming note values — in the strongest case having deliberately sent the victim notes of attacker-chosen values (“tagging”). This adversary’s goal is to determine whether, when, or in what amounts the victim has migrated (see On targeted note tagging).

Why value collision provides privacy

This subsection is non-normative.

Privacy for value-transparent transfers comes from value collision (many wallets emitting the same amount) and ambiguity of grouping (an observer cannot tell which amounts belong together), not from unpredictability of the amount. Randomizing amounts is counterproductive: a high-entropy amount collides with no other wallet and is a near-unique fingerprint.

Every part in this design is a canonical denomination drawn from a small shared set (…, 100, 50, 20, 10, 5, 2, 1, 0.5, …). Many wallets emit identical denominations, so no single part is distinctive by its value.

On multiplicity and cohorts

This subsection is non-normative.

A wallet MAY place several parts into the same cohort. This does not let the adversary attribute those parts to one wallet, because:

This is precisely why multiplicity is safe only under canonical amounts.

What a cohort does reveal is only the aggregate throughput of the entire migrating population (the total value of all parts sharing that anchor), which is population-level information, not any individual’s magnitude.

On subset-sum

This subsection is non-normative.

A worry with canonical decompositions is targeted subset-sum (find a subset summing to a known target). This specification accepts the limited residual exposure on the following grounds:

On targeted note tagging

This subsection is non-normative.

An adversary may target a victim by sending notes of attacker-chosen, distinctive values, hoping to recognize those values (or their sum) when the victim’s funds cross the pool boundary. Three mechanisms defeat this:

What the tagging adversary retains is population-level information: that some wallets migrated during a given period. Determining that a specific victim’s funds have — or have not — migrated requires clustering the victim’s transactions out of that population, which the mechanisms above are designed to prevent.

Accepted residual leaks

This subsection is non-normative.

Whale handling

This subsection is non-normative.

For large balances:

A note on cohort size vs. per-wallet multiplicity

This subsection is non-normative.

Two different quantities should not be conflated:

Deployment

This is a Wallet-category ZIP and does not itself introduce consensus rules. It applies to wallets once the Ironwood pool is activated by its network upgrade 8 and the migration becomes relevant. The note-preparation phase MAY be performed before that activation (see Phase 1, Note preparation).

Reference implementation

TODO: link to the SDK and wallet pull requests implementing this flow. Phase 2 is intended to be implemented in a Rust backend exposed through a public SDK interface, so that wallets can integrate against a stable interface (initially with mocked data) and later switch to the production implementation.

Alternatives

The following alternative designs were considered and rejected.

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 229: Version 6 Transaction Format  ↩︎

  3. Zcash Protocol Specification, Version 2025.6.3 [NU6.1] or later  ↩︎

  4. ZIP 200: Network Upgrade Mechanism  ↩︎

  5. Zcash Protocol Specification, Version 2025.6.3 [NU6.1]. Section 3.12: Mainnet and Testnet  ↩︎

  6. ZIP 315: Best Practices for Wallet Implementations  ↩︎

  7. ZIP 209: Prohibit Negative Shielded Chain Value Pool Balances  ↩︎

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

  9. NU6.2 and NU6.3 updates to the Orchard Circuit (draft)  ↩︎

  10. ZIP 2006: Restricting Transfers into the Orchard Pool  ↩︎

  11. ZIP 308: Sprout to Sapling Migration  ↩︎

  12. ZIP 317: Proportional Transfer Fee Mechanism  ↩︎

  13. Tor Project  ↩︎

  14. Nym  ↩︎

  15. ZIP 203: Transaction Expiry  ↩︎

  16. ZIP 244: Transaction Identifier Non-Malleability  ↩︎