Orchard to Ironwood Migration

Orchard and Ironwood are tracked as separate value pools. An Orchard-to-Ironwood transaction publishes two value balances: the amount leaving Orchard and the amount entering Ironwood. The notes, receivers and ownership remain shielded, but the amount moved between pools is public.

Moving an entire Orchard balance at once would reveal that balance. ZIP 318 instead divides it into common denominations and sends them over time. Every migration amount is public, but using the same amounts and timing as other wallets makes the transactions harder to group into one balance.

Consensus Context

ZIP 258 makes the old Orchard pool withdrawal-only at NU6.3. It does so with two consensus rules:1

  • valueBalanceOrchard must be nonnegative, so value may leave Orchard but no new value may enter it.
  • Every Orchard Action has enableCrossAddress = 0, so its output expanded receiver must equal the expanded receiver of its spend.

The rules apply to Orchard Actions in both V5 and V6 transactions. Wallets send new payments for Orchard-protocol receivers through Ironwood; old Orchard is left for note management and withdrawals.

When a wallet spends a note worth more than it needs, it returns the remainder to itself in a change note. Setting enableOutputs = 0 would prohibit both payments and these change notes, leaving the wallet able to withdraw only exact sums of its existing notes. enableCrossAddress = 0 is narrower: it permits an output back to the spent note's expanded receiver, while rejecting an Orchard output to another receiver.2

Why Amounts Leak

Each Orchard-protocol bundle publishes its net balance: spends minus outputs. For a migration part that moves X ZEC and pays a fee F from Orchard, the public values are:

  • valueBalanceOrchard = +(X + F)
  • valueBalanceIronwood = -X
  • fee = F

Here, X is the canonical migration amount and F is the transaction fee. Both are public. The proof binds the hidden Actions to these values, allowing nodes to account for the pools independently and reject a withdrawal that exceeds prior inflows.3 A wallet can vary only the amounts and broadcast times of its migration transactions.

valueBalanceOrchard= + (X + F)valueBalanceIronwood= − XOrchard poolspends · outputsnotes & receivers hiddenIronwood poolnew notealso shieldedturnstileThe canonical amount X and transaction fee F are both public.

Wallet Migration Strategy

ZIP 318 defines the two-phase wallet flow now being implemented: first create the notes needed for the schedule, then send the scheduled transactions.4

PHASE 1 · SPLIT (SEND-TO-SELF)existing Orchard notesprepare notesinternal send-to-selfexact funding notesQuantizes, splits and/or combines into independent funding notes. They mine, then wait for a boundary.PHASE 2 · SCHEDULED PARTSeach part is funded by one prepared noteIronwoodpoolpart100.0→ Ironwoodpart20.0→ Ironwoodpart2.0→ Ironwoodpart0.5→ Ironwoodshuffled schedule · independent exponential broadcast delaysEach part: one Ironwood output · canonical fee & expiry · anchor drawn from shared past boundaries.Before the first part, the wallet shows the whole schedule and gets consent to these public amounts (ZIP 315).

Note Preparation

The wallet first quantizes its migratable balance into canonical denominations: n × 10^k ZEC, where n is 1, 2, or 5. The current ZIP 318 draft leaves a residual below 0.01 ZEC in Orchard and caps a single migrated denomination at 10,000 ZEC. It may randomize the decomposition, but every resulting amount must remain one of those common values.4

One or more Orchard send-to-self transactions then create the exact funding note for each planned part: denomination plus its canonical fee. Preparation can split large notes, combine small ones, or do both. Each transaction has no external receiver; the mobile guidance pads it to 16 Orchard Actions. Large or fragmented balances can use several preparations, including dependent layers. A wallet whose notes already exactly fund the schedule can skip preparation.

Preparation uses an ordinary near-tip anchor. Once a preparation output is mined, however, the wallet waits for the boundary that closes its bucket before using it in a pool-crossing migration transaction. This ensures that a shared boundary is available as the later transaction's anchor.4

Scheduled Migration Parts

The second phase sends one canonical denomination per transaction. Each part has exactly one Orchard spend, padded to two Orchard Actions, and one unpadded Ironwood output. It has no transparent inputs or outputs, no spends from any other pool, a canonical fee, lock_time = 0, and a canonical expiry. Orchard outflow is the denomination plus fee; the Ironwood output is the denomination. The expiry is bucketed from the planned broadcast height, yielding one to two months of validity in the current draft.4

The wallet shuffles the parts and schedules independent, truncated exponential delays between them (currently a 144-block mean and a 576-block maximum). At proving time it draws the Orchard anchor from a recency-weighted set of shared, past boundary heights—not from the wallet's tip or from the planned broadcast height. The schedule is pre-authorized and stored; version 6 allows its anchor and proof to be updated without another signing session.4

Best-effort background work either synchronizes and updates upcoming proofs or broadcasts, never both in the same window. On every later application open the wallet reconciles overdue parts, warns if an immediate send weakens privacy, and never sends more than one overdue part in that session.4

Before anything leaves Orchard, the wallet shows the complete schedule and asks the user to accept the public amounts, following ZIP 315. It offers a network-privacy step with Tor and, where available, Nym; if neither is available, it should suggest a trusted VPN and explain the IP-correlation risk. The user may still proceed without one. A one-transaction migration remains possible, but the wallet must identify it as the less private option.4

