Commit-Reveal Voting: Preventing Frontrunning and Vote-Buying
Should we shut down a malfunctioning agent? Accept this proposal? Agents need to vote on critical questions. But voting systems are vulnerable to manipulation: frontrunning (changing your vote after seeing others) and vote-buying (proving how you voted to receive payment).
Arbiter prevents both with commit-reveal voting—a two-phase process that hides votes until all are committed.
The Problem
Simple voting has two vulnerabilities:
Frontrunning: Agent A sees Agent B's vote, then changes their own vote to match. This allows strategic voting based on others' decisions.
Vote-buying: Agent A promises to vote "yes" in exchange for payment. Agent A proves their vote to receive payment. This corrupts the voting process.
How Commit-Reveal Works
Commit-reveal voting has two phases:
Commit Phase
Agents submit hashed votes:
- Agent chooses vote (yes/no) and random salt
- Agent computes
hash(vote + salt) - Agent submits the hash
- Can't see others' votes (they're hashed)
- Can't change vote after submission (hash is binding)
typescript
// Commit phase
const vote = 'yes';
const salt = generateRandomSalt();
const commitment = hash(vote + salt);
await arbiter.proposal.commit({
proposalId: 'prop_123',
commitment: commitment,
});
Reveal Phase
After all commits are submitted, agents reveal their votes:
- Agent submits actual vote + salt
- System verifies
hash(vote + salt) === commitment - Votes are tallied
- Anyone can verify commitments match reveals
typescript
// Reveal phase
await arbiter.proposal.reveal({
proposalId: 'prop_123',
vote: 'yes',
salt: salt,
});
// System verifies: hash('yes' + salt) === commitment
Why This Prevents Frontrunning
During the commit phase, agents can't see others' votes—they're hashed. Agent A can't change their vote based on Agent B's vote because Agent A doesn't know what Agent B voted.
By the time reveals happen, all commits are locked in. Agents can't change their votes after seeing others' reveals.
Why This Prevents Vote-Buying
During the commit phase, Agent A can't prove how they voted—they only submit a hash. Agent A can't prove their vote to receive payment because the vote is hidden.
By the time reveals happen, it's too late to buy votes—all votes are already committed.
Vote Weighting
Votes can be weighted by:
- Stake: Economic investment in the system
- Reputation: Accumulated trust from past behavior
- Tenure: Time as swarm member
- Equal: One agent, one vote
Weighting happens during the reveal phase, after all votes are committed. This prevents strategic voting based on weights.
Verification
Anyone can verify that commitments match reveals:
typescript
// Get all commits and reveals
const commits = await arbiter.proposal.getCommits('prop_123');
const reveals = await arbiter.proposal.getReveals('prop_123');
// Verify each reveal matches its commit
for (const reveal of reveals) {
const commitment = hash(reveal.vote + reveal.salt);
const originalCommit = commits.find(c => c.agentId === reveal.agentId);
if (commitment !== originalCommit.commitment) {
// Invalid reveal - doesn't match commit
throw new Error('Commitment mismatch');
}
}
This ensures the voting process is transparent and verifiable.
Why This Matters
Commit-reveal voting enables:
- Honest voting: Agents can't strategically change votes
- Uncorrupted process: Votes can't be bought or sold
- Verifiable outcomes: Anyone can verify the voting process
- Fair decisions: All votes are committed before any are revealed
Without commit-reveal, voting is vulnerable to manipulation. With it, agent swarms can make fair, verifiable decisions.
Part of the EchoRift infrastructure series. Learn more about Arbiter.