P.S. Oh, then the there is number 5 — another longer-term option — the “Long-Term Storage Pool/Sub-pool” idea by Daira-Emma and others. I don’t understand the details yet but the basic idea of sacrificing some functionality (such as transferability, partial privacy, or scalability) in order to be able to use safer, simpler, and post-quantum cryptography sounds like the kind of tradeoff that can work.
By the way, here are formally verified models of the Pallas and Vesta elliptic curves: GitHub - daira/CompElliptic: Computable elliptic-curve abstractions for Lean 4 · GitHub . This didn’t take me very long (a few hours, if you exclude trying to work around Anthropic’s server outages). Claude is very good at Lean.
@fivelittleducks great post, it really it got the gears going for me. I do however want to push back about mitigation list specifically, because I do not think any of the five address the risk they are proposed for.
All five act on honest participants or on the migration window. The run-risk does not live in the migration window. There is no state in which Orchard funds are migratable but not extractable. For value to migrate, it has to be spendable, and once it is spendable the holder can send it anywhere, including out of the pool entirely.
The holder of counterfeit notes has 2 guaranteed exits that none of the proposals touch:
- Exit before Ironwood. Orchard spends were re-enabled at NU6.2. A counterfeit-note holder can unshield or move to another pool today, (capped only by the turnstile)
- Front-run the migration. If they wait, they simply move first once Ironwood opens.
The only two things that would actually bind the attacker are (a) denying the interim exit, i.e. keeping Orchard frozen until Ironwood, and (b) replacing first-come-first-served with a privacy-compatible fair-allocation rule. The first was the soft-fork state during the emergency response and was deliberately lifted at NU6.2 to restore usability, so that trade-off has effectively already been made. The second is constrained by the fact that consensus cannot observe shielded balances to apply an equal haircut. The proposed list is neither of these.
I want to mention none of this is an argument against Ironwood I just wanted to counter the specifc mitigation ideas you mentioned as well as get feedback.
I think Ironwood is a great improvement and will help restore confidence in using the shielded pool.
What I do not fully understand is the need to force users to migrate.
My expected case is that there will always be funds left in orchard (cause there was no actual exploit and legit funds in orchard are lost due to lost keys etc).
If Ironwood is made the default pool in all wallets (which is the reasonable choice and people have lots of incentive to do it), the active supply will move quite quickly.
So I see no reason to change the circuit and consensus so that users are forced to migrate. It only increases complexity of the change (which always adds risks). Furthermore I think that in DeFi, users should not be forced to do things unless its necessary for the correctness of the protocol. And migrating is NOT necessary and actually does not change the correctness. If there has been an exploit, the excess claims to orchard funds is not affected by forcing funds to move to ironwood.
Maybe someone can clarify this point why a forced migration is necessary?
agreed. IF orchard balance goes to 0 (which basically confirms that there was an exploit) we could add a burnfee to each txs which is then used to fill up orchard until it stays positive. This way, the whole ecosystem shares the costs. with high enough usage, this fee can be rather low.
For anyone else having this question, Sean Bowe gave his answer on X: (sorry, I can’t include links)
Forcing users to leave Orchard (through the turnstile) in order to make payments is necessary, or else there is no coherent definition of a supply cap. If people can trade and value ZEC within the Orchard pool as though nothing changed, then people can theoretically transact with more funds than are supposed to exist – without the turnstile being able to identify it.
and:
Restoring confidence in the supply cap and scarcity of ZEC is really important for our project and our social contract. Many of our normal governance functions (like coinholder voting) are affected by this situation so it must be resolved before we can proceed with anything else.
This makes a lot of sense for me. I would still prefer to not force users, but I understand and accept the argument.
This is a good question. I want to echo something Sean said on twitter, that you quoted here, and I want to emphasize it because it is something I care a lot about personally.
As soon as Ironwood activates, you get verification of the current actual supply of ZEC from your full node.
You do not have to wait and see how many ZEC migrate from Orchard to Ironwood and you do not have to do game-theoretic reasoning about how an attacker might behave or how other legitimate users might behave in order to have this verification.
This is important to me, because my goal is to get the most outsiders to start trusting Zcash over the next ten years, and these outsiders can gain trust in Zcash much stronger and much quicker based on their full node verifying the supply directly, instead of based on game theory and based on observation of migrations out of Orchard.
This appears to be super confusing to almost everyone, because they are confusing two different things:
- No counterfeit coins were created.
- The current supply is sound (i.e. 16M ZEC now, 21M ZEC eventually).
These are different things!
I’m prioritizing the second one.
There are two universes we can be in right now
Universe 1: There was an unlimited amount of counterfeit ZEC generated inside the Orchard pool before the vulnerability was closed.
Universe 2: There was not.
The goal of Ironwood is that, regardless of whether we are in universe 1 or universe 2, in both cases everyone gets trustless verification that the supply is sound on Day 1 of Ironwood.
Universe 1: Ironwood activates → On Day 1 you can trustless verify that there are no more than 16M ZEC currently circulating. → Eventually we get a public verification from the turnstile that counterfeiting occurred in Orchard, but this doesn’t change the circulating supply, which is still 16M ZEC now, 21M ZEC eventually.
Universe 2: Ironwood activates → On Day 1 you can trustless verify that there are no more than 16M ZEC currently circulating. → Eventually we start to develop confidence that no counterfeiting ever occurred in Orchard, because less than the correct amount (4.5M ZEC) ever migrates out of Orchard, but this doesn’t change the fact that the circulating supply was correct and was verifiably correct as of Day 1.
Please let me know what you think of this. ![]()
(P.S. There are a few technical caveats to this, and I’m happy to work through all the technical details with anyone in order to help highly technical people gain confidence in the truth of what I say above, but for most people those technical details are not necessary to understand in order to get correct, justified confidence in the truth of the above.)
Very good write up. I totally agree.
I underestimated the part about the trustless guarantee of all circulating supply and that impact on outside trust.
I didn’t confuse the two things, but in my head your point 2 was always just about the funds outside of orchard (which is sound from day 1 too) because “noone who cares would use orchard anymore”. But this ignores that people can still use the fact for FUD.
The more I think about it, the more I agree that closing of orchard is justified. Otherwise we risk unexperienced users to trade within orchard which would provide critics fuel for FUD. “You have to be careful which shielded pool to use, or you end up with counterfeit ZEC” (which in itself leads to even more uncertainty). By closing orchard, this whole vector of FUD is closed at day 1.
Very good choice to close it. thx for helping me understand it.
That is always how it has been specified and implemented. The actual constraints are described in ZIP 209 (which needs to be updated to reflect recent changes; I will do that soon), but the gist is just that each chain value pool balance MUST remain within [0, MAX_MONEY]. There is also a consistency check between two ways of computing the total supply.
If anyone wants to follow along with my own efforts toward formally verifying Orchard, my focus recently has been on CompElliptic, a computable elliptic curve library for Lean. (The elliptic curve support in Lean’s Mathlib is not suited to direct computable use.) It has been going very quickly: in just a couple of days I have formally verified models of the Pallas and Vesta curves, with bridges to Mathlib. Today I’m adding encoding support (abst and repr from the Zcash Protocol Specification). That API allows you to tag depictions of curve points with their intended encoding, and record whether they have been checked to be decodable, canonical, or in specific subsets. Tracking this manually in the Rust code has historically been a significant source of bugs.
CompElliptic is intended to become a general-purpose curve and pairing library that fits into the ArkLib/CompPoly ecosystem, so that its maintenance can be shared across projects. The Zcash-specific parts of the formalization will eventually live in zcash-lean.
I was skeptical about the need for Ironwood but this is indeed the key point that justifies it.
@pjv I think we actually agree on the mechanism — the real difference is about whether it has happened.
Your point is sound: if a large amount of counterfeit ZEC exists in Orchard, the turnstile bounds total exit to the real pool value, so whoever migrates last absorbs the shortfall. That’s a genuine structural dynamic, not FUD, and worth taking seriously.
My view is about likelihood. The evidence points strongly against any counterfeiting having occurred: total supply is intact across the turnstile, the Foundation reports no unauthorized creation, and the exploit is effectively all-or-nothing — it takes under 20 transactions to forge a pool-sized amount. A rational attacker holding a working exploit either drains at scale, which shows up as an anomalous Orchard outflow, or doesn’t move at all. We’ve seen no such drawdown. That isn’t cryptographic proof — a private pool can never rule out a small, unrealized forgery, and the turnstile confirms no net inflation but not the pool’s internal composition, which is exactly why migration matters — but it’s strong evidence the scenario has stayed hypothetical.
So on socializing the loss: I think it’s reasonable to define in advance as a contingency. The cost to weigh is that deliberately inflating to cover a loss breaks the bounded-supply guarantee Ironwood exists to restore — so it belongs on a menu of pre-agreed responses, chosen deliberately, not as the default. And on the current data, the most likely state of the world is that there’s nothing to socialize in the first place.
Hello, I’m a Zcash user and I’d like to know if this migration will be automatic or if I need to make a transaction from an old U address to a new U address to complete the migration. How will the migration work from the perspective of a typical user? Will all wallets, like zingo, have a button for automatic migration?
@idli
Sharp catch, conceded — the migration-gating items (rate-limiting, batching, longer window) act on the wrong surface, since a counterfeit holder just unshields directly post-NU6.2 and skips migration entirely. The only real binds are the two you named: re-freezing Orchard (traded away at NU6.2) or a privacy-compatible haircut (hard — consensus is blind to shielded balances).
But the compensation/backstop items weren’t meant to bind the attacker — they share any loss fairly, which is exactly where your own logic lands: if no rule binds him, fairness can only be restored at the value layer. And all of it only matters in the tail where counterfeiting actually happened — which the evidence argues against: supply intact, no unauthorized creation, no anomalous Orchard drawdown.
Tracking manual style in Rust is a vile task. Thanks for doing this.
@zooko It’s hard for me to tell how much you are obfuscating and even making obvious mis-statements in order to do damage control vs. how much your desire for a particular outcome is warping what you see. I also don’t know what I don’t know and am curious what that is so I’m going to pick apart one little piece of what you wrote, throw out my related thoughts and wait for a response from you or others.
You wrote:
These statements make no logical sense whatsoever. First, since the vulnerability was closed, the word “unlimited” in your universe 1 cannot apply. If unlimited applies, that means it goes on forever (and is right now still going on forever) without a stopping point. I’m guessing what you actually meant was ‘indefinite’ or ‘unrestricted’ which would mean that in the event that there was any counterfeiting at all (prior to the hard stop that did in fact take place) it could have been 1 ZEC or many trillions of ZEC or anything in between.
The way you actually wrote your “universes” there is an obvious third universe which is that there was a limited amount of counterfeit ZEC generated. Whereas what I think you meant is that the two universes are:
- there was some counterfeiting
- there wasn’t
If we are living in universe 2, then there is nothing meaningful to discuss relative to the total quantity and total value of ZEC in existence. It’s obviously a good idea to verify this fact, close any known vulnerabilities, harden guarantees for future ZEC generation, etc.
If we are living in universe 1, then however many total ZEC were counterfeited, there is a meaningful, hard conversation about how the loss of value will be distributed. This is because if we are in universe 1 and some counterfeiting did occur there are more ZEC in existence than there should be, but there is not one ZEC or piece of a ZEC in a shielded pool anywhere in any universe that can be identified as counterfeit. In universe 1 there was counterfeiting, some ZEC were counterfeited, but there are not now any ZEC that can practically be identified as counterfeit. Which is the same thing as saying that there are no counterfeit ZEC while at the same time there are more ZEC than there should be. Which is the same thing as saying that everyone who holds ZEC in the current orchard pool, both the honest and the dishonest, are holding ZEC that have been diluted in value.
The meaningful discussion in universe 1 is how is that loss of value to be distributed. If it is distributed by implementing a turnstile that only allows the “right” amount of ZEC to be migrated from the existing orchard pool to a new valid pool, then that means whoever migrates first gets all the value and whoever migrates last takes the entire haircut. If your position is that this is the right thing to do and that what is more important than a fair distribution of losses is that the total supply of ZEC be returned (again, we’re talking universe 1 here) to the “right” quantity so that the value of the first migrated ZEC and future ZEC is not compromised by the counterfeiting that took place, I think you should say that clearly. Is that your position? Did you ever see the movie The Quick and the Dead?
It seems to me that if it turns out we are living in universe 1, the only ethical thing to do is to acknowledge the dilution of value and let everyone fairly share in that dilution of value. Maybe there is some complex way to do that which is still compatible with a gated turnstile but my mind cannot grasp it. The obvious, simple way to equally fairly distribute the loss in universe 1 is to implement no gating and just allow there to be too many ZEC - however many too many that turns out to be - each of which has less value than it would have if there were no counterfeiting in universe 1’s history. If there was a little counterfeiting, then the value loss is small for everyone. If there was a lot of counterfeiting, then the value loss is large for everyone. If there was a huge amount, then it’s probably approaching a total loss for everyone. If there was no counterfeiting, then we are living in universe 2 and there is nothing whatsoever to discuss about who takes the loss.
So far, every argument that I’ve read against discussing how to deal with the value loss in universe 1 boils down to an assertion that we are living in universe 2 despite the fact that we actually do not know for certain whether that is the case. I personally believe that we are living in universe 2, but universe 2 is pleasantly boring and requires no discussion. The fact is that universe 1 has not yet been ruled out and if you are going to make a technical policy about how to distribute losses in the universe 1 case by assuming the universe 2 case (IOW, it’s ok to create arbitrary winners and losers by migration timing because we believe there will be no losses to eat), that’s completely ethically messed up.
@fivelittleducks Sorry but I can’t make any sense out of your reply.
I don’t think we have any differences over whether “it happened” because I think we both understand that we don’t actually know whether it did or didn’t happen. It also seems like we both believe that it is unlikely that “it happened”. So no difference there.
See my post above in reply to Zooko for the ethical reasoning behind my position about inflation in the unlikely event that “it happened.” I don’t believe that “we think it didn’t happen” is a valid ex ante argument for building a mechanism that will guarantee arbitrary winners and losers if it turns out that “it happened.”
@pjv
What I want to do here is not argue for a final conclusion, but lay out a few constraints that all of us, wherever we start from, have to build on:
First, on scale. The turnstile puts a hard ceiling on the worst case: the most that could ever be affected is the real value recorded in the old Orchard pool — a small fraction of total supply, and never a multiple of it, because any counterfeit beyond that amount simply cannot be spent. And every observable signal so far points to nothing having happened. What we’re discussing is a bounded, low-probability tail, not an unbounded catastrophe.
Second, the genuinely hard part. Because honest and counterfeit notes are indistinguishable — and an honest holder can’t even prove their own note is clean — no mechanism can compensate honest holders without also compensating whoever may have counterfeited. And conversely, doing nothing and letting the turnstile’s default outcome stand means the real loss falls on whoever migrates last. Both paths carry a cost. This isn’t an argument for or against any particular approach; it’s simply a fact that the “protect users” and “protect the supply” instincts both have to confront. It’s what makes this genuinely hard, rather than a simple matter of choosing to do right by people.
As for the choice that remains — whether to absorb a small, bounded residual in order to preserve a verifiable supply, or to spread it across everyone and accept a limited break in that guarantee — that, to my mind, is a real values decision for the community and the protocol’s stewards. It deserves a
deliberate process, not a verdict handed down in a forum thread.
So I don’t think we really disagree. You’re pushing the community to decide fairly, and in advance, and that’s exactly right. I’d just rather treat this as a contingency we prepare for together than as something that has already happened — because on the current evidence, the most likely reality is that there’s nothing to allocate at all.
I don’t live in either universe 1 or universe 2. None of us do. Although they sound like wonderful places to discover new frontiers of analysis paralysis, action rather than abstraction is unequivocally the rational approach here. While there are infinite theoretical possibilities, the results of actions taken are far easier to parse, process and deal with.
A vulnerability was probed for and one was detected. It was addressed. There is no evidence of exploitation, but migration and verification are logical next steps. There is a pragmatic imperative here to simply address an operationally urgent situation in a measured and comprehensive way.
Debates about whether the cat in the box is dead or alive are no more interesting to me than waxing about how many angels can fit on the head of a pin.