Skip to content

Commit

Permalink
feat: add number of valid vote options
Browse files Browse the repository at this point in the history
  • Loading branch information
ctrlc03 authored and 0xmad committed Feb 10, 2025
1 parent 3d7a387 commit cdba5a3
Show file tree
Hide file tree
Showing 52 changed files with 389 additions and 176 deletions.
2 changes: 1 addition & 1 deletion apps/subgraph/schemas/schema.v1.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ type Poll @entity {
endDate: BigInt! # uint256
duration: BigInt! # uint256
treeDepth: BigInt! # uint8
maxVoteOptions: BigInt!
voteOptions: BigInt! # uint256
messageProcessor: Bytes! # address
tally: Bytes! # address
createdAt: BigInt!
Expand Down
4 changes: 2 additions & 2 deletions apps/subgraph/src/maci.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ export function handleDeployPoll(event: DeployPollEvent): void {
const contracts = maciContract.getPoll(id);
const poll = new Poll(contracts.poll);
const pollContract = PollContract.bind(contracts.poll);
const maxVoteOptions = pollContract.maxVoteOptions();
const voteOptions = pollContract.voteOptions();
const treeDepths = pollContract.treeDepths();
const durations = pollContract.getStartAndEndDate();
const duration = durations.value1.minus(durations.value0);

poll.pollId = event.params._pollId;
poll.messageProcessor = contracts.messageProcessor;
poll.tally = contracts.tally;
poll.maxVoteOptions = maxVoteOptions;
poll.voteOptions = voteOptions;
poll.treeDepth = GraphBN.fromI32(treeDepths.value0);
poll.duration = duration;
poll.startDate = durations.value0;
Expand Down
2 changes: 1 addition & 1 deletion apps/subgraph/tests/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const DEFAULT_MESSAGE_PROCESSOR_ADDRESS = Address.fromString("0x000000000
export const DEFAULT_TALLY_ADDRESS = Address.fromString("0x0000000000000000000000000000000000000003");

export function mockPollContract(): void {
createMockedFunction(DEFAULT_POLL_ADDRESS, "maxVoteOptions", "maxVoteOptions():(uint256)").returns([
createMockedFunction(DEFAULT_POLL_ADDRESS, "voteOptions", "voteOptions():(uint256)").returns([
ethereum.Value.fromI32(20),
]);

Expand Down
6 changes: 4 additions & 2 deletions packages/circuits/circom/circuits.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
"newSbCommitment",
"outputBatchHash",
"actualStateTreeDepth",
"coordinatorPublicKeyHash"
"coordinatorPublicKeyHash",
"voteOptions"
]
},
"ProcessMessagesNonQv_10-20-2_test": {
Expand All @@ -38,7 +39,8 @@
"newSbCommitment",
"outputBatchHash",
"actualStateTreeDepth",
"coordinatorPublicKeyHash"
"coordinatorPublicKeyHash",
"voteOptions"
]
},
"TallyVotes_10-1-2_test": {
Expand Down
20 changes: 12 additions & 8 deletions packages/circuits/circom/core/non-qv/processMessages.circom
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ include "../../trees/incrementalQuinaryTree.circom";
signal input actualStateTreeDepth;
// The coordinator public key hash
signal input coordinatorPublicKeyHash;
// The number of valid vote options for the poll.
signal input voteOptions;

// The state leaves upon which messages are applied.
// transform(currentStateLeaf[4], message5) => newStateLeaf4
Expand Down Expand Up @@ -117,10 +119,10 @@ include "../../trees/incrementalQuinaryTree.circom";
computedCurrentSbCommitment === currentSbCommitment;

// -----------------------------------------------------------------------
// 0. Ensure that the maximum vote options signal is valid and if
// the maximum users signal is valid.
var maxVoValid = LessEqThan(32)([maxVoteOptions, VOTE_OPTION_TREE_ARITY ** voteOptionTreeDepth]);
maxVoValid === 1;
// 0. Ensure that the maximum vote options signal is valid and if
// the maximum users signal is valid
var voteOptionsValid = LessEqThan(32)([voteOptions, VOTE_OPTION_TREE_ARITY ** voteOptionTreeDepth]);
voteOptionsValid === 1;

// Check numSignUps <= the max number of users (i.e., number of state leaves
// that can fit the state tree).
Expand Down Expand Up @@ -242,7 +244,8 @@ include "../../trees/incrementalQuinaryTree.circom";
computedCommandsSalt[i],
computedCommandsSigR8[i],
computedCommandsSigS[i],
computedCommandsPackedCommandOut[i]
computedCommandsPackedCommandOut[i],
voteOptions
);

stateRoots[i] <== computedNewVoteStateRoot[i];
Expand Down Expand Up @@ -272,8 +275,6 @@ template ProcessOneNonQv(stateTreeDepth, voteOptionTreeDepth) {
var BALLOT_NONCE_IDX = 0;
// Ballot vote option (VO) root index.
var BALLOT_VO_ROOT_IDX = 1;
// Number of options for this poll.
var maxVoteOptions = VOTE_OPTION_TREE_ARITY ** voteOptionTreeDepth;

// Indices for elements within a state leaf.
// Public key.
Expand Down Expand Up @@ -319,6 +320,9 @@ template ProcessOneNonQv(stateTreeDepth, voteOptionTreeDepth) {
signal input cmdSigS;
signal input packedCmd[PACKED_CMD_LENGTH];

// The number of valid vote options for the poll.
signal input voteOptions;

signal output newStateRoot;
signal output newBallotRoot;

Expand All @@ -330,7 +334,7 @@ template ProcessOneNonQv(stateTreeDepth, voteOptionTreeDepth) {
var computedNewSlPubKey[2], computedNewBallotNonce, computedIsValid, computedIsStateLeafIndexValid, computedIsVoteOptionIndexValid;
(computedNewSlPubKey, computedNewBallotNonce, computedIsValid, computedIsStateLeafIndexValid, computedIsVoteOptionIndexValid) = StateLeafAndBallotTransformerNonQv()(
numSignUps,
maxVoteOptions,
voteOptions,
[stateLeaf[STATE_LEAF_PUB_X_IDX], stateLeaf[STATE_LEAF_PUB_Y_IDX]],
stateLeaf[STATE_LEAF_VOICE_CREDIT_BALANCE_IDX],
ballot[BALLOT_NONCE_IDX],
Expand Down
19 changes: 11 additions & 8 deletions packages/circuits/circom/core/qv/processMessages.circom
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ template ProcessMessages(
signal input actualStateTreeDepth;
// The coordinator public key hash
signal input coordinatorPublicKeyHash;
// The number of valid vote options for the poll.
signal input voteOptions;

// The state leaves upon which messages are applied.
// transform(currentStateLeaf[4], message5) => newStateLeaf4
Expand Down Expand Up @@ -112,10 +114,9 @@ template ProcessMessages(
var computedCurrentSbCommitment = PoseidonHasher(3)([currentStateRoot, currentBallotRoot, currentSbSalt]);
computedCurrentSbCommitment === currentSbCommitment;

// 0. Ensure that the maximum vote options signal is valid and if
// the maximum users signal is valid.
var maxVoValid = LessEqThan(32)([maxVoteOptions, VOTE_OPTION_TREE_ARITY ** voteOptionTreeDepth]);
maxVoValid === 1;
// Ensure that the vote options signal is valid
var voteOptionsValid = LessEqThan(32)([voteOptions, VOTE_OPTION_TREE_ARITY ** voteOptionTreeDepth]);
voteOptionsValid === 1;

// Check numSignUps <= the max number of users (i.e., number of state leaves
// that can fit the state tree).
Expand Down Expand Up @@ -237,7 +238,8 @@ template ProcessMessages(
computedCommandsSalt[i],
computedCommandsSigR8[i],
computedCommandsSigS[i],
computedCommandsPackedCommandOut[i]
computedCommandsPackedCommandOut[i],
voteOptions
);

stateRoots[i] <== computedNewVoteStateRoot[i];
Expand Down Expand Up @@ -267,8 +269,6 @@ template ProcessOne(stateTreeDepth, voteOptionTreeDepth) {
var BALLOT_NONCE_IDX = 0;
// Ballot vote option (VO) root index.
var BALLOT_VO_ROOT_IDX = 1;
// Number of options for this poll.
var maxVoteOptions = VOTE_OPTION_TREE_ARITY ** voteOptionTreeDepth;

// Indices for elements within a state leaf.
// Public key.
Expand Down Expand Up @@ -314,6 +314,9 @@ template ProcessOne(stateTreeDepth, voteOptionTreeDepth) {
signal input cmdSigS;
signal input packedCmd[PACKED_CMD_LENGTH];

// The number of valid vote options for the poll.
signal input voteOptions;

signal output newStateRoot;
signal output newBallotRoot;

Expand All @@ -330,7 +333,7 @@ template ProcessOne(stateTreeDepth, voteOptionTreeDepth) {
var computedNewSlPubKey[2], computedNewBallotNonce, computedIsValid, computedIsStateLeafIndexValid, computedIsVoteOptionIndexValid;
(computedNewSlPubKey, computedNewBallotNonce, computedIsValid, computedIsStateLeafIndexValid, computedIsVoteOptionIndexValid) = StateLeafAndBallotTransformer()(
numSignUps,
maxVoteOptions,
voteOptions,
[stateLeaf[STATE_LEAF_PUB_X_IDX], stateLeaf[STATE_LEAF_PUB_Y_IDX]],
stateLeaf[STATE_LEAF_VOICE_CREDIT_BALANCE_IDX],
ballot[BALLOT_NONCE_IDX],
Expand Down
8 changes: 4 additions & 4 deletions packages/circuits/circom/utils/non-qv/messageValidator.circom
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ template MessageValidatorNonQv() {
signal input numSignUps;
// Vote option index.
signal input voteOptionIndex;
// Maximum number of vote options.
signal input maxVoteOptions;
// Number of valid vote options for the poll.
signal input voteOptions;
// Ballot nonce.
signal input originalNonce;
// Command nonce.
Expand Down Expand Up @@ -53,8 +53,8 @@ template MessageValidatorNonQv() {
// while 1 is for the first actual user.
var computedIsStateLeafIndexValid = SafeLessThan(252)([stateTreeIndex, numSignUps]);

// Check (2) - The max vote option tree index must be correct.
var computedIsVoteOptionIndexValid = SafeLessThan(252)([voteOptionIndex, maxVoteOptions]);
// Check (2) - The vote option index must be less than the number of valid vote options (0 indexed).
var computedIsVoteOptionIndexValid = SafeLessThan(252)([voteOptionIndex, voteOptions]);

// Check (3) - The nonce must be correct.
var computedIsNonceValid = IsEqual()([originalNonce + 1, nonce]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ template StateLeafAndBallotTransformerNonQv() {

// Number of user sign-ups in the state tree.
signal input numSignUps;
// Maximum number of vote options.
signal input maxVoteOptions;
// Number of valid vote options for the poll.
signal input voteOptions;

// The following signals represents a state leaf (signed up user).
// Public key.
Expand Down Expand Up @@ -72,7 +72,7 @@ template StateLeafAndBallotTransformerNonQv() {
cmdStateIndex,
numSignUps,
cmdVoteOptionIndex,
maxVoteOptions,
voteOptions,
ballotNonce,
cmdNonce,
packedCommand,
Expand Down
8 changes: 4 additions & 4 deletions packages/circuits/circom/utils/qv/messageValidator.circom
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ template MessageValidator() {
signal input numSignUps;
// Vote option index.
signal input voteOptionIndex;
// Maximum number of vote options.
signal input maxVoteOptions;
// Number of valid vote options for the poll.
signal input voteOptions;
// Ballot nonce.
signal input originalNonce;
// Command nonce.
Expand Down Expand Up @@ -53,8 +53,8 @@ template MessageValidator() {
// while 1 is for the first actual user.
var computedIsStateLeafIndexValid = SafeLessThan(252)([stateTreeIndex, numSignUps]);

// Check (2) - The max vote option tree index must be correct.
var computedIsVoteOptionIndexValid = SafeLessThan(252)([voteOptionIndex, maxVoteOptions]);
// Check (2) - The vote option index must be less than the number of valid vote options (0 indexed).
var computedIsVoteOptionIndexValid = SafeLessThan(252)([voteOptionIndex, voteOptions]);

// Check (3) - The nonce must be correct.
var computedIsNonceValid = IsEqual()([originalNonce + 1, nonce]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ template StateLeafAndBallotTransformer() {

// Number of user sign-ups in the state tree.
signal input numSignUps;
// Maximum number of vote options.
signal input maxVoteOptions;
// Number of valid vote options for the poll.
signal input voteOptions;

// The following signals represents a state leaf (signed up user).
// Public key.
Expand Down Expand Up @@ -72,7 +72,7 @@ template StateLeafAndBallotTransformer() {
cmdStateIndex,
numSignUps,
cmdVoteOptionIndex,
maxVoteOptions,
voteOptions,
ballotNonce,
cmdNonce,
packedCommand,
Expand Down
4 changes: 4 additions & 0 deletions packages/circuits/ts/__tests__/CeremonyParams.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { PrivKey, Keypair, PCommand, Message, Ballot } from "maci-domainobjs";

import { IProcessMessagesInputs, ITallyVotesInputs } from "../types";

import { maxVoteOptions } from "./utils/constants";
import { generateRandomIndex, circomkitInstance } from "./utils/utils";

describe("Ceremony param tests", () => {
Expand Down Expand Up @@ -54,6 +55,7 @@ describe("Ceremony param tests", () => {
"currentBallotsPathElements",
"currentVoteWeights",
"currentVoteWeightsPathElements",
"voteOptions",
]
>;

Expand Down Expand Up @@ -85,6 +87,7 @@ describe("Ceremony param tests", () => {
treeDepths,
MESSAGE_BATCH_SIZE,
coordinatorKeypair,
maxVoteOptions,
);

poll = maciState.polls.get(pollId)!;
Expand Down Expand Up @@ -228,6 +231,7 @@ describe("Ceremony param tests", () => {
treeDepths,
MESSAGE_BATCH_SIZE,
coordinatorKeypair,
maxVoteOptions,
);

poll = maciState.polls.get(pollId)!;
Expand Down
8 changes: 4 additions & 4 deletions packages/circuits/ts/__tests__/MessageValidator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ describe("MessageValidator circuit", function test() {
"stateTreeIndex",
"numSignUps",
"voteOptionIndex",
"maxVoteOptions",
"voteOptions",
"originalNonce",
"nonce",
"cmd",
Expand Down Expand Up @@ -58,7 +58,7 @@ describe("MessageValidator circuit", function test() {
stateTreeIndex: 0n,
numSignUps: 1n,
voteOptionIndex: 0n,
maxVoteOptions: 1n,
voteOptions: 1n,
originalNonce: 1n,
nonce: 2n,
cmd: command.asCircuitInputs(),
Expand Down Expand Up @@ -182,7 +182,7 @@ describe("MessageValidator circuit", function test() {
"stateTreeIndex",
"numSignUps",
"voteOptionIndex",
"maxVoteOptions",
"voteOptions",
"originalNonce",
"nonce",
"cmd",
Expand Down Expand Up @@ -223,7 +223,7 @@ describe("MessageValidator circuit", function test() {
stateTreeIndex: 0n,
numSignUps: 1n,
voteOptionIndex: 0n,
maxVoteOptions: 1n,
voteOptions: 1n,
originalNonce: 1n,
nonce: 2n,
cmd: command.asCircuitInputs(),
Expand Down
17 changes: 15 additions & 2 deletions packages/circuits/ts/__tests__/PollJoined.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,14 @@ import { Keypair, Message, PCommand } from "maci-domainobjs";

import type { IPollJoinedInputs } from "../types";

import { STATE_TREE_DEPTH, duration, messageBatchSize, treeDepths, voiceCreditBalance } from "./utils/constants";
import {
STATE_TREE_DEPTH,
duration,
maxVoteOptions,
messageBatchSize,
treeDepths,
voiceCreditBalance,
} from "./utils/constants";
import { circomkitInstance } from "./utils/utils";

describe("Poll Joined circuit", function test() {
Expand Down Expand Up @@ -53,7 +60,13 @@ describe("Poll Joined circuit", function test() {
maciState.signUp(userKeypair.pubKey);
});

pollId = maciState.deployPoll(timestamp + BigInt(duration), treeDepths, messageBatchSize, coordinatorKeypair);
pollId = maciState.deployPoll(
timestamp + BigInt(duration),
treeDepths,
messageBatchSize,
coordinatorKeypair,
maxVoteOptions,
);

poll = maciState.polls.get(pollId)!;

Expand Down
10 changes: 9 additions & 1 deletion packages/circuits/ts/__tests__/PollJoining.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,14 @@ import { Keypair, Message, PCommand } from "maci-domainobjs";

import { IPollJoiningInputs } from "../types";

import { STATE_TREE_DEPTH, duration, messageBatchSize, treeDepths, voiceCreditBalance } from "./utils/constants";
import {
STATE_TREE_DEPTH,
duration,
maxVoteOptions,
messageBatchSize,
treeDepths,
voiceCreditBalance,
} from "./utils/constants";
import { circomkitInstance } from "./utils/utils";

describe("Poll Joining circuit", function test() {
Expand Down Expand Up @@ -57,6 +64,7 @@ describe("Poll Joining circuit", function test() {
treeDepths,
messageBatchSize,
coordinatorKeypair,
maxVoteOptions,
);

poll = maciState.polls.get(pollId)!;
Expand Down
Loading

0 comments on commit cdba5a3

Please sign in to comment.