# ZK Proofs Part IV: Tornado Cash **Published by:** [0xDanki ( Tin Erispe )](https://paragraph.com/@tinerispe/) **Published on:** 2023-07-12 **URL:** https://paragraph.com/@tinerispe/zk-proofs-part-iv-tornado-cash ## Content Excuse any typo or grammar lapses in this post. Yer donkey just got poisoned by spoiled milk and is now drunk typing on a high fever. This helps tho. Today’s topic requires some courage to be published. We’d be talking about one of the most controversial protocols in DeFi and how ZK was used for its privacy-preserving properties: Tornado Cash. Do you know one of the founders of got jailed for it… fortunately he’s already released as of today-- just with a monitoring device on his ankles. Gomsh. So anyway, I’m gonna talk about how the protocol works under the hood and maybe add in some ideas on how mixers kan be built better so you can prevent bad elements from using the protocol while avoiding being put on a human cage for trying to preseve everyone’s privacy. Wait. Disclaimer: I don’t by any means encourage illegal activities in the blockchain. And if you use Tornado Cash or any similar mixer, there is a good chance that some protocols and centralized exchanges might blacklist your wallet. This is purely for educational purposes only as Tornado Cash is one of the first ZK-powered dApps that gained popularity among privacy-conscious users.How do Mixers work?A mixer is a special type of smart contract that takes in deposits from different users and allows a different address to withdraw from it without revealing from whom the deposit came from. Well, not really. If there are only a few people who deposited into the mixer, then it’s fairly easy to guess from which address you’re withdrawing. That aside, the closest TradFi equivalent for this would be a bank’s safe deposit box with a lot of people going in and out of the room. In a safe deposit box, anyone who has the key can access whatever is stored in their safe. And while it’s easy to know who withdrew from which deposit box if only one person ever goes in and out of the room, it will be harder and harder to guess if many people frequent the room. There are other custodial mixers in the space, but Tornado Cash is unique because it is totally permissionless and decentralized. You only get to withdraw the tokens you deposited and not a combination of tokens that were relinquished to the protocol by other users and was mixed by a centralized authority. Just by throwing around these ideas, it’s not hard to imagine how Tornado Cash became a tool for hackers to withdraw the crypto they obtained thru nefarious means. I’ll be sharing some ways on how to prevent this from happening later. But first, our ZK lesson…Tornado’s Trusted SetupThe protocol uses a ZK-SNARK based library which, if you remember from a previous post, goes like this:The circuit has a trusted setup which is an algorithm that the verifier uses to create non-interactive proofsIn the setup, the prover has to pick a random number to evaluate from. This answer is run through a hash and becomes part of the proof. The other part of the proof is obtained by having the hash evaluated through another function in the Fiat-Shamir Transformation.Now, in Tornado, the depositor picks two random numbers k and r : k being a nullifier whose hash will be used to make sure that no token can be withdrawn more than once, and r is another random number through which we’ll evaluate the algorithm. These two numbers should be private at all times because they’ll be used to withdraw the deposited funds anonymously. The withdrawer then runs both numbers in a hashing function S[R, h, A, f, t] to prove that he knows the values of k and r. Wait whut iz R, h, A, f, t you say? They are all public variables. R is the merkle root of the tree we’re withdrawing from h is the hash of our nullifier k A is the recipient address of the deposited token f is the fee the recipient pays to the relayer address and t is the relayer address Now, here’s how the prover computes: **S[R, h, A, f, t] = {I KNOW k, r ∈ B 248, l ∈ B 16, O ∈ Z 16 p ** SUCH THAT h = H1(k) AND O is the opening of H2(k||r) at position l to R} Ok, we have a new variable O and l. Simply put, O(T , l) is the Merkle opening for leaf with index l, and T is a merkle tree with a height of 20. You don’t have to worry much about it, it’s just a way of verifying that there’s a node in the tree whose deposit can be unlocked by values k and r. If you would notice, there is really no A and f in the equation above. But adding them in the hashing function is actually a thoughtful move because while these variables are not a necessary part of the computation for the proof, having the recipient address and fee in the hash can prevent a frontrunning attack by MEV bots. Anyway, from these variables we’ll compute for two values again and by the end of the process we’ll have two public parameters: dp and dv which will be used for constructing the proof and the verifier respectively (I won’t go into detail anymore as the functions for computing these params don’t seem very important, but you can read here). When a proof is successfully submitted to the Tornado Cash contract, the tokens are released to recipient address A, the relayer fee f is released to relayer address t, and the nullifier hash is added to a list of hashes that have already been used (to ensure the proof cannot be reused to withdraw). Ok that was some knotty process. Though believe it or not Tornado Cash is one of the simpler ones. It was still dangerous tech tho, so I am also suggesting some ways we can have a privacy-preserving dApp like this while keeping it free from illegal activities.Ideas on How to Make Mixers Less SketchyThe good news is that the web3 landscape is no longer the same as in 2019 when the Tornado Cash whitepaper was published. We have a lot more advanced ways of verifying identity and activities on-chain. One such ways is using DIDs or decentralized IDs to prove that the user has not been on any sanctions list, blacklisted by any blockchain security company, or has not made any red flag transactions before allowing them to deposit into the mixer. Easier said than done. As y’all know, computation in the blockchain is expensive and it might take a lot of gas to do this. Or we might need an oracle but it might beat the purpose of preserving user privacy. A more decentralized way of tackling this is to give the withdrawers the ability to prove that they are not linked to a certain address (without revealing anything else about them). This enables law enforcers to narrow down the addresses who are probably withdrawing funds obtained from criminal activity. And if you’re someone who’s planning to use mixers for shady reasons, know that they are not an end-all-be-all to transaction privacy on chain. There are so many ways you could give away your identity while using these protocols but I deleted the section so good luck in der haha.. If you’re a cybersec and wanna lern how to catch em, contact Danki and I’ll give away some secret movez.Up NextEm not very satisfied with the fact that I haven’t yet explained how we even get these equations to begin with. So the next ZK post will be about how we turn literal programs into a ZK circuit. You’ll be meeting Quadratic Arithmetic Program, R1CS, and the many stages of turning regular programming logic into a ZK-Proof. Might even do a demo on Circom but I can’t promise yet as I’m so hung up on debugging ZK programs. For now I sleeps and recover. Bye frens! ## Publication Information - [0xDanki ( Tin Erispe )](https://paragraph.com/@tinerispe/): Publication homepage - [All Posts](https://paragraph.com/@tinerispe/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@tinerispe): Subscribe to updates