Beispiel #1
0
def GenPolynomial(d, secparams):
    """
    Algorithm 7.8: Generates the coefficients a_0,...,a_d of a random polynomial A(X) = Sigma(i=0...d) a_i X^i mod p' of degree d >= 0.
    The algorithm also accepts d = -1 as input, which we interpret as the polynomial A(X) = 0.
    In this case, the algorithm returns the coefficient list a = (0).

    Args:
       d (int):                            Degree d >= -1
       secparams (SecurityParams):         Collection of public security parameters

    Returns:
       list of mpz:                        A list of coefficients a_0 ... a_d of polynomial A(X)
    """

    AssertInt(d)
    AssertClass(secparams, SecurityParams)
    assert (d >= -1)

    a_bold = []
    a_d = 0

    if (d == -1):
        return [0]

    else:
        for i in range(d):
            a_bold.append(randomMpz(secparams.p_prime, secparams))

        # generate the last coefficient != 0
        while a_d == 0:
            a_d = randomMpz(secparams.p_prime, secparams)

        a_bold.append(a_d)

    return a_bold
Beispiel #2
0
def GenSecretVoterData(p_bold, secparams):
    """
    Algorithm 7.10: Generates the secret data for a single voter, which is sent to the voter prior to an election event via the printing authority.

    Args:
       p_bold (list):                      A list of n points = (p_1, ... , p_n) in Z_p'
       secparams (SecurityParams):         Collection of public security parameters

    Returns:
       tuple:                              Secret voter data (x,y,F,r)
    """

    AssertList(p_bold)
    AssertClass(secparams, SecurityParams)

    q_hat_apos_x = floor(secparams.q_hat_X // secparams.s)
    q_hat_apos_y = floor(secparams.q_hat_Y // secparams.s)
    x = randomMpz(q_hat_apos_x, secparams)
    y = randomMpz(q_hat_apos_y, secparams)

    F = Truncate(RecHash(p_bold, secparams),
                 secparams.L_F)  # Finalization code
    r_bold = []  # Return codes

    n = len(p_bold)
    for i in range(n):
        r_bold.append(Truncate(RecHash(p_bold[i], secparams), secparams.L_R))

    return SecretVoterData(x, y, F, r_bold)
def GenConfirmationProof(y, y_prime, y_hat, secparams):
    """
    Algorithm 7.32: Generates a NIZKP of knowledge of the secret confirmation
    credential y that matches with a given public confirmation credential y_hat.
    Note that this proof is equivalent to a Schnorr identification proof. For the
    verification of pi, see Alg. 7.36.

    Args:
        y:                                   Secret confirmation credential
        y_prime:                             Secret validity credential
        y_hat:                               Public confirmation credential
        secparams (SecurityParams):          Collection of public security parameters

    Returns:
        π:          The NIZKP challenge
    """

    AssertMpz(y)
    AssertClass(secparams, SecurityParams)

    w = randomMpz(secparams.q_hat, secparams)
    t = gmpy2.powmod(secparams.g_hat, w, secparams.p_hat)
    c = GetNIZKPChallenge(y_hat, t, secparams.tau, secparams)
    s = w + c * (y + y_prime) % secparams.q_hat
    pi = (t, s)

    return pi
Beispiel #4
0
def GenPermutationCommitment(psi, h_bold, secparams):
    """
    Algorithm 7.45: Generates a commitment c = com(psi, r_bold) to a permutation psi by committing
    to the columns of the corresponding permutation matrix. This algorithm is used in Alg. 7.44.

    Args:
       psi (list of int):                   Permutation
       h_bold (list of mpz):                Independent generators h = (h_1, ..., h_N), h_i in G_q\{1}
       secparams (SecurityParams):          Collection of public security parameters

    Returns:
        tuple:                              (c,r)
    """

    AssertList(psi)
    AssertList(h_bold)
    AssertClass(secparams, SecurityParams)

    r_bold = [None] * len(psi)
    c_bold = [None] * len(psi)

    N = len(psi)
    for i in range(N):
        r_bold[psi[i]] = randomMpz(secparams.q, secparams)
        c_bold[psi[i]] = (gmpy2.powmod(secparams.g, r_bold[psi[i]],
                                       secparams.p) * h_bold[i]) % secparams.p

    return (c_bold, r_bold)
Beispiel #5
0
def GenQuery(q_bold, pk, secparams):
    """
    Algorithm 7.20: Generates an OT query a from the prime numbers representing the
    voter's selection and a for a given public encryption key (which serves as a
    generator).

    Args:
        q_bold (list):                       Selected primes
        pk (mpz):                            Encryption key
        secparams (SecurityParams):          Collection of public security parameters

    Returns:
        (a, r):                              The OT query
    """

    AssertList(q_bold)
    AssertMpz(pk)
    AssertClass(secparams, SecurityParams)

    k = len(q_bold)
    a_bold = [None] * k
    r_bold = [None] * k

    for j in range(k):
        r_bold[j] = randomMpz(secparams.q, secparams)
        a_j_1 = (q_bold[j] *
                 gmpy2.powmod(pk, r_bold[j], secparams.p)) % secparams.p
        a_j_2 = gmpy2.powmod(secparams.g, r_bold[j], secparams.p)
        a_bold[j] = (a_j_1, a_j_2)

    return (a_bold, r_bold)
Beispiel #6
0
def GenCommitmentChain(c_0, u_bold, secparams):
    """
    Algorithm 7.46: Generates a commitment chain c_0 -> c_1 --> ... --> c_N relative to a list of 
    public challenges u_bold and starting with a given commitment c_0. This algorithm is used in Alg. 7.44

    Args:
       c_0 (mpz):                           Initial commitment c_0 in G_q
       u_bold (list of mpz):                Public challenges u = (u_1, ..., u_N), u_i in Z_q
       secparams (SecurityParams):          Collection of public security parameters

    Returns:
        tuple:                              (c,r)
    """

    r_bold = []
    c_bold = []

    N = len(u_bold)

    c_bold.append(c_0)

    for i in range(N):
        c_i_minus_1 = c_bold[i]
        r_i = randomMpz(secparams.q, secparams)
        c_i = ((gmpy2.powmod(secparams.g, r_i, secparams.p) *
                gmpy2.powmod(c_i_minus_1, u_bold[i], secparams.p)) %
               secparams.p)

        r_bold.append(r_i)
        c_bold.append(c_i)

    del c_bold[0]

    return (c_bold, r_bold)
Beispiel #7
0
def GenBallotProof(x, m, r, x_hat, a_bold, pk, secparams):
    """
    Algorithm 7.21: Generates a NIZKP, which proves that the ballot has been formed properly.
    This proof includes a proof of knowledge of the secret voting credential x that matches with
    the public voting credential x_hat. Note that this is equivalent to a Schnorr Identification proof.

    Args:
        x (mpz):                            Voting credential ∈ Z_q_hat
        m (mpz):                            Product of selected primes m ∈ G_q
        r (mpz):                            Randomization r ∈ Z_q
        a_bold (list):                      OT queries
        pk (mpz):                           Encryption key pk ∈ G_q
        secparams (SecurityParams):         Collection of public security parameters

    Returns:
        tuple:                              ((t_1, t_2, t_3), (s_1, s_2, s_3))
    """

    AssertMpz(x)
    AssertMpz(m)
    AssertMpz(r)
    AssertMpz(x_hat)
    AssertList(a_bold)
    AssertMpz(pk)
    AssertClass(secparams, SecurityParams)

    w_1 = randomMpz(secparams.q_hat, secparams)
    w_2 = randomQuadResMpz(secparams)
    w_3 = randomMpz(secparams.q, secparams)
    t_1 = gmpy2.powmod(secparams.g_hat, w_1, secparams.p_hat)
    t_2 = (w_2 * gmpy2.powmod(pk, w_3, secparams.p)) % secparams.p
    t_3 = gmpy2.powmod(secparams.g, w_3, secparams.p)

    y = (x_hat, a_bold)
    t = (t_1, t_2, t_3)
    c = GetNIZKPChallenge(y, t, secparams.tau, secparams)

    s_1 = (w_1 + c * x) % secparams.q_hat
    s_2 = (w_2 * gmpy2.powmod(m, c, secparams.p)) % secparams.p
    s_3 = (w_3 + c * r) % secparams.q

    s = (s_1, s_2, s_3)

    return BallotProof(t,s)
Beispiel #8
0
def GenKeyPair(secparams):
    """
    Algorithm 7.15: Generates a random ElGamal encryption key pair (sk, pk) ∈ Z_q x G_q.
    This algorithm is used in Prot. 6.3 by the authorities to generate private shares of a common public encryption key.

    Args:
        secparams (SecurityParams):          Collection of public security parameters

    Returns:
        tuple:                               Key Pair (sk, pk) in Z_q x G_q
    """
    AssertClass(secparams, SecurityParams)

    sk = randomMpz(secparams.q, secparams)
    pk = gmpy2.powmod(secparams.g, sk, secparams.p)

    assert IsMember(pk, secparams)

    return (sk, pk)
Beispiel #9
0
def GenPoints(n, k, secparams):
    """
    Algorithm 7.7: Generates a list of n random points picket from t random polynomials
    A_j(X) of degree k_j - 1 (by picking n_j different random points from each polynomial).
    Additional, the values y_j = A_j(0) are computed for all random polynomials and returned together with the random points.

    Args:
        n (int):                            Number of candidates n >= 2
        k (int):                            Number of selections 0 < k < n
        secparams (SecurityParams):         Collection of public security parameters

    Returns:
        tuple:        (p,y'), points p ∈ (Z_p^2)^n, and the y value of x=0
    """

    AssertInt(n)
    AssertInt(k)

    p_bold = []

    a_bold = GenPolynomial(
        k - 1, secparams
    )  # the number of 1's in the eligibility matrix indicate how many selections the voter can make and therefore decides the degree of the polynomial
    X = []

    for i in range(n):
        x = mpz(0)
        # get a unique x from Z_p'
        while True:
            x = randomMpz(secparams.p_prime, secparams)
            if x not in X or secparams.deterministicRandomGen:  # if randomMpz is deterministic, we would be stuck in an endless loop
                X.append(x)
                break

        y = GetYValue(
            x, a_bold, secparams
        )  # get the corresponding y value of x on the polynomial a_j
        p_i = Point(x, y)  # Point tuple
        p_bold.append(p_i)  # part of the private voter data

        y_prime = GetYValue(mpz(0), a_bold, secparams)  # Point (0,Y(0))

    return (p_bold, y_prime)
Beispiel #10
0
def GenDecryptionProof(sk_j, pk_j, e_bold, b_prime_bold, secparams):
    """
    Algorithm 7.50: Generates a decryption proof relative to ElGamal encryptions e and
    partial decryptions b'. This is essentially a NIZKP of knowledge of the private key share
    sk_j satisfying b'_i = b_i^sk_j for all input encryptions e_i = (a_i, b_i) and pk_j = g^sk_j.
    Proof verification, see Alg. 7.52.

    Args:
        sj_j (mpz):                             Decryption key share
        pk_j (mpz):                             Encryption key share
        e_bold (list of ElGamalEncryption):     ElGamal encryptions e_bold
        b_prime_bold (list):                    Partial decryptions
        secparams (SecurityParams):             Collection of public security parameters

    Returns:
        DecryptionProof
    """
    AssertMpz(sk_j)
    AssertMpz(pk_j)
    AssertList(e_bold)
    AssertList(b_prime_bold)
    AssertClass(secparams, SecurityParams)

    w = randomMpz(secparams.q, secparams)
    t_0 = gmpy2.powmod(secparams.g, w, secparams.p)

    t_1_to_N = []
    N = len(e_bold)
    for i in range(N):
        t_1_to_N.append(gmpy2.powmod(e_bold[i].b, w, secparams.p))

    t = (t_0, t_1_to_N)

    b_bold = [e.b for e in e_bold]

    y = (pk_j, b_bold, b_prime_bold)
    c = GetNIZKPChallenge(y, t, secparams.tau, secparams)

    s = (w + c * sk_j) % secparams.q
    pi = DecryptionProof(t, s)

    return pi
Beispiel #11
0
def GenReEncryption(e, pk, secparams):
    """
    Algorithm 7.43: Generates a re-encryption e' = (a * pk^r', b*g^r') of the given ElGamal encryption
    e = (a,b) in G_q^2. The re-encryption e' is returned together with the randomization r' in Z_q

    Args:
       e (tuple):                          ElGamal encryption e = (a,b)
       pk (mpz):                           Encryption key pk
       secparams (SecurityParams):         Collection of public security parameters

    Returns:
        tuple         Re-Encryption (e', r')
    """

    AssertMpz(pk)
    AssertClass(secparams, SecurityParams)

    (a, b) = e
    r_prime = randomMpz(secparams.q, secparams)
    a_prime = (a * gmpy2.powmod(pk, r_prime, secparams.p)) % secparams.p
    b_prime = (b * gmpy2.powmod(secparams.g, r_prime, secparams.p)) % secparams.p
    e_prime = ElGamalEncryption(a_prime, b_prime)

    return (e_prime, r_prime)
Beispiel #12
0
def GenShuffleProof(e_bold, e_prime_bold, r_prime_bold, psi, pk, secparams):
    """
    Algorithm 7.44: Generates a NIZKP of shuffle relative to ElGamal encryptions e and e1,
    which is equivalent to proving knowledge of a permutation psi and randomizations r_prime such
    that e_prime = Shuffle_pk(e,r_prime,psi). The algorithm implements Wikström’s proof of a shuffle
    [19, 18], except for the fact that the offline and online phases are merged. For the proof
    verification, see Alg. 7.48. For further background information we refer to Section 5.5.

    Args:
       e_bold (list):                           ElGamal Encryptions
       e_prime_bold (list):                     Shuffled ElGamal Encryptions e'
       r_prime_bold (list):                     Re-encryption randomizations r'
       psi (list):                              Permutation
       pk (mpz):                                Encryption key pk
       secparams (SecurityParams):              Collection of public security parameters

    Returns:
        ShuffleProof
    """
    AssertList(e_bold)
    AssertList(e_prime_bold)
    AssertList(r_prime_bold)
    AssertList(psi)
    AssertMpz(pk)
    AssertClass(secparams, SecurityParams)

    N = len(e_bold)
    h_bold = GetGenerators(N, secparams)
    (c_bold, r_bold) = GenPermutationCommitment(psi, h_bold, secparams)
    u_bold = GetNIZKPChallenges(N, (e_bold, e_prime_bold, c_bold), secparams.tau, secparams)

    u_prime_bold = [None] * N
    for i in range(N):
        u_prime_bold[i] = u_bold[psi[i]]

    (c_hat_bold, r_hat_bold) = GenCommitmentChain(secparams.h, u_prime_bold, secparams)

    w_1 = randomMpz(secparams.q, secparams)
    w_2 = randomMpz(secparams.q, secparams)
    w_3 = randomMpz(secparams.q, secparams)
    w_4 = randomMpz(secparams.q, secparams)

    w_hat_bold = [None] * N
    w_prime_bold = [None] * N
    for i in range(N):
        w_hat_bold[i] = randomMpz(secparams.q, secparams)
        w_prime_bold[i] = randomMpz(secparams.q, secparams)


    # Computing the T values:

    t_1 = gmpy2.powmod(secparams.g, w_1, secparams.p)
    t_2 = gmpy2.powmod(secparams.g, w_2, secparams.p)

    h_product = mpz(1)
    for i in range(N):
        h_product = (h_product * gmpy2.powmod(h_bold[i],w_prime_bold[i], secparams.p) ) % secparams.p

    t_3 = (gmpy2.powmod(secparams.g, w_3, secparams.p) * h_product) % secparams.p

    a_prime_i_product = mpz(1)
    for i in range(N):
        a_prime_i_product = (a_prime_i_product * gmpy2.powmod(e_prime_bold[i].a, w_prime_bold[i], secparams.p)) % secparams.p
    t_4_1 = (gmpy2.powmod(pk, -w_4, secparams.p) * a_prime_i_product) % secparams.p

    b_prime_i_product = mpz(1)
    for i in range(N):
        b_prime_i_product = (b_prime_i_product * gmpy2.powmod(e_prime_bold[i].b, w_prime_bold[i], secparams.p)) % secparams.p
    t_4_2 = (gmpy2.powmod(secparams.g, -w_4, secparams.p) * b_prime_i_product) % secparams.p

    c_hat_bold_tmp = []
    c_hat_bold_tmp.append(secparams.h)
    c_hat_bold_tmp.extend(c_hat_bold)

    t_hat_bold = [None] * N
    for i in range(N):
        t_hat_bold[i] = (gmpy2.powmod(secparams.g, w_hat_bold[i], secparams.p) * gmpy2.powmod(c_hat_bold_tmp[i], w_prime_bold[i], secparams.p) ) % secparams.p

    del c_hat_bold_tmp[0]   # remove the element c_0 that we manually inserted ???????????

    t = (t_1, t_2, t_3, (t_4_1, t_4_2), t_hat_bold)

    # Computing the challenge:
    y = (e_bold, e_prime_bold, c_bold, c_hat_bold, pk)
    c = GetNIZKPChallenge(y, t, secparams.tau, secparams)

    # Computing the S values:
    r_line = mpz(0)
    for i in range(N):
        r_line = (r_line + r_bold[i]) % secparams.q

    s_1 = mpz(0)
    for i in range(N):
        s_1 = (w_1 + c * r_line) % secparams.q

    v_bold = [None] * N
    v_bold[N-1] = mpz(1)
    for i in reversed(range(N-1)):
        v_bold[i] = (u_prime_bold[i+1] * v_bold[i+1]) % secparams.q

    r_hat = mpz(0)
    for i in range(N):
        r_hat = (r_hat + (r_hat_bold[i] * v_bold[i])) % secparams.q
    s_2 = (w_2 + c * r_hat ) % secparams.q

    r_tilde = mpz(0)
    for i in range(N):
        r_tilde = (r_tilde + (r_bold[i] * u_bold[i])) % secparams.q
    s_3 = (w_3 + c* r_tilde ) % secparams.q

    r_prime = mpz(0)
    for i in range(N):
        r_prime = (r_prime + (r_prime_bold[i] * u_bold[i])) % secparams.q
    s_4 = (w_4 + c* r_prime ) % secparams.q

    s_hat_bold = [None] * N
    s_prime_bold = [None] * N
    for i in range(N):
        s_hat_bold[i] = (w_hat_bold[i] + (c * r_hat_bold[i])) % secparams.q
        s_prime_bold[i] = (w_prime_bold[i] + (c * u_prime_bold[i])) % secparams.q

    s = (s_1, s_2, s_3, s_4, s_hat_bold, s_prime_bold)

    pi = ShuffleProof(t,s,c_bold,c_hat_bold)

    return pi
def GenResponse(v, a_bold, pk, n_bold, k_bold, E_bold, P_bold, secparams):
    """
    Algorithm 7.25: Generates the response beta for the given OT query a. The messages to
    transfer are byte array representations of the n points (p_v,1, ... p_v,n). Along with beta,
    the algorithm also returns the randomizations r used to generate the response.

    Args:
        v (int):                            Voter Index
        a_bold (list of mpz):               Queries
        pk (mpz):                           Encryption Key
        n_bold (list of int):               Number of candidates
        k_bold (list of int):               Number of selections
        E_bold (list of list):              Eligibility matrix
        P_bold (list of list):              Points N x n
        secparams (SecurityParams):         Collection of public security parameters

    Returns:
        tuple:                              (beta, r)
    """

    AssertInt(v)
    AssertList(a_bold)
    for a in a_bold:
        assert IsMember(a[0],
                        secparams), "All elements of a_bold must be in G_q"
    for a in a_bold:
        assert IsMember(a[1],
                        secparams), "All elements of a_bold must be in G_q"
    AssertMpz(pk)
    assert IsMember(pk, secparams), "Public key must be in G_q"
    assert pk != mpz(1), "Public key cannot be equal to 1"
    AssertList(n_bold)
    AssertList(k_bold)
    AssertList(E_bold)
    AssertList(P_bold)
    AssertClass(secparams, SecurityParams)

    n = sum(n_bold)
    k = len(a_bold)
    t = len(n_bold)
    M = []

    z_1 = randomMpz(secparams.q, secparams)
    z_2 = randomMpz(secparams.q, secparams)

    beta = []
    b_bold = []

    for j in range(k):
        beta.append(randomQuadResMpz(secparams))
        b_j = gmpy2.powmod(a_bold[j][0], z_1, secparams.p)
        b_j *= gmpy2.powmod(a_bold[j][1], z_2, secparams.p)
        b_j *= beta[j]
        b_j %= secparams.p
        b_bold.append(b_j)

    l_M = ceil(secparams.L_M / secparams.L)
    p_bold = GetPrimes(n, secparams)

    n_prime = 0
    k_prime = 0

    C_bold = [[None for i in range(sum(k_bold))] for i in range(n)]

    for l in range(len(k_bold)):
        if E_bold[v][l] != 0:
            for i in range(n_prime, n_prime + n_bold[l]):
                p_prime_i = gmpy2.powmod(p_bold[i], z_1, secparams.p)
                M.append(
                    ToByteArrayN(P_bold[v][i].x, secparams.L_M // 2) +
                    ToByteArrayN(P_bold[v][i].y, secparams.L_M // 2))

                for j in range(k_prime, k_prime + E_bold[v][l] * k_bold[l]):
                    k_ij = p_prime_i * beta[j] % secparams.p
                    k_tmp = bytearray()

                    for c in range(l_M):
                        k_tmp += RecHash([k_ij, c], secparams)

                    K_ij = Truncate(k_tmp, secparams.L_M)
                    C_bold[i][j] = XorByteArray([M[i], K_ij])

            k_prime = k_prime + E_bold[v][l] * k_bold[l]
        n_prime = n_prime + n_bold[l]

    d = (gmpy2.powmod(pk, z_1, secparams.p) *
         gmpy2.powmod(secparams.g, z_2, secparams.p)) % secparams.p
    beta = Response(b_bold, C_bold, d)
    z = (z_1, z_2)

    return (beta, z)