Skip to content

Voting

Anonymous Voting with Eligibility Proofs

Commit-reveal enables secure voting where voters prove eligibility without revealing their choice until the tally.

from commit_reveal import CommitRevealScheme
import json


class SecureVotingSystem:
    def __init__(self, candidates, eligible_voters):
        self.cr = CommitRevealScheme(use_zkp=True)
        self.candidates = set(candidates)
        self.eligible_voters = set(eligible_voters)
        self.votes = {}
        self.phase = "voting"

    def cast_vote(self, voter_id, candidate):
        """Cast a vote with commitment and ZKP proof."""
        if voter_id not in self.eligible_voters:
            raise ValueError("Voter not eligible")
        if voter_id in self.votes:
            raise ValueError("Voter has already voted")
        if candidate not in self.candidates:
            raise ValueError("Invalid candidate")

        vote_data = json.dumps(
            {"candidate": candidate, "voter_id": voter_id}, sort_keys=True
        )
        commitment, salt = self.cr.commit(vote_data)

        # ZKP proof of valid vote without revealing choice
        proof = self.cr.create_zkp_proof(vote_data, salt, commitment)

        self.votes[voter_id] = {
            "commitment": commitment,
            "salt": salt,
            "proof": proof,
            "revealed_vote": None,
        }
        return commitment.hex()

    def verify_vote_commitment(self, voter_id):
        """Verify a vote commitment without revealing the vote."""
        if voter_id not in self.votes:
            return False
        vote_data = self.votes[voter_id]
        return self.cr.verify_zkp_proof(vote_data["commitment"], *vote_data["proof"])

    def reveal_vote(self, voter_id, candidate):
        """Reveal a vote and verify it matches the commitment."""
        vote_data = json.dumps(
            {"candidate": candidate, "voter_id": voter_id}, sort_keys=True
        )
        vote_info = self.votes[voter_id]

        if self.cr.reveal(vote_data, vote_info["salt"], vote_info["commitment"]):
            vote_info["revealed_vote"] = candidate
            return True
        return False

    def tally_votes(self):
        """Count all revealed votes."""
        results = {c: 0 for c in self.candidates}
        for vote_data in self.votes.values():
            if vote_data["revealed_vote"] in self.candidates:
                results[vote_data["revealed_vote"]] += 1
        return results

Running an Election

candidates = ["Alice Johnson", "Bob Smith", "Carol Davis"]
voters = ["voter001", "voter002", "voter003", "voter004", "voter005"]

election = SecureVotingSystem(candidates, voters)

# Voting phase -- each voter commits
votes = {
    "voter001": "Alice Johnson",
    "voter002": "Bob Smith",
    "voter003": "Alice Johnson",
    "voter004": "Carol Davis",
    "voter005": "Alice Johnson",
}

for voter_id, candidate in votes.items():
    election.cast_vote(voter_id, candidate)

# Verify all commitments are valid (without seeing votes)
for voter_id in votes:
    assert election.verify_vote_commitment(voter_id)

# Reveal phase
for voter_id, candidate in votes.items():
    election.reveal_vote(voter_id, candidate)

# Tally
results = election.tally_votes()
# {'Alice Johnson': 3, 'Bob Smith': 1, 'Carol Davis': 1}

Security Properties

  • Ballot secrecy -- votes are hidden until the reveal phase
  • Eligibility -- only registered voters can cast votes
  • Uniqueness -- each voter can only vote once
  • Verifiability -- ZKP proofs allow anyone to verify vote validity without seeing the choice
  • Integrity -- commitments are cryptographically binding, preventing vote changes