Skip to main content

14 posts tagged with "security"

View All Tags

MACI Aragon Plugin

· 8 min read
ctrlc03
MACI former team lead
John Guilding
MACI team lead
NicoSerranoP
MACI team member

Hey Anon,

Welcome to another MACI blogpost. Today we are going to be looking at a voting plugin we have been developing to work with the Aragon OSx stack.

As mentioned in our latest roadmap blog post, our team decided to focus on supporting governance projects by integrating with tooling providers such as Aragon. Look out for further announcements over the next month. We're working on some exciting additions to the roadmap to accelerate private governance on Ethereum.

So why integrate MACI with Aragon OSx? Our thesis is simple: **private voting will increase voter participation and protect those voting. It will also lead to more honest and accurate outcomes as people can vote more honestly.**

Current public voting systems create barriers to honest participation. Voters face social pressure, fear of retaliation, and concerns about how their choices might affect future opportunities. Private voting removes these barriers, enabling DAOs to capture the true preferences of their communities.

We chose to integrate with Aragon because their OSx platform provides an excellent foundation for custom DAO governance, and as a reputable team building in the open, they're the perfect partner for this integration.

The real cost of public voting

While transparency is often celebrated in crypto, public voting creates serious barriers to honest participation that threaten the legitimacy of DAO governance.

Fear of retaliation keeps voters silent. Large token holders can pressure smaller voters by threatening to exclude them from future opportunities, airdrops, or partnerships. When voting records are public, retaliation becomes easy to execute, leading many to abstain rather than risk consequences.

Social pressure distorts genuine preferences. Voters often wait to see how others vote before casting their own ballot, leading to herding behavior that doesn't reflect genuine preferences. Some even say governance voting has devolved into a game of politics. The "follow the whale" mentality and politics involved undermine the democratic ideals DAOs strive for.

Vote verification enables problematic markets. When votes are public, it also creates conditions where governance power can be openly traded, as buyers can verify they received what they paid for.

Public real time results can enable whales intervention. If the votes are public and visible in real time while the voting period is happening, whales (or users through token loans) could influence the decision by using their voting power to overpower the community decision.

Why MACI

MACI (Minimal Anti Collusion Infrastructure) is a private voting protocol that aims to reduce collusion and coercion with receipt freeness - this makes it the logical next step for DAOs that really care about the problems highlighted above.

In more detail, every vote is encrypted and can only be decrypted for tallying, by a trusted entity referred to as the coordinator. Voters can override their votes at any point during the voting period, and thus without a clear receipt for their vote, they are not able to prove beyond reasonable doubt that they actually voted for an option. This discourages bribers from buying votes and other voters from attempting to collude.

While the coordinator can decrypt votes, they cannot produce an incorrect tally or censor votes, thanks to zero knowledge proofs and smart contracts.

For more details about MACI and how it works, we recommend reading our other blogposts such as this introductory article and our comprehensive documentation website.

How does Aragon OSx work

Aragon OSx is a smart contract framework that works on EVM compatible chains. DAOs can easily deploy custom governance stacks using Aragon OSx, and can benefit from several plugins to extend their functionality over time. This plugin architecture allows DAOs to customise their governance without rebuilding from scratch.

A plugin is a smart contract with custom governance logic, limited in scope, and with single-purpose logic that can be used to extend OSx-based organisations. Examples include token voting and multisig, and now.. privacy-preserving voting through MACI.

How does the MACI plugin work

The plugin allows DAO members to create new proposals by calling a smart contract function: createProposal. The function checks that the caller has enough governance tokens - this minimum amount is set by the DAO at deployment time. The plugin creates a new MACI poll that hosts the encrypted private votes for that particular proposal.

