Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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

…lot audit
  • Loading branch information...
commit e21b269a7beb5b7f5d4e60a6dbb4b2a1365328fe 1 parent c9aa495
authored
39  contested-ballot-verification.py
@@ -2,9 +2,11 @@
2 2
 The contested ballot verification
3 3
 
4 4
 Usage:
5  
-python contested-ballot-verification.py <DATA_PATH>
  5
+python contested-ballot-verification.py <DATA_PATH> [<CODES_FILE_PATH>]
6 6
 
7 7
 data path should NOT have a trailing slash
  8
+
  9
+The codes_file_path is where the contested codes should be written
8 10
 """
9 11
 
10 12
 # core imports
@@ -12,7 +14,15 @@
12 14
 import base, data, filenames
13 15
 
14 16
 # based on meeting2, and meeting3 for the ballots which aren't needed for parsing until then, nothing in meeting4 needed
15  
-import meeting1, meeting2, meeting3
  17
+import meeting1, meeting2
  18
+
  19
+# use provisional ballots
  20
+try:
  21
+  import meeting3provisional as meeting3
  22
+except:
  23
+  filenames.reset()
  24
+  import meeting3
  25
+
16 26
 election = meeting1.election
17 27
 ballots, cast_ballots = meeting3.ballots, meeting3.ballots_with_codes
18 28
 
@@ -20,7 +30,14 @@
20 30
 contested_ballots_reply_xml = base.file_in_dir(base.DATA_PATH, filenames.CONTESTED_BALLOTS_REPLY, 'Reply to Contested Ballots')
21 31
 contested_ballots = data.parse_ballot_table(contested_ballots_reply_xml)
22 32
 
23  
-def verify(output_stream):
  33
+def verify(output_stream, codes_output_stream=None):
  34
+  
  35
+  if codes_output_stream:
  36
+    codes_output_stream.write('Serial #,P-table ID')
  37
+    for q_id in sorted(contested_ballots.values()[0].questions.keys()):
  38
+      codes_output_stream.write(",question %s"%q_id)
  39
+    codes_output_stream.write("\n")    
  40
+
24 41
   # for each contested ballot:
25 42
   for contested_ballot in contested_ballots.values():
26 43
     # is it a cast ballot?
@@ -29,6 +46,12 @@ def verify(output_stream):
29 46
     # does it verify against the original ballots
30 47
     assert ballots[contested_ballot.pid].verify_code_openings(contested_ballot, election.constant)
31 48
     
  49
+    if codes_output_stream:
  50
+      codes_output_stream.write('%s,%s' % (contested_ballot.webSerial, contested_ballot.pid))
  51
+      for q_id in sorted(contested_ballot.questions.keys()):
  52
+        codes_output_stream.write(',"%s"' % ",".join([q['code'] for q in contested_ballot.questions[q_id].values()]))
  53
+      codes_output_stream.write("\n")
  54
+    
32 55
   # go through the contested ballots
33 56
   output_stream.write("""Election ID: %s
34 57
 Contested Ballots Audit Successful
