Skip to content

Commit

Permalink
feat: voice credits per poll
Browse files Browse the repository at this point in the history
  • Loading branch information
ctrlc03 committed Dec 18, 2024
1 parent 7288e18 commit d7a2143
Show file tree
Hide file tree
Showing 71 changed files with 397 additions and 660 deletions.
2 changes: 1 addition & 1 deletion apps/subgraph/src/maci.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export function handleDeployPoll(event: DeployPollEvent): void {

export function handleSignUp(event: SignUpEvent): void {
const user = createOrLoadUser(event.params._userPubKeyX, event.params._userPubKeyY, event);
createOrLoadAccount(event.params._stateIndex, event, user.id, event.params._voiceCreditBalance);
createOrLoadAccount(event.params._stateIndex, event, user.id);

const maci = createOrLoadMACI(event);
maci.numSignUps = maci.numSignUps.plus(ONE_BIG_INT);
Expand Down
2 changes: 1 addition & 1 deletion apps/subgraph/templates/subgraph.template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ dataSources:
eventHandlers:
- event: DeployPoll(uint256,indexed uint256,indexed uint256,uint8)
handler: handleDeployPoll
- event: SignUp(uint256,indexed uint256,indexed uint256,uint256,uint256,uint256)
- event: SignUp(uint256,uint256,indexed uint256,indexed uint256)
handler: handleSignUp
file: ./src/maci.ts
templates:
Expand Down
36 changes: 6 additions & 30 deletions packages/circuits/circom/anon/pollJoining.circom
Original file line number Diff line number Diff line change
@@ -1,75 +1,51 @@
pragma circom 2.0.0;

// circomlib import
include "./mux1.circom";
// zk-kit imports
include "./safe-comparators.circom";
// local imports
include "../utils/hashers.circom";
include "../utils/privToPubKey.circom";
include "../trees/incrementalMerkleTree.circom";

template PollJoining(stateTreeDepth) {
// Constants defining the structure and size of state.
var STATE_LEAF_LENGTH = 4;
// Constants defining the tree structure
var STATE_TREE_ARITY = 2;

// Public key IDs.
var STATE_LEAF_PUB_X_IDX = 0;
var STATE_LEAF_PUB_Y_IDX = 1;
// Voice Credit balance id
var STATE_LEAF_VOICE_CREDIT_BALANCE_IDX = 2;
var N_BITS = 252;

// User's private key
signal input privKey;
// Poll's private key
signal input pollPrivKey;
// Poll's public key
signal input pollPubKey[2];
// The state leaf and related path elements.
signal input stateLeaf[STATE_LEAF_LENGTH];
// Siblings
signal input siblings[stateTreeDepth][STATE_TREE_ARITY - 1];
// Indices
signal input indices[stateTreeDepth];
// User's hashed private key
signal input nullifier;
// User's credits for poll joining (might be <= oldCredits)
signal input credits;
// MACI State tree root which proves the user is signed up
signal input stateRoot;
// The actual tree depth (might be <= stateTreeDepth) Used in BinaryMerkleRoot
signal input actualStateTreeDepth;

var computedNullifier = PoseidonHasher(1)([privKey]);
nullifier === computedNullifier;

// User private to public key
var derivedPubKey[2] = PrivToPubKey()(privKey);
derivedPubKey[0] === stateLeaf[STATE_LEAF_PUB_X_IDX];
derivedPubKey[1] === stateLeaf[STATE_LEAF_PUB_Y_IDX];
// Poll private to public key
// Hash the public key
var pubKeyHash = PoseidonHasher(2)([derivedPubKey[0], derivedPubKey[1]]);

// Poll private to public key to verify the correct one is used to join the poll (public input)
var derivedPollPubKey[2] = PrivToPubKey()(pollPrivKey);
derivedPollPubKey[0] === pollPubKey[0];
derivedPollPubKey[1] === pollPubKey[1];

// Inclusion proof
var stateLeafHash = PoseidonHasher(4)(stateLeaf);
var stateLeafQip = BinaryMerkleRoot(stateTreeDepth)(
stateLeafHash,
pubKeyHash,
actualStateTreeDepth,
indices,
siblings
);

stateLeafQip === stateRoot;

// Check credits
var isCreditsValid = SafeLessEqThan(N_BITS)([credits, stateLeaf[STATE_LEAF_VOICE_CREDIT_BALANCE_IDX]]);
isCreditsValid === 1;

// Check nullifier
var hashedPrivKey = PoseidonHasher(1)([privKey]);
hashedPrivKey === nullifier;
Expand Down
2 changes: 1 addition & 1 deletion packages/circuits/circom/circuits.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"file": "./anon/pollJoining",
"template": "PollJoining",
"params": [10],
"pubs": ["nullifier", "credits", "stateRoot", "pollPubKey"]
"pubs": ["nullifier", "stateRoot", "pollPubKey"]
},
"ProcessMessages_10-20-2_test": {
"file": "./core/qv/processMessages",
Expand Down
2 changes: 2 additions & 0 deletions packages/circuits/circom/trees/incrementalMerkleTree.circom
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
pragma circom 2.0.0;

// zk-kit imports
include "./safe-comparators.circom";
// circomlib import
include "./mux1.circom";
include "./comparators.circom";
Expand Down
8 changes: 4 additions & 4 deletions packages/circuits/ts/__tests__/CeremonyParams.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ describe("Ceremony param tests", () => {
before(() => {
// Sign up and publish
const userKeypair = new Keypair(new PrivKey(BigInt(1)));
maciState.signUp(userKeypair.pubKey, voiceCreditBalance, BigInt(Math.floor(Date.now() / 1000)));
maciState.signUp(userKeypair.pubKey);

pollId = maciState.deployPoll(
BigInt(Math.floor(Date.now() / 1000) + duration),
Expand All @@ -90,7 +90,7 @@ describe("Ceremony param tests", () => {
poll = maciState.polls.get(pollId)!;

// update the state
poll.updatePoll(BigInt(maciState.stateLeaves.length));
poll.updatePoll(BigInt(maciState.pubKeys.length));

// Join the poll
const { privKey } = userKeypair;
Expand Down Expand Up @@ -221,7 +221,7 @@ describe("Ceremony param tests", () => {
const commands: PCommand[] = [];
// Sign up and publish
const userKeypair = new Keypair();
maciState.signUp(userKeypair.pubKey, voiceCreditBalance, BigInt(Math.floor(Date.now() / 1000)));
maciState.signUp(userKeypair.pubKey);

pollId = maciState.deployPoll(
BigInt(Math.floor(Date.now() / 1000) + duration),
Expand All @@ -233,7 +233,7 @@ describe("Ceremony param tests", () => {
poll = maciState.polls.get(pollId)!;

// update the state
poll.updatePoll(BigInt(maciState.stateLeaves.length));
poll.updatePoll(BigInt(maciState.pubKeys.length));

// Join the poll
const { privKey } = userKeypair;
Expand Down
19 changes: 2 additions & 17 deletions packages/circuits/ts/__tests__/PollJoining.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ describe("Poll Joining circuit", function test() {
"siblings",
"indices",
"nullifier",
"credits",
"stateRoot",
"actualStateTreeDepth",
];
Expand Down Expand Up @@ -52,7 +51,7 @@ describe("Poll Joining circuit", function test() {
users = new Array(NUM_USERS).fill(0).map(() => new Keypair());

users.forEach((userKeypair) => {
maciState.signUp(userKeypair.pubKey, voiceCreditBalance, BigInt(Math.floor(Date.now() / 1000)));
maciState.signUp(userKeypair.pubKey);
});

pollId = maciState.deployPoll(
Expand All @@ -63,7 +62,7 @@ describe("Poll Joining circuit", function test() {
);

poll = maciState.polls.get(pollId)!;
poll.updatePoll(BigInt(maciState.stateLeaves.length));
poll.updatePoll(BigInt(maciState.pubKeys.length));

// Join the poll
const { privKey } = users[0];
Expand Down Expand Up @@ -100,12 +99,10 @@ describe("Poll Joining circuit", function test() {
it("should produce a proof", async () => {
const privateKey = users[0].privKey;
const stateLeafIndex = BigInt(1);
const credits = BigInt(10);

const inputs = poll.joiningCircuitInputs({
maciPrivKey: privateKey,
stateLeafIndex,
credits,
pollPrivKey,
pollPubKey,
}) as unknown as IPollJoiningInputs;
Expand All @@ -116,12 +113,10 @@ describe("Poll Joining circuit", function test() {
it("should fail for fake witness", async () => {
const privateKey = users[0].privKey;
const stateLeafIndex = BigInt(1);
const credits = BigInt(10);

const inputs = poll.joiningCircuitInputs({
maciPrivKey: privateKey,
stateLeafIndex,
credits,
pollPrivKey,
pollPubKey,
}) as unknown as IPollJoiningInputs;
Expand All @@ -130,15 +125,5 @@ describe("Poll Joining circuit", function test() {
const fakeWitness = Array(witness.length).fill(1n) as bigint[];
await circuit.expectConstraintFail(fakeWitness);
});

it("should fail for improper credits", () => {
const privateKey = users[0].privKey;
const stateLeafIndex = BigInt(1);
const credits = BigInt(105);

expect(() =>
poll.joiningCircuitInputs({ maciPrivKey: privateKey, stateLeafIndex, credits, pollPrivKey, pollPubKey }),
).to.throw("Credits must be lower than signed up credits");
});
});
});
Loading

0 comments on commit d7a2143

Please sign in to comment.