Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Review Ycash fork to ensure Ycash nodes will not cause problems on the Zcash network #4007

Open
daira opened this issue May 10, 2019 · 17 comments

Comments

@daira
Copy link
Contributor

commented May 10, 2019

Ycash is a proposed chain fork of Zcash (not endorsed by Electric Coin Company or the Zcash Foundation): https://github.com/ycashfoundation/ycash/

Based on the PR #3978 that was mistakenly targeted to this repo, it looks like they will be handling the fork using the Network Upgrade mechanism. This is generally a good approach that guarantees a bilateral fork with replay protection. There is no change to the network magics, though; unless additional changes are made, Ycash nodes will continue to receive (invalid, from their point of view) Zcash blocks and vice-versa.

@daira daira added this to Needs Prioritization in Protocol Team via automation May 10, 2019

@tromer

This comment has been minimized.

Copy link
Contributor

commented May 10, 2019

There's still the privacy problem of pre-fork notes being linkable when spent on both sides of the fork (since they use the same nullifier).

That's inherent to any Zcash state-fork. Is there a suggested mitigation?

@zookozcash

This comment has been minimized.

Copy link

commented May 11, 2019

How about this for a suggested mitigation: run the Migration Tool on one or both forks, but instead of migrating from Sprout pool to Sapling pool, it migrates from the Sapling pool back into the Sapling pool. Now you just have to run the Migration Tool one time after the fork on at least one (preferably both) of the two forks, before you otherwise spend any notes on either fork, and your linkability problems are solved! 🙂

@tearodactyl

This comment has been minimized.

Copy link

commented May 11, 2019

Can we assume that Y will snapshot and then startup a separate network on a different port, with own seeds, pools, explorer, etc?
@daira two years later, is this idea still valid? https://forum.zcashcommunity.com/t/zclassic-zencash-trading-suspended-due-to-replay-attack/16927/6
@leto is SIGHASH_FORKID still the standard for replay protection?

@hloo

This comment has been minimized.

Copy link

commented May 11, 2019

@daira, I appreciate you opening up this issue. (And I apologize for the mistakenly targeted pull request.) I have asked the engineers working on Ycash to interface with the ECC (and all other interested parties) via this issue.

We are implementing additional changes to make the forking event go as smooth as possible. In addition to changing the BRANCH_ID specified by ZIP 200, we are also changing the Protocol Version number. I'll let the engineers actually working on the code chime in with the details, but my understanding is that peers with different Protocol Version numbers will disconnect from each other.

