[ZIP 318] Orchard to Ironwood migration#1317
Conversation
Co-authored-by: Pacu <francisco.gindre@gmail.com>
8ece50f to
5df468a
Compare
5df468a to
8c18192
Compare
…ration draft This unifies two earlier Orchard-to-Ironwood migration drafts into a single Wallet best-practices draft: - Adopts the issue #1315 "Path A" mechanism as the normative wallet flow: a two-phase process (mandatory note-splitting send-to-self, then scheduled, pre-signed, background-broadcast migration transactions de-correlated from app opens), with best-effort background scheduling (iOS BGTaskScheduler / Android WorkManager), an on-launch fallback, sync decoupled from broadcast, a Tor opt-in network-privacy step, and detailed progress/error/platform requirements. - Folds schell's canonical power-of-ten quantization in as the RECOMMENDED amount-selection heuristic inside the Phase 2 split/scheduling algorithm, with the collision-privacy argument as rationale and random amounts listed among rejected alternatives. - Unifies the timing concept: Path A's ~6h anchor-height buckets and schell's height-mod-M boundaries/cohorts are merged into one network-wide bucket/boundary scheme forming cohorts that mix wallets. - Keeps schell's non-normative analysis (consensus context, why amounts leak, threat model, why collision provides privacy, multiplicity/cohorts, subset-sum, accepted residual leaks, whale handling, anchor selection) and his rejected-alternatives table, extended with Path A's rejected on-open approach. - Resolves the state conflict explicitly: the mechanism is stateful (persisted schedule + pre-signed transactions); statelessness/multi-device recovery are non-requirements. The stateless, chain-recoverable approach is preserved as a discussed rejected alternative with its tradeoff rationale. - Updates preamble (dual owners, Kris credit, issue #1315 discussions link) and adds user-path and error-case appendices as non-normative details blocks. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
8c18192 to
d6ffeaf
Compare
| The migration flow MUST satisfy the following high-level goals. The Specification | ||
| section defines how they are met; this section does not itself impose conformance | ||
| requirements beyond those. | ||
|
|
||
| * The user MUST be able to migrate *Orchard-pool* funds to the *Ironwood pool*, | ||
| and MUST be informed that doing so is necessary to retain access to those funds. | ||
|
|
||
| * The wallet MUST obtain the user's consent, before any funds leave the | ||
| *Orchard pool*, to the public revelation of pool-crossing amounts, consistent | ||
| with ZIP 315. [^zip-0315] | ||
|
|
||
| * All *Orchard-pool* funds at or above the dust floor SHOULD eventually be | ||
| transferred to the *Ironwood pool*. | ||
|
|
||
| * By default the migration SHOULD de-correlate individual transfers from each | ||
| other and from the user's interaction with the application, to the extent | ||
| practical on the target platform. In particular it SHOULD mitigate leakage of: | ||
| the linkage of particular migration transactions to one another (clustering); | ||
| information about the distribution of individual note values; and information | ||
| about a wallet's total balance. | ||
|
|
||
| * The migration SHOULD let a user complete migration with a small number of | ||
| signing sessions for typical balances, because adoption drives the size of the | ||
| anonymity set on which everyone's privacy depends. | ||
|
|
||
| * The migration SHOULD complete reliably even when best-effort background | ||
| scheduling does not run, without requiring the user to keep the application in | ||
| the foreground. | ||
|
|
||
| * The user MUST be given an informed choice about network-layer privacy (Tor or | ||
| VPN) before the migration begins. | ||
|
|
||
| * The wallet MUST report migration progress and MUST NOT present the fallback | ||
| (prompting on the next application open) as an error. | ||
|
|
||
| * The migration MUST adapt safely when the user spends *Orchard-pool* funds | ||
| outside the migration, when scheduled transactions expire, or when the | ||
| application is reinstalled. |
There was a problem hiding this comment.
nit: requirements don't use conformance language; these are bounds that we evaluate against to determine whether the specification below satisfies the requirements.
There was a problem hiding this comment.
Good point — updated in 4d46580. The Requirements section no longer uses BCP 14 conformance keywords; the goals are now stated as plain declarative bounds ("The user can migrate…", "All Orchard-pool funds… are eventually transferred…", etc.), and the intro clarifies that these are the bounds the Specification is evaluated against, with conformance language reserved for the Specification section.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Address review: the Requirements section stated high-level goals using BCP 14 conformance keywords (MUST/SHOULD/etc.). Requirements are bounds the Specification is evaluated against, not conformance requirements themselves, so restate them in plain declarative language and keep the conformance keywords to the Specification. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| * The exact splitting heuristic (number of notes and their sizes) is an open | ||
| point for the Zcash core team. Sizing notes so that the canonical denominations | ||
| of [Amount selection, canonical quantization](#amountselectioncanonicalquantization) | ||
| can each be funded without waiting on change is a natural target. |
There was a problem hiding this comment.
Should we include note consolidation here too? Is that a viable alternative?
If I have two Orchard notes of 4, 6 + N ZEC, where N is the amount I would need to pay as fee for a consolidation transaction, wouldn't it make more sense to just consolidate instead of splitting my notes into ten 1 ZEC notes?
There was a problem hiding this comment.
The ideal is that you split your balance into transactions that are fee inclusive in a way that the balances can't be easily be deduces as belonging to the same wallet.
…sent ZIP 318 (zcash/zips#1317, Turnstile section) confirms the spec target: payments to Orchard receivers must travel as Ironwood once NU6.3 activates. The pinned zebrad/librustzcash stack does not yet enforce that routing, and the 2026-07-14 live runs adjudicated the open hypotheses the other way: coinbase and ordinary sends still land as legacy Orchard notes with V5-era fees. The ADR now states both layers and defines the live suite's i: 0 assertions as canaries that flip to the spec-target expectation when the stack catches up, rather than regressions. The glossary attributes the receiver-routing rule to the ZIP 318 Turnstile and gains a Turnstile entry, so the Ironwood entry no longer presents unenforced spec behavior as an observed chain fact. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
This can be renamed to zip-0318.md since the ZIP number has now been assigned.
|
Shielded Labs has written a threat model doc, visible to anyone who has this link: https://docs.google.com/document/d/1z4Aj7tO34RKk0SXZYkNXtswxdBXKbR_IJ_Xw5EJljkc . It includes a slightly different algorithm for selecting amounts and timings and anchors (Appendix A), but don't get hung up on that! The point of the document is that Appendix A is much less important for practical protection of real users than the other parts. :-) And, as described in that document, we currently think that it is not necessary for all or many wallet implementations and users to use compatible (indistinguishable on the blockchain) migration transactions, so that's another reason that Appendix A is less important than the rest of it. Please review! If there are any major errors in this doc, please let us know ASAP. The main recommendation is to use Tor/Nym in specific ways, and we don't yet know how feasible this will be, and Zodl in particular is at the head of the class on that particular area, so please teach us. |
Generalize Phase 1 from note splitting to note preparation, covering the full spectrum of existing note distributions (splitting, joining, or both). Preparation is restated as the pre-signing prerequisite: an exact-value funding note must exist on-chain for every scheduled part. Specify the canonical migration transaction shape as exactly one Orchard spend padded to two actions and one Ironwood output, so that the presence of change is unobservable and automated migration transactions are indistinguishable from manual Orchard -> Ironwood spends. Document the consequences: an enlarged anonymity set, change carrying operational cost but no privacy penalty, and owner-side chain recovery disambiguated by viewing-key information. Update the residual rule (deterministic sub-DUST_FLOOR remainder), error handling (preparation partitioning, canonical fee changes), and open issues accordingly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Remove the Ironwood pool exposition from the Abstract and lead the Motivation with the primary purpose of the pool: enabling verification of the Zcash shielded supply after NU6.2 mitigated an Orchard circuit soundness flaw. Remove the non-normative "Consensus context" section, folding its load-bearing content into the sections that use it: the turnstile and migration necessity into the Motivation, the routing-change scope exclusion into the Motivation's goal paragraph, the post-upgrade old-pool population argument into the canonical-transaction-shape rationale, and the predicate/consensus-shape alignment into the amount-selection section. Well-known pool mechanics are dropped in favor of references. Remove the "Why amounts leak" section; the Motivation now simply notes that pool-crossing transfers reveal net amounts, keeping the corollary that amount shape and broadcast timing are the only privacy levers. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Move amount selection into Phase 1 as its first step, since the note
preparation transactions cannot be constructed without the target note
values; the canonical migration transaction structure remains in Phase 2
under its own heading.
Replace pure power-of-ten denominations with the 1-2-5 series
(v = n * 10^k, n in {1, 2, 5}), with 10000 ZEC as the largest
pool-crossing denomination and DENOM_CAP = 10000 ZEC plus the canonical
fee bounding funding-note values. Add an optional randomized
decomposition for balance hiding, with provisional selection frequencies
biased toward larger denominations.
Fix the canonical note-preparation transaction size at 16 Orchard
actions (provisional) and require confirmation to the end of the anchor
epoch before prepared notes are spendable.
Rename DUST_FLOOR to MAX_RESIDUAL_VALUE, define both quantization
parameters at first use, and add a terminology entry giving the privacy
rationale for the residual: preventing small user-identifying amounts
from leaking in pool-crossing transactions.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…t model Break the single de-correlation requirement into named privacy invariants: transfer unlinkability, behavioural de-correlation, balance privacy, note-distribution privacy, holdings-concentration privacy, and migration-status privacy (resistance to note tagging by an adversary seeking to learn whether a victim has migrated). Extend the threat model with the targeted adversary who knows or chooses a victim's incoming note values, and add a non-normative analysis of why note tagging fails: quantization severs received values from migrated values, note preparation absorbs tagged notes invisibly, and randomized decomposition makes the emitted multiset unpredictable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ection Rewrite Transfer scheduling: parts are shuffled into random order, then scheduled in block deltas with inter-transfer delays drawn from an exponential distribution (mean MEAN_DELAY = 144 blocks, draws above MAX_DELAY = 576 blocks redrawn), forming a Poisson process; all scheduling and decomposition randomness requires a CSPRNG. Background processing windows either synchronize (updating anchors and proofs of upcoming transactions) or broadcast, never both. A new rationale subsection covers memorylessness, Poisson superposition, the need for delays comparable to the bucket interval, and why routine background synchronization is safe under shared boundary anchors. Specify bucketed expiry heights: the most recent multiple of EXPIRY_MODULUS (34560 blocks) plus 69120, a one-to-two-month rolling window shared by every wallet constructing in the same 30-day period. Set the anchor bucket modulus M to 144 blocks (3 hours), equal to MEAN_DELAY and an exact divisor of EXPIRY_MODULUS; the prior 256 was a holdover from a predecessor draft. Update Pre-signed transaction storage and the anchor-selection rationale to reflect that the version 6 format commits anchors as authorizing data, so pre-signed transactions' anchors and proofs are updated at broadcast time without re-signing. Replace the Rejected-alternatives table with a top-level Alternatives section (per the ZIP 231 precedent), adding short-interval memoryless timing as a rejected alternative, and strip references to the predecessor drafts throughout. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace previous-boundary anchor pinning with a randomized draw from the candidate anchor set: boundaries above the NU6.3 activation height, at or after the funding note's creation, and at or before the most recent boundary observed at proving time. Pinning to the newest boundary would bottleneck the anonymity set at each boundary to the wallets that had already scanned past it — a set a compromised light wallet server can approximate — and shortly after each boundary that set is small. A randomized anchor implies only that its creator scanned beyond that boundary at some time before broadcast; consequently no privacy-preserving block-download mechanism is required for the document's invariants. Weight the draw by recency: the anchor age in boundaries is geometric with parameter 1/2 over ages >= 1 (the most recent boundary is never used), capped at ANCHOR_AGE_CAP = 16 boundaries and truncated to the candidate set. The rationale records the trade-off analysis: a fixed, capped distribution makes anchor age identical across wallets rather than a fingerprint of preparation date, bounds the inherent preparation-time leak, concentrates transactions into large per-anchor cohorts, aligns with the recent anchors of manual cross-pool spends, and bounds proving-state retention; the cost, a sharper posterior on proving time, is blunted by proving/broadcast decoupling and the exponential scheduling delays. Redefine cohorts as transactions sharing a boundary anchor, note that M no longer affects migration speed, and update the synchronization-timing analysis, fallback rescheduling, and open issues accordingly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Reconcile the specification with the Poisson schedule and randomized anchors: multiplicity now emerges from the anchor-age draws (K_MAX enforced by redrawing), the signing-session machinery is replaced by single-session authorization with additional sessions only for multi-layer preparation not pre-signed as a chain, and stale pinned-anchor phrasing is updated throughout (terminology, overview, whale handling, accepted leaks, open issues). Represent layered preparation: when a funding note must combine value from more notes than one transaction can spend, or a large note must be divided into more funding notes than one transaction can produce, preparation proceeds in layers that may be signed in a single session but cost one bucket interval each to prove and broadcast. Layered splitting (whales) and layered consolidation (many small notes) are indistinguishable on-chain. Correct the pre-signing justification: Orchard nullifiers are position-independent, so the schedule can be signed as soon as the preparation transactions are constructed; only proving requires mined notes and a candidate boundary anchor. Adopt NU6.3 action-counting semantics (actions = spends + outputs, each paired with a fabricated counterpart), updating the canonical-shape mechanism text and the 16-action preparation budget (fan-in/out ~15). Surface the migration entry point once NU6.3 is scheduled, enabling pre-activation preparation; align the network-privacy section with the Requirements by offering Nym alongside Tor; replace the undefined "anchor epoch" term with anchor-height bucket. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
|
||
| ### Note preparation transactions | ||
|
|
||
| A migration transaction spends exactly one *Orchard-pool* note (see |
There was a problem hiding this comment.
Human review/implementation note (will be edited) - don't review:
Let's define
The value
The user wallet has
We want at the end to have a set
The problem of note preparation is actually a note consolidation problem, which is actually a system of multilinear equations, where variables are existing notes, quanta and changes, with "selectors" between rows to pick or not the previously created changes.
The problem is to create
For each quantum
with
The change will go back to a change address authorized by the Orchard pool after NU6.3. This change will become part of a set
The consolidation problem will happen in layers, which we can see as a finite sequence of intermediary set
If we develop the set of
with
We can relax the system by having a set of system of equations (or layers) where all
There was a problem hiding this comment.
Note: we're getting a DAG of notes.
Summary
This PR rewrites
zips/draft-schell-ironwood-migration.mdin place into asingle unified draft that integrates two earlier Orchard-to-Ironwood migration
drafts: the stateful, background-scheduled wallet flow from issue
#1315 ("Path A") and this branch's
stateless, canonical-quantization proposal. Editing the same file keeps the
review diff clean as an update/counter-proposal to the existing draft.
How the two designs were reconciled
note-splitting (wallet-internal send-to-self), then (2) scheduled, pre-signed,
background-broadcast migration transactions de-correlated from app opens.
Best-effort background scheduling (iOS BGTaskScheduler / Android WorkManager)
with an on-launch fallback; synchronization decoupled in time from broadcast;
Tor opt-in network-privacy step; detailed progress, notification, platform,
and error-handling requirements.
heuristic inside Phase 2's split/scheduling algorithm. The split now produces
canonical power-of-ten denominations rather than high-entropy random sizes,
with the collision-privacy argument as rationale; "random arbitrary/partitioned
amounts" are listed among rejected alternatives.
height ≡ 0 mod Mboundaries/cohorts (~5.3h) are merged into a singlenetwork-wide bucket/boundary scheme forming cohorts that mix wallets. The
shared previous-boundary anchor and the auth-data forward-looking
recommendation are retained.
schedule + pre-signed transactions); statelessness and multi-device recovery are
non-requirements (per [ZIP 318] Orchard to Ironwood Migration #1315). The stateless, chain-recoverable approach is
preserved as a discussed rejected alternative with its tradeoff rationale,
not silently dropped.
Where schell's analysis was preserved (non-normative)
The following are kept and clearly marked non-normative: Consensus context, Why
amounts leak, Threat model, Why value collision provides privacy, On multiplicity
and cohorts, On subset-sum, Accepted residual leaks, Whale handling, cohort size
vs. per-wallet multiplicity, Rationale for anchor selection, and the
Rejected-alternatives table (extended with Path A's rejected on-open / "Path B"
approach and the stateless alternative).
Path A's user-path and error-case material is included as non-normative
appendices in
<details>blocks.Preamble / conventions
Dual owners (Schell Carl Scivally, Pacu Gindre), Kris Nuttycombe credited,
Status: Draft,Category: Wallet,Discussions-To→ issue #1315. BCP 14boilerplate lists only the keywords actually used. Validated with
multimarkdown:definition lists render (10
<dt>), no unresolved footnote refs, every internal(#anchor)link resolves to a generated id, and all headings are unique.Refs #1315. This integrates that issue's "Path A" specification; it intentionally does not use a closing keyword, since the issue should remain open as the discussion thread and this PR targets a feature branch rather than the default branch.
AI disclosure
Claude Opus 4.8 was used to integrate and draft this unified document under
maintainer direction; the human contributor is the responsible author. The commit
carries the corresponding
Co-Authored-By:trailer.🤖 Generated with Claude Code