On the third weekend of May 2024, my three teammates and I went to the ETHBerlin at CIC Innovation Center in Berlin. It’s a 3-day hackathon focusing on privacy, anti-surveillance, freedom of speech, etc. I even went to the pre-event on Wednesday to learn more that this hackathon event will not be any other you might attend.
The ETHBerlin event this time is themed on “Identity Crisis.” This topic is brought up with the increasingly abusive usage of societal data on the traditional Internet. This time, they emphasized the importance of privacy and pushed hard on technology to protect it. They wanted to show that privacy and a massively used application can exist.
Unlike other usual hackathons, ETHBerlin4 had only 4 tracks: Defensive Tooling, Freedom to Transact, Social Technologies, and Infrastructure. The Defensive Tooling is for projects focusing on security enhancement, decentralization, anonymization, etc. If you are building something that prevents the government or other authorities from tracking you, this category is definitely for you. The second track, Freedom to Transact, allows secure, private, and censorship-resistant transactions. The Social Technology track, which my team and I applied, focuses on transparent governance, decentralized community, and collaboration. This track was the most general one and, thus, the most teams applied for. The last one is the Infrastructure track, which is for architects and builders who do projects for underlying infrastructure supporting the blockchain environment.

Nowadays, most discussion platforms, such as Reddit and Jodel, are still centralized. This condition is not very different from that of traditional public reporting platforms. Such an approach is vulnerable to censorship and backtracking that would prevent people from creating reports. Of course, this scenario will beat the purpose of the reporting system.
During the hackathon, we wanted to improve this community reporting system, which is similar to whistleblowing but for anyone and anywhere. We want to provide a safe place for everyone to post any abusive behaviors from authorities and the privileged. Hence, we aim for total anonymity (not only pseudonymity!) to enhance privacy and assure everyone that they can express their voice without any worry about being prosecuted. Considering the magnitude of this application, we want to ensure that our application cannot be censored no matter how hard governments try to censor it. This is why a decentralized on-chain application best suits our case.
We design our application to have a no-moderator system to provide and ensure freedom of speech. We have seen many cases in social media where moderation is forced by authority, which potentially can be used to silence a minority voice that needs the audience the most. On top of that, including content moderation will significantly reduce trust, and it also puts the responsibility burden on the moderator. However, we still need to provide information that can prove the content's trustworthiness. To do this, we allow our application to self-govern itself by introducing an upvote-downvote system, a digitalized version of the stick-and-carrot system. By providing a rating, users can understand how credible a post is.

To allow total anonymity in decentralized apps, we should prevent using any information that can be tied to more than one post. Using a single wallet to post all reports can create a traceable history in the blockchain network (you can see them on the Etherscan transaction history). Worse, if the wallet is also used in another application or for another transaction, we can determine the entity that created the report using some forensics. As a solution, we derive a new temporary wallet every time a user interacts with the UI (creating a report, upvoting, and downvoting), which we call an ephemeral wallet. This is the first and most important feature of our application.
To do this, we generate a local master wallet on the front end with a mnemonic and store it locally in browser storage. Of course, we should implement a security mechanism for the user to securely store such data, but we left it for simplicity's sake during the hackathon. After that, we generate a new ephemeral wallet from a predetermined enumerable derivation path every time a user tries to interact with the application. Without the secret key of the master wallet, it is impossible to know which master wallet an ephemeral wallet belongs to. This is a perfect case for creating an anonymous interaction.
However, using an ephemeral wallet for every transaction poses a new challenge. As you may know, interacting with blockchain networks will mostly incur costs due to gas fees. Unfortunately, the Ethereum network has not yet implemented the sponsored transaction protocol (see EIP-3074 or EIP-7702). With this condition, the wallet must have funds before any on-chain transaction (or interaction, in our case). However, we don’t want our users to fund their ephemeral wallets themselves since it will create an apparent connection between their main and ephemeral wallets. One possible fix my teams and I did was with a faucet that will fund users’ ephemeral wallets on request. So, after the ephemeral wallet, our next feature is the automated faucet system.
Our faucet system has two components: the smart contract and the API back-end endpoint. The smart contract is separated from our main reporting smart contract to reduce the economic incentive for attacking our report smart contract and reduce the attack vector on each component. Our back-end is built directly into the routing file of NextJs, which accepts a POST request from the user containing the wallet address. After that, it sends a transaction to the smart contract to send funds to the mentioned address.
We used smart contracts to contain the funds instead of our wallet for two reasons. The first is to reduce the economic incentive to attack our main wallet on the backend because our main wallet is also used for other functionalities, such as sending Proof-of-Human-Work, which will be explained later. If, for some reason, an attacker obtains access to our secret key, not only can they extract all the funds in one go but also obtain various access to the smart contracts. Another reason is that we want everyone to send funds for the projects. If we send our smart wallet directly to send funds to the smart contract, people have to send money to our wallet, which people do not seem very pleased about. With smart contracts, people can perform a more transparent audit of what limitations the contracts can have and how they will behave, increasing trust. To do this, people can see any block scanner service to verify the smart contract code.
As an example, our faucet smart contract is deployed on address 0xc4C54b325bA64c473c478102C2f257774725d336, which, if you see in Etherscan by clicking the text, you can see how the actual source code is and whether the smart contract is verified or not. It increases the trust of people who want to fund the smart contract.

