def distribute_votes(self): """ Distribute cast votes among MixServers """ for race_id in self.election.race_ids: for px in self.election.p_list: for i in self.election.server.row_list: vote = self.election.cast_votes[race_id][px][i] # save these values in our server data structures # in a non-simulated real election, this would be done # by communicating securely from voter (or tablet) to the # first column of servers. sdbp = self.election.server.sdb[race_id][i][0] sdbp['ballot_id'][px] = vote['ballot_id'] sdbp['x'][px] = vote['x'] sdbp['u'][px] = vote['u'] sdbp['v'][px] = vote['v'] sdbp['ru'][px] = vote['ru'] sdbp['rv'][px] = vote['rv'] sdbp['cu'][px] = vote['cu'] sdbp['cv'][px] = vote['cv'] # distribute votes to mix servers for race_id in self.election.race_ids: for i in self.election.server.row_list: sdbp = self.election.server.sdb[race_id][i][0] for s in self.servers_alive[SC.ROLE_MIX]: response = json_client(ip=s[0], port=s[1], title=SC.MESSAGE_SPLIT_VALUE_VOTES, body=(race_id, i, sdbp), origin=(self.server_address[0], self.server_address[1]), auth="")
def ask_sbb_to_post(self, msg_header, msg_dict=None, time_stamp=True): for s in self.servers_alive[SC.ROLE_SBB]: response = json_client(ip=s[0], port=s[1], title=SC.MESSAGE_POST_TO_SBB, body=(msg_header, msg_dict, time_stamp), origin=(self.server_address[0], self.server_address[1]), auth="")
def ask_sbb_hash(self, public=True): for s in self.servers_alive[SC.ROLE_SBB]: response = json_client(ip=s[0], port=s[1], title=SC.MESSAGE_HASH_SBB, body=public, origin=(self.server_address[0], self.server_address[1]), auth="") return response[SC.MSG_BODY]
Output: Done""" self.server.sbb.close() response = self.get_incomplete_response(request_data[SC.MSG_TITLE]) response[SC.MSG_BODY] = "Done" return response def handle_verify_sbb(self, request_data): """ServerX -> SBB[Verify SBB] Input: Request to verify SBB, sbb_filename Action: Verify SBB Output: Done""" import sv_verifier sbb_filename = request_data[SC.MSG_BODY] sv_verifier.verify(sbb_filename) response = self.get_incomplete_response(request_data[SC.MSG_TITLE]) response[SC.MSG_BODY] = "Done" return response if __name__ == "__main__": response = json_client(ip = SC.CONTROLLER_HOST, port = SC.CONTROLLER_PORT, title = SC.MESSAGE_PING_CONTROLLER_1, body = "" , origin = "", auth = "") ip, port = response[SC.MSG_BODY] # Create the server, binding to the same ip address server, server_addr = getTCPSocketServer(Handler = GenericHandler, addr = (ip, port)) # Let Controller know to which address server is listening to response = json_client(ip = SC.CONTROLLER_HOST, port = SC.CONTROLLER_PORT, title = SC.MESSAGE_PING_CONTROLLER_2, body = SC.ROLE_SBB, origin = server_addr, auth = "") # Activate the server; this will keep running until you # interrupt the program with Ctrl-C server_thread = threading.Thread(target=server.serve_forever, daemon = True) #daemon threads allow us to finish the program execution, even though some threads may be running server_thread.start() stop = input("Stop?")
def handle_mix(self, request_data): """ Controller -> Mix [Mix Votes] Input: Request to Mix, phase Action: Mix Votes Output: Done """ response = self.get_incomplete_response(request_data[SC.MSG_TITLE]) phase = request_data[SC.MSG_BODY] role_index = self.server.role_index row_index = self.server.election.server.get_server_row_index( role_index) col_index = self.server.election.server.get_server_col_index( role_index) num_columns = self.server.election.server.cols if phase == 0: # self.server.election.server.mix() response[SC.MSG_BODY] = "phase " + str( phase) + " completed for role_index " + str(role_index) elif phase == 1: if col_index == 0: # only first column has input to be replicated self.server.election.server.mix_phase_replicate_input( row_index, col_index) response[SC.MSG_BODY] = "phase " + str( phase) + " completed for role_index " + str(role_index) elif phase == 2: if row_index == 'a': # only first row is enough and info is propagated each column dict_update_to_share = self.server.election.server.mix_phase_generate_permutations( row_index, col_index) target_servers = [ ] # propagating updates to serves in the same column for target_row in self.server.election.server.row_list: if target_row == row_index: continue target_role_idx = self.server.election.server.get_server_index( target_row, col_index) target_servers.append(self.server.servers_alive[ SC.ROLE_MIX][target_role_idx]) for s in target_servers: response = json_client( ip=s[0], port=s[1], title=SC.MESSAGE_UPDATE_SDB_DATABASE, body=dict_update_to_share, origin=(self.server.server_address[0], self.server.server_address[1]), auth="") response[SC.MSG_BODY] = "phase " + str( phase) + " completed for role_index " + str(role_index) elif phase == 3: if row_index == 'a': # only first row is enough and info is propagated each column dict_update_to_share = self.server.election.server.mix_phase_generate_obfuscation_values( row_index, col_index) target_servers = [ ] # propagating updates to serves in the same column for target_row in self.server.election.server.row_list: if target_row == row_index: continue target_role_idx = self.server.election.server.get_server_index( target_row, col_index) target_servers.append(self.server.servers_alive[ SC.ROLE_MIX][target_role_idx]) for s in target_servers: response = json_client( ip=s[0], port=s[1], title=SC.MESSAGE_UPDATE_SDB_DATABASE, body=dict_update_to_share, origin=(self.server.server_address[0], self.server.server_address[1]), auth="") response[SC.MSG_BODY] = "phase " + str( phase) + " completed for role_index " + str(role_index) elif phase > 3 and phase <= 3 + num_columns: # get it on (i,j) forward it to (i,j+1), first process all 1st column, when ready, all 2nd column if col_index == phase - 4 and col_index != num_columns - 1: # one column at a time, data is propagated left-to-right dict_update_to_share = self.server.election.server.mix_phase_process_left_to_right( row_index, col_index) target_role_idx = self.server.election.server.get_server_index( row_index, col_index + 1) s = self.server.servers_alive[SC.ROLE_MIX][target_role_idx] response = json_client(ip=s[0], port=s[1], title=SC.MESSAGE_UPDATE_SDB_DATABASE, body=dict_update_to_share, origin=(self.server.server_address[0], self.server.server_address[1]), auth="") elif col_index == phase - 4 and col_index == num_columns - 1: # one column at a time, data is propagated left-to-right dict_update_to_share = self.server.election.server.mix_phase_process_left_to_right( row_index, col_index) target_servers = [] for target_row in self.server.election.server.row_list: if target_row == row_index: continue target_role_idx = self.server.election.server.get_server_index( target_row, col_index) target_servers.append(self.server.servers_alive[ SC.ROLE_MIX][target_role_idx]) for s in target_servers: # TODO this should happen only for k in opl -> move this to tally phase response = json_client( ip=s[0], port=s[1], title=SC.MESSAGE_UPDATE_SDB_DATABASE, body=dict_update_to_share, origin=(self.server.server_address[0], self.server.server_address[1]), auth="") response[SC.MSG_BODY] = "phase " + str( phase) + " completed for role_index " + str(role_index) else: response[SC.MSG_BODY] = "Done" # self.server.election.server.test_mix() -> TODO is this the correct test? Ron was not running it print("Mixing", response[SC.MSG_BODY]) return response
def handle_prove(self, request_data): """ Controller -> Mix [Prove] Input: Request proofs, phase Action: Make Proofs, post to SBB Output: Done """ response = self.get_incomplete_response(request_data[SC.MSG_TITLE]) phase = request_data[SC.MSG_BODY] role_index = self.server.role_index row_index = self.server.election.server.get_server_row_index( role_index) col_index = self.server.election.server.get_server_col_index( role_index) cols = self.server.election.server.cols election = self.server.election # Prove! if phase == 0: msg_header, msg_dict = sv_prover.compute_output_commitments( election, row_index, col_index) if col_index == cols - 1: self.server.ask_sbb_to_post(msg_header, msg_dict, time_stamp=False) response[SC.MSG_BODY] = "phase " + str( phase) + " completed for role_index " + str(role_index) elif phase == 1: # as of now, this phase cannot be done simultaneously by multiple servers, because of modifications on sbb sbb_hash_hex = self.server.ask_sbb_hash(public=True) sbb_hash = sv.hex2bytes(sbb_hash_hex) msg_header, msg_dict = sv_prover.make_cut_verifier_challenges( election, sbb_hash) if role_index == cols * self.server.election.server.rows - 1: # last server so that other sbb_hash not affected self.server.ask_sbb_to_post(msg_header, msg_dict, time_stamp=False) response[SC.MSG_BODY] = "phase " + str( phase) + " completed for role_index " + str(role_index) elif phase == 2: dict_update_to_share = sv_prover.share_icl_pik_dict( election, election.server.challenges, row_index, col_index) for s in self.server.servers_alive[SC.ROLE_MIX]: if s[0] == self.server.server_address[0] and s[ 1] == self.server.server_address[1]: continue # skips itself response = json_client(ip=s[0], port=s[1], title=SC.MESSAGE_UPDATE_SDB_DATABASE, body=dict_update_to_share, origin=(self.server.server_address[0], self.server.server_address[1]), auth="") response[SC.MSG_BODY] = "phase " + str( phase) + " completed for role_index " + str(role_index) elif phase == 3: msg_header, msg_dict = sv_prover.compute_and_post_pik_dict( election, election.server.challenges, row_index, col_index) if role_index == 0: self.server.ask_sbb_to_post(msg_header, msg_dict, time_stamp=False) response[SC.MSG_BODY] = "phase " + str( phase) + " completed for role_index " + str(role_index) elif phase == 4: if col_index == 0: dict_update_to_share = sv_prover.share_icl_ux_uy_dict( election, election.server.challenges, row_index, col_index) target_role_idx = self.server.election.server.get_server_index( row_index, cols - 1) s = self.server.servers_alive[SC.ROLE_MIX][ target_role_idx] # sensitive information only share it with server in same row, last column response = json_client(ip=s[0], port=s[1], title=SC.MESSAGE_UPDATE_SDB_DATABASE, body=dict_update_to_share, origin=(self.server.server_address[0], self.server.server_address[1]), auth="") response[SC.MSG_BODY] = "phase " + str( phase) + " completed for role_index " + str(role_index) elif phase == 5: if col_index == cols - 1: msg_header, msg_dict = sv_prover.compute_and_post_t_values( election, election.server.challenges, row_index, col_index) self.server.ask_sbb_to_post(msg_header, msg_dict, time_stamp=False) response[SC.MSG_BODY] = "phase " + str( phase) + " completed for role_index " + str(role_index) elif phase == 6: # as of now, this phase cannot be done simultaneously by multiple servers, because of modifications on sbb sbb_hash_hex = self.server.ask_sbb_hash(public=True) sbb_hash = sv.hex2bytes(sbb_hash_hex) msg_header, msg_dict = sv_prover.make_leftright_verifier_challenges( election, sbb_hash) if role_index == cols * self.server.election.server.rows - 1: # last server so that other sbb_hash not affected self.server.ask_sbb_to_post(msg_header, msg_dict, time_stamp=False) response[SC.MSG_BODY] = "phase " + str( phase) + " completed for role_index " + str(role_index) elif phase == 7: if col_index == cols - 1: msg_header, msg_dict = sv_prover.prove_outcome_correct( election, election.server.challenges, row_index, col_index) self.server.ask_sbb_to_post(msg_header, msg_dict, time_stamp=False) response[SC.MSG_BODY] = "phase " + str( phase) + " completed for role_index " + str(role_index) elif phase == 8: if col_index == 0: msg_header, msg_dict = sv_prover.prove_input_consistent_input_openings( election, election.server.challenges, row_index, col_index) self.server.ask_sbb_to_post(msg_header, msg_dict, time_stamp=False) response[SC.MSG_BODY] = "phase " + str( phase) + " completed for role_index " + str(role_index) elif phase == 9: if col_index == cols - 1: msg_header, msg_dict = sv_prover.prove_input_consistent_output_openings( election, election.server.challenges, row_index, col_index) self.server.ask_sbb_to_post(msg_header, msg_dict, time_stamp=False) response[SC.MSG_BODY] = "phase " + str( phase) + " completed for role_index " + str(role_index) else: response[SC.MSG_BODY] = "Done" print("Proof", response[SC.MSG_BODY]) return response