def mix_phase_generate_obfuscation_values(self, row_index, col_index): assert row_index == 'a' election = self.election # generate obfuscation values used in each column # in practice, these could be generated by row 0 server # and sent securely to the others in the same column. for race in election.races: race_id = race.race_id j = col_index rand_name = self.sdb[race_id]['a'][j]['rand_name'] for k in election.k_list: fuzz_dict = dict() # fuzz_dict[i][pnn] for i in self.row_list: fuzz_dict[i] = dict() for v in election.p_list: share_list = sv.share(0, self.rows, self.threshold, rand_name, race.race_modulus) for row, i in enumerate(self.row_list): fuzz_dict[i][v] = share_list[row][1] for i in self.row_list: # note that fuzz_dict[i] is dict of size n self.sdb[race_id][i][j][k]['fuzz_dict'] = fuzz_dict[i] dict_update_to_share = dict() for race_id in election.race_ids: dict_update_to_share[race_id] = dict() for i in self.row_list: dict_update_to_share[race_id][i] = dict() j = col_index assert type(j)==int dict_update_to_share[race_id][i][j] = dict() for k in election.k_list: dict_update_to_share[race_id][i][j][k] = dict() dict_update_to_share[race_id][i][j][k]['fuzz_dict'] = self.sdb[race_id][i][j][k]['fuzz_dict'] return dict_update_to_share
def cast_vote(self, race): """ Cast random vote for this voter for this race in simulated election. Of course, in a real election, choices come from voter via tablet. """ election = self.election cvs = election.cast_votes race_id = race.race_id race_modulus = race.race_modulus rand_name = self.rand_name px = self.px # cast random vote (for this simulation, it's random) choice_str = race.random_choice() # returns a string choice_int = race.choice_str2int(choice_str) # convert to integer # ballot_id is random hex string of desired length ballot_id_len = election.ballot_id_len ballot_id = sv.bytes2hex(sv.get_random_from_source(rand_name)) ballot_id = ballot_id[:ballot_id_len] assert len(ballot_id) == election.ballot_id_len # secret-share choice n = election.server.rows t = election.server.threshold share_list = sv.share(choice_int, n, t, rand_name, race_modulus) # double-check that shares reconstruct to desired choice assert choice_int == sv.lagrange(share_list, n, t, race_modulus) # double-check that shares are have indices 1, 2, ..., n assert all([share_list[i][0] == i + 1 for i in range(n)]) # then strip off indices, since they are equal to row number + 1 share_list = [share[1] for share in share_list] # save ballots on election data structure for row, x in enumerate(share_list): (u, v) = sv.get_sv_pair(x, rand_name, race_modulus) ru = sv.bytes2base64(sv.get_random_from_source(rand_name)) rv = sv.bytes2base64(sv.get_random_from_source(rand_name)) cu = sv.com(u, ru) cv = sv.com(v, rv) i = election.server.row_list[row] vote = { "ballot_id": ballot_id, "x": x, "u": u, "v": v, "ru": ru, "rv": rv, "cu": cu, "cv": cv } cvs[race_id][px][i] = vote # compute voter receipt as hash of her ballot_id and commitments # note that voter gets a receipt for each race she votes in receipt_data = [ballot_id] d = dict() for i in election.server.row_list: cu = cvs[race_id][px][i]['cu'] cv = cvs[race_id][px][i]['cv'] d[i] = {'cu': cu, 'cv': cv} receipt_data.append(d) receipt_data_str = sv.dumps(receipt_data) receipt_hash = sv.bytes2base64(sv.secure_hash(receipt_data_str)) self.receipts[ballot_id] = {'race_id': race_id, 'hash': receipt_hash}
def mix(self): """ Mix votes. Information flows left to right. """ election = self.election # replicate input to become first-column x inputs for each race & pass for race_id in election.race_ids: for k in election.k_list: for i in self.row_list: x = self.sdb[race_id][i][0]['x'] # dict of n x's self.sdb[race_id][i][0][k]['x'] = x.copy() # generate permutations (and inverses) used in each column # in practice, these could be generated by row 0 server # and sent securely to the others in the same column. for race_id in election.race_ids: for j in range(self.cols): rand_name = self.sdb[race_id]['a'][j]['rand_name'] for k in election.k_list: pi = sv.random_permutation(election.p_list, rand_name) pi_inv = sv.inverse_permutation(pi) for i in self.row_list: self.sdb[race_id][i][j][k]['pi'] = pi self.sdb[race_id][i][j][k]['pi_inv'] = pi_inv # generate obfuscation values used in each column # in practice, these could be generated by row 0 server # and sent securely to the others in the same column. for race in election.races: race_id = race.race_id for j in range(self.cols): rand_name = self.sdb[race_id]['a'][j]['rand_name'] for k in election.k_list: fuzz_dict = dict() # fuzz_dict[i][pnn] for i in self.row_list: fuzz_dict[i] = dict() for v in election.p_list: share_list = sv.share(0, self.rows, self.threshold, rand_name, race.race_modulus) for row, i in enumerate(self.row_list): fuzz_dict[i][v] = share_list[row][1] for i in self.row_list: # note that fuzz_dict[i] is dict of size n self.sdb[race_id][i][j][k]['fuzz_dict'] = fuzz_dict[i] # process columns left-to-right, mixing as you go for race in self.election.races: race_id = race.race_id race_modulus = race.race_modulus for j in range(self.cols): for k in election.k_list: for i in self.row_list: # shuffle first pi = self.sdb[race_id][i][j][k]['pi'] # length n # note that pi is independent of i x = self.sdb[race_id][i][j][k]['x'] # length n xp = sv.apply_permutation(pi, x) # length n # then obfuscate by adding "fuzz" fuzz_dict = self.sdb[race_id][i][j][k]['fuzz_dict'] xpo = dict() for v in election.p_list: xpo[v] = (xp[v] + fuzz_dict[v]) % race_modulus y = xpo self.sdb[race_id][i][j][k]['y'] = y # this column's y's become next column's x's. # in practice would be sent via secure channels if j < self.cols - 1: self.sdb[race_id][i][j+1][k]['x'] = y
def mix(self): """ Mix votes. Information flows left to right. """ election = self.election # replicate input to become first-column x inputs for each race & pass for race_id in election.race_ids: for k in election.k_list: for i in self.row_list: x = self.sdb[race_id][i][0]['x'] # dict of n x's self.sdb[race_id][i][0][k]['x'] = x.copy() # generate permutations (and inverses) used in each column # in practice, these could be generated by row 0 server # and sent securely to the others in the same column. for race_id in election.race_ids: for j in range(self.cols): rand_name = self.sdb[race_id]['a'][j]['rand_name'] for k in election.k_list: pi = sv.random_permutation(election.p_list, rand_name) pi_inv = sv.inverse_permutation(pi) for i in self.row_list: self.sdb[race_id][i][j][k]['pi'] = pi self.sdb[race_id][i][j][k]['pi_inv'] = pi_inv # generate obfuscation values used in each column # in practice, these could be generated by row 0 server # and sent securely to the others in the same column. for race in election.races: race_id = race.race_id for j in range(self.cols): rand_name = self.sdb[race_id]['a'][j]['rand_name'] for k in election.k_list: fuzz_dict = dict() # fuzz_dict[i][pnn] for i in self.row_list: fuzz_dict[i] = dict() for v in election.p_list: share_list = sv.share(0, self.rows, self.threshold, rand_name, race.race_modulus) for row, i in enumerate(self.row_list): fuzz_dict[i][v] = share_list[row][1] for i in self.row_list: # note that fuzz_dict[i] is dict of size n self.sdb[race_id][i][j][k]['fuzz_dict'] = fuzz_dict[i] # process columns left-to-right, mixing as you go for race in self.election.races: race_id = race.race_id race_modulus = race.race_modulus for j in range(self.cols): for k in election.k_list: for i in self.row_list: # shuffle first pi = self.sdb[race_id][i][j][k]['pi'] # length n # note that pi is independent of i x = self.sdb[race_id][i][j][k]['x'] # length n xp = sv.apply_permutation(pi, x) # length n # then obfuscate by adding "fuzz" fuzz_dict = self.sdb[race_id][i][j][k]['fuzz_dict'] xpo = dict() for v in election.p_list: xpo[v] = (xp[v] + fuzz_dict[v]) % race_modulus y = xpo self.sdb[race_id][i][j][k]['y'] = y # this column's y's become next column's x's. # in practice would be sent via secure channels if j < self.cols - 1: self.sdb[race_id][i][j + 1][k]['x'] = y