Recently BlockX Labs receive a grant from MolochDAO to build a front end for Argent Labs Hopper contract. This project consisted of research and work from HarryR (ethsnarks), members from the Argent team, and of course us.
What and Why is a Mixer?
A mixer’s job is to take the funds from one account and transfer it to another account while maintaining larger anonymity than just a straight transfer. This is a pretty easy concept when you build this from a centralized platform. If you send money to a third party then the third party waits some time and send it to a new account after some time it is pretty simple.
What makes this project harder is to do this in a decentralized manner. This is the blockchain space after all. How do you simulate this middle man without ever having to trust a middle man. Well that question will be answered over the course of this post, and spoilers it involves merkle trees, new hashing algorithms, ZK-snarks and WebAssembly.
Let’s now talk about why a Mixer? Imagine Alice wants to use a DApp. It can be any DApp. Usually what happens is that Alice would end up fingerprinting her account. For whatever reason. Imagine if it is a DApp like Amazon and she sends a package to her house. Well now Amazon has a link between her and her account. As DApps become more popularized this issue with tying identity to your account will arise more and more.
So what does Alice do? Alice can send the funds she needs to a new account. However, those funds need to come from somewhere. So if Alice takes her main account and sends it to the account she will use for her DApp (account 2), she has created a direct path and again has low anonymity.
By using a mixer she can obfuscate that transaction making no clear path back. So very easily someone can create anonymous accounts and accounts tied to an identity for DApps.
The Smart Contract
To eliminate the middleman the Argent team created a smart contract to deal with this. This is how it works.
Let’s say Alice has two accounts, Alice and Alice prime. Alice is her main account with her funds in it and Alice prime is the account she wants to use the DApp with.
Alice will first create a challenge and put it on chain. Required with the challenge is a deposit of 1 ether. Once received this will put her in the merkle tree of the smart contract. To receive the funds all anyone needs to do is provide proof that, that leaf exists and that it has not been already withdrawn.
The proving mechanism was provided by HarryR in the form of a tool called ethsnarks. “EthSnarks is a collection of zkSNARK circuits and supporting libraries to use them with Ethereum smart contracts”.
The purpose of this is so people can generate computationally heavy proofs in their browser and then light verifications can go on chain. Therefore the heavy computation remains off the blockchain, but the important part the proofs, are light and can be replicated over and over by every node.
This reduces the price of these type of zero knowledge operations and allows them to be used in smart contracts.
A huge question when making this project is how do you run these proofs in browser? The code is written in C++. Luckily the Mozillia foundation has been building a compiler called WebAssembly.
This revolutionary technology allows us to compile the C++ code down into something that can be run natively in browser. Thus we can now generate our proofs.
Now that we understand the pieces let’s go through the full flow.
Alice starts by choosing the address she wants to send her funds to (the Alice Prime account).
On sending, this will prompt her to allow Metamask to send 1 Ether to the smart contract along with a hash of the Alice Prime address and a nullifier secret. This hash will be placed on chain, making it impossible to know that Alice has a link to the Alice Prime address since the information provided is just a hash of the information.
After sending the address Alice will receive an encoded message that is a JSON object of the information anyone needs to generate a ZKsnark proof.
She should probably copy it and keep it somewhere safe because it isn’t stored anywhere else and is the only way she can retrieve the funds.
Next she will probably want to claim the funds. Technically any account can withdraw the funds but read the section on increasing your anonymity set to understand why any account should not.
Clicking the claim button will create the proof generation process.
To generate the proof we need the merkle root, the alice prime address, nullifier, nullifier secret, address, and path to our leaf.
This calculation proves to the contract that there is a leaf with a deposit that goes towards the alice prime address and reveals the nullifier which is a hash of the nullifier secret.
The contract then checks the nullifier to see if it has been spent already, if it has then the transaction fails, if it has not then a withdrawal is made.
All this happened and at no time was it revealed that the Alice account was the account that funded the Alice Prime account.
Any mixer is not perfect. There is no such thing as total anonymity, at least that I know of. The Mixer is no different. So let us understand the potential flaws and how they can be mitigated.
First off the mixer doesn’t fully hide the transactions. They turn a one input to one output path into a multiple input to multiple output. Instead of Alice to Alice Prime it can be anyone who has used the mixer to fund Alice Prime and Alice could have funded any of the withdrawls.
One thing we do is lock the price of using the mixer to 1 eth. For example, if Alice deposited 1.00213435 eth then it would be pretty obvious the pathway since only Alice Prime would have withdrawn that amount.
Increasing the liquidity of the people using the contract. The more inputs and outputs the greater the security. This is why we have this liquidity pool piece at the bottom for users to see.
Finally withdrawing the funds. Do not withdraw the funds from an account tied to your prime account, this could also decrease anonymity.