def read_cut_verifier_challenges(sbb_dict, sbb, db): """ Read verifier challenges from proof:cutandchoose_verifier_challenges; save into db. """ chs = sbb_dict['proof:cutandchoose_verifier_challenges']['challenges'] assert isdict(chs, ['cut']) assert isdict(chs['cut'], ['icl', 'opl']) icl = chs['cut']['icl'] assert isinstance(icl, list) assert len(icl) == db['n_reps'] // 2 assert set(icl).issubset(db['k_list']) opl = chs['cut']['opl'] assert isinstance(opl, list) assert len(opl) == db['n_reps'] // 2 assert set(opl).issubset(db['k_list']) assert set(icl).isdisjoint(set(opl)) db['icl'] = icl db['opl'] = opl # now check that icl and opl are consistent with sbb_hash # see make_cut_verifier_challenges in sv_prover.py rand_name = 'cut_verifier_challenges' sbb_hash = sbb_dict['proof:cutandchoose_verifier_challenges']['sbb_hash'] stop_before_header = 'proof:cutandchoose_verifier_challenges' sbb_hash2 = sv.bytes2hex(hash_sbb(sbb, stop_before_header)) assert sbb_hash2 == sbb_hash, "sbb_hash2: " + str( sbb_hash2) + "sbb_hash: " + str(sbb_hash) sv.init_randomness_source(rand_name, sv.hex2bytes(sbb_hash)) pi = sv.random_permutation(db['n_reps'], rand_name) m = db['n_reps'] // 2 pi = [pi[i] for i in range(2 * m)] icl2 = [db['k_list'][i] for i in sorted(pi[:m])] opl2 = [db['k_list'][i] for i in sorted(pi[m:])] assert icl2 == icl assert opl2 == opl print('read_cut_verifier_challenges: successful.')
def mix_phase_generate_permutations(self, row_index, col_index): assert row_index == 'a' election = self.election # 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: j = col_index rand_name = self.sdb[race_id]['a'][j]['rand_name'] sv.init_randomness_source(rand_name) # optional - TODO remove after transition to unshared memory only 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 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]['pi'] = self.sdb[race_id][i][j][k]['pi'] dict_update_to_share[race_id][i][j][k]['pi_inv'] = self.sdb[race_id][i][j][k]['pi_inv'] return dict_update_to_share
def read_leftright_verifier_challenges(sbb_dict, sbb, db): """ Read verifier challenges from proof:leftright_verifier_challenges; save into db. """ chs = sbb_dict['proof:leftright_verifier_challenges']['challenges'] assert isdict(chs, ['leftright']) leftright = chs['leftright'] assert isdict(leftright, db['race_ids']) for race_id in leftright.keys(): lr_dict = leftright[race_id] assert set(lr_dict.keys()) == set(db['p_list']) for p in db['p_list']: lr = lr_dict[p] assert lr == 'left' or lr == 'right' db['leftright'] = leftright # now check that icl, opl, and leftright are consistent with sbb_hash # see make_verifier_challenges in sv_prover.py rand_name = 'leftright_verifier_challenges' sbb_hash = sbb_dict['proof:leftright_verifier_challenges']['sbb_hash'] stop_before_header = 'proof:leftright_verifier_challenges' sbb_hash2 = sv.bytes2hex(hash_sbb(sbb, stop_before_header)) assert sbb_hash2 == sbb_hash, "sbb_hash2: " + str( sbb_hash2) + "sbb_hash: " + str(sbb_hash) sv.init_randomness_source(rand_name, sv.hex2bytes(sbb_hash)) leftright2 = make_left_right_challenges(rand_name, db) assert leftright2 == leftright print('read_leftright_verifier_challenges: successful.')
def __init__(self, election, voter_id, px): """ Initialize voter object for this election. Here voter_id is a string identifying the voter, and px is a "position identifier": 'p0', 'p1', ... """ self.election = election assert isinstance(voter_id, str) self.voter_id = voter_id self.px = px # randomness source per voter self.rand_name = "voter:"+voter_id sv.init_randomness_source(self.rand_name) self.receipts = dict() # maps ballot_id to hash value of receipt
def make_cut_verifier_challenges(election, sbb_hash): """ Return a dict containing "verifier challenges" for this proof. This is based on randomness (hash of sbb, fiat-shamir style), but could also incorporate additional random input (e.g. dice rolls). """ election.sbb_hash = sbb_hash rand_name = "cut_verifier_challenges" sv.init_randomness_source(rand_name, sbb_hash) challenges = dict() make_cut_and_choose_challenges(election, rand_name, challenges) sv.update_nested_dict(election.server.challenges, challenges) proof = ("proof:cutandchoose_verifier_challenges", { "sbb_hash": sv.bytes2hex(sbb_hash), "challenges": challenges }) return proof
def __init__(self, election, voter_id, px): """ Initialize voter object for this election. Here voter_id is a string identifying the voter, and px is a "position identifier": 'p0', 'p1', ... """ self.election = election assert isinstance(voter_id, str) self.voter_id = voter_id self.px = px # randomness source per voter self.rand_name = "voter:" + voter_id sv.init_randomness_source(self.rand_name) self.receipts = dict() # maps ballot_id to hash value of receipt
def read_verifier_challenges(sbb_dict, sbb, db): """ Read verifier challenges from proof:verifier_challenges; save into db. """ chs = sbb_dict['proof:verifier_challenges']['challenges'] assert isdict(chs, ['cut', 'leftright']) assert isdict(chs['cut'], ['icl', 'opl']) icl = chs['cut']['icl'] assert isinstance(icl, list) assert len(icl) == db['n_reps'] // 2 assert set(icl).issubset(db['k_list']) opl = chs['cut']['opl'] assert isinstance(opl, list) assert len(opl) == db['n_reps'] // 2 assert set(opl).issubset(db['k_list']) assert set(icl).isdisjoint(set(opl)) db['icl'] = icl db['opl'] = opl leftright = chs['leftright'] assert isdict(leftright, db['race_ids']) for race_id in leftright.keys(): lr_dict = leftright[race_id] assert set(lr_dict.keys()) == set(db['p_list']) for p in db['p_list']: lr = lr_dict[p] assert lr == 'left' or lr == 'right' db['leftright'] = leftright # now check that icl, opl, and leftright are consistent with sbb_hash # see make_verifier_challenges in sv_prover.py rand_name = 'verifier_challenges' sbb_hash = sbb_dict['proof:verifier_challenges']['sbb_hash'] stop_before_header = 'proof:verifier_challenges' sbb_hash2 = sv.bytes2hex(hash_sbb(sbb, stop_before_header)) assert sbb_hash2 == sbb_hash sv.init_randomness_source(rand_name, sv.hex2bytes(sbb_hash)) pi = sv.random_permutation(db['n_reps'], rand_name) m = db['n_reps'] // 2 pi = [pi[i] for i in range(2 * m)] icl2 = [db['k_list'][i] for i in sorted(pi[:m])] opl2 = [db['k_list'][i] for i in sorted(pi[m:])] assert icl2 == icl assert opl2 == opl leftright2 = make_left_right_challenges(rand_name, db) assert leftright2 == leftright print('read_verifier_challenges: successful.')
def read_verifier_challenges(sbb_dict, sbb, db): """ Read verifier challenges from proof:verifier_challenges; save into db. """ chs = sbb_dict['proof:verifier_challenges']['challenges'] assert isdict(chs, ['cut', 'leftright']) assert isdict(chs['cut'], ['icl', 'opl']) icl = chs['cut']['icl'] assert isinstance(icl, list) assert len(icl) == db['n_reps'] // 2 assert set(icl).issubset(db['k_list']) opl = chs['cut']['opl'] assert isinstance(opl, list) assert len(opl) == db['n_reps'] // 2 assert set(opl).issubset(db['k_list']) assert set(icl).isdisjoint(set(opl)) db['icl'] = icl db['opl'] = opl leftright = chs['leftright'] assert isdict(leftright, db['race_ids']) for race_id in leftright.keys(): lr_dict = leftright[race_id] assert set(lr_dict.keys()) == set(db['p_list']) for p in db['p_list']: lr = lr_dict[p] assert lr == 'left' or lr == 'right' db['leftright'] = leftright # now check that icl, opl, and leftright are consistent with sbb_hash # see make_verifier_challenges in sv_prover.py rand_name = 'verifier_challenges' sbb_hash = sbb_dict['proof:verifier_challenges']['sbb_hash'] stop_before_header = 'proof:verifier_challenges' sbb_hash2 = sv.bytes2hex(hash_sbb(sbb, stop_before_header)) assert sbb_hash2 == sbb_hash sv.init_randomness_source(rand_name, sv.hex2bytes(sbb_hash)) pi = sv.random_permutation(db['n_reps'], rand_name) m = db['n_reps'] // 2 pi = [pi[i] for i in range(2*m)] icl2 = [db['k_list'][i] for i in sorted(pi[:m])] opl2 = [db['k_list'][i] for i in sorted(pi[m:])] assert icl2 == icl assert opl2 == opl leftright2 = make_left_right_challenges(rand_name, db) assert leftright2 == leftright print('read_verifier_challenges: successful.')
def make_verifier_challenges(election): """ Return a dict containing "verifier challenges" for this proof. This is based on randomness (hash of sbb, fiat-shamir style), but could also incorporate additional random input (e.g. dice rolls). """ sbb_hash = election.sbb.hash_sbb(public=True) election.sbb_hash = sbb_hash rand_name = "verifier_challenges" sv.init_randomness_source(rand_name, sbb_hash) challenges = dict() make_cut_and_choose_challenges(election, rand_name, challenges) make_left_right_challenges(election, rand_name, challenges) election.sbb.post("proof:verifier_challenges", {"sbb_hash": sv.bytes2hex(sbb_hash), "challenges": challenges}, time_stamp=False) return challenges
def __init__(self, election, race_id, choices): """ Initialize race race_id is a string choices is list consisting of one string for each allowable candidate/choice name a string "************************" of stars of the maximum allowable length of a write-in if write-ins are allowed. Example: race_id = "President" choices = ("Smith", "Jones", "********") defines a race (for President), and for this race the voter may vote for Smith, for Jones, or may cast a write-in vote of length at most 8 characters. """ assert isinstance(race_id, str) and len(race_id) > 0 assert isinstance(choices, (list, tuple)) and len(choices) > 0 # must be more than one choice, except if sole choice is for write-ins assert len(choices) > 1 or choices[0] in "*"*1000 # choices must be distinct assert len(choices) == len(set(choices)) # choices must be strings assert all([isinstance(choice, str) for choice in choices]) self.election = election self.race_id = race_id self.choices = choices # set race.race_modulus = modulus for representing choices in this race. # note that for computation and comparison purposes, choices will # be converted to type bytes # make race_modulus a prime big enough to encode all possible choices self.max_choice_len = max([len(choice.encode()) for choice in choices]) self.race_modulus = sv.make_prime(256**self.max_choice_len) self.tally = None rand_name = "random:"+race_id # only for simulation self.rand_name = rand_name sv.init_randomness_source(rand_name)
def make_verifier_challenges(election): """ Return a dict containing "verifier challenges" for this proof. This is based on randomness (hash of sbb, fiat-shamir style), but could also incorporate additional random input (e.g. dice rolls). """ sbb_hash = election.sbb.hash_sbb(public=True) election.sbb_hash = sbb_hash rand_name = "verifier_challenges" sv.init_randomness_source(rand_name, sbb_hash) challenges = dict() make_cut_and_choose_challenges(election, rand_name, challenges) make_left_right_challenges(election, rand_name, challenges) election.sbb.post("proof:verifier_challenges", { "sbb_hash": sv.bytes2hex(sbb_hash), "challenges": challenges }, time_stamp=False) return challenges
def __init__(self, election, n_fail, n_leak): """ Initialize server. This is one for the whole election. The server array has the given number of rows and columns as parts or sub-servers. Here we simulate the actions of these sub-servers. n_fail = number of servers that could fail n_leak = number of servers that my leak information """ assert isinstance(n_fail, int) and n_fail >= 0 assert isinstance(n_leak, int) and n_leak >= 0 self.election = election self.n_fail = n_fail self.n_leak = n_leak if self.n_fail > 0: self.cols = 1 + n_leak self.rows = 2 + n_fail + n_leak self.threshold = 2 + n_leak # number of rows needed to reconstruct else: self.cols = 1 + n_leak self.rows = 1 + n_leak self.threshold = 1 + n_leak rows = self.rows cols = self.cols threshold = self.threshold # each row has an identifier in "abcd..." assert rows <= 26 self.row_list = sv.row_list(rows) self.challenges = dict() # The state of the server in row i, col j is represented # here in the dictionary P[race_id][i][j] for the given race # where i in row_list and 0 <= j < cols. # create one top-level dict sdb as database for this main server self.sdb = dict() # within the top level dict sdb, create a three-dimensional array of # sub-dicts for data storage, each addressed as sdb[race_id][i][j] for race in election.races: race_id = race.race_id self.sdb[race_id] = dict() for i in self.row_list: self.sdb[race_id][i] = dict() for j in range(cols): self.sdb[race_id][i][j] = dict() # each server has its own random-number source for each race # in practice, these could be derived from true random seeds input # independently to each server for race_id in election.race_ids: for i in self.row_list: for j in range(cols): rand_name = "server:" + race_id + ":" + \ str(i) + ":" + str(j) self.sdb[race_id][i][j]['rand_name'] = rand_name sv.init_randomness_source(rand_name) # within each sub-dict sdb[race_id][i][j] create a variety of lists for # storage of cast votes and associated data, including 2m-way replicated # lists needed for the 2m mixes (passes) needed. for race_id in election.race_ids: for i in self.row_list: # first-column lists for storing cast votes and secrets sdbp = self.sdb[race_id][i][0] sdbp['ballot_id'] = dict() # ballot_id (indices from p_list) sdbp['cu'] = dict() # commitments to u sdbp['cv'] = dict() # commitments to v sdbp['x'] = dict() # choice x, where x = u+v mod M sdbp['u'] = dict() # u sdbp['v'] = dict() # v sdbp['ru'] = dict() # randomness to open com(u) sdbp['rv'] = dict() # randomness to open com(v) # for all columns, have 2m-way replicated data structures for j in range(cols): sdbp = self.sdb[race_id][i][j] for k in election.k_list: sdbp[k] = dict() sdbp[k]['x'] = dict() # inputs on pass k sdbp[k]['y'] = dict() # outputs on pass k # last-column lists for storing published lists of commitments for k in election.k_list: sdbp = self.sdb[race_id][i][self.cols-1][k] sdbp['y'] = dict() sdbp['u'] = dict() sdbp['v'] = dict() sdbp['ru'] = dict() sdbp['rv'] = dict() sdbp['cu'] = dict() sdbp['cv'] = dict() # create one top-level dict sdb as database for this main server (a unshared copy of sbd) self.sdb = deepcopy(self.sdb) # TODO remove
def __init__(self, election, n_fail, n_leak): """ Initialize server. This is one for the whole election. The server array has the given number of rows and columns as parts or sub-servers. Here we simulate the actions of these sub-servers. n_fail = number of servers that could fail n_leak = number of servers that my leak information """ assert isinstance(n_fail, int) and n_fail >= 0 assert isinstance(n_leak, int) and n_leak >= 0 self.election = election self.n_fail = n_fail self.n_leak = n_leak if self.n_fail > 0: self.cols = 1 + n_leak self.rows = 2 + n_fail + n_leak self.threshold = 2 + n_leak # number of rows needed to reconstruct else: self.cols = 1 + n_leak self.rows = 1 + n_leak self.threshold = 1 + n_leak rows = self.rows cols = self.cols threshold = self.threshold # each row has an identifier in "abcd..." assert rows <= 26 self.row_list = sv.row_list(rows) # The state of the server in row i, col j is represented # here in the dictionary P[race_id][i][j] for the given race # where i in row_list and 0 <= j < cols. # create one top-level dict sdb as database for this main server self.sdb = dict() # within the top level dict sdb, create a three-dimensional array of # sub-dicts for data storage, each addressed as sdb[race_id][i][j] for race in election.races: race_id = race.race_id self.sdb[race_id] = dict() for i in self.row_list: self.sdb[race_id][i] = dict() for j in range(cols): self.sdb[race_id][i][j] = dict() # each server has its own random-number source for each race # in practice, these could be derived from true random seeds input # independently to each server for race_id in election.race_ids: for i in self.row_list: for j in range(cols): rand_name = "server:" + race_id + ":" + \ str(i) + ":" + str(j) self.sdb[race_id][i][j]['rand_name'] = rand_name sv.init_randomness_source(rand_name) # within each sub-dict sdb[race_id][i][j] create a variety of lists for # storage of cast votes and associated data, including 2m-way replicated # lists needed for the 2m mixes (passes) needed. for race_id in election.race_ids: for i in self.row_list: # first-column lists for storing cast votes and secrets sdbp = self.sdb[race_id][i][0] sdbp['ballot_id'] = dict() # ballot_id (indices from p_list) sdbp['cu'] = dict() # commitments to u sdbp['cv'] = dict() # commitments to v sdbp['x'] = dict() # choice x, where x = u+v mod M sdbp['u'] = dict() # u sdbp['v'] = dict() # v sdbp['ru'] = dict() # randomness to open com(u) sdbp['rv'] = dict() # randomness to open com(v) # for all columns, have 2m-way replicated data structures for j in range(cols): sdbp = self.sdb[race_id][i][j] for k in election.k_list: sdbp[k] = dict() sdbp[k]['x'] = dict() # inputs on pass k sdbp[k]['y'] = dict() # outputs on pass k # last-column lists for storing published lists of commitments for k in election.k_list: sdbp = self.sdb[race_id][i][self.cols-1][k] sdbp['y'] = dict() sdbp['u'] = dict() sdbp['v'] = dict() sdbp['ru'] = dict() sdbp['rv'] = dict() sdbp['cu'] = dict() sdbp['cv'] = dict() # post on log that server array is set up election.sbb.post("setup:server-array", {"rows": rows, "cols": cols, "n_reps": election.n_reps, "threshold": threshold, 'json_indent': election.json_indent}, time_stamp=False)
def compute_output_commitments(election, row_index, col_index): """ Make commitments to all output values and save them in sdbp. For each race, for each of n_reps copies (indexed by k), for each row (indexed by i) for each of the n vote shares (call them y) compute two commitments (cu and cv) to split-value rep (u,v) of y. using randomization values ru and rv. """ cols = election.server.cols full_output = dict() for race in election.races: race_modulus = race.race_modulus race_id = race.race_id full_output[race_id] = dict() for k in election.k_list: full_output[race_id][k] = dict() for py in election.p_list: full_output[race_id][k][py] = dict() if col_index == cols - 1: # TODO move this logic to ServerMix handler i = row_index rand_name = \ election.server.sdb[race_id][i][cols-1]['rand_name'] sv.init_randomness_source( rand_name) # TODO optional remove later sdbp = election.server.sdb[race_id][i][cols - 1][k] y = sdbp['y'][py] (u, v) = sv.get_sv_pair(y, 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) sdbp['u'][py] = u sdbp['v'][py] = v sdbp['ru'][py] = ru sdbp['rv'][py] = rv sdbp['cu'][py] = cu sdbp['cv'][py] = cv ballot = { 'y': y, 'u': u, 'v': v, 'ru': ru, 'rv': rv, 'cu': cu, 'cv': cv } full_output[race_id][k][py][i] = ballot election.full_output = full_output coms = dict() # same as full_output, but only giving non-secret values (i.e. cu, cv) for race in election.races: race_id = race.race_id coms[race_id] = dict() for k in election.k_list: coms[race_id][k] = dict() for py in election.p_list: coms[race_id][k][py] = dict() '''for i in election.server.row_list: # TODO remove this for loop -> shared memory coms[race_id][k][py][i] = \ {'cu': full_output[race_id][k][py][i]['cu'], 'cv': full_output[race_id][k][py][i]['cv']}''' coms[race_id][k][py] = dict() if col_index == cols - 1: # TODO move this logic to ServerMix handler i = row_index coms[race_id][k][py][i] = \ {'cu': full_output[race_id][k][py][i]['cu'], 'cv': full_output[race_id][k][py][i]['cv']} election.output_commitments = coms return ("proof:output_commitments", {"commitments": coms})