In my two previous posts, I introduced and explained the first version of “Make It Snow” - a social giveaway app built on the Avalanche chain. The primary problem we ran into was front running bots: bots that monitors data in the mining pool and pays extra gas fee to “get ahead” of a transaction. To solve this problem, we implemented a “commit and reveal” strategy. By doing this, however, we sacrificed user experience by requiring users to commit two transactions before claiming their giveaway reward.
The reason for the above complexity stems from how data in blockchain transactions are open for all to inspect. This makes “password” or “secrets” impossible to keep.
As a commenter asked in my previous post, “Why not use Zero Knowledge Proofs?”
Zero Knowledge Proofs (ZKP) is a cryptographic method by which the prover can prove to the verifier that a given statement is true without revealing any information other than the statement itself. It’s not possible to explain this easily in a paragraph; I suggest those unfamiliar check out this ELI5 youtube video instead. For the purpose of Make It Snow, ZKP can theoretically allow users to prove that they know the giveaway password without revealing the password. If they can do that, the front running bot problem would not exist.
User: I’ve a ZKP that proves I know the password. Give me my reward, now! Contract: The ZKP is valid. Here’s your reward.
In practice, using ZKP to solve this problem is not so straightforward. We don’t want to have a separate ZKP for every possible giveaway password; we want a single ZKP for all possible passwords.
Instead of the user proving they have the password, the user instead proves they’ve created a hashed string without cheating.
User: I'd like to claim cashbag 123 with the hashed password hxyz. I have a ZKP that proves 1. I'm the creator of the ZKP and 2. I know the unhashed string (i.e the password) used to create this hashed password. Contract: the ZKP is valid. In addition, the hashed password matches that in our storage. Here's your reward.
The ZKP must be unique to each user / wallet address; otherwise, malicious bots can still copy the ZKP and front run the transaction. Similarly, the ZKP must ascertain that the user actually knows the password and didn’t just copy the the hashed password by inspecting on chain data. Finally, the contract checks that the hashed password matches with that in storage.
With this setup, bots have full access to the hashed password, but they cannot do much with it. It is theoretically impossible to get the unhashed password from the hashed one and it is cryptographically impossible to generate the needed ZKP without knowing the original password.
With that, we’re good to go! From a product and technical standpoint, we’ve resolved the front running bot problem without sacrificing user experience.
Nothing is perfect, though. Using ZKPs come with some baggage.
For one, ZKPs are really hard to understand. It’s not orthodox programming; it’s not orthodox smart contract programming either. It is more cryptographic and mathematical in nature and there are very few engineers who have done anything with ZKPs.
The toolchain is very raw: Circom - the circuit compiler used to compile the ZKP circuit into smart contract code, only released version 2 a few months ago.
What’s wrong with that? Well, we as a team have no idea whether our circuit is working as intended. We’ve tested it a few times and it seems to work, but who’s to say there aren’t any security loopholes we don’t understand?
At least with smart contracts, there are security best practices and external auditors. An astute engineer “knows what they don’t know” with smart contracts. With ZKPs, we have no idea what we don’t know.
The uncertainty was such that we didn’t feel comfortable launching the ZKP version of Make It Snow; we discussed putting security disclaimers and asking users to limit their giveaway spend.
Thankfully, after doing a bit more research, we found out that the Tornado Cash project is using a very similar circuit in their code. Tornado Cash is a battle tested project and that gave us much more confidence that our ZKP circuit works as intended.
At this point, we’re pretty satisfied with the state of Make It Snow. It’s not perfect, of course. One issue we chose not to solve was that of a single user grabbing multiple rewards via different wallet addresses. A user can create multiple wallets and either manually or programmatically claim giveaway rewards. As of today, there isn’t a golden standard to validating a user’s uniqueness in web3. A wallet is a wallet.
Imperfect solutions are abound; one might consider restricting usage to those wallets with an associated Bright ID. Another idea is to only allow wallets with significant transaction history - whatever “significant” here means. Perhaps we can have a “no leechers” policy by only allowing users who have created giveaways to take rewards.
In the end, we concluded that solving this problem is beyond the scope of Make It Snow. We think problems around identity, reputation, and humanness are certainly worth solving, but not via Make It Snow. After all, this was meant to be our foray into web3 development - a pet project so to speak.
Development on Make It Snow will pause for now. We hope you enjoyed our little adventure. Going forward, our team will focus on different problems - bigger problems. If this sounds interesting, follow me on Twitter or reach out to chat!