Skip to content

Instantly share code, notes, and snippets.

@karlfloersch
Last active May 10, 2023 15:13
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save karlfloersch/0ba69290f5d18823548dc32fe1f6a250 to your computer and use it in GitHub Desktop.
Save karlfloersch/0ba69290f5d18823548dc32fe1f6a250 to your computer and use it in GitHub Desktop.
pragma solidity ^0.4.7;
contract CommitRevealElection {
// The two choices for your vote
string public choice1;
string public choice2;
// Information about the current status of the vote
uint public votesForChoice1;
uint public votesForChoice2;
uint public commitPhaseEndTime;
uint public numberOfVotesCast = 0;
// The actual votes and vote commits
bytes32[] public voteCommits;
mapping(bytes32 => string) voteStatuses; // Either `Committed` or `Revealed`
// Events used to log what's going on in the contract
event logString(string);
event newVoteCommit(string, bytes32);
event voteWinner(string, string);
// Constructor used to set parameters for the this specific vote
function CommitRevealElection(uint _commitPhaseLengthInSeconds,
string _choice1,
string _choice2) {
if (_commitPhaseLengthInSeconds < 20) {
throw;
}
commitPhaseEndTime = now + _commitPhaseLengthInSeconds * 1 seconds;
choice1 = _choice1;
choice2 = _choice2;
}
function commitVote(bytes32 _voteCommit) {
if (now > commitPhaseEndTime) throw; // Only allow commits during committing period
// Check if this commit has been used before
bytes memory bytesVoteCommit = bytes(voteStatuses[_voteCommit]);
if (bytesVoteCommit.length != 0) throw;
// We are still in the committing period & the commit is new so add it
voteCommits.push(_voteCommit);
voteStatuses[_voteCommit] = "Committed";
numberOfVotesCast ++;
newVoteCommit("Vote committed with the following hash:", _voteCommit);
}
function revealVote(string _vote, bytes32 _voteCommit) {
if (now < commitPhaseEndTime) throw; // Only reveal votes after committing period is over
// FIRST: Verify the vote & commit is valid
bytes memory bytesVoteStatus = bytes(voteStatuses[_voteCommit]);
if (bytesVoteStatus.length == 0) {
logString('A vote with this voteCommit was not cast');
} else if (bytesVoteStatus[0] != 'C') {
logString('This vote was already cast');
return;
}
if (_voteCommit != keccak256(_vote)) {
logString('Vote hash does not match vote commit');
return;
}
// NEXT: Count the vote!
bytes memory bytesVote = bytes(_vote);
if (bytesVote[0] == '1') {
votesForChoice1 = votesForChoice1 + 1;
logString('Vote for choice 1 counted.');
} else if (bytesVote[0] == '2') {
votesForChoice2 = votesForChoice2 + 1;
logString('Vote for choice 2 counted.');
} else {
logString('Vote could not be read! Votes must start with the ASCII character `1` or `2`');
}
voteStatuses[_voteCommit] = "Revealed";
}
function getWinner () constant returns(string) {
// Only get winner after all vote commits are in
if (now < commitPhaseEndTime) throw;
// Make sure all the votes have been counted
if (votesForChoice1 + votesForChoice2 != voteCommits.length) throw;
if (votesForChoice1 > votesForChoice2) {
voteWinner("And the winner of the vote is:", choice1);
return choice1;
} else if (votesForChoice2 > votesForChoice1) {
voteWinner("And the winner of the vote is:", choice2);
return choice2;
} else if (votesForChoice1 == votesForChoice2) {
voteWinner("The vote ended in a tie!", "");
return "It was a tie!";
}
}
}
@showmeyourcode
Copy link

Thanks for explaining commit reveal.

A little security issue in this example, thought that I should I call it out.

WHAT?
Since there are only two choices, which might be the case for many such applications, a better way of taking input could to bucket all even number to one choice and all odd numbers to other choice.

WHY?
Since any one could figure out what the hashed for two choices are they can actually see how many votes have gone through before reveal phase.

@mrwillis
Copy link

mrwillis commented Sep 6, 2018

@showmeyourcode I'm not sure that's correct. The secret is unique to every vote, so even if you tried both (binary) possibilities, you would still need the secret to match the hashes up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment