Election of a single candidate by HMAC
Voter code yS2MuD4+iPrmZOoSIY76qLCMQWS/wQxnql8MmpN9AUY= votes for Pirates | |
non interactively | |
echo -e "yS2MuD4+iPrmZOoSIY76qLCMQWS/wQxnql8MmpN9AUY=\nPirates" | python3 hmac_vote.py | |
interactively | |
python3 hmac_vote.py | |
What's your code? > yS2MuD4+iPrmZOoSIY76qLCMQWS/wQxnql8MmpN9AUY= | |
Your code is: | |
yS2MuD4+iPrmZOoSIY76qLCMQWS/wQxnql8MmpN9AUY= | |
1) Ninjas | |
2) Pirates | |
Who are you voting for? > Pirates | |
your ballot is: | |
cjiMwzbLl570aaPCyzUOvu223WamIgGSHnGhbdTj4ME= | |
Voter code yS2MuD4+iPrmZOoSIY76qLCMQWS/wQxnql8MmpN9AUY= votes for Ninjas | |
ZGLCwApfT/35GrhTko3AmsNjZegkcnjCZUoqhuLs/2E= | |
Voter code VZtI0Jykc9DdUdqwfY0Qkg43RZozm0zsmjewIRaG4OE= votes for Pirates | |
xxxUP45I8XgAlYz9bY698jbieK1RaKfwm685AgrOQbk= | |
Voter code VZtI0Jykc9DdUdqwfY0Qkg43RZozm0zsmjewIRaG4OE= votes for Ninjas | |
MWX3Bo5kly78FI/Anj/T4JHPSKqVMUbuwXYTQK8EwnM= | |
Counting ballots | |
python3 hmac_vote_count.py example_voter_codes.txt <<VOTES | |
cjiMwzbLl570aaPCyzUOvu223WamIgGSHnGhbdTj4ME= | |
xxxUP45I8XgAlYz9bY698jbieK1RaKfwm685AgrOQbk= | |
VOTES | |
2 Pirates | |
0 Ninjas | |
0 spoiled |
yS2MuD4+iPrmZOoSIY76qLCMQWS/wQxnql8MmpN9AUY= | |
VZtI0Jykc9DdUdqwfY0Qkg43RZozm0zsmjewIRaG4OE= |
#!/usr/bin/env python3 | |
from __future__ import print_function | |
from __future__ import division | |
from random import SystemRandom | |
from base64 import b64encode | |
from sys import argv, version_info | |
if version_info[0] >= 3: | |
def eight_bit_int_to_byte(n): | |
return int.to_bytes(n, 1, 'big') | |
else: | |
eight_bit_int_to_byte = chr | |
sysrandom = SystemRandom() | |
def generate_voting_code(): | |
random_256_bits_as_bytes = b''.join( | |
eight_bit_int_to_byte(sysrandom.getrandbits(8)) | |
for i in range(256//8) ) | |
return b64encode(random_256_bits_as_bytes).decode('ascii') | |
n_codes = 1 if len(argv) < 2 else int(argv[1]) | |
print( '\n'.join( generate_voting_code() for i in range(n_codes) ) ) |
#!/usr/bin/env python3 | |
from __future__ import print_function | |
from __future__ import division | |
from random import SystemRandom | |
import hmac | |
import hashlib | |
import base64 | |
import sys | |
if sys.version_info[0] >= 3: | |
raw_input = input | |
candidates = [ | |
"Pirates", | |
"Ninjas", | |
] | |
SystemRandom().shuffle(candidates) | |
def create_code_signed_ballot(code, vote): | |
ballot_hmac = hmac.new(code.encode('UTF-8'), vote.encode('UTF-8'), | |
digestmod=hashlib.sha256) | |
base_64_bytes = base64.b64encode(ballot_hmac.digest()) | |
return base_64_bytes.decode('ascii') | |
def get_valid_vote(candidates): | |
candidates_enumerated = list(enumerate(candidates, 1)) | |
candidate_lookup_by_number = dict( candidates_enumerated ) | |
while True: | |
print() # blank line | |
for i, candidate in candidates_enumerated: | |
print("%d) %s" % (i, candidate)) | |
candidate_selection_w_newline = raw_input("Who are you voting for? > ") | |
candidate_selection = candidate_selection_w_newline.strip() | |
if candidate_selection in candidates: | |
return candidate_selection | |
else: | |
try: | |
candidate_number = int(candidate_selection) | |
except ValueError: | |
pass | |
else: # only if conversion of candidate_selection to int works | |
if candidate_number in candidate_lookup_by_number: | |
return candidate_lookup_by_number[candidate_number] | |
def get_valid_code(): | |
while True: | |
code_w_newline = raw_input("What's your code? > ") | |
code = code_w_newline.strip() | |
try: | |
decoded_code = base64.b64decode(code) | |
except: | |
print("invalid code") | |
else: | |
if len(decoded_code) == (256//8): | |
break | |
else: | |
print("invalid code") | |
print("Your code is:") | |
print(code) | |
print() | |
return code | |
def main(): | |
code = get_valid_code() | |
vote = get_valid_vote(candidates) | |
code_signed_ballot = create_code_signed_ballot(code, vote) | |
print("your ballot is:") | |
print(code_signed_ballot) | |
if __name__ == "__main__": | |
main() |
#!/usr/bin/env python3 | |
# invoke with argument 1 being a test file with the voting codes | |
# and stdin being the ballots | |
from itertools import product | |
import sys | |
from hmac_vote import candidates, create_code_signed_ballot | |
def construct_possible_ballots(voter_codes, candidates): | |
return { | |
create_code_signed_ballot(voter_code, candidate): | |
(voter_code, candidate) | |
for voter_code, candidate in product(voter_codes, candidates) | |
} # dict comprehension | |
def main(): | |
with open(sys.argv[1]) as f: | |
voter_codes = [line.strip() for line in f ] | |
possible_ballots = construct_possible_ballots(voter_codes, candidates) | |
vote_counts = { candidate: 0 | |
for candidate in candidates } # dict comprehension | |
spoiled = 0 | |
for line in sys.stdin: | |
line_newline_stripped = line.strip() | |
if line_newline_stripped in possible_ballots: | |
voter_code, candidate_voted_for = \ | |
possible_ballots[line_newline_stripped] | |
vote_counts[candidate_voted_for] += 1 | |
# remove all possible ballots for this voter_code | |
# to prevent voting twice | |
for candidate in candidates: | |
del possible_ballots[ create_code_signed_ballot( | |
voter_code, candidate) ] | |
else: | |
spoiled += 1 | |
results = [ (vote_count, candidate) | |
for candidate, vote_count in vote_counts.items() ] | |
print( '\n'.join( | |
"%d %s" % (vote_count, candidate) | |
for vote_count, candidate in results )) | |
print("%d spoiled" % spoiled) | |
if __name__ == "__main__": | |
main() |
#!/usr/bin/env python3 | |
# based on https://stackoverflow.com/a/4618361 | |
# but modified to use SystemRandom, sys.argv[1] and sys.argv[2], and with blocks | |
from random import SystemRandom | |
import sys | |
sysrandom = SystemRandom() | |
with open(sys.argv[1]) as f: | |
lines = f.readlines() | |
sysrandom.shuffle(lines) | |
with open(sys.argv[2], 'w') as f: | |
f.writelines(lines) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment