Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

added unused ballot auditing, fixed meeting4, and fixed contested bal…

…lot audit
  • Loading branch information...
commit e21b269a7beb5b7f5d4e60a6dbb4b2a1365328fe 1 parent c9aa495
Ben Adida authored
View
39 contested-ballot-verification.py
@@ -2,9 +2,11 @@
The contested ballot verification
Usage:
-python contested-ballot-verification.py <DATA_PATH>
+python contested-ballot-verification.py <DATA_PATH> [<CODES_FILE_PATH>]
data path should NOT have a trailing slash
+
+The codes_file_path is where the contested codes should be written
"""
# core imports
@@ -12,7 +14,15 @@
import base, data, filenames
# based on meeting2, and meeting3 for the ballots which aren't needed for parsing until then, nothing in meeting4 needed
-import meeting1, meeting2, meeting3
+import meeting1, meeting2
+
+# use provisional ballots
+try:
+ import meeting3provisional as meeting3
+except:
+ filenames.reset()
+ import meeting3
+
election = meeting1.election
ballots, cast_ballots = meeting3.ballots, meeting3.ballots_with_codes
@@ -20,7 +30,14 @@
contested_ballots_reply_xml = base.file_in_dir(base.DATA_PATH, filenames.CONTESTED_BALLOTS_REPLY, 'Reply to Contested Ballots')
contested_ballots = data.parse_ballot_table(contested_ballots_reply_xml)
-def verify(output_stream):
+def verify(output_stream, codes_output_stream=None):
+
+ if codes_output_stream:
+ codes_output_stream.write('Serial #,P-table ID')
+ for q_id in sorted(contested_ballots.values()[0].questions.keys()):
+ codes_output_stream.write(",question %s"%q_id)
+ codes_output_stream.write("\n")
+
# for each contested ballot:
for contested_ballot in contested_ballots.values():
# is it a cast ballot?
@@ -29,6 +46,12 @@ def verify(output_stream):
# does it verify against the original ballots
assert ballots[contested_ballot.pid].verify_code_openings(contested_ballot, election.constant)
+ if codes_output_stream:
+ codes_output_stream.write('%s,%s' % (contested_ballot.webSerial, contested_ballot.pid))
+ for q_id in sorted(contested_ballot.questions.keys()):
+ codes_output_stream.write(',"%s"' % ",".join([q['code'] for q in contested_ballot.questions[q_id].values()]))
+ codes_output_stream.write("\n")
+
# go through the contested ballots
output_stream.write("""Election ID: %s
Contested Ballots Audit Successful
@@ -39,4 +62,12 @@ def verify(output_stream):
""" % (election.spec.id, len(contested_ballots.keys()), base.fingerprint_report()))
if __name__ == '__main__':
- verify(sys.stdout)
+ if len(sys.argv) > 2:
+ codes_output = open(sys.argv[2], "w")
+ else:
+ codes_output = None
+
+ verify(sys.stdout, codes_output)
+
+ if codes_output:
+ codes_output.close()
View
16 filenames.py
@@ -35,6 +35,16 @@ def go_provisional():
MEETING_THREE_IN = "MeetingThreeIn-Provisional-Manual.xml"
MEETING_THREE_OUT = "MeetingThreeOut-Provisional-Manual.xml"
MEETING_THREE_OUT_CODES = "MeetingThreeOutCodes-Provisional-Manual.xml"
+
+def reset():
+ # oh I feel dirty, but this is what happens when a new piece of the process is introduced without warning
+ global MEETING_THREE_IN
+ global MEETING_THREE_OUT
+ global MEETING_THREE_OUT_CODES
+
+ MEETING_THREE_IN = "MeetingThreeIn.xml"
+ MEETING_THREE_OUT = "MeetingThreeOut.xml"
+ MEETING_THREE_OUT_CODES = "MeetingThreeOutCodes.xml"
# fourth meeting
MEETING_FOUR_IN = "MeetingFourIn.xml"
@@ -46,4 +56,8 @@ def go_provisional():
# spoiled ballots
SPOILED_BALLOTS_CODES = "SpoiledBallotsCodes.xml"
-SPOILED_BALLOTS_MIXNET = "SpoiledBallotsMixnet.xml"
+SPOILED_BALLOTS_MIXNET = "SpoiledBallotsMixnet.xml"
+
+# unused ballots
+UNUSED_BALLOTS_CODES = "PrintAuditBallots.xml"
+UNUSED_BALLOTS_MIXNET = "PrintAuditMixnet.xml"
View
0  meeting3-provisional.py → meeting3provisional.py
File renamed without changes
View
16 meeting4.py
@@ -12,12 +12,15 @@
import base, data, filenames
# use the meeting1,2,3 data structures too
-import meeting1, meeting2, meeting3
+import meeting1, meeting2
+
+# use provisional ballots as well
+import meeting3provisional as meeting3
# fourth meeting
meeting_four_in_xml = base.file_in_dir(base.DATA_PATH, filenames.MEETING_FOUR_IN, 'Meeting Four In')
meeting_four_out_xml = base.file_in_dir(base.DATA_PATH, filenames.MEETING_FOUR_OUT, 'Meeting Four Out')
-meeting_four_random_data = base.file_in_dir(base.DATA_PATH, filenames.MEETING_FOUR_RANDOM_DATA, "Random Data for Meeting Four Challenges", xml=False)
+meeting_four_random_data = base.file_in_dir(base.DATA_PATH, filenames.MEETING_FOUR_RANDOM_DATA, "Random Data for Meeting Four Challenges", xml=False, correct_windows=True)
# from meeting1 and meeting 2
election, d_table_commitments, already_open_d_tables = meeting1.election, meeting1.partitions, meeting2.response_partitions
@@ -35,7 +38,7 @@
def verify(output_stream):
# verify that challenges are appropriately generated
- challenges_match_randomness = False
+ challenges_match_randomness = True
# we assume that one D table always opens on the same side
# we do a bit of an odd thing here to keep the partitions and d tables in order
@@ -76,12 +79,17 @@ def verify(output_stream):
for row in d_table_challenge.rows.values():
# does it match the randomness?
if row['side'] != expected_challenge_sides[p_id][instance_id]:
+ import pdb; pdb.set_trace()
challenges_match_randomness = False
# response row
response_row = d_table_response.rows[row['id']]
# partially decrypted choices, d3 out of d2,d3,d4, so index 1.
- d_choices = cast_ballot_partitions[p_id][instance_id].get_permutations_by_row_id(row['id'], partition_map_choices[p_id])[1]
+ try:
+ d_choices = cast_ballot_partitions[p_id][instance_id].get_permutations_by_row_id(row['id'], partition_map_choices[p_id])[1]
+ except:
+ import pdb; pdb.set_trace()
+ print "oy"
# check the appropriate side
if row['side'] == 'LEFT':
View
84 unused-ballots.py
@@ -0,0 +1,84 @@
+"""
+The unused ballot verification
+
+Usage:
+python unused-ballot-verification.py <DATA_PATH> [<CODES_FILE_PATH>]
+
+data path should NOT have a trailing slash
+
+CODES_FILE_PATH is the path to a file which, when provided, will be where
+this script writes its list of confirmation codes for each ballot.
+"""
+
+# core imports
+import sys
+import base, data, filenames
+
+# based on meeting2, and meeting3 for the ballots
+import meeting1, meeting2, meeting3
+election = meeting1.election
+ballots, cast_ballots = meeting3.ballots, meeting3.ballots_with_codes
+
+# unused ballots codes
+unused_ballots_codes_xml = base.file_in_dir(base.DATA_PATH, filenames.UNUSED_BALLOTS_CODES, 'Unused Ballots Codes')
+unused_ballots = data.parse_ballot_table(unused_ballots_codes_xml)
+
+# unused ballots mixnet
+unused_ballots_mixnet_xml = base.file_in_dir(base.DATA_PATH, filenames.UNUSED_BALLOTS_MIXNET, 'Unused Ballots Mixnet')
+unused_p_table, unused_partitions = data.parse_database(unused_ballots_mixnet_xml)
+
+def verify(output_stream, codes_output_stream=None):
+
+ if codes_output_stream:
+ BALLOTS = {}
+ def new_code(webSerial, pid, q_id, s_id, confirmation_code):
+ if not BALLOTS.has_key(webSerial):
+ BALLOTS[webSerial] = {'pid': pid, 'questions': {}}
+
+ if not BALLOTS[webSerial]['questions'].has_key(q_id):
+ BALLOTS[webSerial]['questions'][q_id] = []
+
+ BALLOTS[webSerial]['questions'][q_id].append(confirmation_code)
+ else:
+ new_code = None
+
+ # check codes
+ for unused_ballot in unused_ballots.values():
+ # does it verify against the original ballots
+ assert ballots[unused_ballot.pid].verify_code_openings(unused_ballot, election.constant, code_callback_func = new_code)
+
+ # we just verify that the D and P tables are opened properly
+ # same as meeting2, only without a specific challenge set
+ assert meeting2.verify_open_p_and_d_tables(election, meeting1.p_table, meeting1.partitions, unused_p_table, unused_partitions), "bad reveal of P and D tables"
+
+ # we write out the codes
+ if new_code:
+ codes_output_stream.write('Serial #,P-table ID')
+ for q_id in sorted(BALLOTS.values()[0]['questions'].keys()):
+ codes_output_stream.write(",question %s"%q_id)
+ codes_output_stream.write("\n")
+
+ for serial in sorted(BALLOTS.keys()):
+ codes_output_stream.write('%s,%s' % (serial, BALLOTS[serial]['pid']))
+ for q_id in sorted(BALLOTS[serial]['questions'].keys()):
+ codes_output_stream.write(',"%s"' % ",".join(BALLOTS[serial]['questions'][q_id]))
+ codes_output_stream.write("\n")
+
+ # go through the contested ballots
+ output_stream.write("""Election ID: %s
+Unused Ballots Audit Successful
+
+%s ballots opened successfully
+
+%s
+""" % (election.spec.id, len(unused_ballots.keys()), base.fingerprint_report()))
+
+if __name__ == '__main__':
+ if len(sys.argv) > 2:
+ codes_output = open(sys.argv[2], "w")
+ else:
+ codes_output = None
+ verify(sys.stdout, codes_output)
+
+ if codes_output:
+ codes_output.close()
Please sign in to comment.
Something went wrong with that request. Please try again.