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)a few large notessend-to-self txno external receiverindependent notesCreates independently spendable notes. The split must confirm before those notes fund migration parts.PHASE 2 · SCHEDULED PARTSeach part is funded by one of the split notesIronwoodpoolpart10.0→ Ironwoodpart10.0→ Ironwoodpart1.0→ Ironwoodpart0.1→ Ironwoodassigned to future height buckets & scheduled broadcast windowsEach part: one Ironwood output · canonical fee & expiry · shared-bucket anchor · no other pool.Before the first part, the wallet shows the whole schedule and gets consent to these public amounts (ZIP 315).

Note Splitting

The wallet begins with an Orchard send-to-self transaction. Its outputs can fund later migration parts independently, rather than making each part wait for change from the previous one. The split has no external receiver and must confirm before the schedule can spend its outputs. A wallet whose existing notes already fit the schedule can skip it.

The exact split heuristic is still being finalized together with the denomination cap, dust floor, fee accounting and practical Action limits.

Scheduled Migration Parts

The second phase sends one canonical power-of-ten denomination per transaction. Each transaction has one Ironwood output, no transparent or other shielded-pool component, a canonical fee and expiry, and an Orchard anchor from a network-wide height bucket. Orchard outflow is the denomination plus fee; the Ironwood output is the denomination.

The wallet saves and pre-authorizes the schedule. Best-effort background work broadcasts each part later. Synchronization and broadcast happen at different times, making it harder for a light-wallet server to pair a scan request with a send. If the operating system misses a background window, the wallet resumes the schedule the next time it opens.

Before anything leaves Orchard, the wallet shows the complete schedule and asks the user to accept the public amounts, following ZIP 315. It also offers a choice of direct submission or a private network path such as Tor or a VPN.4 A one-transaction migration remains possible, but the wallet must identify it as the less private option.

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 powers of ten. 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 DENOMINATIONS10.010.01.00.1may be sharedby many wallets→ value alonedoesn't identifyA common value can collide with other wallets.Broadcast timing is separated from wallet activity.Parts are assigned to future height buckets. The operating system chooses the execution timewithin each requested window; every wallet in a bucket uses the same boundary anchor.

Canonical amounts can still be clustered if timing identifies their source. ZIP 318 assigns each part to a future anchor-height bucket and separates broadcasts from wallet synchronization and application opens. The operating system chooses the exact execution time within the requested window. Every wallet broadcasting in the same bucket uses the previous boundary as its Orchard anchor, so the anchor does not reveal an individual wallet's synchronization height.

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. ZIP 318 leaves the denomination cap, bucket size and per-wallet multiplicity open because those parameters depend on adoption and observed migration traffic.

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 defines the wallet procedure now being implemented. Its split algorithm, DENOM_CAP, DUST_FLOOR, anchor-bucket modulus, expiry policy and multiplicity limits are still being finalized. ZIP 2006 is currently 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.