The plugin then captures the current block number (minus one) as a snapshot to determine voter eligibility. Once they decide to vote, they can register their interest to vote via their DAO frontend (in MACI's context we call this process join a poll), and their voting power is determined by their token balance at the time of proposal creation. Voters can use their real wallet holding their tokens to register themselves by publishing a MACI public key created on their devices. After that, the voter can use any wallet to submit an encrypted message containing the registered public key and their selected option.

Voters are then able to vote using their full voting power by choosing one of the options available, which at this time are Yes, No or Abstain. Voting is completely handled by MACI’s smart contracts, therefore voters do not actually ever interact with the DAO plugin.

Once the proposal ends, MACI’s backend service (the coordinator service), starts processing the votes, and generate zk-SNARK proofs to be validated on chain. Voters can be sure of the correct execution thanks to those proofs verifying on chain. Finally, the results are uploaded and the proposal execution can be triggered.

The full flow can be observed in the diagram below:

new-flow-maci

A proposal execution can range from transferring funds, calling a function on the DAO smart contract itself, calling out an external contract (for instance to initiate a token swap), or setting up a new plugin.

An example proposal shown below, with a proposal requesting users to vote on whether they are happy to convert part of the DAOs USDC reserves to ETH.

dao1

The familiar voting interface makes privacy seamless - voters simply select their choice without needing to understand the cryptography running behind the scenes.

voting1

Implementation Considerations

  • Network Support: Currently compatible with all EVM chains such as Ethereum, Arbitrum, Optimism, and some zkEVM networks such as Scroll and Linea. Here is a list of all compatible networks.
  • Timeline: Vote processing is not immediate due to the need to process votes offchain and to generate zk-SNARK proofs of correct execution. The time it takes to process votes can be reduced by using more powerful hardware.
  • Reliance on trusted coordinator: MACI in its current form relies on a trusted coordinator entity which can decrypt the votes - this is an automated piece of software that can run on a server or a Trusted Execution Environment for more security. The team is working on decentralising the coordinator entity and will soon begin working on an upgraded version that uses homomorphic encryption and threshold encryption to distribute the responsibilities across multiple entities. Please note that while the coordinator can see the votes, they cannot censor users nor provide incorrect results.
  • Costs: Using MACI can be more costly than traditional blockchain-based voting. While these costs are negligible in layer 2 networks, costs can increase in Ethereum mainnet. Please refer to our costs section in the documentation website for more details on current benchmarks.

Next steps

As DAOs evolve from experimental communities to serious organisations managing significant resources, governance systems must evolve too. The current landscape presents an ideal opportunity for DAOs to pioneer MACI, thus we are looking for forward-thinking DAOs to pilot MACI’s governance plugin - especially those facing challenges around voter participation, sensitive decision-making, or community pressure. Ready to be among the first? Reach out at maci@pse.dev or join our Discord. Governance on Ethereum needs a privacy shake up, stay in the loop if you're interested in hearing what else the team has been working on.

References and resources

Acknowledgements

Thanks to the Aragon team for review.

2025 High Level Roadmap and recap

· 8 min read
ctrlc03
MACI team lead

Greetings anon, it’s been a while.

We’re excited to share with you what we're planning to build over 2025. Yes, we know it’s already March, so let’s start with a recap of what the team has been up to in the recent months, before moving to what’s up next.

MACI Coordinator service

We are happy to announce that we completed the work on developing a service to automate MACI coordinator functionality. This includes:

  • Contract deployment
  • Subgraph deploying
  • Proof generation
  • Proof and results submission

This server exposes a REST API, as well as some Websocket endpoints (for proof generation only). We soon will publish a detailed guide on how to use, and how to integrate it via its SDK -stay tuned for a separate blog post.

For anyone interested in the code, you can find it here.

MACI Offchain voting support

After Vitalik’s post original idea, the team worked on an implementation of offchain voting for MACI. This comes in the form of a relayer service, which can be run by the coordinator to support offchain vote submission, effectively reducing the cost for users to only the signup transaction.

In the future we plan to research how to extend support to signups too.

In a nutshell, the service exposes a REST API that allows voters to submit MACI messages, they only need to prove that they are signed up by posting a zk proof to avoid spam on the service. The coordinator will wait for batches of n messages to be collected, then post the hashes of the messages to the Poll smart contract, alongside an IPFS hash where these messages are stored. This allows to keep costs down for coordinators, as they would only need to post the message hashes compared to relaying message by message and hashing them on-chain. At the same time, users can vote for free, and if they do believe they have been censored, for instance they do not see their vote on the IPFS file, they can go directly on-chain and use MACI as normal.

It should be noted that at this time, using this feature might result in failure if either of the two are true:

  • The coordinator calls relayMessagesBatch with invalid message hashes (there is no corresponding message on IPFS or local relayer storage)
  • The coordinator posts message hashes on chain before they are stored on IPFS and local storage is lost

While both of these result in a liveness issue, MACI does not provide liveness guarantees either way, as in its current form the coordinator could choose to not complete a poll, and no one else would be able to process votes on their behalf. We will be looking to improve on this guarantees in out future work.

MACI v3

We are very close to completing a new version of MACI - v3. This new version comes with features that have been requested in the past, such as polls being more customisable, in terms of voice credits assigned to voters, and gatekeeping mechanisms.

At a high level, the new features/improvements are:

  1. Custom voice credits per poll
  2. Custom gatekeeping per poll
  3. Replacement of vote merkle trees for more efficient hash-chains

Up until now, MACI has not prioritised reusability of the smart contracts. More often than not, production votes using MACI relied on deploying new instances of the main MACI smart contract, resulting in users joining with a new set of keys every time. This by consequence results in these keys not holding more value than a single vote, thus enabling key selling. With this new version, we envision a single MACI smart contract to be the entry point for several polls, where voters are “forced” to signup to individual polls with the same key that they used to signup to the main smart contract. In production use cases, this could be follow this script:

  1. The main MACI contract is set to gatekeep access using a very strong sybil mechanism, such as proof of passport
  2. Users signup by proving they are human
  3. For each poll that is created, voters can join with the same key if they wish to participate and if they can pass the specific poll gatekeeping requirements. For instance a specific poll might allow only Indian voters, thus use a Anon Adhaar policy to gate access

User research

In order to inform MACI’s future roadmap and which use cases to tackle, we started to conduct user research. MACI has been historically used only in public goods funding, via protocols such as clr.fund, QFI, Gitcoin’s Allo stack, and MACI Platform. As we see a diminished interest and need for private voting in public goods funding, we decided to focus on a new use case which clearly has a larger demand for MACI - governance.

While still in the early discovery phase, we identified demand for MACI to be integrated into DAO governance protocol stacks like Aragon’s OSX in the form of a plugin. We are aiming to build a demo plugin and showcase it to Aragon in the coming months.

We hope to partner with several governance providers to enhance your voting offerings through modules/plugins.

2025 - What will we focus the rest of the year

For this year, we plan to tackle a few different epics:

  1. Release of MACI v3
  2. Begin work to decentralize the coordinator using either homomorphic encryption or collaborative SNARKs
  3. Integrate MACI into Aragon OSX’s stack
  4. Continue with user research

MACI v3

We have just talked about MACI v3, so what is left to add is that we will be looking to complete the documentation updates, clean up the code and release it as soon as possible. Get ready for an even better version of MACI, and please reach out if you would like to integrate v3, we are here to support.

What about coordinator decentralisation?

That sounds interesting.. Let’s talk about that.

One of MACI long standing issues has been the privileges that the coordinator role has. They are able to see all of the votes in cleartext, which allows them to collude with bribers themselves, as well as voters. As we look to tackle use cases such as DAO governance where lot of money is involved in proposals, we need to ensure that collusion between the coordinator and voters/bribers is reduced. This can be accomplished in several ways:

  • Use Multi Party Computation (MPC)
  • Use Homomorphic Encryption (HE)
  • Use a Trusted Execution Environment (TEE)

Without going into much details here (keep an eye out for a separate post), to actually decentralise the coordinator role we will need either MPC (in the forms of co-SNARKs) or HE. The team is researching the available technologies to come up with a proposal on how to tackle this problem. We are very excited to improve MACI’s security and bring an even better primitive to projects that want private and secure voting.

Integrating MACI into the Aragon OSX stack

After some discussion with Aragon, we decided to build a demo to showcase how MACI could be used in DAOs created using Aragon’s OSX stack.

The goal is to get a working demo in the coming months that allow to create new voting proposals where DAO token holders can vote Yes, No, or Abstain. At this time, we will be making a very simple integration, and in the future we plan to integrate some features into the MACI protocol which would make it more suited for DAO governance, such as:

  • Have a custom type of polls where one can only vote with all of their voting power (currently there is no option to restrict this and voters can allocate their voting power as they prefer across several available options)
  • Count the number of votes for each option (currently this is not possible, the coordinator would need to provide this information, without a way to prove its correctness)

Once the demo is out and some DAOs test it out, we look forward to preparing this to be production ready and target running some DAO voting, from a supportive perspective.

You can track progress of development on this repo.

Continue with user research

While we have identified a new use case to tackle, governance, we still want to continue speaking with different projects and individuals to learn even more where can provide value in the short, and long term.

We have identified some projects that we want to chat with, however are open to suggestion - know anyone that is interested in private and anti collusion voting? Introduce them to us to help us understand how we can help democracy thrive.

Getting Started with MACI

· 7 min read
Crisgarner
MACI team contributor

Hey folks! We’re thrilled to kick off a series of tutorials covering everything you need to know about MACI. This guide will focus on installing MACI and deploying the contracts to a testnet. Let’s get started!

Understanding Roles

MACI protocol has two main roles, User (Voter) and Coordinator. A simplified version would be to say that the coordinator is in charge of deploying the MACI smart contracts, initiating the polls, tallying the final results of a vote, and finalizing polls by publishing the final results on-chain. Usually the contract deployer is the coordinator, but this can be a separate entity.

Requirements

Let's install the required tools first:

  • Node.js: use a JS toolchain manager like nvm or volta to install Node.js. We recommend using Node 20 or above.
  • pnpm: Fast, disk space efficient package manager.

Installation

Now you can run the following commands to install MACI locally:

git clone https://github.com/privacy-scaling-explorations/maci.git && \
cd maci && \
git checkout v2.5.0 && \
pnpm i && \
pnpm run build
note

Unless you are looking to contribute to the MACI codebase, we suggest you use the latest released version. You can check all the releases here.

Download the zero knowledge artifacts

MACI has two main zk-SNARK circuits, and each of them is parameterized. There should be one .zkey file for each circuit and set of parameters.

Unless you wish to generate a fresh set of .zkey files, you should obtain them from someone who has performed a multi-party trusted setup for said circuits. For more details on which artifacts have undergone a trusted setup, please refer to the Trusted Setup page.

important

Note the locations of the .zkey files cause you will need it when deploying contracts. (put in the deploy-config.json)

Download test artifacts

For all but production use cases, we suggest using the test artifacts, with the latest dev code, you can download them by running:

pnpm download-zkeys:test

Download ceremony artifacts

For production you need to use the ceremony artifacts which have undergone a trusted setup, you can download them with the command:

pnpm download-zkeys:ceremony
info

Currently, the ceremony artifacts work with MACI version up to 2.x

Deploy Contracts

Before deploying the contracts we need to do some final configurations to our repository.

Set the environment variables

Head to the packages/contracts folder and copy the .env.example file.

cd packages/contracts && \
cp .env.example .env

Make sure to include a mnemonic and RPC url (make sure to replace NETWORK with the network you want to use).

MNEMONIC = "your ethereum secret key";
NETWORK_RPC_URL = "the eth provider url";
NETWORK_ETHERSCAN_API_KEY = "etherscan api key";

Generate Coordinator Keys

In order to run MACI polls, a coordinator is required to publish their MACI public key. You will need to generate a MACI keypair, and treat the private key just as your ethereum private keys. Please store them in a safe place as you won't be able to finish a round if you lose access, or if compromised a bad actor could decrypt the vote and publish them online. You can generate a new key pair using maci-cli by running the following commands:

cd packages/cli && \
node build/ts/index.js genMaciKeyPair

Set the configuration file

note

There are already some deployed contracts that could be reused. More information can be found in the (incremental documentation page)[docs/getting-started#deploy-maci-contracts].

Head back to the contracts folder and copy the config example and update the fields as necessary:

cd ../contracts && \
cp deploy-config-example.json deploy-config.json

ConstantInitialVoiceCreditProxy

Defines how many credits will get each voter.

Gatekeeper

MACI uses a "gatekeeper" contract to configure and enforce the eligibility criteria of voters who can participate in MACI polls. In other words, it is a way to allowlist signups to the system to protect against sybil attacks. Please refer to the gatekeeper page in the documentation for more information on the supported Gatekeepers.

important

For testing we suggest using the FreeForAllGatekeeper as it allows anyone to signup on MACI.

MACI

This property defines which Gatekeeper and stateTreeDepth MACI is going to use. The stateTreeDepth defines how many users the system supports.

important

The stateTreeDepth value for test artifacts is: 10. For ceremony keys: 14.

VkRegistry

The VkRegistry hold the verifying keys used to verify the proofs, on the zkeys field we define the path to the zero knowledge artifacts we downloaded in the previous steps.

important

The values for test keys are: 10-1-2-2-1. For ceremony keys: 14-5-9-3-2.

Poll

Configures the poll duration in seconds, determines whether quadratic voting is enabled, and sets the public key of the Coordinator.

Deploy MACI Contracts

To deploy the MACI contracts to a specific network you can append :network to the deployment commands, e.g. pnpm deploy:sepolia - please refer to the supported networks documentation page to see all available networks.

pnpm deploy:NETWORK

Deploy Poll

Before deploying a Poll, make sure you have set the coordinator MACI public key to which you own the private key. To deploy your first Poll you can run the following command:

pnpm deploy-poll:NETWORK
important

Starting another poll doesn't require deploying MACI contracts again, you can run pnpm deploy-poll:NETWORK command and then use the new poll-id.

Poll Finalization

As a coordinator, first you need to merge signups and messages (votes). Messages are stored in a queue so when the poll is over, the coordinator needs to create the merkle tree from the queue (AccQueue). This optimization is needed to reduce gas cost for voters. Then the coordinator generates proofs for the message processing, and tally calculations. This allows to publish the poll results on-chain and then everyone can verify the results when the poll is over. You run a merge with:

pnpm merge:[network] --poll [poll-id]

Then you need to generate the proofs with the following command:

pnpm run prove:[network] --poll [poll-id] \
--coordinator-private-key [coordinator-maci-private-key] \
--tally-file ../proofs/tally.json \
--output-dir ../proofs/proofs/ \
--start-block [block-number] \
--blocks-per-batch [number-of-blocks]
important

You can reduce the time of the proving by including more blocks per batch, you can try with 500.

Submit On-chain

Now it's time to submit the poll results on-chain so that everyone can verify the results:

pnpm submitOnChain:[network] --poll [poll-id] \
--output-dir proofs/ \
--tally-file proofs/tally.json

Tally

Once the proofs are generated, and results tallied, the results (Tally) are written to a file. Let's take a look at one:

{
"maci": "0xd54b47F8e6A1b97F3A84f63c867286272b273b7C",
"pollId": "0",
"network": "localhost",
"chainId": "31337",
"isQuadratic": true,
"tallyAddress": "0xD4fbAF1dFe100d07f8Ef73d8c92e93d0Bcf7b45D",
"newTallyCommitment": "0x2f55cc85f7f141098ba791a9f6a646f8773b9bb4f5852ccc33b5a28e7b0756e5",
"results": {
"tally": [
"9",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0"
],
"salt": "0x2e9cd240b86cf456fa4deced8e7420c45e3c16941d2dcec308f8b6d48264dda3",
"commitment": "0x296eac2a7289974f23497bebd39e86599d0b7032796fb84dcc1f6bbda38262ca"
},
"totalSpentVoiceCredits": {
"spent": "81",
"salt": "0x24f57b75c227987727c13d1e83409d70478b42bdc12a4a4df8129c72fbaf5aaf",
"commitment": "0xb4ebe68b0da828c0b978ddee86ba934b8e215499ac766491f236ad85fd606de"
},
"perVOSpentVoiceCredits": {
"tally": [
"81",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0",
"0"
],
"salt": "0x2590434ea2d600f7bd2396ba7fa454ad4c975c29424ee481561d9786538a5e48",
"commitment": "0x54ec996599886da21c4b07c25d1de544292a8b7c38b79726995c869c9e95db"
}
}

We observe an array named results, which holds the aggregated votes for each option. Each option corresponds to an index in the array. In the example above, the first option (index 0) received a total of 9 votes, while all other options received no votes

The totalSpentVoiceCredits object contains the total amount of voice credits spent in the poll. This is the sum of all voice credits spent by all voters, and in quadratic voting, is the sum of the squares of all votes.

The perVOSpentVoiceCredits will contain the amount of voice credits spent per vote option. In this case, the first option received 81 voice credits, and every other option received 0 voice credits. This is because there was only one valid vote casted, with a weight of 9. Given the quadratic voting formula, the total amount of voice credits spent is 81.


That should be all for this tutorial, feel free to join our discord for any questions or recommendations, and feel free to read our documentation for more in depth resources.

The birth of MACI Platform

· 7 min read
ctrlc03, Doris, Hodlon
MACI team members

MACI Platform - an exciting evolution for MACI

Hey folks, welcome to another update from the MACI team! Today we are excited to officially announce MACI Platform, a comprehensive platform that enables secure voting for all kinds of use cases and communities.

MACI Platform began as a fork of easy-retro-rpgf with the MACI protocol integrated. We called it “MACI-RPGF”, and it provided a base product that could run retroactive public goods funding with privacy and anti-collusion properties.

Moving forward, the plan is to add even more features over time to fulfill a vision of the ultimate platform for super secure voting and funding that communities can easily deploy.

Overview

The platform is composed of three components:

  • A web interface for both voters and round organizers to interact with the contracts.
  • The MACI Platform smart contracts, an extended set of the MACI smart contracts that include registries for projects and fund disbursement features.
  • The Coordinator service allows for the complete automation of MACI.

MACI Platform Audience

MACI Platform is designed for a wide range of use cases: public goods funding, hackathon judging, grant making, community governance, and even state elections, to name a few. At its core, the product consists of three types of users: the Round Operator (the host of a voting round), the Applicant (those wishing to submit an application for inclusion in the round), and a subset of members that are allowed to participate in that voting round, or the Voters.

Having worked with the MACI protocol for years, we understand the ins-and-outs of its implementation and usage, and believe it is a powerful tool for creating a more democratic approach to building consensus within groups of people. However, we also understand that the user experience of MACI in its current implementation is far from accessible to many people. For this reason, MACI Platform is being built to be as easy and intuitive as possible for anyone to use.

The Vision

The vision for MACI Platform is to provide a clean and simple interface for communities to run different types of secure, anti-collusion voting and funding rounds.

While the current implementation of the platform is only built for the public goods funding use case, there are plans to focus on governance and local elections in the coming year.

From the operator’s perspective, our goal is to allow the creation of a round in less than 10 minutes. This includes setting up MACI contracts and creating a voting or funding round. All the information required to customize the round will be input through the frontend, and by passing it to the backend (the MACI coordinator service), all the necessary contracts will be deployed.

Projects applying to be part of a round can submit the required information via a form, which will be customizable by the round operator to include all required and relevant information for that specific round. Approvals of those projects will be at the discretion of the operators.

Finally, users/voters will be able to access the voting rounds only if they pass the gatekeeping requirements. Currently, it is possible to gate voting rounds using different strategies:

  • allowing anyone to participate
  • accepting only users with a certain EAS attestation
  • accepting only users part of a Semaphore group
  • accepting only users with a certain Hat
  • accepting only users with a certain Zupass credential

...and many more to come. Please refer to MACI’s gatekeeper page

Roadmap

What have we built so far? As of now, we have just released a version 1. This release focuses on voter and applicant project experience, enabling them to interact smoothly with the platform by signing up, submitting applications, and voting. Finally, users can also see results once the votes have been tallied by the coordinator.

V2 on the other hand, will focus on the round organizer experience. At a high level, the core devs are focusing on implementing the following features:

  • Dashboard for contract deployment and round configuration
  • Allowing multiple rounds to live within one MACI Platform instance
  • Payout disbursement via the interface by either the voters, applicants, or operators
  • Full integration with MACI’s coordinator service to allow finalization of rounds within the interface
  • Continued integration with different gatekeepers like Gitcoin Passport

Furthermore, we plan to experiment with AA (account abstraction) to enable smooth experiences for both users and organisers. For users, we have implemented an end-to-end flow using an embedded wallet and paymaster as part of PSE’s internal hackathon, as well as for the Devcon round. For organizers we will be using a smart account and session keys to safely interact with the coordinator service and interact with MACI contracts.

Ecosystem Harmony

Projects like Gitcoin, Dorahacks, Snapshot, Devfolio, and Jokerace all seem to offer very similar voting, polling, and quadratic funding solutions. So what makes MACI different?

At MACI, our goal isn’t to compete, but to help push the ecosystem toward using safer, more private, and collusion-resistant voting mechanisms. We're actively working with many of the above projects to integrate the MACI protocol, ensuring that the benefits of secure voting can be used where they’re needed most. MACI Platform presents itself as just one more quadratic funding platform for communities to choose from.

It's important to note that while the anti-collusion properties of MACI provide higher security guarantees, they do come with tradeoffs— particularly in terms of user experience (UX), cost, and simplicity. The MACI team is continuously working to address these tradeoffs, but for certain use cases, these tradeoffs may not be worthwhile. For example, the encryption of votes at the end of a round may not actually be desirable or aligned with the spirit or values of any specific community. MACI Platform aims to provide privacy solutions where they’re needed the most, and to augment and support existing voting platforms.

How to get involved

If you are a community event organizer and want to run a voting or funding round using MACI Platform, please reach out to us using this form. If you are a developer and want to contribute to the code then head over to our GitHub repo and take a look at the “good first issues” tags, or open a new one that you think it’s beneficial and you would like to work on.

Also, stay tuned for recurring voting rounds on demo.maci.vote and our participation in hackathon as sponsors.

References

2024 Q3 Review

· 4 min read
ctrlc03
MACI team lead

Glad to have you here! It's again that time where we have a few MACI roadmap updates to share.

We’re going to take a moment to look at what we accomplished in Q3, but before we start, we would like to express our gratitude to all our collaborators and contributors to the MACI protocol.

MACI Platform ✅

This quarter, the team continued to focus on building a comprehensive voting platform with MACI. The platform is now turning into an all-in-one solution for voting, quadratic funding, and RPGF rounds. We made the product much more stable by fixing several bugs, and plan on integrating many more features in the future.

In terms of current features, the platform supports these gating mechanisms:

It now also possible to run quadratic and non quadratic voting rounds, as well as running sequential rounds on the same interface. Soon you will also be able to run multiple concurrent rounds.

With the MACI Platform, we were able to support three community rounds, EthMexico, EthTegucigalpa, and Cryptoversidad. All rounds completed successfully with nearly $30,000.00 distributed to several projects and individuals across the three communities. We also received a lot of great feedback that helped improve the platform overall. We couldn’t be happier to work with such wonderful collaborators and help them make a real world impact.

As always, if you're interested in running a round for your community, please get in touch

Coordinator Service ✅

The Coordinator Service is the ultimate automation of MACI’s main pain-points. It now includes three new features for the frontend interface to provide a very neat experience to MACI operators.

Because we prioritise robust security features whenever possible, the service does not hold any wallet seed phrase to communicate with the various chains. Instead, we implemented a flow that uses ephemeral session keys for short lived approvals, greatly decreasing the impact of a key compromise. This is all possible thanks to account abstraction features such as session keys.

With the flow described above, we implemented a deployer service to easily deploy all needed MACI contracts, as well as an endpoint to merge the MACI state and message trees, an important step required to be able to tally the results.

Account Abstraction Exploration ✅

Together with a fellow PSE team developer, John, the MACI team is working on a fork of the MACI platform that implements account abstraction features, such as smart wallets and paymasters.

This fork was used in PSE’s first internal hackathon, and allows PSE and EF team members to vote on their favourite hackathon project without spending a single cent from their wallet onchain.

This was a successful experiment that will prove fundamental in our future efforts to improve the MACI platform and make it even more accessible to a general “non crypto native” user base.

Stay tuned for a case study of this experiment!

MACI Protocol Improvements ✅

The 3327 team successfully completed their Anonymous Poll Joining grant. This work enabled unconditional voter privacy, further strengthening user privacy in the protocol. For more details, please refer to their blog post.

With regard to implementing Vitalik’s latest MACI proposal Mostly Offchain Happy Path, we have not been able to start due to other priorities, however we have defined the tasks required and unblocked the epic by implementing the session keys flow on the coordinator service, so that it can be re-used for a secure relayer service.

In terms of developer experience, we always try to make it easier to onboard new developers to the protocol. As a result, we have been making improvements to the deployment tasks, documentation and smart contracts code. Now developers can more easily override deployment steps to integrate MACI's smart contracts into their own projects; and can extend smart contract functions to support custom logic.

Finally, our internal team has also been brainstorming features and improvements for MACI v3, however no plan is set in stone yet. Stay tuned for more.

MACI v2.0 Release

· 7 min read
ctrlc03
MACI team lead

We are pleased to announce the release of MACI v2.0.0!

This is our second big release of the year, after the MACI v1.2 release in February of this year. MACI v2.0 brings a more secure and efficient protocol, with improved developer experience, and clearer documentation for users looking to learn about and use MACI.

Background

MACI - Minimal Anti-Collusion Infrastructure - is an application that provides privacy and collusion resistance for on-chain voting. If you're new to MACI, we first recommend reading our documentation for background information and technical details.

New Features and improvements

More compact codebase

We have removed some features that were never used in production, namely Topup and Subsidy. This allowed us to reduce the codebase size, making it cheaper to deploy, as well as reducing the complexity of the zk-SNARK circuits.

We highly thank Chao for his work on these two features over the past years, and look forward to integrating similar features in the future as we come up with new use cases and performance improvements.

On top of that, the merkle tree-like structure holding the signups has been swapped out for a more efficient incremental merkle tree (LazyIMT). This offers some savings for users signing up, as well as simplifies the steps required to finalise a poll, by merging all leaves together and removing the need to compute the subroots and root of the tree.

Improved contract tasks

It is now possible to deploy contracts and finalise polls using the contracts tasks only. This makes the protocol much easier to use, as there is no need to use the maci-cli anymore, which often came with a large number of flags and options. You will just need to fill a json file with the correct parameters and run few simple commands.

Concurrent Polls

It is now finally possible to run multiple polls concurrently from a single MACI instance. Users will no longer need to signup again to vote on proposals published by a single organiser. One thing to note is that each poll will have the same amount of voting power, and new users will need to pass the same gating process as existing users.

We believe this feature will work best when used for coordinating several polls for the participants of a single event where signup is gated by the conference ticket and there are multiple voting rounds, like at Devcon or Devconnect.

New Gatekeepers

Custom Gatekeepers are a great way to guard MACI against Sybil attacks, and with this release we have integrated a number of new protocols, together with the help of our community:

For instance, with Gitcoin Passport as the gatekeeper, the MACI round organiser can set a threshold score and only allow new users with a passport score greater or equal to that threshold. Additionally, with Zupass, we can now gate access to holders of specific event tickets.

We expect to continue to expand our gatekeeper capabilities and welcome the community to come up with new and innovative ways to grant access to MACI's rounds, helping make MACI more customizable and sybil-resilient.

Documentation

You gave us the feedback that the MACI documentation was way too tough to digest, and we heard you! To make it easier to understand, we have grouped documentation entries under a more logical structure, with different sections for different audiences and objectives.

We continue to use our docs website as the definitive resource for all information related to MACI, including blog releases, documentation updates, and roadmap progress. As always, we welcome suggestions on how to make it better and encourage you to report any inconsistencies you may find.

Security Audit

As usual before a major release, the protocol has been thoroughly audited by PSE's internal Audit team, and this time no significant issues were found. However, thanks to the auditors' hard work, we have been able to further optimise the protocol and clean up our technical documentation.

For more details on this recent audit, please refer to our audit docs or view the full report.

With more and more eyes on the protocol, we feel more and more confident about MACI's security posture.

Trusted Setup Ceremony

We are preparing for a new ceremony to cover the changes in our v2.0.0 circuits. To accomplish this, we'll leverage the tooling of p0tion, which helps to streamline and automate Groth16 phase2 ceremonies.

We'll update this page after the ceremony completes to include the production-ready zkey artifacts. In the meantime, the artifacts for v.1.2 can be found on our website, and the artifacts can still be used in production for releases 1.2.0 up to 1.2.5.

Get Involved

MACI is deeply committed to our community, through our open initiatives like public roadmaps, transparent repository management, and a public Discord channel for interaction with our team.

With every issue, PR, feature and roadmap iteration, we welcome feedback to ensure that the continued development of MACI reflects your and the community's needs. Keep an eye on our documentationGitHub discussions and our official Twitter/X account for updates.

For those looking to contribute directly, report bugs, or offer feedback, our GitHub repository is open for issues and discussions. We're eager to assist with your projects or contributions.

For practical implementation insights, review our docs as well as the clr.fund, Allo Stack with MACI, and maci-platform repositories as reference implementations. The first two integrations are quadratic funding implementations, a mechanism which otherwise is highly susceptible to collusion and bribery.

For any other questions or feedback, please reach out to us via PSE's Discord, in our #🗳️-maci channel. We're excited to connect and collaborate with you!

References

Release

Here's the link to the new release code in GitHub: v2.0.0 Release.

2024 Q3 Roadmap

· 4 min read
ctrlc03
MACI team lead

Greetings anon,

We’re excited to share with you what we're building over the next few months. You'll see some of the same themes as our Q2 roadmap as we strive to make MACI and MACI-RPGF more user-friendly and accessible.

If you haven’t read the Q2 in review yet to learn what we’ve been up to the last three months you can check that out here.

MACI Platform

The team is doubling down efforts to build a comprehensive voting platform with MACI powering it all. Initially called maci-rpgf, the project is soon turning into an all-in-one solution for hosting voting, quadratic funding, and rpgf rounds. We plan to work on improving the product with the following high-level initiatives:

  • Complete the integration of the PSE's design team’s new design
  • Bootstrap an e2e testing framework to ensure the code is more robust and reliable
  • Support quadratic voting
  • Support the use of different signup mechanisms
  • Move application's data storage from Vercel to IPFS
  • Support contributing/voting to multiple rounds on the same deployment

Our efforts will include supporting community organisers who want to fork and operate MACI Platform rounds in production. If you're interested in running a round for your community, please get in touch!

Coordinator Service

After successfully implementing a proof generation service as part of our effort of reducing the burden on round organisers, we have plans to continue automating all MACI related operations. This includes contract deployment, proof generation and submission, contract details storage, automatic upload of final tally results to IPFS and more.

We see the “Coordinator Service” as the ultimate automation of MACI’s main pain-points, and look forward to building a secure and efficient service that will abstract away all the operational burdens of using MACI. For more information on the full feature list that this service will include, please refer to this GitHub issue.

Explore Account Abstraction

It is clear that mass adoption of blockchain applications will be difficult if users, especially first time users, must pay to interact with dapps. Furthermore, having a crypto wallet installed and configured to work on a specific chain might also not be straightforward for an average user.

To support this thesis, the MACI team will start a collaboration with other PSE teams involved in researching and implementing account abstraction (AA) solutions. We look forward to bringing some proof of concepts (PoC) for MACI Paymasters and more, which will help remove friction when it comes to web3 UX.

MACI Protocol Improvements

As always, we plan to improve the MACI protocol both in terms of making it cheaper and easier to use, as well as making it more secure.

As part of this effort, we are currently working with the 3327 team to integrate their Anonymous Poll Joining grant work into a new MACI version. The effort can be tracked in this public GitHub board. This work enables unconditional voter privacy, further strengthening user privacy in the protocol. For more details, please refer to this blog post.

On top of this, the team will begin the ground work to implement Vitalik’s latest MACI proposal Mostly Offchain Happy Path - in a nutshell, the proposal seeks to completely remove transaction costs for users by moving certain operations offchain. For maximum privacy and trustlessness, voters will still be able to go directly on-chain and submit their own signup/vote actions.

How does that sound?

Questions? Concerns? Ideas? We’d love to hear from you!

If there is a feature you think we should work on, or an initiative you'd like to collaborate with us on, please let us know! We welcome input from anyone in the community. The best ways to get in touch are to hop in our Discord (#🗳️-maci channel), tag us on X, or create an issue on GitHub.

Onward and upward 🚀

2024 Q2 Review

· 5 min read
ctrlc03
MACI team lead

Greetings anon,

Glad to have you here! It's that time of the year where we have a few MACI roadmap updates to share. We’re going to take a moment to look at what we accomplished in Q2, as the most active project in the entire PSE GitHub org.

Before we start, we would like to express our gratitude to all our collaborators and contributors to the MACI protocol.

Q2 in review

In our q2 roadmap, we aimed at a few major Q2 goals that all tied together:

✅ MACI-RPGF

A lot has happened with MACI-RPGF this last quarter. Much time has been spent improving the product in order to provide a more functional and stable product with a better overall user experience.

PSE's design team came up with a beautiful design that will soon be merged into the stable version of the code. We are looking forward to implementing this major update and are excited for you to try it!

maci-rpgf-design

On the outreach and support side, we also engaged with several communities to run a round using MACI-RPGF. There are three rounds ongoing with EthMexico, ETH Tegucigalpa and Cryptoversidad. Our developers have been working closely with their development teams to deploy and run MACI-RPGF. We look forward to supporting them throughout their rounds and helping facilitate the distribution of funds directly into community members building amazing things in the Ethereum ecosystem.

✅ MACI Coordinator Service

The use of a Coordinator Service would greatly simplify the operation requirements when running MACI. To better support communities running MACI polls, whether as a QF round or a simple voting application, the team has prioritised the development of a Coordinator Service that can be used by any Round Operator.

In the last three months we successfully completed the first iteration of a proof generation service, which can be used to more easily finalise MACI polls. Additionally, work on a frontend dashboard has started. This dashboard can be used to more easily deploy contracts in a customisable way via an intuitive user interface.

✅ MACI Core Protocol Improvements

To achieve our Q2 goal of “Unconditional Privacy" we worked with the 3327 team (responsible for the ElGamal on MACI implementation) to come up with an effective solution and a better user experience that we could have hoped for. More on this can be found in our blog, but we have now started this grant work and are looking forward to seeing this in action in the coming months.

We have also been busy working on some new features and improvements to the codebase. It is now easier than ever to deploy MACI instances, as well as re-use certain smart contracts that have already been deployed and will not need changing.

Furthermore, we have managed to slightly reduce the costs for users by removing unused features, as well as using different and more optimised data structures. This brought several improvements, such as allowing for concurrent polls to be run from one MACI instance (finally!).

Finally, we worked with the community to integrate a number of different gatekeepers:

You can now use these (plus more) to gatekeep signups to MACI and shoot down those sybil attacks!!.

Stay tuned for an upcoming MACI release where all these efforts can be seen in action.

✅ Support Gitcoin Allo protocol integration

Throughout May and June, Gitcoin and Nick Lionis in particular worked hard to integrate MACI in the Allo Stack. You can find the code on their GitHub. The stack will soon be used in production by Gitcoin to support running grant rounds privately.

We are excited to see rounds being run with this integration, and look forward to continue to collaborate with the Allo team to improve MACI and integrate new versions into their stack.

✅ Support ETHDam hackathon QV round

In April, we successfully supported the ETHDam team to run a private quadratic voting (QV) round for the ETHDam hackathon, powered by MACI. Conference attendees used clr.fund to vote on their favourite hackathon projects in order to allocate $10,000 to projects building novel privacy and security solutions in the ecosystem.

✅ MACI starter kit

We've teamed up with Buidl Guild and the Scaffold-ETH team to build a MACI starter kit: a web app that integrates MACI in order to run polls. Thanks to Yash's efforts we now have a ready-to-use MACI starter kit. This has already been used in two hackathons (as an example here's an Eth Berlin project) to quickly prototype projects using MACI. We thank Yash for all his effort with this and are looking forward to see what the community will build with it.

That was a lot, and there’s more to come! Be sure to keep an eye out here for our next post where we look forward to what is coming for MACI in Q3, 2024.

Upcoming grants for MACI protocol improvements

· 6 min read
ctrlc03
MACI dev

Minimal Anti Collusion Infrastructure (MACI) is a public good that allows one to run secure, private, on-chain voting polls.

Given MACI's open source nature, it's common for our core team to develop new features or to fix issues based on community feedback. However, it's been less common for external contributors to make significant changes to the core protocol.

Well, this soon will be a reality thanks to a MACI improvement proposal sent by the 3327 team. 3327 is collective of 10+ people working on improving blockchain technologies, with a focus on research and engineering. Their engineering team previously worked on implementing the ElGamal flow into MACI (here's a nice presentation on it from Marija Mikić at EthCC [6]). The work described in this post aims to be its direct replacement due to its simplified nature and several additional benefits.

This proposal can be divided into two parts:

  1. bring unconditional privacy to MACI's voters
  2. optimise inefficient merkle tree structure holding messages, by replacing it with a hash chain

1) Enable unconditional voter privacy

Currently with MACI, if a voter performs a key change, the voter's new key would not be anonymous to the coordinator. The coordinator could collude with a bad actor to inform the latter of the key change, as the coordinator would have access to all decrypted messages.

The key focus of this improvement is to enable users to be completely anonymous by removing the link between the original signup key and the key used for voting. How would this work? Well, users sign up to vote via the MACI contract, and depending on the gatekeeper in use, they'd have to prove that they've passed the entry condition. Now, given knowledge of this key, they can signup with a new key to polls deployed by this same MACI contract.

Thus, voters can prove anonymously that they know the preimage of a StateLeaf, by passing this information to a zk-SNARK circuit, and validating this proof within the poll contract when joining with the new key. You might be thinking that everyone knows the preimage of a state leaf, as it's public information that can be taken from the contracts' logs. However, the circuit will not accept the public key directly but would instead take the private key and use it to generate the public key. This way, only users with knowledge of a specific private key can generate a valid inclusion proof.

Now after signing up to the Poll with this new key, there will not be any link to the original key, and users will effectively be anonymous. Of course users should ensure that they are using different wallets where possible.

Finally, with the use of a nullifier, it will not be possible for the same original key to be used to signup more than once for each new poll.

Are there any drawbacks? Well, yes. There will be an extra step for users to register to individual Polls. We aim to offset this cost and additional step soon either with gasless transactions or by moving some logic off-chain.

2) Message structure optimisation

On top of the improvements to anonymity, the 3327 team aims to also replace the Merkle tree used for storing messages with a hash chain. Some of the benefits of this approach are:

  • unlimited number of messages
  • removal of expensive merge operations from the coordinator
  • cheaper to send messages as only one hash is required to update the hash chain
  • less constraints on the circuits due to simplified logic

Unlimited messages

Merkle trees are usually bound by a depth property. Together with the number of leaves per node, we can calculate the max capacity of a tree. For instance, for a binary tree with a depth of 10, we can host up to 2^10 (1024) leaves. On the other hand, hash chains do not have a limit, unless if we wanted to set one, so we technically can support an unlimited number of messages.

Cheaper operations

Hashing the previous hash chain with the message is cheaper than inserting into a Merkle tree. Additionally, removing the need for the coordinator to perform merge operations on the accumulator queues that were used on chain will greatly reduce costs and processing time.

Smaller circuits

As cited in their proposal, processing message inclusion proofs for k messages in a tree with height h requires k * h hashing operations within the circuit with 2 * k * h signal values for inclusion proofs. Processing messages with chain hashes removes the unnecessary inclusion proofs and requires only k hashes to be computed for k messages without any extra signals, as the requirement is to prove that the order and inclusion of all messages are correct.

A call for MACI grant proposals

So what does this mean for you, Anon?

As an open-source project of PSE with support from the Ethereum Foundation, MACI is fortunate to have the resources to invest in the maintenance and improvement of the protocol. This means we're able to fund full-time developers as well as allocate grants for various research and development initiatives.

We encourage all community members to contribute to the improvement and ongoing development of MACI! After all, our goal is to build the most secure e-voting system, and this cannot be accomplished without all of your support.

As a team, we are incredibly excited about this proposal and will continue to work hard to help the 3327 team get this upgrade production-ready over the next 3 months.

To contribute to MACI, submit issues, or learn more about it, you can reach out to us either via Discord or GitHub issues.

If you have an ambitious idea you'd like to work on, reach out to us and we could create a proposal to build together! If you don't yet have a specific idea but are still keen to work on MACI, we have some research ideas which might inspire you and we could collaborate on a grant together. Feel free to explore these ideas below and get in touch:

References

ETHDam(n)

· 9 min read
ctrlc03
MACI dev

During ETHDam's Quadratic Funding round, run on clr.fund, we discovered a critical bug in MACI. The issue stemmed from the lack of validation on MACI public keys within the Poll contract. A user (spoiler alert, it was a self-inflicted denial of service (DoS)) was able to submit a MACI public key which was not a point of the Baby JubJub elliptic curve, and it broke everything.

So... what happened, really?

Well, during the ETHDam round, there was an issue with the subgraph that caused the frontend web app to incorrectly display that the voting period had ended, which prevented users from voting.

A quick way for us to identify the issue was to directly call the Poll's smart contract to submit an invalid vote. If the contract accepted votes, that meant that it was not a MACI issue. Given the contract accepted votes, it immediately helped us confirm that the bug was a frontend issue. What we didn't know at the time was that this vote, as well as its associated key, would cause a denial of service.

The message in question can be seen on Gnosis Chain's block explorer. Below is proof that the wallet which submitted the invalid key is from one of our teammates (just in case you thought we'd want to censor it :P).

{
"address": "0xc59975735ed4774b3Ee8479D0b5A26388B929a34",
"msg": "This is proof that I control this wallet and dossed MACI by mistake while doing an invalid vote",
"sig": "0x8962b66462630f12476d7bdb348f08af574ba40dd32c6f149ea26717830f13f50f4e95574e8fc909dd3dd1e20bcd85ae2c3caaf41bed6b123973353635483b7f1b",
"version": "2"
}

One can verify the message using etherscan, paste the address, message and signature. Don't take our word for it, verify!

The message was sent alongside an invalid MACI public key. As a result, due to how MACI messages are processed, the zk-SNARK circuit failed to generate a proof, which prevented the QF round from finalizing.

A MACI public key is (supposedly, at least) a point on the Baby JubJub elliptic curve. The mistake that MACI's code made was to not validate at the smart contract level that the keys accepted as arguments were actually valid points on the curve. At the time the bug was triggered, the two coordinates of the point (x and y) were only checked to be less or equal to the curve prime order.

The MACI key in question looked like the below object:

{
"x": 1,
"y": 1
}

In MACI, messages are (well, should be) encrypted using a shared key generated using a random keypair and the coordinator's public key. This allows for the coordinator to reverse the process - as long as they have the random public key - and decrypt the message using the same shared key. This is achieved using Elliptic-curve Diffie–Hellman (ECDH).

Shared key generation from the user's side:

ECDH(randomKeyPair.privateKey, coordinatorPublicKey)

Shared key generation from the coordinator's side:

ECDH(coordinatorPrivateKey, randomKeyPair.publicKey)

The randomKeyPair.publicKey that was sent as {x: 1, y: 1} was eventually passed by the coordinator to a zk-SNARK circuit to try and decrypt the corresponding message and perform further processing.

When passed to the circuit, the code would perform the ECDH operation by performing a scalar multiplication between the public and the coordinator private key. This happens inside the MessageToCommand template, which calls the ECDH template. Here, there is a call to escalarMulAny which in turns calls SegmentMulAny, where we encounter the final call to Edwards2Montgomery where the error pops up.

Looking inside the Edwards2Montgomery template, we can see the operation that is performed on the public key. In short, the point is converted from the Twisted Edwards form to Montgomery form, as it allows for cheaper operations inside the circuit (whereas outside it is represented in its original Twisted Edward form).

The equation to convert between the two forms is presented below:

                1 + y       1 + y
[u, v] = [ ------- , ---------- ]
1 - y (1 - y)x

We can see how passing a y of 1, the equation would result in a division by zero. Below you can see the full stack trace of the error:

Error in template Edwards2Montgomery_349 line: 38
Error in template SegmentMulAny_362 line: 81
Error in template EscalarMulAny_364 line: 163
Error in template Ecdh_365 line: 23

Please note that passing x as 0 would also trigger this error, though within the EscalarMulAny template, this case is handled and the G8 point is passed instead, preventing an error while generating the proof.

Given this issue, we weren't able to complete the proof generation for message processing. It is somewhat good news, as once a message is posted to MACI's smart contracts, it's not possible to censor it even if these messages trigger bugs.

How was the round saved?

After understanding the bug, the team came up with a solution that would both allow EthDAM to pay out projects with cryptographic guarantee of the results, as well as provide a solution that is fully transparent and verifiable. After all, MACI is all about verifiability.

Given that the clr.fund round was run using a token with no monetary value (EthDAMToken), instead of spinning up a new round and asking users to re-submit their votes, we opted for an automated solution which would scrap all signups and contribution of this token, as well as all messages, and to re-submit them to the new clr.fund round contracts.

This way, voters can validate that all signups and votes were included, and by not submitting this invalid message, being able to generate zk-SNARK proofs and validate publicly the final tally result.

The script in question can be found in a gist. In a nutshell, the script pulled all signups from the original round fundingRound contract, and submitted them on the new contract, after having approved the new contract to spend all EthDAMToken tokens. Then, it pulls the messages, aside from the invalid one, and posts them to the new Poll contract.

After this, the EthDAM team was able to complete the tally alongside ZK proofs to be submitted on chain.

How did we fix MACI?

To fix the bug, we added code to validate that a given point is on the curve. The Solidity library, found within the original Baby JubJub paper, was originally developed by yondonfu and for sake of simplicity, it was copied over to the MACI's repo. The code needed just a couple of small upgrades to work with more recent Solidity versions (0.8.20).

/**
* @dev Check if a given point is on the curve
* (168700x^2 + y^2) - (1 + 168696x^2y^2) == 0
*/
function isOnCurve(uint256 _x, uint256 _y) internal pure returns (bool) {
uint256 xSq = mulmod(_x, _x, Q);
uint256 ySq = mulmod(_y, _y, Q);
uint256 lhs = addmod(mulmod(A, xSq, Q), ySq, Q);
uint256 rhs = addmod(1, mulmod(mulmod(D, xSq, Q), ySq, Q), Q);
return submod(lhs, rhs, Q) == 0;
}

As seen in the code above, the function will evaluate the Baby JubJub equation using the input public key x and y values. Any value that is not on the curve, will be rejected, as shown below:

// check if the public key is on the curve
if (!CurveBabyJubJub.isOnCurve(_encPubKey.x, _encPubKey.y)) {
revert InvalidPubKey();
}

The bug was fixed with this PR. On top of preventing such invalid values from being accepted by the contract, we also added more validation across the TypeScript libraries to make it harder for users to make such mistakes.

Footnote

The MACI team would like to first of all thank EthDAM's team for their patience while we navigated through this issue, and trusting us with coming up with a transparent solution for the round.

Furthermore, we thank mikerah from HashCloak for helping to review the fix, and their expertise in handling security incidents like this. Together with them, we looked at other repositories using similar code, looking for the same mistake, though we did not find similar protocols where an invalid key would cause a denial of service. If you are a ZK developer reading this, we hope this was a lesson that would help remind us all to always validate user input for future scenarios.

Finally, a big thank you to Raphael for explaining the math behind the issue, and suggesting that full point validation would end up being a much better solution than just not accepting y = 1.

Contract addresses

Below is a list of the contract addresses for this EthDAM round. All code is verified on Gnosis's block explorer and can be reviewed.

RoundToken

clr.fund Instance

Original round

New Round

MACI New Version

We decided to publish a new version of MACI with the fix (and other changes made since the 1.2 release). The new version is 1.2.1.

Please do not use the 1.2 version of the contracts for any new deployments, as it contains the bug described in this post. All other packages are safe, though 1.2.1 is the recommended version to use.