IPrivateVoting
Title: IPrivateVoting
Author: David Dada <daveproxy80@gmail.com> (https://github.com/dadadave80)
External interface for anonymous one-person-one-vote polling. A poll is bound to a Semaphore
group (the electorate); a member casts a ballot with a Semaphore proof whose scope is the
poll id and whose message is the vote choice. The scope-bound nullifier gives each member
exactly one vote per poll while keeping the vote anonymous.
Composes the ISemaphore module: voting reuses that group's membership + the audited verifier
for the zero-knowledge check, and keeps its OWN per-poll nullifier set for double-vote
protection (so voting nullifiers never collide with general Semaphore signalling). This is
1-person-1-vote, NOT token-weighted: private weighted voting needs a bespoke circuit and is out
of scope. The ISemaphore module must be present in the same diamond and its groups created
there; proof.scope MUST equal the poll id.
Functions
createPoll
Creates a poll over groupId. Only the group admin may create polls for it.
function createPoll(uint256 groupId, uint32 numChoices, uint64 startTime, uint64 endTime)
external
returns (uint256 pollId);Parameters
| Name | Type | Description |
|---|---|---|
| groupId | uint256 | The Semaphore group whose members may vote. |
| numChoices | uint32 | Number of options (>= 2). |
| startTime | uint64 | Unix time voting opens (0 = immediately). |
| endTime | uint64 | Unix time voting closes (0 = never). |
Returns
| Name | Type | Description |
|---|---|---|
| pollId | uint256 | The new poll id (1-based); voters must use this as the Semaphore scope. |
vote
Casts an anonymous ballot in pollId. proof.scope must equal pollId and
proof.message is the chosen option; the nullifier prevents a second ballot.
function vote(uint256 pollId, ISemaphore.SemaphoreProof calldata proof) external;Parameters
| Name | Type | Description |
|---|---|---|
| pollId | uint256 | The poll to vote in. |
| proof | ISemaphore.SemaphoreProof | The Semaphore proof of membership binding the choice + poll. |
pollCount
Returns the number of polls created.
function pollCount() external view returns (uint256);Returns
| Name | Type | Description |
|---|---|---|
| <none> | uint256 |
getPoll
Returns the public configuration of pollId.
function getPoll(uint256 pollId) external view returns (PollView memory);Parameters
| Name | Type | Description |
|---|---|---|
| pollId | uint256 |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | PollView |
getVotes
Returns the vote count for choice in pollId.
function getVotes(uint256 pollId, uint256 choice) external view returns (uint256);Parameters
| Name | Type | Description |
|---|---|---|
| pollId | uint256 | |
| choice | uint256 |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | uint256 |
hasVoted
Returns whether nullifier has already voted in pollId.
function hasVoted(uint256 pollId, uint256 nullifier) external view returns (bool);Parameters
| Name | Type | Description |
|---|---|---|
| pollId | uint256 | |
| nullifier | uint256 |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | bool |
Events
PollCreated
Emitted when a poll is created.
event PollCreated(
uint256 indexed pollId,
uint256 indexed groupId,
address indexed creator,
uint32 numChoices,
uint64 startTime,
uint64 endTime
);Parameters
| Name | Type | Description |
|---|---|---|
| pollId | uint256 | |
| groupId | uint256 | |
| creator | address | |
| numChoices | uint32 | |
| startTime | uint64 | |
| endTime | uint64 |
VoteCast
Emitted when a ballot is counted. nullifier is the public, scope-bound tag (not linkable
to an identity); choice is the counted option.
event VoteCast(uint256 indexed pollId, uint256 indexed choice, uint256 nullifier);Parameters
| Name | Type | Description |
|---|---|---|
| pollId | uint256 | |
| choice | uint256 | |
| nullifier | uint256 |
Errors
PrivateVotingPollDoesNotExist
Thrown when the poll id does not exist.
error PrivateVotingPollDoesNotExist();PrivateVotingNotGroupAdmin
Thrown when the caller is not the admin of the poll's Semaphore group.
error PrivateVotingNotGroupAdmin();PrivateVotingInvalidNumChoices
Thrown when creating a poll with fewer than two choices.
error PrivateVotingInvalidNumChoices();PrivateVotingInvalidTimeWindow
Thrown when endTime is set and is not after startTime.
error PrivateVotingInvalidTimeWindow();PrivateVotingNotOpen
Thrown when voting before startTime.
error PrivateVotingNotOpen();PrivateVotingClosed
Thrown when voting after endTime.
error PrivateVotingClosed();PrivateVotingScopeMismatch
Thrown when proof.scope is not the poll id (the ballot is for a different poll).
error PrivateVotingScopeMismatch();PrivateVotingInvalidChoice
Thrown when proof.message (the choice) is >= numChoices.
error PrivateVotingInvalidChoice();PrivateVotingInvalidProof
Thrown when the Semaphore membership proof does not verify.
error PrivateVotingInvalidProof();PrivateVotingAlreadyVoted
Thrown when the proof's nullifier has already voted in this poll.
error PrivateVotingAlreadyVoted();Structs
PollView
A poll's public configuration (the per-choice tally is read via getVotes).
struct PollView {
uint256 groupId;
uint32 numChoices;
address creator;
uint64 startTime;
uint64 endTime;
uint256 totalVotes;
}Properties
| Name | Type | Description |
|---|---|---|
| groupId | uint256 | The Semaphore group whose members may vote. |
| numChoices | uint32 | Number of valid options; votes use 0 .. numChoices-1. |
| creator | address | The group admin who created the poll. |
| startTime | uint64 | Unix time voting opens (0 = open immediately). |
| endTime | uint64 | Unix time voting closes (0 = never closes). |
| totalVotes | uint256 | Total ballots cast. |