tornadocash / tornado-core

Tornado cash. Non-custodial private transactions on Ethereum.
https://tornado.cash
GNU General Public License v3.0
1.49k stars 561 forks source link

Proposal to move the MerkleTree from the smart contract to offchain computation for ~66% gas cost reduction #58

Open arnaucube opened 4 years ago

arnaucube commented 4 years ago

Instead of doing the MerkleTree computation onchain, it can be done offchain, and proved the correctness inside a zkSNARK proof.

This means that with the current approach (MerkleTree onchain) it needs 1M gas for the deposit, while with this new approach (MerkleTree offchain + zkproof of correctness) in the tests that I did the gast cost is arround 0.3M gas. This is thanks to the fact that the MerkleTree is moved to offchain computation and then proved its correctness inside the snark proof which is much cheaper to verify in the smart contract. (The withdraw continues very similar as it is now, as it is already with a zkproof verified in the contract).

I've made a proof of concept that works here: https://github.com/arnaucube/miksi-core , that can be tried here: https://arnaucube.github.io/miksi-app/ (still needs some improvements, but it works and can be currently used in Göerli testnet).

A bit of more detailed explaination:

Deposit

All computation & constructions are done offchain and then proved inside a zkSNARK to the Smart Contract

Withdraw

All computation & constructions are done offchain and then proved inside a zkSNARK to the Smart Contract

The proposal would be then, to move the MerkleTree computation offchain, and instead of building the MerkleTree in Solidity, could be done in the client side, and then proved its corretness inside the zk-proof.

poma commented 4 years ago

This approach has a few issues:

This can be solved by introducing fallback to onchain merkle tree update in case of incorrect or empty proof, but we don't want to introduce this additional complexity. Besides, tornado v2 contracts are already immutable.

In tornado pool (v3) we already use this approach since it stores additional data in commitment and requires a snark proof on deposit anyway.

poma commented 4 years ago

You can check out our implementation of this technique here: https://github.com/tornadocash/tornado-pool/blob/master/circuits/treeUpdater.circom

arnaucube commented 4 years ago

Cool! Yes:

I guess that is a tradeoff with a bit of more complexity, and with the extra steps to cover these cases, butgetting less gas cost in the deposit transactions.

Anyway, nice to know that those things are been taking in account, I'll take a look to Tornado Cash docs to know better how Tornado specifically works ^^

poma commented 4 years ago

If we submit the proof for the previous user, then he will be unable to withdraw until someone deposits after him. I don't see how is it different from requiring users to submit a proof for themselves.

Let me clarify a smart contract case. Imagine for example some lottery where users submit their commitments, and then at some point the smart contract randomly chooses a winning commitment and funds it by calling deposit function (this was the first design of Thresher contract to deal with leftover change without breaking privacy). In this case the smart contract would be unable to fund the chosen commitment without someone generating and submitting a proof for merkle tree update.