Privacy Argument

Random-looking amounts are bad camouflage. A value such as 3.7194 ZEC is likely to be unique on chain, and a set of unique parts can be searched for a sum that reconstructs the migrated balance. ZIP 318 instead chooses from the common 1, 2, and 5 × 10^k denominations. If many wallets follow the same rule, their transactions collide by value and the amount alone does not identify a wallet.4

RANDOM PARTITION3.71941.20560.84312.1319sums to oneexact balance→ subset-sumcan link partsEach amount is a near-unique fingerprint.CANONICAL DENOMINATIONS20.020.02.00.5may be sharedby many wallets→ value alonedoesn't identifyA common value can collide with other wallets.Broadcast timing is separated from wallet activity.Parts are shuffled and spread by independent, scheduled delays. The operating system chooses the execution timewithin each requested window; anchors are drawn from shared past boundary heights.

Canonical amounts can still be clustered if timing identifies their source. ZIP 318 separates the planned broadcast height from anchor selection: it shuffles the parts, spreads them with independent exponential delays, and at proving time chooses each anchor from eligible shared past boundaries. The recency-weighted draw makes the most recent boundary ineligible and avoids revealing an individual wallet's synchronization height. The operating system still chooses the exact execution time within a requested background window.

This is camouflage, not an anonymity proof. Amounts and block times remain public. A small cohort, a known balance, a large holding, repeated denominations or distinctive wallet behavior can collapse the ambiguity. Direct submission can also expose the wallet's IP address. The current draft supplies provisional values for the denomination cap, residual floor, boundary interval, delays, expiry, and multiplicity controls; those values may change while ZIP 318 remains a Draft.4

Restricted Bundle Construction

enableCrossAddress is bit 2 of the bundle flags. It uses the enabled sense: 1 permits an ordinary transfer, while 0 requires the spend and output in an Action to use the same expanded receiver. Inside the circuit, the corresponding public input has the opposite name and polarity: disableCrossAddress.3

This changes how the Orchard builder assembles Actions. With cross-address transfers disabled, it constructs complete spend/output pairs:2

  • Each real spend is paired with a fabricated zero-valued output at the spent note's expanded receiver.
  • Each change output is paired with a fabricated wallet-controlled zero-valued spend at the change receiver.
  • A requested Orchard output to any other receiver causes construction to fail.

The fabricated output paired with a real spend cannot carry a normal note ciphertext. Anyone with the receiver's incoming viewing key could decrypt that output in the same Action that publishes the spend nullifier, linking the two. A future adversary may also recover the incoming viewing key before it can recover the nullifier key. The builder therefore fills enc_ciphertext with random bytes. ZIP 326 makes this wallet and signer behavior explicit.5

enableCrossAddress = 0 · bit 2 of the bundle flagsoutput receiver must equal the spend's expanded receiverPAIR A · REAL SPENDreal spendvalue v · receiver R+fabricated outputzero value · receiver Rrandomized enc_ciphertextA normal ciphertext would let anincoming-viewing-key holder linkthe spend's nullifier to R.PAIR B · CHANGE OUTPUTfabricated spendzero value · receiver R′+change outputvalue c · receiver R′Change stays at the samereceiver R′, so no valuecrosses to another user.An Orchard output to any other receivercauses construction to fail — ordinary payments between users cannot use the Orchard pool.

PCZT and Hardware-Wallet Support

A background schedule is practical only if a hardware wallet does not have to review every transaction again at broadcast time. Version 6 helps by moving the Sapling, Orchard and Ironwood anchors out of effecting data and into authorizing data. Re-anchoring no longer changes the transaction ID. A wallet can collect spending authorization first, then attach the final witness, anchor and proof before broadcast.3

effecting data fixes the transaction ID — replacing an anchor does not change it1 · BUILDFix effecting dataCreate the PCZT and itstransaction ID withoutcommitting to an anchor.2 · AUTHORIZEReview and signThe hardware wallet checksthe batch and returns acompact signature set.3 · FINALIZEFill & broadcastBackground work adds thewitness, anchor and proof,then sends each part.Keystone, 10-note migration:≈ 15 min → ≈ 2.5 minfirmware development benchmark,not a protocol claim

The supporting librustzcash work added anchor updates, witness updates, batch-signing messages, and a preverified signer path that avoids redundant full-viewing-key derivation on constrained devices.

Keystone reviews the PCZT batch atomically, shows one aggregate migration summary, reuses verified state across the batch and returns signatures instead of full PCZTs. Its ten-note development benchmark fell from roughly 15 minutes to 2.5 minutes end to end.6 That is a firmware benchmark, not a protocol performance claim.

Moving the notes also changes their recovery properties. ZIP 2005 gives Ironwood notes the material needed by a future recovery protocol if the current discrete-log-based protocols have to be suspended. Notes left in Orchard do not have that material.7

Specification Status

ZIP 258 and ZIP 229 define the deployed consensus rules. ZIP 318 is a Draft Wallet ZIP that specifies the current migration procedure; its current provisional parameters include a 0.01 ZEC residual floor, 10,000 ZEC denomination cap, 144-block anchor boundaries, and 30-day expiry buckets. ZIP 2006 remains a reserved stub, so the detailed cross-address behavior is documented in ZIPs 229 and 258 and in the Orchard implementation.

See Ironwood Resources for the rest of the specification and implementation links.