@maci-protocol/website 0.0.0-ci.1e276ed

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (415) hide show
  1. package/.eslintrc.js +157 -0
  2. package/CHANGELOG.md +566 -0
  3. package/LICENSE +22 -0
  4. package/README.md +58 -0
  5. package/babel.config.js +3 -0
  6. package/blog/2021-10-12-maci-v1.md +100 -0
  7. package/blog/2022-09-22-maci-v1-technical-introduction.md +180 -0
  8. package/blog/2023-01-18-maci-v1.1.1.md +121 -0
  9. package/blog/2024-01-18-roadmap.md +106 -0
  10. package/blog/2024-02-28-maci-v1.2.0.md +121 -0
  11. package/blog/2024-04-10-roadmap-q2.md +96 -0
  12. package/blog/2024-05-08-ethdam.md +169 -0
  13. package/blog/2024-05-22-the-origins-of-maci.md +38 -0
  14. package/blog/2024-05-28-upcoming-grants.md +85 -0
  15. package/blog/2024-06-17-understanding-maci.md +63 -0
  16. package/blog/2024-06-21-deciphering-maci.md +48 -0
  17. package/blog/2024-06-28-revolusioning-public-goods-funding.md +32 -0
  18. package/blog/2024-07-23-q2-review.md +72 -0
  19. package/blog/2024-07-30-roadmap-q3.md +61 -0
  20. package/blog/2024-08-10-maci-v2.md +102 -0
  21. package/blog/2024-08-29-anonymous-poll-joining.md +47 -0
  22. package/blog/2024-10-29-q3-review.md +63 -0
  23. package/blog/2024-11-20-maci-platform.md +93 -0
  24. package/blog/2024-12-01-maci-getting-started.md +294 -0
  25. package/blog/2025-03-21-roadmap-2025.md +112 -0
  26. package/blog/assets/MACI_Bob_SignUp_1.png +0 -0
  27. package/blog/assets/MACI_Bob_SignUp_2.png +0 -0
  28. package/blog/assets/MACI_Complex_Message.png +0 -0
  29. package/blog/assets/MACI_Contracts.png +0 -0
  30. package/blog/assets/MACI_Sign_Up.png +0 -0
  31. package/blog/assets/MACI_Simple_Message.png +0 -0
  32. package/blog/assets/MACI_Verifier_1.png +0 -0
  33. package/blog/authors.yml +5 -0
  34. package/docusaurus.config.ts +213 -0
  35. package/package.json +65 -0
  36. package/src/components/ActionCard/index.tsx +30 -0
  37. package/src/components/ActionCard/styles.module.css +96 -0
  38. package/src/components/HomepageFeatures/index.tsx +91 -0
  39. package/src/components/HomepageFeatures/styles.module.css +17 -0
  40. package/src/components/ProjectCard/index.tsx +74 -0
  41. package/src/components/ProjectCard/styles.module.css +77 -0
  42. package/src/components/ProjectList/index.tsx +218 -0
  43. package/src/components/ProjectList/styles.module.css +180 -0
  44. package/src/content/projects.json +294 -0
  45. package/src/css/card.module.css +130 -0
  46. package/src/css/custom.css +91 -0
  47. package/src/icons/IconDiscord.tsx +16 -0
  48. package/src/icons/IconGithub.tsx +16 -0
  49. package/src/icons/IconWebsite.tsx +16 -0
  50. package/src/pages/blogs.tsx +58 -0
  51. package/src/pages/index.module.css +152 -0
  52. package/src/pages/index.tsx +66 -0
  53. package/src/pages/projects.tsx +44 -0
  54. package/src/pages/roadmap.md +150 -0
  55. package/src/pages/typedoc.tsx +11 -0
  56. package/src/plugins/blog-plugin/index.ts +86 -0
  57. package/src/react-app-env.d.ts +1 -0
  58. package/src/scripts/setupSolidityDocs.ts +67 -0
  59. package/src/scripts/setupTypedoc.ts +112 -0
  60. package/src/scripts/utils.ts +115 -0
  61. package/src/utils/getProjectsByFilter.ts +40 -0
  62. package/static/.nojekyll +0 -0
  63. package/static/audit_reports/20210922_Hashcloak_audit_report.pdf +0 -0
  64. package/static/audit_reports/202220930_Hashcloak_audit_report.pdf +0 -0
  65. package/static/audit_reports/20240223_PSE_Audit_audit_report.pdf +0 -0
  66. package/static/audit_reports/20240731_PSE_Audit_audit_report.pdf +0 -0
  67. package/static/fonts/DM_Sans.woff2 +0 -0
  68. package/static/fonts/Share_Tech_Mono.woff2 +0 -0
  69. package/static/img/box.png +0 -0
  70. package/static/img/box_dark.png +0 -0
  71. package/static/img/chain.png +0 -0
  72. package/static/img/chain_dark.png +0 -0
  73. package/static/img/chart.png +0 -0
  74. package/static/img/chart_dark.png +0 -0
  75. package/static/img/circuits/MACI-Circuits.excalidraw +39652 -0
  76. package/static/img/circuits/calculateTotal.svg +21 -0
  77. package/static/img/circuits/ecdh.svg +21 -0
  78. package/static/img/circuits/messageToCommand.svg +21 -0
  79. package/static/img/circuits/messageValidator.svg +21 -0
  80. package/static/img/circuits/poseidonHasher13.svg +21 -0
  81. package/static/img/circuits/privToPubkey.svg +21 -0
  82. package/static/img/circuits/processMessages.svg +21 -0
  83. package/static/img/circuits/processMessagesInputHasher.svg +21 -0
  84. package/static/img/circuits/processMessages_2_0.svg +21 -0
  85. package/static/img/circuits/processOne.svg +21 -0
  86. package/static/img/circuits/processTopup.svg +21 -0
  87. package/static/img/circuits/processingAfterPollEnds.svg +21 -0
  88. package/static/img/circuits/quinBatchLeavesExists.svg +21 -0
  89. package/static/img/circuits/quinCheckRoot.svg +21 -0
  90. package/static/img/circuits/quinGeneratePathIndices.svg +21 -0
  91. package/static/img/circuits/quinSelector.svg +21 -0
  92. package/static/img/circuits/resultsCommitmentVerifier.svg +21 -0
  93. package/static/img/circuits/splicer.svg +21 -0
  94. package/static/img/circuits/tallyInputHasher.svg +21 -0
  95. package/static/img/circuits/tallyVotes.svg +21 -0
  96. package/static/img/circuits/unpackElement.svg +21 -0
  97. package/static/img/circuits/verifySignature.svg +21 -0
  98. package/static/img/completingAPoll.svg +4 -0
  99. package/static/img/contracts.svg +16 -0
  100. package/static/img/coordinatorComponents.svg +21 -0
  101. package/static/img/favicon.ico +0 -0
  102. package/static/img/generateProofs.svg +4 -0
  103. package/static/img/hero.svg +9 -0
  104. package/static/img/maci-card.png +0 -0
  105. package/static/img/maci-rpgf-design.jpg +0 -0
  106. package/static/img/messageProcessingLocal.svg +21 -0
  107. package/static/img/offlineProcessing.svg +21 -0
  108. package/static/img/pse-logo-round.png +0 -0
  109. package/static/img/relayer-diagram.png +0 -0
  110. package/static/img/tallyCommitments.svg +4 -0
  111. package/static/img/voteTallyingLocal.svg +21 -0
  112. package/tsconfig.json +34 -0
  113. package/versioned_docs/version-v0.x/circuits.md +22 -0
  114. package/versioned_docs/version-v0.x/contract.md +186 -0
  115. package/versioned_docs/version-v0.x/faq.md +67 -0
  116. package/versioned_docs/version-v0.x/introduction.md +119 -0
  117. package/versioned_docs/version-v0.x/quadratic-vote-tallying-circuit.md +138 -0
  118. package/versioned_docs/version-v0.x/state-root-transition-circuit.md +230 -0
  119. package/versioned_docs/version-v1.2/audit.md +160 -0
  120. package/versioned_docs/version-v1.2/ci-pipeline.md +38 -0
  121. package/versioned_docs/version-v1.2/circuits.md +508 -0
  122. package/versioned_docs/version-v1.2/cli.md +689 -0
  123. package/versioned_docs/version-v1.2/contracts.md +445 -0
  124. package/versioned_docs/version-v1.2/contributing/code-of-conduct.md +91 -0
  125. package/versioned_docs/version-v1.2/contributing/contributing.md +129 -0
  126. package/versioned_docs/version-v1.2/coordinator-processing.md +46 -0
  127. package/versioned_docs/version-v1.2/deployment.md +122 -0
  128. package/versioned_docs/version-v1.2/installation.md +175 -0
  129. package/versioned_docs/version-v1.2/integrating.md +200 -0
  130. package/versioned_docs/version-v1.2/introduction.md +94 -0
  131. package/versioned_docs/version-v1.2/key-change.md +182 -0
  132. package/versioned_docs/version-v1.2/overview.md +47 -0
  133. package/versioned_docs/version-v1.2/poll-types.md +68 -0
  134. package/versioned_docs/version-v1.2/primitives.md +216 -0
  135. package/versioned_docs/version-v1.2/project-ideas.md +14 -0
  136. package/versioned_docs/version-v1.2/purpose.md +62 -0
  137. package/versioned_docs/version-v1.2/solidity-docs/MACI.md +345 -0
  138. package/versioned_docs/version-v1.2/solidity-docs/MessageProcessor.md +266 -0
  139. package/versioned_docs/version-v1.2/solidity-docs/MessageProcessorFactory.md +26 -0
  140. package/versioned_docs/version-v1.2/solidity-docs/Poll.md +381 -0
  141. package/versioned_docs/version-v1.2/solidity-docs/PollFactory.md +50 -0
  142. package/versioned_docs/version-v1.2/solidity-docs/SignUpToken.md +27 -0
  143. package/versioned_docs/version-v1.2/solidity-docs/Subsidy.md +218 -0
  144. package/versioned_docs/version-v1.2/solidity-docs/SubsidyFactory.md +27 -0
  145. package/versioned_docs/version-v1.2/solidity-docs/Tally.md +311 -0
  146. package/versioned_docs/version-v1.2/solidity-docs/TallyFactory.md +27 -0
  147. package/versioned_docs/version-v1.2/solidity-docs/TallyNonQv.md +296 -0
  148. package/versioned_docs/version-v1.2/solidity-docs/TallyNonQvFactory.md +27 -0
  149. package/versioned_docs/version-v1.2/solidity-docs/TopupCredit.md +61 -0
  150. package/versioned_docs/version-v1.2/solidity-docs/VkRegistry.md +457 -0
  151. package/versioned_docs/version-v1.2/solidity-docs/benchmarks/HasherBenchmarks.md +44 -0
  152. package/versioned_docs/version-v1.2/solidity-docs/crypto/Hasher.md +125 -0
  153. package/versioned_docs/version-v1.2/solidity-docs/crypto/IVerifier.md +11 -0
  154. package/versioned_docs/version-v1.2/solidity-docs/crypto/MockVerifier.md +17 -0
  155. package/versioned_docs/version-v1.2/solidity-docs/crypto/Pairing.md +85 -0
  156. package/versioned_docs/version-v1.2/solidity-docs/crypto/PoseidonT3.md +9 -0
  157. package/versioned_docs/version-v1.2/solidity-docs/crypto/PoseidonT4.md +9 -0
  158. package/versioned_docs/version-v1.2/solidity-docs/crypto/PoseidonT5.md +9 -0
  159. package/versioned_docs/version-v1.2/solidity-docs/crypto/PoseidonT6.md +9 -0
  160. package/versioned_docs/version-v1.2/solidity-docs/crypto/SnarkCommon.md +16 -0
  161. package/versioned_docs/version-v1.2/solidity-docs/crypto/SnarkConstants.md +40 -0
  162. package/versioned_docs/version-v1.2/solidity-docs/crypto/Verifier.md +61 -0
  163. package/versioned_docs/version-v1.2/solidity-docs/gatekeepers/EASGatekeeper.md +121 -0
  164. package/versioned_docs/version-v1.2/solidity-docs/gatekeepers/FreeForAllSignUpGatekeeper.md +40 -0
  165. package/versioned_docs/version-v1.2/solidity-docs/gatekeepers/SignUpGatekeeper.md +26 -0
  166. package/versioned_docs/version-v1.2/solidity-docs/gatekeepers/SignUpTokenGatekeeper.md +93 -0
  167. package/versioned_docs/version-v1.2/solidity-docs/gatekeepers/hatsGatekeepers/HatsGatekeeperBase.md +79 -0
  168. package/versioned_docs/version-v1.2/solidity-docs/gatekeepers/hatsGatekeepers/HatsGatekeeperMultiple.md +48 -0
  169. package/versioned_docs/version-v1.2/solidity-docs/gatekeepers/hatsGatekeepers/HatsGatekeeperSingle.md +42 -0
  170. package/versioned_docs/version-v1.2/solidity-docs/index.md +4 -0
  171. package/versioned_docs/version-v1.2/solidity-docs/initialVoiceCreditProxy/ConstantInitialVoiceCreditProxy.md +40 -0
  172. package/versioned_docs/version-v1.2/solidity-docs/initialVoiceCreditProxy/InitialVoiceCreditProxy.md +26 -0
  173. package/versioned_docs/version-v1.2/solidity-docs/interfaces/IEAS.md +40 -0
  174. package/versioned_docs/version-v1.2/solidity-docs/interfaces/IHats.md +103 -0
  175. package/versioned_docs/version-v1.2/solidity-docs/interfaces/IMPFactory.md +26 -0
  176. package/versioned_docs/version-v1.2/solidity-docs/interfaces/IMessageProcessor.md +31 -0
  177. package/versioned_docs/version-v1.2/solidity-docs/interfaces/IPoll.md +217 -0
  178. package/versioned_docs/version-v1.2/solidity-docs/interfaces/IPollFactory.md +29 -0
  179. package/versioned_docs/version-v1.2/solidity-docs/interfaces/ITallyFactory.md +28 -0
  180. package/versioned_docs/version-v1.2/solidity-docs/interfaces/ITallySubsidyFactory.md +27 -0
  181. package/versioned_docs/version-v1.2/solidity-docs/interfaces/IVerifier.md +25 -0
  182. package/versioned_docs/version-v1.2/solidity-docs/interfaces/IVkRegistry.md +70 -0
  183. package/versioned_docs/version-v1.2/solidity-docs/mocks/MockHatsProtocol.md +133 -0
  184. package/versioned_docs/version-v1.2/solidity-docs/trees/AccQueue.md +464 -0
  185. package/versioned_docs/version-v1.2/solidity-docs/trees/AccQueueBinary.md +60 -0
  186. package/versioned_docs/version-v1.2/solidity-docs/trees/AccQueueBinary0.md +40 -0
  187. package/versioned_docs/version-v1.2/solidity-docs/trees/AccQueueBinaryMaci.md +34 -0
  188. package/versioned_docs/version-v1.2/solidity-docs/trees/AccQueueQuinary.md +75 -0
  189. package/versioned_docs/version-v1.2/solidity-docs/trees/AccQueueQuinary0.md +40 -0
  190. package/versioned_docs/version-v1.2/solidity-docs/trees/AccQueueQuinaryBlankSl.md +40 -0
  191. package/versioned_docs/version-v1.2/solidity-docs/trees/AccQueueQuinaryMaci.md +40 -0
  192. package/versioned_docs/version-v1.2/solidity-docs/trees/EmptyBallotRoots.md +13 -0
  193. package/versioned_docs/version-v1.2/solidity-docs/utilities/CommonUtilities.md +25 -0
  194. package/versioned_docs/version-v1.2/solidity-docs/utilities/DomainObjs.md +40 -0
  195. package/versioned_docs/version-v1.2/solidity-docs/utilities/Params.md +36 -0
  196. package/versioned_docs/version-v1.2/solidity-docs/utilities/Utilities.md +79 -0
  197. package/versioned_docs/version-v1.2/spec.md +944 -0
  198. package/versioned_docs/version-v1.2/testing-in-detail.md +209 -0
  199. package/versioned_docs/version-v1.2/testing.md +472 -0
  200. package/versioned_docs/version-v1.2/topup.md +43 -0
  201. package/versioned_docs/version-v1.2/troubleshooting.md +51 -0
  202. package/versioned_docs/version-v1.2/trusted-setup.md +76 -0
  203. package/versioned_docs/version-v1.2/typedoc/cli/.nojekyll +1 -0
  204. package/versioned_docs/version-v1.2/typedoc/cli/index.md +15 -0
  205. package/versioned_docs/version-v1.2/typedoc/cli/interfaces/AirdropArgs.md +89 -0
  206. package/versioned_docs/version-v1.2/typedoc/cli/interfaces/DeployArgs.md +154 -0
  207. package/versioned_docs/version-v1.2/typedoc/cli/interfaces/DeployPollArgs.md +154 -0
  208. package/versioned_docs/version-v1.2/typedoc/cli/interfaces/DeployedContracts.md +130 -0
  209. package/versioned_docs/version-v1.2/typedoc/cli/interfaces/GenLocalStateArgs.md +168 -0
  210. package/versioned_docs/version-v1.2/typedoc/cli/interfaces/GenProofsArgs.md +388 -0
  211. package/versioned_docs/version-v1.2/typedoc/cli/interfaces/IGenKeypairArgs.md +37 -0
  212. package/versioned_docs/version-v1.2/typedoc/cli/interfaces/IRegisteredUserArgs.md +63 -0
  213. package/versioned_docs/version-v1.2/typedoc/cli/interfaces/MergeMessagesArgs.md +76 -0
  214. package/versioned_docs/version-v1.2/typedoc/cli/interfaces/MergeSignupsArgs.md +76 -0
  215. package/versioned_docs/version-v1.2/typedoc/cli/interfaces/PollContracts.md +53 -0
  216. package/versioned_docs/version-v1.2/typedoc/cli/interfaces/ProveOnChainArgs.md +128 -0
  217. package/versioned_docs/version-v1.2/typedoc/cli/interfaces/PublishArgs.md +154 -0
  218. package/versioned_docs/version-v1.2/typedoc/cli/interfaces/SignupArgs.md +89 -0
  219. package/versioned_docs/version-v1.2/typedoc/cli/interfaces/SubsidyData.md +73 -0
  220. package/versioned_docs/version-v1.2/typedoc/cli/interfaces/TallyData.md +166 -0
  221. package/versioned_docs/version-v1.2/typedoc/cli/interfaces/TopupArgs.md +89 -0
  222. package/versioned_docs/version-v1.2/typedoc/cli/interfaces/VerifyArgs.md +128 -0
  223. package/versioned_docs/version-v1.2/typedoc/cli/modules.md +556 -0
  224. package/versioned_docs/version-v1.2/typedoc/core/.nojekyll +1 -0
  225. package/versioned_docs/version-v1.2/typedoc/core/classes/MaciState.md +295 -0
  226. package/versioned_docs/version-v1.2/typedoc/core/classes/Poll.md +1098 -0
  227. package/versioned_docs/version-v1.2/typedoc/core/index.md +110 -0
  228. package/versioned_docs/version-v1.2/typedoc/core/interfaces/BatchSizes.md +50 -0
  229. package/versioned_docs/version-v1.2/typedoc/core/interfaces/IJsonMaciState.md +77 -0
  230. package/versioned_docs/version-v1.2/typedoc/core/interfaces/IProcessMessagesCircuitInputs.md +242 -0
  231. package/versioned_docs/version-v1.2/typedoc/core/interfaces/ISubsidyCircuitInputs.md +198 -0
  232. package/versioned_docs/version-v1.2/typedoc/core/interfaces/ITallyCircuitInputs.md +231 -0
  233. package/versioned_docs/version-v1.2/typedoc/core/interfaces/MaxValues.md +37 -0
  234. package/versioned_docs/version-v1.2/typedoc/core/interfaces/TreeDepths.md +63 -0
  235. package/versioned_docs/version-v1.2/typedoc/core/modules.md +289 -0
  236. package/versioned_docs/version-v1.2/typedoc/crypto/.nojekyll +1 -0
  237. package/versioned_docs/version-v1.2/typedoc/crypto/classes/AccQueue.md +770 -0
  238. package/versioned_docs/version-v1.2/typedoc/crypto/classes/G1Point.md +115 -0
  239. package/versioned_docs/version-v1.2/typedoc/crypto/classes/G2Point.md +140 -0
  240. package/versioned_docs/version-v1.2/typedoc/crypto/classes/IncrementalQuinTree.md +470 -0
  241. package/versioned_docs/version-v1.2/typedoc/crypto/index.md +44 -0
  242. package/versioned_docs/version-v1.2/typedoc/crypto/interfaces/Keypair.md +33 -0
  243. package/versioned_docs/version-v1.2/typedoc/crypto/interfaces/PoseidonFuncs.md +115 -0
  244. package/versioned_docs/version-v1.2/typedoc/crypto/interfaces/Queue.md +33 -0
  245. package/versioned_docs/version-v1.2/typedoc/crypto/interfaces/Signature.md +37 -0
  246. package/versioned_docs/version-v1.2/typedoc/crypto/modules.md +913 -0
  247. package/versioned_docs/version-v1.2/typedoc/domainobjs/.nojekyll +1 -0
  248. package/versioned_docs/version-v1.2/typedoc/domainobjs/classes/Ballot.md +274 -0
  249. package/versioned_docs/version-v1.2/typedoc/domainobjs/classes/Keypair.md +181 -0
  250. package/versioned_docs/version-v1.2/typedoc/domainobjs/classes/Message.md +244 -0
  251. package/versioned_docs/version-v1.2/typedoc/domainobjs/classes/PCommand.md +409 -0
  252. package/versioned_docs/version-v1.2/typedoc/domainobjs/classes/PrivKey.md +206 -0
  253. package/versioned_docs/version-v1.2/typedoc/domainobjs/classes/PubKey.md +289 -0
  254. package/versioned_docs/version-v1.2/typedoc/domainobjs/classes/StateLeaf.md +340 -0
  255. package/versioned_docs/version-v1.2/typedoc/domainobjs/classes/TCommand.md +200 -0
  256. package/versioned_docs/version-v1.2/typedoc/domainobjs/classes/VerifyingKey.md +240 -0
  257. package/versioned_docs/version-v1.2/typedoc/domainobjs/index.md +81 -0
  258. package/versioned_docs/version-v1.2/typedoc/domainobjs/interfaces/ICommand.md +104 -0
  259. package/versioned_docs/version-v1.2/typedoc/domainobjs/interfaces/IG1ContractParams.md +31 -0
  260. package/versioned_docs/version-v1.2/typedoc/domainobjs/interfaces/IG2ContractParams.md +31 -0
  261. package/versioned_docs/version-v1.2/typedoc/domainobjs/interfaces/IJsonBallot.md +42 -0
  262. package/versioned_docs/version-v1.2/typedoc/domainobjs/interfaces/IJsonCommand.md +32 -0
  263. package/versioned_docs/version-v1.2/typedoc/domainobjs/interfaces/IJsonKeyPair.md +31 -0
  264. package/versioned_docs/version-v1.2/typedoc/domainobjs/interfaces/IJsonPCommand.md +111 -0
  265. package/versioned_docs/version-v1.2/typedoc/domainobjs/interfaces/IJsonStateLeaf.md +42 -0
  266. package/versioned_docs/version-v1.2/typedoc/domainobjs/interfaces/IJsonTCommand.md +67 -0
  267. package/versioned_docs/version-v1.2/typedoc/domainobjs/interfaces/IMessageContractParams.md +31 -0
  268. package/versioned_docs/version-v1.2/typedoc/domainobjs/interfaces/IStateLeaf.md +39 -0
  269. package/versioned_docs/version-v1.2/typedoc/domainobjs/interfaces/IStateLeafContractParams.md +42 -0
  270. package/versioned_docs/version-v1.2/typedoc/domainobjs/interfaces/IVkContractParams.md +64 -0
  271. package/versioned_docs/version-v1.2/typedoc/domainobjs/interfaces/IVkObjectParams.md +108 -0
  272. package/versioned_docs/version-v1.2/typedoc/domainobjs/interfaces/Proof.md +46 -0
  273. package/versioned_docs/version-v1.2/typedoc/domainobjs/interfaces/VoteOptionTreeLeaf.md +24 -0
  274. package/versioned_docs/version-v1.2/typedoc/domainobjs/modules.md +110 -0
  275. package/versioned_docs/version-v1.2/typedoc/index.md +4 -0
  276. package/versioned_docs/version-v1.2/versioning.md +94 -0
  277. package/versioned_docs/version-v1.2/workflow.md +142 -0
  278. package/versioned_docs/version-v2.x/case-studies.md +35 -0
  279. package/versioned_docs/version-v2.x/contributing/_category_.json +4 -0
  280. package/versioned_docs/version-v2.x/contributing/code-of-conduct.md +92 -0
  281. package/versioned_docs/version-v2.x/contributing/contributing.md +149 -0
  282. package/versioned_docs/version-v2.x/contributing/project-ideas.md +78 -0
  283. package/versioned_docs/version-v2.x/core-concepts/_category_.json +4 -0
  284. package/versioned_docs/version-v2.x/core-concepts/ballot.md +19 -0
  285. package/versioned_docs/version-v2.x/core-concepts/coordinator-processing.md +46 -0
  286. package/versioned_docs/version-v2.x/core-concepts/hashing-and-encryption.md +45 -0
  287. package/versioned_docs/version-v2.x/core-concepts/key-change.md +179 -0
  288. package/versioned_docs/version-v2.x/core-concepts/maci-keys.md +84 -0
  289. package/versioned_docs/version-v2.x/core-concepts/maci-messages.md +44 -0
  290. package/versioned_docs/version-v2.x/core-concepts/merkle-trees.md +23 -0
  291. package/versioned_docs/version-v2.x/core-concepts/poll-types.md +106 -0
  292. package/versioned_docs/version-v2.x/core-concepts/spec.md +883 -0
  293. package/versioned_docs/version-v2.x/core-concepts/state-leaf.md +42 -0
  294. package/versioned_docs/version-v2.x/core-concepts/workflow.md +142 -0
  295. package/versioned_docs/version-v2.x/getting-started.md +313 -0
  296. package/versioned_docs/version-v2.x/guides/_category_.json +4 -0
  297. package/versioned_docs/version-v2.x/guides/compile-circuits.md +163 -0
  298. package/versioned_docs/version-v2.x/guides/frontend.md +99 -0
  299. package/versioned_docs/version-v2.x/guides/integrating.md +73 -0
  300. package/versioned_docs/version-v2.x/guides/maciWrapper.md +173 -0
  301. package/versioned_docs/version-v2.x/guides/subgraph.md +79 -0
  302. package/versioned_docs/version-v2.x/guides/testing/_category_.json +4 -0
  303. package/versioned_docs/version-v2.x/guides/testing/testing-in-detail.md +203 -0
  304. package/versioned_docs/version-v2.x/guides/testing/testing.md +163 -0
  305. package/versioned_docs/version-v2.x/guides/troubleshooting.md +161 -0
  306. package/versioned_docs/version-v2.x/introduction.md +146 -0
  307. package/versioned_docs/version-v2.x/processes/_category_.json +4 -0
  308. package/versioned_docs/version-v2.x/processes/ci-pipeline.md +38 -0
  309. package/versioned_docs/version-v2.x/processes/versioning.md +94 -0
  310. package/versioned_docs/version-v2.x/resources.md +33 -0
  311. package/versioned_docs/version-v2.x/security/_category_.json +4 -0
  312. package/versioned_docs/version-v2.x/security/audit.md +167 -0
  313. package/versioned_docs/version-v2.x/security/trusted-setup.md +166 -0
  314. package/versioned_docs/version-v2.x/supported-networks/_category_.json +4 -0
  315. package/versioned_docs/version-v2.x/supported-networks/deployed-contracts.md +1108 -0
  316. package/versioned_docs/version-v2.x/supported-networks/supported-networks.md +47 -0
  317. package/versioned_docs/version-v2.x/technical-references/_category_.json +4 -0
  318. package/versioned_docs/version-v2.x/technical-references/smart-contracts/AccQueue.md +21 -0
  319. package/versioned_docs/version-v2.x/technical-references/smart-contracts/Gatekeepers.md +40 -0
  320. package/versioned_docs/version-v2.x/technical-references/smart-contracts/MACI.md +152 -0
  321. package/versioned_docs/version-v2.x/technical-references/smart-contracts/MessageProcessor.md +13 -0
  322. package/versioned_docs/version-v2.x/technical-references/smart-contracts/Params.md +32 -0
  323. package/versioned_docs/version-v2.x/technical-references/smart-contracts/Poll.md +104 -0
  324. package/versioned_docs/version-v2.x/technical-references/smart-contracts/PollFactory.md +43 -0
  325. package/versioned_docs/version-v2.x/technical-references/smart-contracts/Tally.md +45 -0
  326. package/versioned_docs/version-v2.x/technical-references/smart-contracts/VkRegistry.md +57 -0
  327. package/versioned_docs/version-v2.x/technical-references/smart-contracts/VoiceCreditProxy.md +18 -0
  328. package/versioned_docs/version-v2.x/technical-references/smart-contracts/_category_.json +8 -0
  329. package/versioned_docs/version-v2.x/technical-references/technical-references.md +47 -0
  330. package/versioned_docs/version-v2.x/technical-references/typescript-code/_category_.json +4 -0
  331. package/versioned_docs/version-v2.x/technical-references/typescript-code/cli.md +699 -0
  332. package/versioned_docs/version-v2.x/technical-references/zk-snark-circuits/_category_.json +4 -0
  333. package/versioned_docs/version-v2.x/technical-references/zk-snark-circuits/processMessages.md +107 -0
  334. package/versioned_docs/version-v2.x/technical-references/zk-snark-circuits/setup.md +101 -0
  335. package/versioned_docs/version-v2.x/technical-references/zk-snark-circuits/tallyVotes.md +79 -0
  336. package/versioned_docs/version-v2.x/technical-references/zk-snark-circuits/utilities.md +131 -0
  337. package/versioned_docs/version-v2.x/technical-references/zk-snark-circuits/zk-snark-circuits.md +37 -0
  338. package/versioned_docs/version-v2.x/use-cases/_category_.json +4 -0
  339. package/versioned_docs/version-v2.x/use-cases/governance.md +18 -0
  340. package/versioned_docs/version-v2.x/use-cases/polling.md +10 -0
  341. package/versioned_docs/version-v2.x/use-cases/public-goods.md +65 -0
  342. package/versioned_docs/version-v3.x/case-studies.md +35 -0
  343. package/versioned_docs/version-v3.x/contributing/_category_.json +4 -0
  344. package/versioned_docs/version-v3.x/contributing/code-of-conduct.md +92 -0
  345. package/versioned_docs/version-v3.x/contributing/contributing.md +149 -0
  346. package/versioned_docs/version-v3.x/contributing/project-ideas.md +78 -0
  347. package/versioned_docs/version-v3.x/core-concepts/_category_.json +4 -0
  348. package/versioned_docs/version-v3.x/core-concepts/ballot.md +19 -0
  349. package/versioned_docs/version-v3.x/core-concepts/coordinator-processing.md +46 -0
  350. package/versioned_docs/version-v3.x/core-concepts/coordinator-service.md +16 -0
  351. package/versioned_docs/version-v3.x/core-concepts/hashing-and-encryption.md +45 -0
  352. package/versioned_docs/version-v3.x/core-concepts/key-change.md +179 -0
  353. package/versioned_docs/version-v3.x/core-concepts/maci-keys.md +84 -0
  354. package/versioned_docs/version-v3.x/core-concepts/maci-messages.md +44 -0
  355. package/versioned_docs/version-v3.x/core-concepts/merkle-trees.md +16 -0
  356. package/versioned_docs/version-v3.x/core-concepts/offchain-voting.md +14 -0
  357. package/versioned_docs/version-v3.x/core-concepts/poll-types.md +58 -0
  358. package/versioned_docs/version-v3.x/core-concepts/polls.md +81 -0
  359. package/versioned_docs/version-v3.x/core-concepts/spec.md +883 -0
  360. package/versioned_docs/version-v3.x/core-concepts/state-leaf.md +42 -0
  361. package/versioned_docs/version-v3.x/core-concepts/workflow.md +149 -0
  362. package/versioned_docs/version-v3.x/guides/_category_.json +4 -0
  363. package/versioned_docs/version-v3.x/guides/compile-circuits.md +175 -0
  364. package/versioned_docs/version-v3.x/guides/integrating.md +137 -0
  365. package/versioned_docs/version-v3.x/guides/subgraph.md +79 -0
  366. package/versioned_docs/version-v3.x/guides/testing/_category_.json +4 -0
  367. package/versioned_docs/version-v3.x/guides/testing/testing-in-detail.md +191 -0
  368. package/versioned_docs/version-v3.x/guides/testing/testing-introduction.md +158 -0
  369. package/versioned_docs/version-v3.x/guides/troubleshooting.md +161 -0
  370. package/versioned_docs/version-v3.x/introduction.md +153 -0
  371. package/versioned_docs/version-v3.x/processes/_category_.json +4 -0
  372. package/versioned_docs/version-v3.x/processes/ci-pipeline.md +38 -0
  373. package/versioned_docs/version-v3.x/processes/versioning.md +94 -0
  374. package/versioned_docs/version-v3.x/quick-start.md +318 -0
  375. package/versioned_docs/version-v3.x/resources.md +33 -0
  376. package/versioned_docs/version-v3.x/security/_category_.json +4 -0
  377. package/versioned_docs/version-v3.x/security/audit.md +167 -0
  378. package/versioned_docs/version-v3.x/security/trusted-setup.md +172 -0
  379. package/versioned_docs/version-v3.x/supported-networks/_category_.json +4 -0
  380. package/versioned_docs/version-v3.x/supported-networks/deployed-contracts.md +112 -0
  381. package/versioned_docs/version-v3.x/supported-networks/supported-networks.md +53 -0
  382. package/versioned_docs/version-v3.x/technical-references/_category_.json +4 -0
  383. package/versioned_docs/version-v3.x/technical-references/coordinator-service/_category_.json +8 -0
  384. package/versioned_docs/version-v3.x/technical-references/coordinator-service/index.md +10 -0
  385. package/versioned_docs/version-v3.x/technical-references/coordinator-service/installation.md +43 -0
  386. package/versioned_docs/version-v3.x/technical-references/offchain-relayer/_category_.json +8 -0
  387. package/versioned_docs/version-v3.x/technical-references/offchain-relayer/index.md +51 -0
  388. package/versioned_docs/version-v3.x/technical-references/offchain-relayer/installation.md +109 -0
  389. package/versioned_docs/version-v3.x/technical-references/smart-contracts/MACI.md +160 -0
  390. package/versioned_docs/version-v3.x/technical-references/smart-contracts/MessageProcessor.md +13 -0
  391. package/versioned_docs/version-v3.x/technical-references/smart-contracts/Params.md +33 -0
  392. package/versioned_docs/version-v3.x/technical-references/smart-contracts/Policies.md +39 -0
  393. package/versioned_docs/version-v3.x/technical-references/smart-contracts/Poll.md +170 -0
  394. package/versioned_docs/version-v3.x/technical-references/smart-contracts/PollFactory.md +33 -0
  395. package/versioned_docs/version-v3.x/technical-references/smart-contracts/Tally.md +43 -0
  396. package/versioned_docs/version-v3.x/technical-references/smart-contracts/VkRegistry.md +62 -0
  397. package/versioned_docs/version-v3.x/technical-references/smart-contracts/VoiceCreditProxy.md +18 -0
  398. package/versioned_docs/version-v3.x/technical-references/smart-contracts/_category_.json +8 -0
  399. package/versioned_docs/version-v3.x/technical-references/technical-references.md +48 -0
  400. package/versioned_docs/version-v3.x/technical-references/zk-snark-circuits/_category_.json +4 -0
  401. package/versioned_docs/version-v3.x/technical-references/zk-snark-circuits/joinPoll.md +53 -0
  402. package/versioned_docs/version-v3.x/technical-references/zk-snark-circuits/processMessages.md +106 -0
  403. package/versioned_docs/version-v3.x/technical-references/zk-snark-circuits/setup.md +96 -0
  404. package/versioned_docs/version-v3.x/technical-references/zk-snark-circuits/tallyVotes.md +79 -0
  405. package/versioned_docs/version-v3.x/technical-references/zk-snark-circuits/utilities.md +131 -0
  406. package/versioned_docs/version-v3.x/technical-references/zk-snark-circuits/zk-snark-circuits.md +42 -0
  407. package/versioned_docs/version-v3.x/use-cases/_category_.json +4 -0
  408. package/versioned_docs/version-v3.x/use-cases/governance.md +18 -0
  409. package/versioned_docs/version-v3.x/use-cases/polling.md +10 -0
  410. package/versioned_docs/version-v3.x/use-cases/public-goods.md +65 -0
  411. package/versioned_sidebars/version-v0.x-sidebars.json +8 -0
  412. package/versioned_sidebars/version-v1.2-sidebars.json +8 -0
  413. package/versioned_sidebars/version-v2.x-sidebars.json +8 -0
  414. package/versioned_sidebars/version-v3.x-sidebars.json +8 -0
  415. package/versions.json +1 -0
