Skip to content

Instantly share code, notes, and snippets.

@markjenkins
Last active August 5, 2020 04:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save markjenkins/297343b6eb487738da94ae0be2215ccd to your computer and use it in GitHub Desktop.
Save markjenkins/297343b6eb487738da94ae0be2215ccd to your computer and use it in GitHub Desktop.
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