We are pleased to announce the release of an updated version of MACI - Minimal Anti-Collusion Infrastructure v1.1.1.
This new release brings a more secure product, new features, and a much needed documentation refresh. Before we dive into the updates, let's refresh your memory on what MACI is and what it was created to achieve.
Background
MACI is an application that provides collusion resistance for on-chain voting processes. It was originally created after Vitalik's post, and has since been revisited and improved.
MACI revolves around the need for a trusted coordinator. The coordinator is in charge of setting up the system, publishing its public key, and computing the tally of the votes. Below are the main properties of MACI:
Property | Description |
---|
Collusion Resistance | No one except a trusted coordinator should be certain of the validity of a vote, reducing the effectiveness of bribery. |
Receipt-freeness | No one can prove (besides to the coordinator) which way they voted. |
Privacy | No one except a trusted coordinator should be able to decrypt a vote. |
Uncensorability | No one — not even the trusted coordinator, should be able to censor a vote. |
Unforgeability | Only the owner of a user's private key may cast a vote tied to its corresponding public key. |
Non-repudiation | No one may modify or delete a vote after it is cast, although a user may cast another vote to nullify it. |
Correct execution | No one, not even the trusted coordinator, should be able to produce a false tally of votes. |
Since its inception, MACI has been adopted by different projects, most notably clr.fund and QFI. These projects prove how effective MACI can be, especially when integrated with applications that are otherwise prone to collusion, such as funding Public Goods.
For a more detailed description of MACI, please refer to the v1 technical introduction article.
Security Audit
MACI was audited by HashCloak in the summer of 2022. The audit team discovered certain high risk vulnerabilities, whose fixes were the focus of the MACI team in the past months.
In more details, the audit revealed two high risk issues within the zk-SNARK circuits:
- Incomplete validation when processing messages
- Integer overflow which could have allowed users to affect a coordinator's effort of calculating the subsidy by either making it incorrect or by intercepting the calculation
Another notable security issue was the lack of initialization of the AccQueue
contract. This contract is used to store messages (votes or topups) for the different polls. Without inserting a zero value hash into the merkle tree contract as the first message during initialization, a malicious user could have performed a denial of service attack on a poll. This could have resulted in the poll results taking a very long time before being tallied by the coordinator.
All of these issues have been successfully resolved, on top of fixing minor issues and general code optimizations. The updated product uses a more up to date and secure version of Solidity, and more thorough test cases to verify the correctness of the solution.
New Features
Feature | Description |
---|
Top Up Credit | Users can now top up credits rather than having to sign up with a different MACI key |
Pairwise Subsidy | Enhanced protection against collusion in quadratic funding |
Coordinator Service | Sample coordinator server for easier MACI use |
Top Up Credit
Rather than requiring a user to sign up multiple times, it is now possible to top up voice credits by sending a top up message on the Poll contract. Withdrawals are not enabled as this would allow a malicious user to bribe others offline to transfer their keys.
Now, the Poll contract will hold all the funds deposited from users for the current poll. At the end of a poll, the coordinator can transfer the funds to a hardcoded address which can be used to fund public goods.
When a user deposits tokens by calling topup, they will also need to specify the stateTree index. The topup function will insert a topup message into the message queue for them. When the voting period ends, any call of topup function will be rejected. Both voting and topup messages have the same ending time, which ensures there is a well-defined ending state for each poll.
Please note that in this approach, the initial credit is still shared across multiple polls, and the actual credit an user can spend in a given poll is the following: totalCredit=initialCredit+topupCredit
where the topupCredit
is the voice credit amount deposited by the user during the voting period of the given pollID.
For a detailed description, please refer to this document.
Pairwise Subsidy
Pairwise subsidy is a new way to reduce collusion in quadratic funding applications. If two contributors collude with each other, they can extract most of the public funding pool if they have enough funds.
In this post, Vitalik introduced this kind of collusion and also proposed a protocol to penalize this behavior. As a generalized solution, the more correlation between contributions, the smaller subsidy should be allocated to this project, as this reduces the risk of collusion between contributors. It should be noted that this solution assumes that an identity system is in place to prevent the same entity from registering with two different identities.
Please refer to this post for a more detailed explanation of the implementation.
Finally, please note that currently it is not possible to generate the zkeys
for the subsidy circuit with with the vote options
parameter larger than 52. This issue is documented here and the team will focus on finding a solution to be able to support larger vote options.
Coordinator Service
MACI now includes a sample coordinator service.
There are two roles in the coordinator service: admin (i.e. MACI coordinator) and user (i.e. a voter). The admin's responsibility is to ensure that the code remains updated and that the backend services are live. The user can then simply send HTTP requests to the backend server to interact with MACI, for instance, by signing up and publishing a message on chain.
The coordinator service has been wrapped into two docker instances: one for the backend server to accept user requests; one for the Mongodb service to store all necessary information on the current state such as smart contract addresses, zero knowledge proof keys and so on.
For further reading on coordinator services, please refer to this doc.
How to use MACI
MACI can be used as a standalone application to carry out on-chain polls, or be implemented into new projects that can then benefit from its properties.
For use as a standalone application, a cli
package is provided which allows coordinators and voters to use MACI. Please refer to this doc for details on how to use it.
To implement MACI into a project, the documentation can be used a reference, as well as reviewing how clr.fund and qf use MACI in their code.
MACI 0.x
MACI version 0.x will be discontinued. MACI 1.x has feature parity, more robust code and newest features. Users are encouraged to use the latest version. Starting February 7, 2023, the team will focus solely on resolving issues for MACI 1.x, and will cease to provide support for version 0.x.
How to get involved
Should you wish to get involved with MACI or simply report a bug, feel free to visit the repository and open an issue, or comment under an open issue to notify the team of your intention to work on it.
For any other enquiry, please reach out to us via the Privacy and Scaling Explorations (PSE) Discord.
References
Release
Here is a link to the new release code in GitHub - v1.1.1 Release.