@@ -39,4 +62,12 @@ def verify(output_stream):
39 62
 """ % (election.spec.id, len(contested_ballots.keys()), base.fingerprint_report()))
40 63
 
41 64
 if __name__ == '__main__':
42  
-  verify(sys.stdout)
  65
+  if len(sys.argv) > 2:
  66
+    codes_output = open(sys.argv[2], "w")
  67
+  else:
  68
+    codes_output = None
  69
+    
  70
+  verify(sys.stdout, codes_output)
  71
+  
  72
+  if codes_output:
  73
+    codes_output.close()
16  filenames.py
@@ -35,6 +35,16 @@ def go_provisional():
35 35
   MEETING_THREE_IN = "MeetingThreeIn-Provisional-Manual.xml"
36 36
   MEETING_THREE_OUT = "MeetingThreeOut-Provisional-Manual.xml"
37 37
   MEETING_THREE_OUT_CODES = "MeetingThreeOutCodes-Provisional-Manual.xml"
  38
+  
  39
+def reset():
  40
+  # oh I feel dirty, but this is what happens when a new piece of the process is introduced without warning
  41
+  global MEETING_THREE_IN
  42
+  global MEETING_THREE_OUT
  43
+  global MEETING_THREE_OUT_CODES
  44
+
  45
+  MEETING_THREE_IN = "MeetingThreeIn.xml"
  46
+  MEETING_THREE_OUT = "MeetingThreeOut.xml"
  47
+  MEETING_THREE_OUT_CODES = "MeetingThreeOutCodes.xml"
38 48
 
39 49
 # fourth meeting
40 50
 MEETING_FOUR_IN = "MeetingFourIn.xml"
@@ -46,4 +56,8 @@ def go_provisional():
46 56
 
47 57
 # spoiled ballots
48 58
 SPOILED_BALLOTS_CODES = "SpoiledBallotsCodes.xml"
49  
-SPOILED_BALLOTS_MIXNET = "SpoiledBallotsMixnet.xml"
  59
+SPOILED_BALLOTS_MIXNET = "SpoiledBallotsMixnet.xml"
  60
+
  61
+# unused ballots
  62
+UNUSED_BALLOTS_CODES = "PrintAuditBallots.xml"
  63
+UNUSED_BALLOTS_MIXNET = "PrintAuditMixnet.xml"
0  meeting3-provisional.py → meeting3provisional.py
File renamed without changes
16  meeting4.py
@@ -12,12 +12,15 @@
12 12
 import base, data, filenames
13 13
 
14 14
 # use the meeting1,2,3 data structures too
15  
-import meeting1, meeting2, meeting3
  15
+import meeting1, meeting2
  16
+
  17
+# use provisional ballots as well
  18
+import meeting3provisional as meeting3
16 19
 
17 20
 # fourth meeting
18 21
 meeting_four_in_xml = base.file_in_dir(base.DATA_PATH, filenames.MEETING_FOUR_IN, 'Meeting Four In')
19 22
 meeting_four_out_xml = base.file_in_dir(base.DATA_PATH, filenames.MEETING_FOUR_OUT, 'Meeting Four Out')
20  
-meeting_four_random_data = base.file_in_dir(base.DATA_PATH, filenames.MEETING_FOUR_RANDOM_DATA, "Random Data for Meeting Four Challenges", xml=False)
  23
+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)
21 24
 
22 25
 # from meeting1 and meeting 2
23 26
 election, d_table_commitments, already_open_d_tables = meeting1.election, meeting1.partitions, meeting2.response_partitions
@@ -35,7 +38,7 @@
35 38
 
36 39
 def verify(output_stream):
37 40
   # verify that challenges are appropriately generated
38  
-  challenges_match_randomness = False
  41
+  challenges_match_randomness = True
39 42
   
40 43
   # we assume that one D table always opens on the same side
41 44
   # 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):
76 79
       for row in d_table_challenge.rows.values():
77 80
         # does it match the randomness?
78 81
         if row['side'] != expected_challenge_sides[p_id][instance_id]:
  82
+          import pdb; pdb.set_trace()
79 83
           challenges_match_randomness = False
80 84
 
81 85
         # response row
82 86
         response_row = d_table_response.rows[row['id']]
83 87
         # partially decrypted choices, d3 out of d2,d3,d4, so index 1.
84  
-        d_choices = cast_ballot_partitions[p_id][instance_id].get_permutations_by_row_id(row['id'], partition_map_choices[p_id])[1]
  88
+        try:
  89
+          d_choices = cast_ballot_partitions[p_id][instance_id].get_permutations_by_row_id(row['id'], partition_map_choices[p_id])[1]
  90
+        except:
  91
+          import pdb; pdb.set_trace()
  92
+          print "oy"
85 93
 
86 94
         # check the appropriate side  
87 95
         if row['side'] == 'LEFT':
84  unused-ballots.py
... ...
@@ -0,0 +1,84 @@
  1
+"""
  2
+The unused ballot verification
  3
+
  4
+Usage:
  5