@tearodactyl The Network Upgrade mechanism described in ZIP 200 and introduced in Overwinter provides replay protection, and we are using that mechanism, not SIGHASH_FORKID. (@daira's forum post that you linked to was written pre-Overwinter, and the post itself alludes to the replay protection that was coming in Overwinter.) Yes, we'll use different port numbers and we'll have our own seeder. As to some of your other questions, I'll ask the engineers to post answers here.

@denverbdr

This comment has been minimized.

Copy link

commented May 12, 2019

To add more technical details to @hloo's answer, We're trying to make the fork compatible with ZIP-200

  1. Ycash will be a new "upgrade", with a new branchID: https://github.com/ycashfoundation/ycash/blob/master/src/consensus/upgrades.cpp#L33
  2. YCash will also bump the protocol version to 270007: https://github.com/ycashfoundation/ycash/blob/master/src/chainparams.cpp#L293

My understanding is that by doing (1), we'll get the fork and the replay protection. By doing (2), we'll get a split of the Ycash and Zcash nodes.

I tested this on a private testnet. Up till the fork block, the Ycash and Zcash nodes talk to each other (because they're on the previous protocol version). At the fork block, the Ycash nodes and Zcash nodes disconnect from each other (because of the protocol version mismatch).

@daira: Is that enough to make a clean split of the nodes? It seemed to work when I tested it privately. My understanding of the network magic numbers is that they need to be the same, because the two networks will have a common history.

Additionally, the Ycash network has implemented:

  1. Address formats are different. Testnet addresses begin with s4/ycashtestnet, and will similarly be different for the mainnet addresses: https://github.com/ycashfoundation/ycash/blob/master/src/chainparams.cpp#L325
    (Some of the other types aren't implemented yet, but the address formats will change for multi-sig and sprout as well)

  2. Change the PoW to Equihash <192,7>: https://github.com/ycashfoundation/ycash/blob/master/src/consensus/upgrades.cpp#L71
    If all else fails, the blocks will not validate on other networks, so they should still fork cleanly (because the solution size is different)

@nathan-at-least

This comment has been minimized.

Copy link
Contributor

commented Jun 5, 2019

I see two categories of issue here. The first is "direct collision" or functional issues, such as accidentally having Ycash and Zcash nodes connected and relaying blocks or transactions, or having a standalone transaction from either network be ambiguous.

The second category is the privacy complications. The reason I consider this separate is that we could solve all of the "functional" issues and everything would appear functional without problem to users, whereas there's actually a potentially dangerous privacy flaw.

I just realized we want some reusable / decoupled test vectors for Zcash to ensure multiple implementations interoperate on Zcash (such as the forthcoming Parity code that the Foundation will inherit). Maybe we need a similar kind of "safety test vector" that has negative tests like "Here's a Ycash transaction. If your Zcash implementation's transaction parser doesn't spit out an error, that's a bug." (Note this "anti-interop" testing could also help any given codebase support both networks, which seems potentially desirable until the two designs diverge too much.)

Should we track the two categories and the "anti-interop test vector" ideas all in this ticket or break out three tickets?

@daira

This comment has been minimized.

Copy link
Contributor Author

commented Jun 7, 2019

To handle the network magic issue, Ycash nodes could initially accept two network magics (the Zcash one and another one), from peers. Just after the fork, they change to sending the other magic. Some time later, they change to only accept that magic from peers.

@gojomo

This comment has been minimized.

Copy link

commented Jun 7, 2019

The same nullifier-correlation concern affects the temporary-stub-chain-for-straw-polling sketch I've added at Zips:#219.

@daira

This comment has been minimized.

Copy link
Contributor Author

commented Jun 8, 2019

I know of no way to solve the nullifier privacy leak. I think the best that can be done is to make sure users are fully aware of its implications and are not relying on unlinkability of transactions when they spend on both forks.

@gojomo

This comment has been minimized.

Copy link

commented Jun 11, 2019

I can believe that under some implied constraints for this issue – a Ycash fork of the existing codebase and Sprout/Sapling pools, using minimal code changes (and specifically no new zk-proofs) – there's "no way to solve the nullifier privacy leak".

For the larger, more-general issue – "will such forks always necessarily involve a nullifier privacy leak, in both current and future shielded pools?" – could something be figured out? (Perhaps that less-constrained question deserves a separate issue for discussion.)

In particular, even in the hard case of an existing in-use shielded pool, with an existing nullifier set, what if the forking team was willing to introduce new zk-proving requirements (with all the attendant extra setup-costs/risks/etc)? Might it then be possible for post-fork transactions to (a) use some new intentionally-incompatible nullifier with regard to consumption of incrementally-new post-fork transactions; (b) use some new zk-proof that any pre-fork nullifier used was not in a (frozen-at-the-last-shared-block) set of pre-fork nullifiers? It seems this could potentially limit the privacy lost to: "this post-fork in-fork transaction used a pre-fork input", rather than "this post-fork in-fork transaction used the exact same pre-fork input as this other post-fork main-chain transaction".

@daira

This comment has been minimized.

Copy link
Contributor Author

commented Jun 11, 2019

There's no way to safely change the nullifier derivation in the fork. That would allow double-spending of notes that had been spent prior to the fork.

In the case of notes that are created after the fork on the forked branch, there's no privacy leak anyway. So a) does not help.

For b), yes, technically it would be possible for a post-fork spend to prove in zk that the old-style nullifier was not in the frozen set. Non-membership proofs are very expensive though, even for a fixed set. It would more than double the cost of the Spend circuit, I think.

@gojomo

This comment has been minimized.

Copy link

commented Jun 11, 2019

If you change the nullifier-derivation alone (a), then yes, it would allow double-spending. Which is why you'd also simultaneously need a new zk-proof (b), showing that the (unrevealed) old-style nullifier wasn't in the frozen-at-fork-set. So <post-fork&on-fork> transactions would include both the new-nullifier – allowing efficient/standard revelation of <post-fork&on-fork> collisions without creating any correlation with <post-fork&on-main> transactions – and also the new extra zk-proof. If such a proof is too expensive to be practical, that's good to know – but ultimately I suppose the Ycash tech team would want to step up to design & choose their own privacy-vs-cost tradeoffs.

(I'm also interested in friendly temporary stub forks for polling purposes, as per my comment here. There, even very expensive proofs for the sake of privacy might be OK, given the other compromises being made like a single "poller" miner.)

A possible sociotechnical salve that a fork like Ycash could offer, to make it easier for their users to perform the same-pool-churn-migration-mitigation of Zooko's comment, could be to consensus-subsidize any shielded transactions using pre-fork nullifiers as no-fee transactions. (EG: Any transaction using only pre-fork nullifiers is free.) Then, there'd be no (transaction-cost) deterrent for the Ycash client not to "self-churn" all pre-fork balances, before ever spending to a real destination. That is, the Ycash client would consider all pre-fork inputs as 'tainted' until self-churned. The privacy leak is then limited to roughly: "the person who made this <post-fork&on-main> spend once ran a Ycash node to churn". (This no-fee-for-old-nullifiers could even be a limited-time-offer – such as the 1st year/n-blocks – though I would see an "indefinite" offer as being friendlier to the parent fork holders, who may want to "wait & see" indefinitely before trying a fork.)

@zookozcash

This comment has been minimized.

Copy link

commented Jul 1, 2019

I know of no way to solve the nullifier privacy leak. I think the best that can be done is to make sure users are fully aware of its implications and are not relying on unlinkability of transactions when they spend on both forks.

Daira, what about this mitigation:

#4007 (comment)

@daira

This comment has been minimized.

Copy link
Contributor Author

commented Jul 12, 2019

@zookozcash wrote:

How about this for a suggested mitigation: run the Migration Tool on one or both forks, but instead of migrating from Sprout pool to Sapling pool, it migrates from the Sapling pool back into the Sapling pool. Now you just have to run the Migration Tool one time after the fork on at least one (preferably both) of the two forks, before you otherwise spend any notes on either fork, and your linkability problems are solved! slightly_smiling_face

I don't think that gives any privacy improvement over just allowing the two transactions to be linked, but making them fully shielded and submitting them at the same time.

@zookozcash

This comment has been minimized.

Copy link

commented Jul 12, 2019

@zookozcash wrote:

I don't think that gives any privacy improvement over just allowing the two transactions to be linked, but making them fully shielded and submitting them at the same time.

I don't fully understand what alternative you're suggesting. You mean the user manually runs a Zcash fullnode and also a Ycash fullnode, and then for each note that they have, they manually construct a transaction on Zcash and a matching transaction on Ycash, spending the same note, and then they post the two transactions to the two blockchains at the same time as each other? That sounds extremely challenging, even for an expert.

The alternative I'm suggesting is:

  1. Either Ycash Foundation or some Zcash devs or both make a migration tool, very similar to the Sprout->Sapling migration tool,
  2. The user runs that tool on whichever chain they find easiest to connect to.
@gojomo

This comment has been minimized.

Copy link

commented Jul 13, 2019

By my understanding, analogizing this to pool-migration makes it seem like a bigger deal than it needs to be.

A Ycash user should just send their entire Y-Sprout-shielded balance to their own Y-Sprout address, and their whole Y-Sapling balance to their own Y-Sapling address, before any other Ycash shielded spends. (No fancy "migration tool" timing- or amount-choosing required, though I suppose a script could be provided to make this self-churn slightly easier.)

This ensures the nullifier leak, when the same funds are spent on the Z-chain, only reveals that the same-spender was active that churn-moment on the Y-chain – which seems as good as can be achieved in the situation. There's no other correlation of spending targets/amounts, as there could be by fund-receivers without this churn.

Of course, this could be done on the Z-chain instead, but I'm guessing the transaction fees will be lower on the Y-chain – and perhaps zero if my suggestion in Ycash#11 is ever implemented. (I suppose someone who didn't even want their Z-chain fund-recipients to know that they ever churned-on-Y-chain could pre-churn on Z-chain, as well.)

(A user who fears a network-omniscient adversary correlating the nullifier with their IP address might have extra concerns, but that seems to me roughly the same as such concerns on Z-chain only, just with two occurrences.)

@denverbdr

This comment has been minimized.

Copy link

commented Aug 15, 2019

FYI, a nullifier migration tool will be available in Ycash 2.0.6

https://www.ycash.xyz/docs/nullifier_migration/
https://github.com/ycashfoundation/yecwallet/pull/18/files

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
8 participants
You can’t perform that action at this time.