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.