An open-source mixer for private transfers on Ethereum
You don’t have to be nervous of your “market research” on SpankChain to want better privacy on Ethereum. In fact, the Ethereum community has repeatedly highlighted its support for an open source initiative that allows for one-off private transfers from any Ethereum account to any other.
Because of this need we’ve spent the past few months building Hopper, a zero-knowledge-based trustless mixer. We’d love for the wider community to now join us in developing it further.
This post explains what Hopper is; how you can use it to make a private transfer; how it works; and what its limitations are. For more technical information, check out our github repository.
1. What is Hopper?
Whenever they want, users can deposit 1 ETH into the Hopper smart contract and later withdraw this deposit to a different account. They do this by providing a zero-knowledge proof that they previously deposited 1 ETH into the mixer. That proof does not reveal from which account the ether was sent.
You can only deposit and then withdraw 1 ETH at a time (because more distinctive numbers would likely break your anonymity). But you can deposit as often as you want.
We decided to make this project entirely open-source and all code is available on our github repository. It currently consists of the Hopper smart-contract and a proof-of-concept iOS app available on Tesflight. If you’re a developer, we’d love for you to contribute! The next steps include developing web and Android clients, auditing the smart-contract, agreeing on a trusted setup, and opening up the system to competing relayers.
2. How to make a private transfer using Hopper?
⚠️ Please note that Hopper is in alpha state and should be used with caution. It has not been properly audited and may contain bugs that result in the loss of your funds. ⚠️
- Download the Hopper iOS app from Testflight or build and run the Xcode project directly from our github repository.
- In the iOS app:
(a) Tap the “+” button in the upper-right corner.
(b) Enter the origin address (the address from which you want to send value) and the destination address (the address that will receive the value transfer).
(c) Tap “Commit”. Your intention to perform a private transfer gets sent to the Hopper contract. An entry gets inserted into the app’s table to represent your commitment.
- Send 1 ETH from the origin address to the Mixer smart contract address, using a gas limit¹ of 1,000,000. You can see the Mixer address by tapping the “Fund” button next to your commitment in the app’s table.
- When your transfer gets mined, it will be detected by the app and the “Fund” button will change into a “Withdraw” button. You can see how many other people have transferred a note to the Mixer since you funded your commitment. Wait for a few commitments to be added to the Mixer by others in order to increase your anonymity set. When you’re satisfied that you have waited long enough, tap “Withdraw” to generate a zero-knowledge proof that you previously sent a commitment to the Mixer. The Mixer contract receives and validates the proof and sends 1 ETH to the destination address (minus the gas cost paid by the relayer).
3. How does Hopper work?
Say Alice wants to privately transfer 1 ETH to Bob.
- Alice uses the iOS app to send a commitment to a relayer, which sends it to the mixer smart contract. This commitment is the hash of a secret number concatenated to Bob’s address. She then funds her commitment by sending 1 ETH to the mixer contract. At that point, the contract adds her commitment as a new leaf of a Merkle tree, updating the root of the tree, which is always publicly known.
- Some time later, she decides to withdraw her commitment to Bob’s address. She then uses the iOS app to generate a zero-knowledge proof (zkSNARK) that she knows a Merkle path in the Merkle tree along with the secret number behind the leaf of this path. The app sends the proof to a relayer, which sends it to the mixer contract. The contract verifies the proof and sends the note to Bob, minus the gas cost paid by the relayer.
More details on the zkSNARK circuit used by Hopper can be found in our github repository.
Thanks to the use of relayers, Bob can receive Alice’s note without first having to top up his account with ether (which would likely compromise the privacy of the transfer if Alice and Bob were the same person). For now, Hopper uses Argent relayers but our goal is for Hopper to be entirely decentralised, using a registry of relayers as recently proposed by Vitalik.
MiMC hash functions
The zero-knowledge proof takes only a few seconds to be generated on mobile. This is because we use a special type of hash function for our Merkle tree, known as MiMC, that have Minimal Multiplicative Complexity and are therefore zkSNARK-friendly. Because the security properties of this type of hashing function are still being studied, we chose to use the highly reliable sha256 hash method to compute the commitment leaf, which partially mitigates the risk of using MiMC.
- The first limitation is significant. Hopper needs wide adoption to be useful. This is because the anonymity set of a transfer (i.e. the set of all the deposits that your withdrawal could originate from) directly depends on how many others use the mixer. You want a higher anonymity set, so you want more users. In other words, you want more hay in the haystack.
- At the moment, Hopper can only be used to transfer notes of 1 ETH. This is because if you were to deposit and then withdraw 1.256 ETH, it would be easy for an observer to link the recipient with the sender given the specificity of the amount used. We are researching ways to support private transfer of custom amounts of ETH and of other types of asset.
- As mentioned above, we use MiMC hash functions in our zkSNARK circuit, whose security properties are still being researched.
- The Hopper contract can be used up to 32768 times in total before the Merkle tree fills up and a new contract must be deployed. This corresponds to a tree depth of 15 which was chosen to keep the gas cost of a commitment under 1,000,000 gas. We are exploring ways to increase the depth of the tree while keeping the gas cost at an acceptable level.
5. Get Involved
 Sending 1 ETH to Hopper requires a relatively high gas limit because the contract needs to update the Merkle tree to include the new commitment, which involves writing to storage as many times as the depth of the tree.