Skip to main content
Version: v1.2

MACI Security Audits

Full reports

  • Audit by PSE Audit 2024/02 report
  • Audit by HashCloak 2022/09 report
  • Audit by HashCloak 2021/09 report

PSE audit 2024

In February 2024 the PSE Audit team audited the MACI codebase with a focus on the smart contracts, TypeScript core, and Circom circuits Three critical bugs were found: two within the Circom circuits and one in the smart contracts. All three of these have been fixed.

Please see the PSE Audit report for details.

Veridise disclosure 2023

In March 2023, Veridise responsibly disclosed a number of issues to the MACI team, which were identified using their new tool for catching ZK circuit bugs.

Out of five issues disclosed, only three were relevant and have been since fixed by the MACI team. The other two issues were disregarded as they were present in older version of code which is not in use anymore.

We would like to thank the Veridise team for their effort in keeping open source projects safe.

Issue 1


In the template QuinSelector, if you want to confirm the input signal index is a valid integer less than 2**3, you should add Num2bits(3) to check it.

Code Location



Code location

// Ensure that index < choices
component lessThan = SafeLessThan(3);

This was fixed by adding a new Template, SafeLesThan which uses Num2Bits as further check on the signals:

// the implicit assumption of LessThan is both inputs are at most n bits
// so we need to add range check for both inputs
template SafeLessThan(n) {
assert(n <= 252);
signal input in[2];
signal output out;

component n2b1 = Num2Bits(n); <== in[0];
component n2b2 = Num2Bits(n); <== in[1];

component n2b = Num2Bits(n+1); <== in[0]+ (1<<n) - in[1];

out <== 1-n2b.out[n];

Issue 2


This issue is the same issue number 1, this time for the input signal index.

Code Location



PR with fix

As with issue number 1, a new template SafeGreaterThan was added:

// N is the number of bits the input have.
// The MSF is the sign bit.
template SafeGreaterThan(n) {
signal input in[2];
signal output out;

component lt = SafeLessThan(n);[0] <== in[1];[1] <== in[0];
lt.out ==> out;

And then used it to constrain the index input signal:

greaterThan[i] = SafeGreaterThan(3);
greaterThan[i].in[0] <== i;
greaterThan[i].in[1] <== index;

Issue 3


In the template QuinGeneratePathIndices, the constraints of the signal n[levels + 1] don't perform well for division and modulo counting.

Code Location



The updated code uses the SafeLessThen template, as shown below:

for (var i = 0; i < levels; i++) {
// Check that each output element is less than the base
leq[i] = SafeLessThan(3);
leq[i].in[0] <== out[i];
leq[i].in[1] <== BASE;
leq[i].out === 1;

// Re-compute the total sum
sum.nums[i] <== out[i] * (BASE ** i);

HashCloak audit 2022

In the summer of 2022, MACI v1 was audited by HashCloak. The audit covered both the zk-SNARK circuits and the Solidity smart contracts.

This audit revealed a number of high severity issues which have been remediated by the MACI development team. All issues were successfully fixed and reflected in MACI v1.1.1.

Please see the HashCloak report for details.

HashCloak audit 2021

From July 5th, 2021 to August 2nd, 2021, the Ethereum Foundation’s Applied ZKPs team engaged HashCloak for an audit of the MACI protocol. The audit was conducted with 3 auditors over 15 person weeks.

The following packages were in scope:

  • Circuits
  • Contracts
  • Core
  • Crypto
  • Domainobjs

From August 18, 2021 to September 22, 2021, Hashcloak assisted the MACI team in resolving the issues.

Please see the HashCloak report for details.