forked from benadida/scantegrity-audit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
meeting4.py
134 lines (99 loc) · 5.25 KB
/
meeting4.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
"""
The meeting four verification
Usage:
python meeting4.py <DATA_PATH>
data path should NOT have a trailing slash
"""
# core imports
import sys
import base
import data
import filenames
# use the meeting1,2,3 data structures too
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, correct_windows=False)
# from meeting1 and meeting 2
election, d_table_commitments, already_open_d_tables = meeting1.election, meeting1.partitions, meeting2.response_partitions
p_table_votes = meeting3.p_table_votes
# from meeting3, the D tables with intermediate decrypted votes
cast_ballot_partitions = data.parse_d_tables(meeting3.meeting_three_out_xml)
# challenge and response to those rows
d_table_challenges = data.parse_d_tables(meeting_four_in_xml)
d_table_responses = data.parse_d_tables(meeting_four_out_xml)
# r tables
r_tables_by_partition = data.parse_r_tables(meeting3.meeting_three_out_xml)
def verify(output_stream):
# verify that challenges are appropriately generated
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
# because that's how counter is decided
counter = 0
# a dictionary of partition_ids, with values a dictionary of d_table ID
expected_challenge_sides = {}
seed = meeting_four_random_data + election.constant
for p_id in sorted(cast_ballot_partitions.keys()):
partition = cast_ballot_partitions[p_id]
expected_challenge_sides[p_id] = {}
# get the D tables ordered by their integer ID
for d_table in data.sort_by_id(partition.values()):
instance_id = d_table.id
# which side is this d table opened on?
expected_challenge_sides[p_id][instance_id] = ("LEFT","RIGHT")[base.prng(seed,counter,2)]
counter += 1
partition_map = election.partition_map
partition_map_choices = election.partition_map_choices
# go through the challenges and verify the corresponding commitments
for p_id, partition in d_table_challenges.iteritems():
for instance_id, d_table_challenge in partition.iteritems():
d_table = d_table_commitments[p_id][instance_id]
d_table_response = d_table_responses[p_id][instance_id]
# check that the open rows now are disjoint from the open rows before
assert set(d_table_challenge.rows.keys()).isdisjoint(set(already_open_d_tables[p_id][instance_id].rows.keys())), 'some challenges repeat the challenges from meeting2'
# check opening of the new challenges
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.
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':
# check proper reveal
assert d_table.check_cl(p_id, instance_id, response_row, election.constant)
d_left_perm = [data.Permutation(p) for p in d_table_response.get_permutations_by_row_id(row['id'], partition_map[p_id])[0]]
# get the corresponding P3 permutation (index 2, then partition)
p_choices = p_table_votes.get_permutations_by_row_id(response_row['pid'], partition_map_choices)[2][p_id]
for q_num, p_choice in enumerate(p_choices):
assert d_left_perm[q_num].permute_list(p_choice) == d_choices[q_num]
else:
# check reveal
assert d_table.check_cr(p_id, instance_id, response_row, election.constant)
# check right-hand permutation
d_right_perm = [data.Permutation(p) for p in d_table_response.get_permutations_by_row_id(row['id'], partition_map[p_id])[2]]
# get the corresponding R-table permutation (partition, then index 0)
r_choices = r_tables_by_partition[p_id].get_permutations_by_row_id(response_row['rid'], partition_map_choices[p_id])[0]
for q_num, r_choice in enumerate(r_choices):
assert d_right_perm[q_num].permute_list(d_choices[q_num]) == r_choice
output_stream.write("""Election ID: %s
Meeting 4 Successful
Challenges Match Randomness? %s
%s
""" % (election.spec.id, challenges_match_randomness, base.fingerprint_report()))
if __name__ == "__main__":
if len(sys.argv) > 2:
# Note that the path provided as the second argument must be relative to the data directory, not absolute
filenames.set_meeting_four_random_data(sys.argv[2])
verify(sys.stdout)