@@ -0,0 +1,883 @@
1
+ ---
2
+ title: MACI v1.0 Specification
3
+ description: A detailed specification meant to assist auditors in reviewing MACI version 1.0
4
+ sidebar_label: Specification
5
+ sidebar_position: 10
6
+ ---
7
+
8
+ # MACI v1.0 Specification
9
+
10
+ :::info
11
+ This document is a copy of the [MACI 1.0 Specification (for audit) document](https://hackmd.io/AP6zPSgtThWxx6pjXY7R8A), created in July 2021 for one of [MACI's formal audits](/docs/security/audit).
12
+
13
+ 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.
14
+ :::
15
+
16
+ This is a detailed specification meant to assist auditors in reviewing [MACI version 1.0](https://github.com/privacy-scaling-explorations/maci/releases/tag/v1.0.0).
17
+
18
+ We thank the Zkopru team for their [protocol specification](https://github.com/zkopru-network/protocol-specification/), which this document adopts.
19
+
20
+ ## Audit scope
21
+
22
+ The commit hashes relevant to this audit are the following:
23
+
24
+ | Name | Commit |
25
+ | --------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
26
+ | `appliedzkp/maci` (`v1` branch) | [`2db5f625b67a6b810bd851950d7a42c26189088b`](https://github.com/appliedzkp/maci/tree/2db5f625b67a6b810bd851950d7a42c26189088b) |
27
+ | `weijiekoh/circomlib` (`feat/poseidon-encryption` branch) | [`0e78dde8c813b95f4585b0613927e9c4269de500`](https://github.com/weijiekoh/circomlib/tree/0e78dde8c813b95f4585b0613927e9c4269de500) |
28
+
29
+ The scope of the audit with regards to the `circomlib` library covers:
30
+
31
+ - all the JS files that MACI references, **excluding** those which are not referenced by MACI's TS files
32
+ - all circuit files **excluding** those which are not referenced by MACI's circuit files
33
+
34
+ ### Statements that we wish to challenge
35
+
36
+ Through this audit, we wish to challenge the following statements:
37
+
38
+ 1. MACI exhibits collusion resistance
39
+ - No one except a trusted coordinator should be certain of the validity of a vote, reducing the effectiveness of bribery
40
+ 2. MACI exhibits receipt-freeness
41
+ - No voter may prove (besides to the coordinator) which way they voted
42
+ 3. MACI provides privacy
43
+ - No one except a trusted coordinator should be able to decrypt a vote
44
+ 4. MACI is uncensorable:
45
+ - No one (not even the trusted coordinator) should be able to censor a vote
46
+ 5. MACI provides unforgeability
47
+ - Only the owner of a user's private key may cast a vote tied to its corresponding public key
48
+ 6. MACI provides non-repudiation
49
+ - No one may modify or delete a vote after it is cast, although a user may cast another vote to nullify it
50
+ 7. Correct execution
51
+ - No one (not even the trusted coordinator) should be able to produce a false tally of votes
52
+
53
+ ## 1. Cryptographic primitives
54
+
55
+ ### Elliptic Curve Cryptography
56
+
57
+ MACI uses the Baby Jubjub Elliptic Curve as defined in [this paper by Whitehat, Baylina, and Bellés](https://iden3-docs.readthedocs.io/en/latest/_downloads/33717d75ab84e11313cc0d8a090b636f/Baby-Jubjub.pdf).
58
+
59
+ #### 1.1. The Baby Jubjub curve
60
+
61
+ Following the Baby Jubjub paper, we define the scalar field \\(p\\) as such:
62
+
63
+ $p = 21888242871839275222246405745257275088548364400416034343698204186575808495617$
64
+
65
+ The field $\mathbb{F}_p$ is the finite field with modulo $p$.
66
+
67
+ The generator point of Baby Jubjub $G$ is:
68
+
69
+ ```
70
+ 995203441582195749578291179787384436505546430278305826713579947235728471134,
71
+ 5472060717959818805561601436314318772137091100104008585924551046643952123905
72
+ ```
73
+
74
+ #### 1.2. Private key generation
75
+
76
+ A private key is a random integer in the field $\mathbb{F}_p$.
77
+
78
+ MACI uses the Node.js [`crypto.randomBytes(32)`](https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback) function to generate a cryptographically strong pseudorandom 32-byte value, as well as an algorithm to prevent [modulo bias](https://research.kudelskisecurity.com/2020/07/28/the-definitive-guide-to). In pseudocode this is expressed as:
79
+
80
+ ```
81
+ lim = 2 ** 256
82
+ min = lim - p
83
+ rand = null
84
+ while true:
85
+ rand = BigInt(crypto.getRandomBytes(32))
86
+ if rand >= min:
87
+ break
88
+
89
+ privKey = rand % p
90
+ ```
91
+
92
+ #### 1.3. Private key formatting
93
+
94
+ 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.
95
+
96
+ 1. Public key generation
97
+ 2. ECDH shared key generation
98
+
99
+ The algorithm to do so is as such:
100
+
101
+ 1. Hash the private key using $\mathsf{blake512}$ as such: $h_1 = \mathsf{blake512}(s)$
102
+ 2. Take the lowest 32 bytes of $h_1$ as a buffer and prune it to derive $h_2$. To prune the buffer, we:
103
+ 2.1. Clear the lowest three bits of the 0th byte
104
+ 2.2. Clear the highest bit of the 31st byte
105
+ 2.3. Set the second-highest bit of the 31st byte to `1`.
106
+ 3. Convert $h_2$ to its little-endian integer representation. We denote this as $h_3$
107
+ 4. Shift $h_3$ right by 3 bits to get the formatted private key $h_4$
108
+
109
+ #### 1.4. Public key generation
110
+
111
+ A public key is a point on the Baby Jubjub curve. It is deterministically derived from a private key $s$, the procedure to do so is almost identical to [RFC8032](https://datatracker.ietf.org/doc/html/rfc8032#section-5.1.5).
112
+
113
+ 1. Format the private key [1.3]
114
+ 2. Multiply $G$ by 8 and multiply the resulting point by the formatted private key to derive the public key $A$:
115
+ $B = 8 \cdot G$
116
+ $A = B \cdot h_4$
117
+
118
+ #### 1.5. Digital signature generation
119
+
120
+ We use the Edwards-curve Digital Signature Algorithm (EdDSA) to sign messages. The code which implements signature generation and verification is iden3's [implementation](https://github.com/iden3/circomlib/blob/861a75e0cb3384d49c25d1f9d39de6a7ec60229f/src/eddsa.js) in the circomlib library.
121
+
122
+ Given a private key $s$, its public key $A$ [1.4] and a message $M \in \mathbb{F}_p$, we derive the signature $R8, S$ as such:
123
+
124
+ 1. Hash the private key using $\mathsf{blake512}$ as such: $h_1 = \mathsf{blake512}(s)$
125
+ 2. Format $s$ [1.3] to generate $A$ [1.4]
126
+ 3. Convert $M$ to a buffer in little-endian format, concatenate it with the 32nd to 64th bytes of $h_1$, and hash the result with $\mathsf{blake512}$, and interpret the hash in little-endian format as a value $r$ in the field $\mathbb{F}_p$
127
+ 4. Multiply $r$ with $B$ to get $R8$
128
+ 5. Hash $R8$, $A$, and $M$: $hm = \mathsf{poseidon_4}([R8[0], R8[1], A[0], A[1], m])$
129
+ 6. Calculate $S = hm \cdot h_3 + r$
130
+ 7. The signature is $R8, S$
131
+
132
+ #### 1.6. Digital signature verification
133
+
134
+ Given a message $M$, a signature $R8$, $S$, and a public key $A$, we verify the signature in this manner:
135
+
136
+ 1. $hm = \mathsf{poseidon_4}(R8[0], R8[1], A[0], A[1], M)$
137
+ 2. The signature is valid if the following are equal:
138
+ 2.1. $(G \cdot 8) \cdot S$
139
+ 2.2. $((hm \cdot 8) \cdot A) + R8$
140
+
141
+ ### Hash functions
142
+
143
+ #### 1.7. Poseidon
144
+
145
+ We define $\mathsf{poseidon_n}$ as a hash function which accepts $n$ inputs and produces one output $y$:
146
+
147
+ $y = \mathsf{poseidon_n}([x_1, x_2, ..., x_n])$
148
+
149
+ where $x_i, y \in \mathbb{F}_p$.
150
+
151
+ We use the implementation provided by `circomlib`, which uses the S-box $x^5$ and the following $R_F$ and $R_P$ values:
152
+
153
+ | $n$ | $t$ | $R_F$ | $R_P$ |
154
+ | --- | --- | ----- | ----- |
155
+ | 2 | 3 | 8 | 57 |
156
+ | 3 | 4 | 8 | 56 |
157
+ | 4 | 5 | 8 | 60 |
158
+ | 5 | 6 | 8 | 60 |
159
+
160
+ We verified that `circomlib`'s $\mathsf{poseidon_n}$ implementation matches the reference implementation using the procedure documented [here](https://github.com/appliedzkp/poseidon_in_circomlib_check).
161
+
162
+ #### 1.8. SHA256
163
+
164
+ SHA256 is used to compress public inputs to a circuit into a single field element in $\mathbb{F}_p$. This reduces zk-SNARK verification gas costs. SHA256 is defined in [RFC6234](https://datatracker.ietf.org/doc/html/rfc6234). We use implementations in the EVM as well as [ethers.js](https://docs.ethers.io/v5/api/utils/hashing/#utils-soliditySha256).
165
+
166
+ ### Symmetric encryption
167
+
168
+ #### 1.9. Poseidon in DuplexSponge mode
169
+
170
+ We use the Poseidon permutation function in DuplexSponge mode to encrypt each command and its signature. This method is described by the authors of the Poseidon hash function [here](https://drive.google.com/file/d/1EVrP3DzoGbmzkRmYnyEDcIQcXVU7GlOd/view).
171
+
172
+ We refer to the encryption function which produces ciphertext $C$ as $\mathsf{poseidonEncrypt}(k_s[0], k_s[1], N, l, t[])$ where:
173
+
174
+ - $k_s$ is the shared key, a point on the Baby Jubjub curve
175
+ - $N$ is the nonce, which we hardcode to 0
176
+ - $l$ is the length of the plaintext $t[]$
177
+
178
+ At the time of writing, the Javascript and circom code for Poseidon encryption / decryption is in [this fork](https://github.com/weijiekoh/circomlib/) of the original iden3 codebase.
179
+
180
+ $\mathsf{poseidonDecrypt}(k_s[0], k_s[1], N, l, C)$ is the decryption function that reverses $\mathsf{poseidonEncrypt}$.
181
+
182
+ ### Shared-key generation
183
+
184
+ #### 1.10. Elliptic-curve Diffie–Hellman (ECDH)
185
+
186
+ As will be described below, each command [2.5] is encrypted with a key that only the coordinator and the user know. In order to securely generate this shared key, we use the ECDH algorithm.
187
+
188
+ The coordinator's public key $cPk$ is known to all. Their private key $cSk$ is secret.
189
+
190
+ When the user publishes a message (i.e. casts a vote), they generate an ephemeral keypair with private key $eSk$ and public key $ePk$.
191
+
192
+ The user generates the shared key $k$ using the coordinator's public key $cPk$ and the user's ephemeral private key $eSk$.
193
+
194
+ The user encrypts the command and signature with $k$ to form a message [2.6].
195
+
196
+ The user sends their ephemeral public key $ePk$ along with the ciphertext. The coordinator can recover the same shared key using their private key $cSk$ and the given ephemeral public key $ePk$.
197
+
198
+ To generate $k$ from $cPk$ and $eSk$:
199
+
200
+ 1. Format $eSk$ [1.3]
201
+ 2. Multiply the point $cPk$ by the above result
202
+
203
+ ### Merkle trees
204
+
205
+ We use quinary Merkle trees (5 leaves per node) rather than binary Merkle trees (2 leaves per node) due to the [gas and circuit constraints](https://ethresear.ch/t/gas-and-circuit-constraint-benchmarks-of-binary-and-quinary-incremental-merkle-trees-using-the-poseidon-hash-function/7446) when using the Poseidon hash function.
206
+
207
+ #### 1.10. Accumulator queue
208
+
209
+ When users sign up or publish messages, they invoke a smart contract function that _enqueues_ a leaf into an accumulator queue (which we dub an AccQueue). This is a data structure which is akin to a quinary Merkle tree. When a user inserts a leaf into the `AccQueue`, the Merkle root of all the leaves is _not_ yet updated. Rather, the leaf is either simply stored or the root of a _subtree_ is updated.
210
+
211
+ The height of the subtree $t_s$ is less than the full height of the tree $t_d$. The coordinator must _merge_ all the subtrees to compute the Merkle root of all the leaves, allowing users to save gas when they enqueue leaves.
212
+
213
+ It exposes the following interface:
214
+
215
+ 1. `enqueue(leaf)`: Enqueues a leaf into a subtree
216
+ 2. `mergeSubRoots()`: Merge all subtree roots into the shortest possible Merkle tree to fit
217
+ 3. `merge()`: Calculate the Merkle root of all the leaves at height $t_d$
218
+
219
+ The AccQueue keeps track of $\mathsf{levels}$ and $\mathsf{indices}$ for the latest subtree. It also keeps track of a list of all the subtree roots.
220
+
221
+ An AccQueue which supports subtrees of depth $d$ has the following as mutable state:
222
+
223
+ | State item | Description |
224
+ | ------------------------------- | ---------------------------------------------------------- |
225
+ | $\mathsf{levels[33][4]}$ | Leaf/node values at each subtree level |
226
+ | $\mathsf{indices[33]}$ | The next available leaf/node index per subtree level |
227
+ | $\mathsf{subRootLevels[33][4]}$ | Leaf/node values for the tree formed by subroots as leaves |
228
+ | $\mathsf{subRootIndices[33]}$ | The next available leaf/node index per subroot level |
229
+ | $\mathsf{subRoots[]}$ | All the roots of complete subtrees |
230
+ | $\mathsf{numLeaves}$ | The number of enqueued leaves |
231
+
232
+ ##### 1.10.1. Enqueuing a leaf
233
+
234
+ To enqueue a leaf $l$ in an AccQueue:
235
+
236
+ 1. For each $n$ in $0...(d+1)$, either:
237
+ - Store the leaf in $\mathsf{levels[n][indices[n]]}$ if $indices[n] < 5$, and break from the loop, or
238
+ - Compute $\mathsf{poseidon_5}([levels[n][0], levels[n][1], levels[n][2], levels[n][3], l)$, clear all values of $levels[n]$, clear $indices[n]$, and continue the loop with the hash as $l$
239
+ 2. Increment $\mathsf{numLeaves}$ by 1
240
+ 3. If $\mathsf{numLeaves}$ is a multiple of $5^{t_s}$:
241
+ - Append $\mathsf{levels}[t_s][0]$ to $subRoots$
242
+ - Clear $\mathsf{levels}[t_s]$
243
+ - Clear $\mathsf{indices}$
244
+
245
+ Effectively, four out of five times it is invoked, an enqueue operation _may or may not_ require the contract to perform a hash function. When it does, only up to $t_d$ required number of hashes need to be computed.
246
+
247
+ ##### 1.10.2. Merging subroots
248
+
249
+ Before computing the main Merkle root, it is necessary to compute the `smallSRTroot` (the smallest subroot tree root). This is the Merkle root of a tree which is small enough to fit all the subroots, it uses a similar mechanism to enqueuing leaves [1.10.2].
250
+
251
+ The `AccQueue.sol` contract provides the `mergeSubRoots(uint256 _numSrQueueOps)` function which allows the coordinator to specify the number of queue operations to execute. The entire tree may be merged in a single transaction, or it may not. Multiple calls to `mergeSubRoots` may be required due to the block gas limit.
252
+
253
+ ##### 1.10.3. Computing main root
254
+
255
+ A similar operation to [1.10.2] and [1.10.3] is used to derive the main Merkle root (with depth $t_d$).
256
+
257
+ #### 1.11. Groups on the alt_bn128 elliptic curve
258
+
259
+ We refer to the $G_1$ and $G_2$ cyclic groups as defined in [EIP-197](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-197.md).
260
+
261
+ ## 2. Domain objects
262
+
263
+ ### 2.1. Verifying key
264
+
265
+ A verifying key $vk$ is comprised of the following elements:
266
+
267
+ 1. $\alpha$, a point in the curve on which $G_1$ is defined
268
+ 2. $\beta$, a point in the curve on which $G_2$ is defined
269
+ 3. $\gamma$, a point in the curve on which $G_2$ is defined
270
+ 4. $\delta$, a point in the curve on which $G_2$ is defined
271
+ 5. $ic[]$, a list of points in the curve on which $G_1$ is defined
272
+
273
+ A verifying key is used to validate a zk-SNARK proof. Each unique permutation of parameters to a particular circuit has a different verifying key.
274
+
275
+ ### 2.2. Private key
276
+
277
+ A private key $k$ represents a participant's ability to broadcast or decrypt messages under a unique identity and generation of a shared key [1.9], it translates to a scalar point on the Baby Jubjub elliptical curve. To avoid confusion with Ethereum's ECDSA encryption, MACI requires serialisation bound with the prefix `macisk.`
278
+
279
+ #### 2.2.1. Serialisation
280
+
281
+ To represent $k$ as a serialised private key, it is converted into big-endian hexadecimal format (lowercase; using the Node.js [`BigInt.toString(16)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt/toString) function) and concatenated with the prefix, no padding is applied during this process.
282
+
283
+ For example, the following private key in decimal format:
284
+
285
+ $3785182559838189109279346060397029719208250533050190830847077167272231264061$
286
+
287
+ is serialised as:
288
+
289
+ `macisk.85e56605303139aca49355df30d94f225788892ec71a5cfdbe79266563d5f3d`
290
+
291
+ #### 2.2.2. Deserialisation
292
+
293
+ To revert a serialised key back to its unserialised form $k$, the string is manipulated to isolate the hexadecimal value by removing the prefix (through the Node.js operation [`String.slice()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice)) and is prepended `0x` for conversion from hexadecimal back to its big-endian primitive.
294
+
295
+ ### 2.3. Public key
296
+
297
+ A public key $p$ represents a users identity derived from $k$ and therefore is also a point on the Baby Jubjub curve. It too requires serialisation, but to clarify the contrast to private keys it is assigned the prefix `macipk.`
298
+
299
+ #### 2.3.1. Serialisation
300
+
301
+ To get a serialised public key from public key coordinates, the variable $u$ is defined as public key's y-coordinate, a 32 bit buffer $v$ is created and iterated over each uninitialised byte to:
302
+
303
+ 1. assign the result of a bitwise [`AND (&)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_AND) operation between values $u$ and $255$ to byte $n$
304
+ 2. shift $u$ right by 8 bits ([`>>`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Right_shift))
305
+
306
+ The result $v$ is a hexadecimal big-endian value which is prendend its prefix to declare it as a serialised key.
307
+
308
+ #### 2.3.2. Deserialisation
309
+
310
+ To reverse the effects of serialisation and return the unpacked public key, we must remove the prefix (using the method defined in [2.2.2]) and convert back to a buffer from hexadecimal. A return variable $y$ is initialised and the buffer is then iterated over each byte to:
311
+
312
+ 1. shift $u$ left by the result of $8$ multiplied by $n$ bits ([`<<`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Left_shift))
313
+ 2. assign $y$ the result of addition between $y$ and $u$
314
+
315
+ The result $y$ is the public key's y-coordinate, to then compute the x-coordinate we must look at the equation for the twisted Edwards elliptic curve (as defined in [`EIP-2494`](https://eips.ethereum.org/EIPS/eip-2494)):
316
+
317
+ $ax^2 + y^2 = 1 + dx^2y^2$
318
+
319
+ solving for $x$, results:
320
+
321
+ $x$ = $\mathsf{\sqrt{\frac{dy^2 - a}{y^2 - 1}}}$
322
+
323
+ ### 2.4. Keypair
324
+
325
+ A keypair is a private key and its corresponding public key.
326
+
327
+ ### 2.5. Command
328
+
329
+ A command represents an action that a user may take. Such as casting a vote in a poll or changing their public key if bribed. It is made up of the following parameters:
330
+
331
+ | Symbol | Name | Size | Description |
332
+ | ------------ | ----------------------- | ---- | --------------------------------------------------------------------------------------------------- |
333
+ | $cm_i$ | State index | 50 | State leaf index where the signing key is located |
334
+ | $cm_{p_{x}}$ | Public key x-coordinate | 253 | If no change is necessary this parameter should reflect the current public key's x-coordinate |
335
+ | $cm_{p_{y}}$ | Public key y-coordinate | 253 | If no change is necessary this parameter should reflect the current public key's y-coordinate |
336
+ | $cm_{i_{v}}$ | Vote option index | 50 | Option state leaf index of preference to assign the vote for |
337
+ | $cm_w$ | Voting weight | 50 | Voice credit balance allocation, this is an arbitrary value dependent on a user's available credits |
338
+ | $cm_n$ | Nonce | 50 | State leaf's index of actions committed plus one |
339
+ | $cm_{id}$ | Poll id | 50 | The poll's identifier to cast in regard to |
340
+ | $cm_s$ | Salt | 253 | An entropy value to inhibit brute force attacks |
341
+
342
+ The parameters; $cm_i$, $cm_{i_{v}}$, $cm_n$, $cm_w$ and $cm_{id}$ are packed into a singular 250 bit value $p$, defined as the sum of bitwise right shifts from 0 to 250, incrementing by 50 for each parameter. This reduces gas expenditures when generating a $\mathsf{poseidon_{4}}$ hash of a command $h_{cm}$, expressed as:
343
+
344
+ $h_{cm}$ = $\mathsf{poseidon_{4}([p, cm_{p_{x}}, cm_{p_{y}}, cm_s])}$
345
+
346
+ #### 2.5.1. Signing a command
347
+
348
+ To sign a command with a public key $A$:
349
+
350
+ 1. Compute $M = h_{cm}$
351
+ 2. Sign $M$ using EdDSA [1.5]
352
+ 3. The signature is $R8, S$
353
+
354
+ #### 2.5.2. Verifying a signature
355
+
356
+ We use the method described in [1.6]
357
+
358
+ ### 2.6. Message
359
+
360
+ A message represents an encrypted command. Given a shared key $k_s$ derived using ECDH [1.10] and plaintext $t$, we compute:
361
+
362
+ $t = [p, cm_{p_{x}}, cm_{p_{y}}, cm_s, R8[0], R8[1], S]$
363
+
364
+ $M$ = $\mathsf{poseidonEncrypt}(k_s[0], k_s[1], cm_n, 7, t)$
365
+
366
+ #### 2.6.1. Decrypting a message
367
+
368
+ To decrypt a message using $k_s$ is expressed as
369
+
370
+ $[p, R8[0], R8[1], cm_s]$ = $\mathsf{poseidonDecrypt}(M, k_s[0], k_s[1], cm_n, 7)$
371
+
372
+ To unpack $p$ to its original five parameters, it must be separated into 50 bit values from the parent 250 bit value. To extract 50 bits at byte $n$, we:
373
+
374
+ 1. initialise 50 bits
375
+ 2. shift left by $n$ bits
376
+ 3. bitwise AND with $p$
377
+ 4. shift right by $n$ bits
378
+
379
+ ### 2.7. Ballot
380
+
381
+ A Ballot represents a particular user's votes in a poll, as well as their next valid nonce. It is akin to a voting slip, which belongs to only one voter and contains a list of their choices.
382
+
383
+ | Symbol | Name | Comments |
384
+ | --------- | -------------------------- | -------------------------------------------------------------------------- |
385
+ | $blt_{v}$ | An array of vote weights | $blt_{v[i]}$ refers to the vote weights assigned to vote option $i$ |
386
+ | $blt_n$ | The current nonce | Starts from 0 and increments, so the first valid command must have nonce 1 |
387
+ | $blt_d$ | The vote option tree depth | |
388
+
389
+ The hash $blt$ is computed as such:
390
+
391
+ 1. Compute the Merkle root of $blt_v$, arity 5, of a tree of depth $blt_d$; let this value be $blt_r$
392
+ 2. Compute $\mathsf{poseidon_2}([blt_n, blt_r])$
393
+
394
+ ### 2.8. State leaf
395
+
396
+ A state leaf represents a user's participation declared through an identity (their public key) and information relevant to their ability or right to cast votes in a poll (their voice credit balance and the block timestamp at which they signed up).
397
+
398
+ We define a state leaf $sl$ as the $\mathsf{poseidon_4}$ hash of the following:
399
+
400
+ | Symbol | Name | Comments |
401
+ | ---------- | ------------------------- | ------------------------------------------- |
402
+ | $sl_{P_x}$ | Public key's x-coordinate | |
403
+ | $sl_{P_y}$ | Public key's y-coordinate | |
404
+ | $sl_{v}$ | Voice credit balance | |
405
+ | $sl_{t}$ | Block timestamp | In Unix time (seconds since Jan 1 1970 UTC) |
406
+
407
+ The hash $sl$ is computed as such:
408
+
409
+ $sl = \mathsf{poseidon_4}([sl_{A_x}, sl_{A_y}, sl_{v}, sl_{t}])$
410
+
411
+ #### 2.8.1. Blank state leaf
412
+
413
+ A blank state leaf $sl_B$ has the following value:
414
+
415
+ $6769006970205099520508948723718471724660867171122235270773600567925038008762$
416
+
417
+ This value is computed as such:
418
+
419
+ $A_{b_x} = 10457101036533406547632367118273992217979173478358440826365724437999023779287$
420
+ $A_{b_y} = 19824078218392094440610104313265183977899662750282163392862422243483260492317$
421
+ $sl_B = \mathsf{poseidon_4}([A_{b0}, A_{b1}, 0, 0])$
422
+
423
+ The code to derive $A_{b_x}$ and $A_{b_y}$ is [here](https://github.com/iden3/circomlib/blob/d5ed1c3ce4ca137a6b3ca48bec4ac12c1b38957a/src/pedersen_printbases.js). The function call required is `pedersenHash.getBasePoint('blake', 0)`
424
+
425
+ 1. Hash the string `PedersenGenerator_00000000000000000000000000000000_00000000000000000000000000000000` with $\mathsf{blake_{256}}$. In big-endian hexadecimal format, the hash should be `1b3ef77ef2cd620fd2358e69dd564f35556aad552fdd7f06b777bd3a1d697160`
426
+ 2. Set the 255th bit to 0. The result should be `1b3ef77ef2cd620fd2358e69dd564f35556aad552fdd7f06b777bd3a1d697120`
427
+ 3. Use the method to convert a buffer to a point on the BabyJub curve described in [2.3.2]
428
+ 4. Multiply the point by 8. The result is the point with x-value $A_{b_x}$ and y-value $A_{b_y}$
429
+
430
+ Given the [elliptic curve discrete logarithm problem](https://wstein.org/edu/2007/spring/ent/ent-html/node89.html), we assume that no-one knows the private key $s \in \mathbb{F}_p$ and by using the public key generation procedure in [1.4], we can derive $A_{b_x}$ and $A_{b_y}$. Furthermore, the string above (`PedersenGenerator...`) acts as a nothing-up-my-sleeve value.
431
+
432
+ ## 3. Higher-level concepts
433
+
434
+ ### 3.1. Actors
435
+
436
+ There is a coordinator and one or more users.
437
+
438
+ #### Coordinator
439
+
440
+ The coordinator's public key is $cPk$ and their private key is $cSk$.
441
+
442
+ #### User
443
+
444
+ A user's ephemeral public key is $ePk$ and their ephemeral private key is $eSk$.
445
+
446
+ ### 3.2. How MACI prevents collusion
447
+
448
+ In governing systems, collusion can be described as the ability to distort any ballot through acts of influence, most often witnessed as bribery. Such arrangements require the bribee to vote in a manner requested by the briber, and for the former to provide proof (such as the transaction hash of a vote) to receive compensation (e.g. a monetary incentive) for their compliance.
449
+
450
+ MACI provides collusion-resistance assuming that:
451
+
452
+ - it uses an identity system which is sybil-resistant
453
+ - the coordinator is honest
454
+
455
+ That said, even if the coordinator is dishonest, they can neither tamper nor censor with its execution.
456
+
457
+ In MACI, the contents of a vote can only be decrypted by the coordinator. Moreover, the validity of a vote cannot be proven, as participants can revoke past actions through key-changes. Therefore, inhibiting the adversary in validating the fulfillment of such agreements.
458
+
459
+ To clarify how this works, consider the following situation between Alice and Eve involving a vote option A:
460
+
461
+ 1. Alice registers her identity during the sign up period, in preparation for the upcoming poll
462
+ 2. The sign up period ends and the voting period begins, Eve bribes Alice to oppose option A
463
+ 3. Alice casts a message for option A, in which she simultaneously:
464
+ - Votes in opposition of A
465
+ - Changes her keypair by submitting a new public key
466
+ 4. Eve is uncertain whether Alice has voted for her preference due to the secrecy of the message, regardless she assumes confirmation upon receiving the transaction hash
467
+ 5. Alice broadcasts a message from the new keypair registered in step 3 and casts a vote in support of poll A in turn, voiding her initial vote in opposition
468
+
469
+ Eve is doubtful whether her request was actually satisfied and is unaware of Alice casting a new vote to void the first, she decides not to compensate Alice because of the uncertainty surrounding her compliance.
470
+
471
+ ### 3.3. Gatekeeper contract
472
+
473
+ The gatekeeper contract is an abstraction of logic that any deployment of MACI can modify. It is a way to whitelist signups to the system. For example, a custom gatekeeper contract may only allow addresses that own a certain ERC721 token for registration.
474
+
475
+ ### 3.4. Initial voice credit proxy
476
+
477
+ The voice credit contract is another abstraction of logic that any deployment can configure at preference. It is a mechanism to define or admit voting power among participants based on, for instance, one's token balances. MACI only supports $2^{32}$ (`unit256`) values for voice credit balances.
478
+
479
+ ### 3.5. Verifying key registry
480
+
481
+ In MACI there are two zkSNARK circuits each ensuring:
482
+
483
+ - the correct registration of messages to the state tree
484
+ - the correct execution of the tallying of votes
485
+
486
+ Each of these circuits involves ownership of an independent verifying key to validate each when successfully executed, these are generated during the trusted setup and are initialised to the registry for generating proofs.
487
+
488
+ ### 3.6. State
489
+
490
+ #### The state tree
491
+
492
+ Each leaf of the state tree encodes a participant's identity (public key) and the Unix timestamp at which they signed up. It has an arity of 5 and its depth is hardcoded to 10.
493
+
494
+ The default leaf value is the hash of a blank state leaf [2.8.1], insertions begin at index 1. Leaf 0 is reserved to inhibit a denial-of-service attack as explained below in [6.1].
495
+
496
+ #### The ballot tree (per poll)
497
+
498
+ Each leaf within the ballot trees stores a participant's vote within a poll, it shares the same arity and depth as the state tree. It also has index 0 reserved for a blank leaf following the same basis.
499
+
500
+ #### The message tree (per poll)
501
+
502
+ Each leaf within the message tree correlates to a command cast from participants within a poll, it too like the state tree has a default nothing-up-my-sleeve value at leaf zero. Except it is a Keccak256 hash of the string `"Maci"` modulo the SNARK field size $p$ [1.1].
503
+
504
+ ### 3.7. System flow
505
+
506
+ #### When a user signs up
507
+
508
+ Registration is initiated by fulfilling the requirements specified in the gatekeeper contract and calling the `signUp()` method in the MACI contract. This enqueues adding a new leaf to the state tree for it to be merged by the coordinator once appropriate.
509
+
510
+ #### When a user publishes a message
511
+
512
+ Publishing messages requires users to encrypt a command using a shared key generated using ECDH [1.10] and submitting the ciphertext through the `publishMessage()` function. The message is then queued for processing by the co-ordinator once published.
513
+
514
+ #### When the coordinator merges the state queue
515
+
516
+ To subsidise gas costs for users, registration does not require the state root to be updated at its full depth, which would incur a gas cost linear to the depth. Rather, the use of the Accumulator Queue system described in [1.10] enqueues leaves. As such, the coordinator must compute the state tree root after the voting period is over and before they process messages.
517
+
518
+ Which first requires the merging of subroots [1.10.1], this creates the shortest possible tree that contains all the state leaves. Which may or may not require multiple transactions (in the form of batches) due to the restriction of the block gas limit. Once all the subroots have been computed they are merged [1.10.2] to compute the state root at its full depth.
519
+
520
+ After merging, the state-ballot commitment hash `currentSbCommitment` is initialised, which is a $\mathsf{poseidon_{3}}$ representation of the state's Merkle root, the ballot's Merkle root and a salt. At initialisation the Merkle roots are equal to the trees at full depth.
521
+
522
+ #### When the coordinator merges the message queue
523
+
524
+ The process of merging queues are the same in both the message and state trees.
525
+
526
+ #### When the coordinator processes the messages
527
+
528
+ As large zk-SNARK circuits take up a lot of disk space and require a large amount of resources to compile, it is not feasible to prove the correctness of message processing for all messages in a single proof. Rather, we process messages in batches. With each batch of messages at a particular index, the coordinator proves, using a zk-SNARK proof, intermediate `currentSbCommitment` values for subroots at a relative depth. The authenticity of this statement is confirmed using the registry's processing verifying key. The outcome of processing all batches, which must occur in consecutive order, is the same as if all the messages were processed in one go.
529
+
530
+ #### When the coordinator tallies the votes
531
+
532
+ To index tallying of votes in a poll, a tally commitment hash `tallyCommitment` is recorded which conforms similarly to the state-ballot commitment hash. The coordinator submits a new commitment hash and it's relative proof to tally the votes, which requires the verifying tallying key (queried from the registry) and the public input hash to validate the claim. Which is a SHA256 representation of the following parameters:
533
+
534
+ - a packed value of; the number of signups, batch start index and batch size (`packedVals` [6.2])
535
+ - the state-ballot commitment hash
536
+ - the current tally commitment hash
537
+ - the new tally commitment hash
538
+
539
+ The proof is then verified (see below) and the tally commitment hash is updated with the new value, this process is continued through iteration of the batch index until all pending votes have been tallied.
540
+
541
+ #### When a 3rd party verifies the tally
542
+
543
+ Any 3rd party contract may verify a leaf in `tallyCommitment` on-chain using a combination of Merkle proofs and hashing. Client developers should implement these functions as needed. We do not implement these functions in MACI to minimise contract size.
544
+
545
+ ## 4. Command-line interface
546
+
547
+ Applications that use MACI are likely to be run in the browser. Users who sign up and vote can do so via web3 interactions. Only the coordinator needs to run scripts to deploy MACI, set verifying keys, deploy Polls, merge trees, process messages, and tally votes.
548
+
549
+ To make these processes easy to use, we provide command-line interface tools.
550
+
551
+ The integration tests and shell scripts in the `cli` directory provide examples of the order in which to execute them.
552
+
553
+ | Command | Description | Notes |
554
+ | ------------------ | -------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
555
+ | `genMaciPubkey` | Generate a MACI public key from a private key | Only the coordinator needs to run this, as users should generate their keys in the browser and should be automated by the client application |
556
+ | `genMaciKeypair` | Generates a MACI private key and public key | Only the coordinator needs to run this, as users should generate their keys in the browser and should be automated by the client application |
557
+ | `deployVkRegistry` | Deploy the `VkRegistry` contract | Executed only the coordinator |
558
+ | `setVerifyingKeys` | Set verifying keys to the `VkRegistry` | Executed only the coordinator |
559
+ | `create` | Deploy a new instance of MACI | Executed only the coordinator |
560
+ | `deployPoll` | Deploy a new poll on a MACI instance | Executed only the coordinator |
561
+ | `signup` | Sign up a user | Mainly for testing; as users are more likely to use the client application instead of the CLI |
562
+ | `publish` | Submit a message to a poll | Mainly for testing; as users are more likely to use the client application instead of the CLI |
563
+ | `mergeMessages` | Must be executed before generating proofs | Executed only the coordinator |
564
+ | `mergeSignups` | Must be executed before generating proofs | Executed only the coordinator |
565
+ | `genProofs` | Generate all message processing and vote tallying proofs | Executed only the coordinator |
566
+ | `proveOnChain` | Submit proofs to the `PollProcessorAndTallyer` contract | Executed only the coordinator |
567
+
568
+ ## 5. Ethereum contracts
569
+
570
+ ### 5.1. MACI
571
+
572
+ | Function | Permissions | Notes |
573
+ | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
574
+ | `init(VkRegistry _vkRegistry, MessageAqFactory _messageAqFactory)` | Coordinator only | Initialise factory, helper and registry contracts that share equal ownership |
575
+ | `signUp(PubKey memory _pubKey, bytes memory _signUpGatekeeperData, bytes memory _initialVoiceCreditProxyData)` | Executable only during the sign-up period and after initialisation | Participant registration and voice credit assignment |
576
+ | `mergeStateAqSubRoots(uint256 _numSrQueueOps, uint256 _pollId)` | Executable only by poll contract `_pollId` and after initialisation | Merge queued state leaves to form the state tree subroots |
577
+ | `mergeStateAq(uint256 _pollId)` | Executable only by poll contract `_pollId` and after initialisation | Merge the state subroots to form the state root |
578
+ | `getStateTreeRoot()` | Non-applicable | Query the state root |
579
+ | `deployPoll(uint256 _duration, TreeDepths memory _treeDepths, PubKey memory _coordinatorPubKey)` | Executable only after initialisation | Create a new poll |
580
+ | `getPoll(uint256 _pollId)` | Non-applicable | Query a poll address |
581
+
582
+ ### 5.2. Poll
583
+
584
+ | Function | Permissions | Notes |
585
+ | ---------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
586
+ | `getDeployTimeAndDuration()` | Non-applicable | Query the deployment timestamp and duration |
587
+ | `numSignUpsAndMessages()` | Non-applicable | Query the number of participants and messages cast |
588
+ | `currentSbAndTallyCommitments()` | Non-applicable | Query the current state-ballot and tally commitments hashes |
589
+ | `publishMessage(Message memory _message, PubKey memory _encPubKey)` | Executable only during the voting period and if the message limit has not been not met | Submit a message (whether valid or not) to the message queue |
590
+ | `hashMessageAndEncPubKey(Message memory _message, PubKey memory _encPubKey)` | Non-applicable | Query a hash of a message and public key coordinates |
591
+ | `mergeMaciStateAqSubRoots( uint256 _numSrQueueOps, uint256 _pollId)` | Executable only by the coordinator and after the voting period | Merge queued state leaves to form the state subroots |
592
+ | `mergeMaciStateAq(uint256 _pollId)` | Executable only by the coordinator and after the voting period | Merge the state subroots to form the state root and initialise the state-ballot commitment hash |
593
+ | `mergeMessageAqSubRoots(uint256 _numSrQueueOps)` | Executable only by the coordinator and after the voting period | Merge the queued message leaves to form the message tree subroots |
594
+ | `mergeMessageAq()` | Executable only by the coordinator and after the voting period | Merge the message tree subroots to form the message tree root |
595
+ | `batchEnqueueMessage(uint256 _messageSubRoot)` | Executable only by the coordinator and after the voting period | Submit a batch of messages to the queue |
596
+
597
+ ### 5.3. PollFactory
598
+
599
+ | Function | Permissions | Notes |
600
+ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------- | --------------------------------------- |
601
+ | `setMessageAqFactory(MessageAqFactory _messageAqFactory)` | Coordinator only | Initialise the message factory contract |
602
+ | `deploy(uint256 _duration, TreeDepths memory _treeDepths, BatchSizes memory _batchSizes, PubKey memory _coordinatorPubKey, VkRegistry _vkRegistry, IMACI _maci, address _pollOwner)` | Coordinator only | Create a new poll |
603
+
604
+ ### 5.4. VkRegistry
605
+
606
+ | Function | Permissions | Notes |
607
+ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
608
+ | `isProcessVkSet(uint256 _sig)` | Non-applicable | Query whether a signature is valid for message processing |
609
+ | `isTallyVkSet(uint256 _sig)` | Non-applicable | Query whether a signature valid for tallying votes |
610
+ | `genProcessVkSig(uint256 _stateTreeDepth, uint256 _messageTreeDepth, uint256 _voteOptionTreeDepth, uint256 _messageBatchSize)` | Non-applicable | Generate a signature (used for verifying key mapping lookups) for message processing by compressing parameters into a singular value |
611
+ | `genTallyVkSig(uint256 _stateTreeDepth, uint256 _intStateTreeDepth, uint256 _voteOptionTreeDepth)` | Non-applicable | Generate a signature (used for verifying key mapping lookups) for vote tallying by compressing parameters into a singular value |
612
+ | `setVerifyingKeys( uint256 _stateTreeDepth, uint256 _intStateTreeDepth, uint256 _messageTreeDepth, uint256 _voteOptionTreeDepth, uint256 _messageBatchSize, VerifyingKey memory _processVk, VerifyingKey memory _tallyVk)` | Coordinator only | Initialise verifying keys for processing and tallying to the contract alongside specifying each tree depth |
613
+ | `hasProcessVk(uint256 _stateTreeDepth, uint256 _messageTreeDepth, uint256 _voteOptionTreeDepth, uint256 _messageBatchSize)` | Non-applicable | Query whether the signature of the parameters is valid for message processing |
614
+ | `getProcessVkBySig(uint256 _sig)` | Non-applicable | Query a processing verifying key by providing a valid signature |
615
+ | `getProcessVk(uint256 _stateTreeDepth, uint256 _messageTreeDepth, uint256 _voteOptionTreeDepth, uint256 _messageBatchSize)` | Non-applicable | Query a processing verifying key by providing parameters to generate a valid signature |
616
+ | `hasTallyVk(uint256 _stateTreeDepth, uint256 _intStateTreeDepth, uint256 _voteOptionTreeDepth)` | Non-applicable | Query whether the signature of the parameters is valid for vote tallying |
617
+ | `getTallyVkBySig(uint256 _sig)` | Non-applicable | Query a tallying verifying key by providing a valid signature |
618
+ | `getTallyVk(uint256 _stateTreeDepth, uint256 _intStateTreeDepth, uint256 _voteOptionTreeDepth)` | Non-applicable | Query a tallying verifying key by providing parameters to generate a valid signature |
619
+
620
+ ### 5.5. PollProcessorAndTallyer
621
+
622
+ | Function | Permissions | Notes |
623
+ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
624
+ | `sha256Hash(uint256[] memory array)` | Non-applicable | Hash an array of values (using SHA256) moduluo the snark field size |
625
+ | `processMessages(Poll _poll, uint256 _newSbCommitment, uint256[8] memory _proof)` | Executable only by the coordinator and after the voting period | Process state messages relative to a new state-ballot commitment given that the proof is valid |
626
+ | `verifyProcessProof(Poll _poll, uint256 _currentMessageBatchIndex, uint256 _messageRoot, uint256 _currentSbCommitment, uint256 _newSbCommitment, uint256[8] memory _proof)` | Non-applicable | Query whether a message processing proof is valid |
627
+ | `genProcessMessagesPublicInputHash(Poll _poll, uint256 _currentMessageBatchIndex, uint256 _messageRoot, uint256 _numSignUps, uint256 _currentSbCommitment, uint256 _newSbCommitment)` | Non-applicable | Hash of the coordinators public key, `packedVals`, current state-ballot commitment and message root |
628
+ | `genProcessMessagesPackedVals( Poll _poll, uint256 _currentMessageBatchIndex, uint256 _numSignUps)` | Non-applicable | Generate a packed 250-bit value `packedVals` for message processing |
629
+ | `genTallyVotesPackedVals( uint256 _numSignUps, uint256 _batchStartIndex, uint256 _tallyBatchSize)` | Non-applicable | Generate a packed 100-bit value `packedVals` for vote tallying |
630
+ | `genTallyVotesPublicInputHash( uint256 _numSignUps, uint256 _batchStartIndex, uint256 _tallyBatchSize, uint256 _newTallyCommitment )` | Non-applicable | Hash of the current tally commitment, the new tally commitment, `packedVals` and the state-ballot commitment |
631
+ | `tallyVotes(Poll _poll, uint256 _newTallyCommitment, uint256[8] memory _proof)` | Executable only by the coordinator and after the voting period | Tally votes relative to a new tally commitment given that the proof is valid |
632
+ | `verifyTallyProof(Poll _poll, uint256[8] memory _proof, uint256 _numSignUps, uint256 _batchStartIndex, uint256 _tallyBatchSize, uint256 _newTallyCommitment)` | Non-applicable | Query whether a vote tallying proof is valid |
633
+
634
+ ## 6. zk-SNARKs
635
+
636
+ The zk-SNARK circuits in MACI are written in the [circom](https://github.com/iden3/circom) language. Proofs are [Groth16](https://eprint.iacr.org/2016/260.pdf) and are generated using the [`rapidsnark`](https://github.com/iden3/rapidsnark) prover.
637
+
638
+ We use custom tools to simplify the process of writing circuits, testing them, and generating proving and verifying keys. These tools are not in scope of the audit but it is useful to know them.
639
+
640
+ [`circom-helper`](https://github.com/weijiekoh/circom-helper) allows developers to test circom circuits quickly and easily. It compiles circuits and exposes a JSON-RPC API which allows developers to generate witnesses and access signal values without writing command-line glue scripts.
641
+
642
+ [`zkey-manager`](https://github.com/appliedzkp/zkey-manager)
643
+ simplifies the process of zkey file management for circuits written in circom.
644
+
645
+ Please note that MACI requires the coordinator to generate proofs on an x86 machine (Intel / AMD) or VM. Other processors (e.g. ARM) are not supported.
646
+
647
+ ### 6.1. Message processing circuit
648
+
649
+ The message processing circuit, defined in `circuits/circom/processMessages.circom`, allows the coordinator to prove that they have correctly applied each message in reverse order, in a consecutive batch of `5 ^ msgBatchDepth` messages to the respective state leaf within the state tree.
650
+
651
+ #### Parameters
652
+
653
+ | Parameter | Description |
654
+ | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
655
+ | `stateTreeDepth` | Depth of the state tree, this value must be equal to `10` |
656
+ | `msgTreeDepth` | Depth of the message tree, this must be the same value passed to the `deployPoll()` contract function of `MACI.sol` |
657
+ | `msgBatchDepth` | Depth of a tree that exactly fits the number of messages in a batch, this must be the same value passed to the `deployPoll()` contract function of `MACI.sol` |
658
+ | `voteOptionTreeDepth` | Depth of the vote option tree, this must be the same value passed to the `deployPoll()` contract function of `MACI.sol` |
659
+
660
+ The state tree, message tree, and vote option trees all have an arity of 5. As such, it is possible to calculate the maximum number of signups, messages per poll, and vote options per poll.
661
+
662
+ #### Input signals
663
+
664
+ | Input signal | Description |
665
+ | -------------------------------- | --------------------------------------------------------------------------------------- |
666
+ | `numSignUps` | Number of users that have completed the sign up |
667
+ | `index` | The batch index of current message batch |
668
+ | `pollEndTimestamp` | The Unix timestamp at which the poll ends |
669
+ | `msgRoot` | The root of the message tree |
670
+ | `msgs` | The batch of messages as an array of arrays |
671
+ | `msgSubrootPathElements` | As described below |
672
+ | `coordinatorPublicKeyHash` | $\mathsf{poseidon_2}([cPk_x, cPk_y])$ |
673
+ | `newSbCommitment` | As described below |
674
+ | `coordPrivKey` | The coordinator's private key |
675
+ | `batchEndIndex` | The last batch index |
676
+ | `encPubKeys` | The public keys used to generate shared ECDH encryption keys to encrypt the messages |
677
+ | `currentStateRoot` | The state root before the commands are applied |
678
+ | `currentStateLeaves` | The state leaves upon which messages are applied |
679
+ | `currentStateLeavesPathElements` | The Merkle path to each incremental state root |
680
+ | `currentSbCommitment` | As described below |
681
+ | `currentSbSalt` | As described below |
682
+ | `newSbCommitment` | As described below |
683
+ | `newSbSalt` | As described below |
684
+ | `currentBallotRoot` | The root of the ballot tree before messages are applied |
685
+ | `currentBallots` | The ballots upon which ballots are applied |
686
+ | `currentBallotsPathElements` | The Merkle path to each incremental ballot root |
687
+ | `currentVoteWeights` | The existing vote weight for the vote option in the ballot which each command refers to |
688
+ | `currentVoteWeightsPathElements` | The Merkle path from each vote weight to the vote option root in its ballot |
689
+
690
+ ##### `currentSbCommitment` and `newSbCommitment`
691
+
692
+ The `currentSbCommitment` is the $\mathsf{poseidon_3}$ hash of the state tree root, the ballot tree root, and a random salt. The purpose of the random salt, which should be unique to each batch, is to ensure that the value of `currentSbCommitment` always changes even if all the commands in a batch are invalid and therefore do not change the state tree or ballot tree root.
693
+
694
+ The result of applying a batch of messages to `currentSbCommitment` is `newSbCommitment`.
695
+
696
+ ##### `currentSbSalt`
697
+
698
+ The salt used to produce `currentSbCommitment` (see above).
699
+
700
+ ##### `newSbSalt`
701
+
702
+ The salt used to produce `newSbCommitment` (see above).
703
+
704
+ ##### `msgSubrootPathElements`
705
+
706
+ The index of each message in `msgs` is consecutive. As such, in order to prove that each message in `msgs` is indeed a leaf of the message tree, we compute the subtree root of `msgs`, and then verify that the subtree root is indeed a subroot of `msgRoot`.
707
+
708
+ A simplified example using a tree of arity 2:
709
+
710
+ ```
711
+ r
712
+ / \
713
+ s ...
714
+ / \
715
+ o o
716
+ / \ / \
717
+ a b c d
718
+ ```
719
+
720
+ To prove that `a...d` are leaves of the tree with root `r`, we prove that the leaves have the subroot `s` with depth 2, and _then_ prove that `s` is a member of `r` at depth 1.
721
+
722
+ The implementation for this is in the `QuinBatchLeavesExists` circuit in `circuits/circom/trees/incrementalQuinTree.circom`.
723
+
724
+ This method requires fewer circuit constraints than if we verified a Merkle proof for each leaf.
725
+
726
+ #### Statements that the circuit proves
727
+
728
+ 1. That the prover knows the preimage to `currentSbCommitment` (that is, the state root, ballot root, and `currentSbSalt`)
729
+ 2. That `maxVoteOptions <= (5 ^ voteOptionTreeDepth)`
730
+ 3. That `numSignUps <== (5 ^ stateTreeDepth)`
731
+ 4. That `coordinatorPublicKeyHash` is a hash of public key that is correctly derived from `coordPrivKey`
732
+ 5. That each message in `msgs` exists in the message tree
733
+ 6. That after decrypting and applying each message, in reverse order, to the corresponding state and ballot leaves, the new state root, new ballot root, and `newSbSalt` are the preimage to `newSbCommitment`
734
+
735
+ #### How messages are decrypted and applied
736
+
737
+ The circuit uses Poseidon decryption [1.9] to decrypt each message. The shared key is derived using ECDH [1.10] and the nonce is always equal to a value of `0`.
738
+
739
+ The procedure to apply a command to a state leaf and ballot leaf is as such:
740
+
741
+ 1. Check if the signature is valid [1.6]
742
+ 2. Check if the user has enough voice credits
743
+ - To do so , we check if $sl_v + (blt_{v_{cm_{i_v}}})^{2} - (cm_{w})^2 \geq 0$
744
+ 3. Check if the vote weight is less than `147946756881789319005730692170996259609` which is approximately $\sqrt p$
745
+ - This ensures that the square of the vote weight will not overflow $p$
746
+ 4. Check if the nonce is valid
747
+ 5. Check if the state leaf index is valid
748
+ 6. Check if the timestamp is valid
749
+ 7. Check if the vote option index is valid.
750
+
751
+ If any of the above are invalid, the command is invalid.
752
+
753
+ If the command is valid:
754
+
755
+ 1. Verify that the state leaf at $cm_i$ is a member of the state root
756
+ 2. Verify that the ballot leaf at $cm_i$ is a member of the ballot root
757
+ 3. Update the state root by replacing the state leaf at $cm_i$:
758
+ - Set $sl_{P_x}$ to $cm_{P_x}$
759
+ - Set $sl_{P_y}$ to $cm_{P_y}$
760
+ - Set $sl_{v}$ to $cm_{i_v}$
761
+ 4. Update the ballot root by replacing the ballot leaf at $cm_i$:
762
+ - Set $blt_{v[cm_{i_v}]}$ to $cm_{w}$, update $blt_v$, and update $blt$ [2.7]
763
+
764
+ If the command is invalid:
765
+
766
+ 1. Verify that the state leaf at index 0 is a member of the state root
767
+ 2. Verify that the ballot leaf at index 0 is a member of the ballot root
768
+
769
+ The state leaf at index 0 is a _blank state leaf_, and the ballot leaf at index 0 is a _blank ballot leaf_. It should be impossible to update the 0th state leaf or 0th ballot leaf. The reason that these blank leaves exist at index 0 is to prevent an attack where a user sets $cm_i$ to the maximum possible value ($5^{10}$), which would force the coordinator to have to compute the Merkle path of leaf $5_{10} - 1$. Which is would take such a long time that it would constitute a denial-of-service attack on the coordinator that prevents them from generating proofs in a reasonable time.
770
+
771
+ ##### Order of message processing
772
+
773
+ Messages are applied in reverse order. This prevents an attack where a briber colludes with a user to sign up and then immediately change their key to the briber's, ceding control entirely. Rather, the user may render previous commands invalid even if said commands are key-change commands. For instance:
774
+
775
+ ###### If messages are processed in last-in-first-out order
776
+
777
+ 1. User signs up with public key $u$
778
+ 2. Briber tells user to change their key to $b$, they comply
779
+ 3. Briber can now vote for anything they want using $b$ and their commands will be valid
780
+ 4. The user cannot change the key as they do not know the briber's private key
781
+
782
+ ###### If messages are processed in first-in-first-out order
783
+
784
+ 1. User signs up with public key $u$
785
+ 2. Briber tells user to change their key to $b$, the nonce of this command is 2, the user complies
786
+ 3. Briber submits a vote, the nonce of this command is 1
787
+ 4. User changes their key to $k$, the nonce of this command is 2
788
+ 5. User votes for a vote option using public key $u$, the nonce of this command is 1
789
+
790
+ The commands at (3) and (2) are invalid because the commands at (5) and (4) are processed first. The command at (3) is invalid not only because the briber does not know the private key to $k$, but also because the expected nonce is 3.
791
+
792
+ ### 6.2. Ballot tallying circuit
793
+
794
+ After the coordinator processes all message batches, each ballot contains the votes per vote option. The next step is to tally each vote so as to produce the following results:
795
+
796
+ 1. Votes per vote option
797
+ 2. Total voice credits per vote option
798
+ 3. Total spent voice credits
799
+
800
+ As an illustration, consider the following Ballots for 5 uses. Assume that there are 5 vote options and all messages have already been processed.
801
+
802
+ ```
803
+ [1, 2, 3, 4, 5]
804
+ [1, 2, 3, 4, 5]
805
+ [0, 0, 0, 0, 0]
806
+ [0, 0, 0, 0, 0]
807
+ [1, 1, 1, 1, 1]
808
+ ```
809
+
810
+ The final tally should be:
811
+
812
+ 1. Votes per vote option: `[3, 5, 7, 9, 11]`
813
+ 2. Total voice credits per vote option: `[3, 9, 19, 33, 26]`
814
+ 3. Total spent voice credits: `66`
815
+
816
+ The coordinator uses the ballot tallying circuit (`tallyVotes.circom`) to generate proofs that they have correctly computed the tally. As there are many ballots to tally, each proof only computes the tally for a batch of ballots. Each proof is chained to the previous one such that each proof is also a proof of knowledge of the preimage of the previous tally commitment.
817
+
818
+ #### Parameters
819
+
820
+ | Parameter | Description |
821
+ | --------------------- | ----------------------------------------------------------------------------------------------------------------------- |
822
+ | `stateTreeDepth` | Depth of the state tree, this value must be equal to `10` |
823
+ | `intStateTreeDepth` | Depth of the intermediate state tree, `5 ** intStateTreeDepth` is the batch size |
824
+ | `voteOptionTreeDepth` | Depth of the vote option tree, this must be the same value passed to the `deployPoll()` contract function of `MACI.sol` |
825
+
826
+ #### Input signals
827
+
828
+ | Input signal | Description |
829
+ | --------------------------------------- | ---------------------------------------------------------------- |
830
+ | `numSignUps` | The number of users that signup |
831
+ | `index` | Start index of given batch |
832
+ | `sbCommitment` | As described below |
833
+ | `currentTallyCommitment` | As described below |
834
+ | `newTallyCommitment` | As described below |
835
+ | `stateRoot` | The root of the state tree after all messages have been applied |
836
+ | `ballotRoot` | The root of the ballot tree after all messages have been applied |
837
+ | `sbSalt` | The salt used to produce `sbCommitment` |
838
+ | `ballots` | The ballots in the batch being tallied |
839
+ | `ballotPathElements` | The Merkle path to each ballot leaf |
840
+ | `votes` | The votes in each ballot cast per result |
841
+ | `currentResults` | The current tally of votes per vote option |
842
+ | `currentResultsRootSalt` | A random value |
843
+ | `currentSpentVoiceCreditSubtotal` | The subtotal of voice credits spent across all vote options |
844
+ | `currentSpentVoiceCreditSubtotalSalt` | A random value |
845
+ | `currentPerVOSpentVoiceCredits` | The voice credits spent on each vote option so far |
846
+ | `currentPerVOSpentVoiceCreditsRootSalt` | A random value |
847
+ | `newResultsRootSalt` | A random value |
848
+ | `newPerVOSpentVoiceCreditsRootSalt` | A random value |
849
+ | `newSpentVoiceCreditSubtotalSalt` | A random value |
850
+
851
+ ##### `sbCommitment`
852
+
853
+ The commitment to `stateRoot`, `ballotRoot`, and `sbSalt`:
854
+
855
+ $\mathsf{poseidon_3}([\mathsf{stateRoot}, \mathsf{ballotRoot}, \mathsf{sbSalt}])$
856
+
857
+ Proving preimage of `sbCommitment` is one out of the several steps required to prove that the votes were tallied correctly. By establishing that the coordinator knows `ballotRoot`, the coordinator can (using other parts of the circuit) prove that they know the preimage of the ballot leaves in the batch being tallied.
858
+
859
+ ##### `currentTallyCommitment` and `newTallyCommitment`
860
+
861
+ A tally is represented by a _tally commitment_, which is the $\mathsf{poseidon_3}$ hash of:
862
+
863
+ 1. $tc_{r}$: a commitment to the votes per option
864
+ - This is the hash of the Merkle root $r_r$ of the votes and a salt $r_s$, computed as $\mathsf{poseidon_2}([r_r, r_s])$
865
+ 2. $tc_t$: a commitment to the total spent voice credits
866
+ - This is the hash of the total spent voice credits $t_c$ and a salt $t_s$, computed as $\mathsf{poseidon_2}([t_c, t_s])$
867
+ 3. $tc_p$: a commitment to the spent voice credits per vote option
868
+ - This is the hash of the Merkle root of the spent voice credits per vote option $p_v$ and a salt $p_s$, computed as $\mathsf{poseidon_2}([p_v, p_s])$
869
+
870
+ The tally commitment is computed as such:
871
+
872
+ $\mathsf{poseidon_3}([tc_r, tc_t, tc_p])$
873
+
874
+ #### Statements that the circuit proves
875
+
876
+ 1. That the coordinator knows the preimage of `sbCommitment` (see above)
877
+ 2. That `index` is less than or equal to `numSignUps`
878
+ 3. That each ballot in `ballots` is in a member of the ballot tree with the Merkle root `ballotRoot` at indices `batchStartIndex` to `batchStartIndex + (5 ** intStateTreeDepth)`
879
+ 4. That each set of votes (`votes[i]`) has the Merkle root $blt_r$ whose value equals `ballots[i][1]`
880
+ 5. That the tally is valid, which is:
881
+ - That the sum of votes per vote option is correct
882
+ - That the sum of voice credits per vote option is correct
883
+ - That the subtotal of the spent voice credits is correct