+python unused-ballot-verification.py <DATA_PATH> [<CODES_FILE_PATH>]
  6
+
  7
+data path should NOT have a trailing slash
  8
+
  9
+CODES_FILE_PATH is the path to a file which, when provided, will be where
  10
+this script writes its list of confirmation codes for each ballot.
  11
+"""
  12
+
  13
+# core imports
  14
+import sys
  15
+import base, data, filenames
  16
+
  17
+# based on meeting2, and meeting3 for the ballots
  18
+import meeting1, meeting2, meeting3
  19
+election = meeting1.election
  20
+ballots, cast_ballots = meeting3.ballots, meeting3.ballots_with_codes
  21
+
  22
+# unused ballots codes
  23
+unused_ballots_codes_xml = base.file_in_dir(base.DATA_PATH, filenames.UNUSED_BALLOTS_CODES, 'Unused Ballots Codes')
  24
+unused_ballots = data.parse_ballot_table(unused_ballots_codes_xml)
  25
+
  26
+# unused ballots mixnet
  27
+unused_ballots_mixnet_xml = base.file_in_dir(base.DATA_PATH, filenames.UNUSED_BALLOTS_MIXNET, 'Unused Ballots Mixnet')
  28
+unused_p_table, unused_partitions = data.parse_database(unused_ballots_mixnet_xml)
  29
+
  30
+def verify(output_stream, codes_output_stream=None):
  31
+
  32
+  if codes_output_stream:
  33
+    BALLOTS = {}
  34
+    def new_code(webSerial, pid, q_id, s_id, confirmation_code):
  35
+      if not BALLOTS.has_key(webSerial):
  36
+        BALLOTS[webSerial] = {'pid': pid, 'questions': {}}
  37
+        
  38
+      if not BALLOTS[webSerial]['questions'].has_key(q_id):
  39
+        BALLOTS[webSerial]['questions'][q_id] = []
  40
+      
  41
+      BALLOTS[webSerial]['questions'][q_id].append(confirmation_code)
  42
+  else:
  43
+    new_code = None
  44
+
  45
+  # check codes
  46
+  for unused_ballot in unused_ballots.values():
  47
+    # does it verify against the original ballots
  48
+    assert ballots[unused_ballot.pid].verify_code_openings(unused_ballot, election.constant, code_callback_func = new_code)
  49
+  
  50
+  # we just verify that the D and P tables are opened properly
  51
+  # same as meeting2, only without a specific challenge set
  52
+  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"
  53
+
  54
+  # we write out the codes
  55
+  if new_code:
  56
+    codes_output_stream.write('Serial #,P-table ID')
  57
+    for q_id in sorted(BALLOTS.values()[0]['questions'].keys()):
  58
+      codes_output_stream.write(",question %s"%q_id)
  59
+    codes_output_stream.write("\n")
  60
+    
  61
+    for serial in sorted(BALLOTS.keys()):
  62
+      codes_output_stream.write('%s,%s' % (serial, BALLOTS[serial]['pid']))
  63
+      for q_id in sorted(BALLOTS[serial]['questions'].keys()):
  64
+        codes_output_stream.write(',"%s"' % ",".join(BALLOTS[serial]['questions'][q_id]))
  65
+      codes_output_stream.write("\n")
  66
+
  67
+  # go through the contested ballots
  68
+  output_stream.write("""Election ID: %s
  69
+Unused Ballots Audit Successful
  70
+
  71
+%s ballots opened successfully
  72
+
  73
+%s
  74
+""" % (election.spec.id, len(unused_ballots.keys()), base.fingerprint_report()))
  75
+
  76
+if __name__ == '__main__':
  77
+  if len(sys.argv) > 2:
  78
+    codes_output = open(sys.argv[2], "w")
  79
+  else:
  80
+    codes_output = None
  81
+  verify(sys.stdout, codes_output)
  82
+  
  83
+  if codes_output:
  84
+    codes_output.close()

0 notes on commit e21b269

Please sign in to comment.
Something went wrong with that request. Please try again.