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
Exemple #6
0
    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
Exemple #7
0
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
Exemple #10
0
    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})