MACI v1.0 Specification
This document is a copy of the MACI 1.0 Specification (for audit) document, created in July 2021 for one of MACI's formal audits.
This historical document is stored here for informational purposes. We do not intend to edit it. As a result, some of the information within this document may be outdated.
This is a detailed specification meant to assist auditors in reviewing MACI version 1.0.
We thank the Zkopru team for their protocol specification, which this document adopts.
Audit scope
The commit hashes relevant to this audit are the following:
Name | Commit |
---|---|
appliedzkp/maci (v1 branch) | 2db5f625b67a6b810bd851950d7a42c26189088b |
weijiekoh/circomlib (feat/poseidon-encryption branch) | 0e78dde8c813b95f4585b0613927e9c4269de500 |
The scope of the audit with regards to the circomlib
library covers:
- all the JS files that MACI references, excluding those which are not referenced by MACI's TS files
- all circuit files excluding those which are not referenced by MACI's circuit files
Statements that we wish to challenge
Through this audit, we wish to challenge the following statements:
- MACI exhibits collusion resistance
- No one except a trusted coordinator should be certain of the validity of a vote, reducing the effectiveness of bribery
- MACI exhibits receipt-freeness
- No voter may prove (besides to the coordinator) which way they voted
- MACI provides privacy
- No one except a trusted coordinator should be able to decrypt a vote
- MACI is uncensorable:
- No one (not even the trusted coordinator) should be able to censor a vote
- MACI provides unforgeability
- Only the owner of a user's private key may cast a vote tied to its corresponding public key
- MACI provides 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
1. Cryptographic primitives
Elliptic Curve Cryptography
MACI uses the Baby Jubjub Elliptic Curve as defined in this paper by Whitehat, Baylina, and Bellés.
1.1. The Baby Jubjub curve
Following the Baby Jubjub paper, we define the scalar field \(p\) as such:
The field is the finite field with modulo .
The generator point of Baby Jubjub is:
995203441582195749578291179787384436505546430278305826713579947235728471134,
5472060717959818805561601436314318772137091100104008585924551046643952123905
1.2. Private key generation
A private key is a random integer in the field .
MACI uses the Node.js crypto.randomBytes(32)
function to generate a cryptographically strong pseudorandom 32-byte value, as well as an algorithm to prevent modulo bias. In pseudocode this is expressed as:
lim = 2 ** 256
min = lim - p
rand = null
while true:
rand = BigInt(crypto.getRandomBytes(32))
if rand >= min:
break
privKey = rand % p
1.3. Private key formatting
The following procedures require that a private key be formatted into a scalar that can be multiplied with a point on the Baby Jubjub curve.
- Public key generation
- ECDH shared key generation
The algorithm to do so is as such:
- Hash the private key using as such:
- Take the lowest 32 bytes of as a buffer and prune it to derive . To prune the buffer, we:
2.1. Clear the lowest three bits of the 0th byte
2.2. Clear the highest bit of the 31st byte
2.3. Set the second-highest bit of the 31st byte to
1
. - Convert to its little-endian integer representation. We denote this as
- Shift right by 3 bits to get the formatted private key
1.4. Public key generation
A public key is a point on the Baby Jubjub curve. It is deterministically derived from a private key , the procedure to do so is almost identical to RFC8032.
- Format the private key [1.3]
- Multiply by 8 and multiply the resulting point by the formatted private key to derive the public key :