One thing that is also important for the application is anti-spam. We should prevent or at least make it harder for spammers to flood the system with unnecessary data. The gas fee already reduced the incentive in the economy area, but since we are against people with authority or privilege, we need to assume that such a gas fee does not prevent them from launching such an attack. To tackle this problem, we created an umbrella term, Proof-of-Human-Work (PoHW), similar to Proof-of-Work but more human-friendly, yet it cannot be solved by a machine alone. A straightforward example of such proof is a captcha. The captcha system involves challenging the user with a captcha question or task from the captcha server and then queries the information of the captcha challenge using the API exposed by the captcha provider.
Integrating captcha services into the blockchain ecosystem requires the involvement of an Oracle that posts PoHW to the chain to be queried by our application. To do this, we designed an endpoint on the backend system of our application that has the only access to submit PoHW. When the user solves the captcha challenge, our frontend will submit the solution to the backend. Afterward, our backend checks the validity of the solution provided by the user and submits the value on the chain when it is valid. With this, our reporting smart contract can query the data on-chain, too.
Submitting the PoHW information on the chain is an important design choice because we want to be transparent about why a post is being rejected, which is an invalid PoHW submission. We can make the smart contract to emit an event that informs our backend that a report with a certain PoHW is submitted, but this is no other than providing a not auditable black box as gatekeeper, which we do not want to do in the first place.
Another problem created by using an ephemeral wallet is the rating. Traditionally, you connect rating collection to a single entity (a user or a post). In our case, directly connecting rating data to a user is impossible because we don’t have any information regarding the actual entity creating the post. Thus, we can only connect ratings to each post. Yet, we also want the user to provide information regarding the credibility of the user who posted it. To solve this, we created a Zero-Knowledge Proof (ZKP) to check how many posts and the average upvotes-downvotes.
Apart from post count and reaction ratio, we also need to prove that users do not selectively include or exclude wallets with certain conditions to outsmart the credibility-proof system. For example, a user can choose only wallets whose posts received good ratings and thus have a higher rating average. To address this, we designed our ZKP circuit to require all ephemeral wallets (we can check it by enumerating the derivation path from the main wallet up to the currently used wallet). Creating such proof is no trivial matter; thus, it was our last feature.

Our smart contract is implemented in Solidity and deployed with Foundry. The front and back end are implemented using NextJs. The ZK Proof circuit is implemented in Circom. The BlockWhisper application is open-sourced on GitHub. You can take a look at how the actual implementation.
https://github.com/itsmeyaw/blockwhisper
Apart from the repository, we also rendered several screenshots of the application.


During the hackathon, we discussed several times the best solution to implement. One consideration was implementing provable personhood while ensuring that each post does not show a single entity that posted it. We discussed this with a mentor from 0xPARC (the organization is also actively involved in developing Zupass and the lecture Modern ZK Cryptography at MIT). He was nice to us to explain interesting stuff about Zupass and how it can perfectly suit our use case. He also showed us their latest cool experimental project: to build a Telegram chatbot that ensures anyone in a group can send something to the bot.
We can use Zupass for the product, but we were unsure about its anonymity guarantee. However, I think it will be a good enough level to achieve pseudo-anonymity at this point because achieving 100% anonymity on the internet is hard and almost impossible. There will always be breadcrumbs we left here and there, either IP addresses, connection fingerprints, or anything. But I found it cool to use the ephemeral wallet method.
Another thing worth noting is that we want to eliminate the need for a (centralized) backend endpoint to fund users’ ephemeral wallets and submit the PoHW. Although it does not play a pivotal role, having a centralized backend can affect the whole software ecosystem. You can think of a case where the government took down the backend server and prevented users from getting the funds needed to create a report. We need a method to accurately target our funds to those who positively contribute to the networks.
Another possible case is where our captcha system is suddenly blocked by the provider because they seem to disagree with our usage of their product. As you already see, the PoHW mechanism is essential to our system to deter spam. A possible fix is using semaphore, which is also used in proof-of-personhood (PoP) on the Worldcoin network (combined with the Zupass). However, this will only limit the number of wallets interacting with the system. A machine can still imitate the person when it owns the secret key. One possible way is to create a cooldown method, where people can only post once within a minute. This will be a good fix without requiring complex stuff on the smart contract side.

In my opinion, ETHBerlin is a one-of-a-kind event that is hard to compare with other hackathons. It feels like they demand you to be a rebel (haha!). Extreme claim aside, they asked you to challenge the status quo and devise a solution. The place was nice; the people were warm, and the food was delicious (ahem)! Still, I think one of the best hackathons was the Solana 24H Hackathon, held on the same week as ETHBerlin, where people could stay in tents from the committee in the venue, which was very cool.
During the hackathon, I met many incredible people and learned much from them. For example, I learned that you can simulate a (deployed and verified) smart contract using Tenderly. That tool helped me so much when I was confused by the weird responses from the JSON RPC when performing transactions.

Despite not winning the hackathon, I was really happy with the result. I find it really cool that we can pull this project off within 3 days. Moreover, I learned a lot from this event, which made me happy.

