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)
def CheckAllShuffleProofs(pi_bold, e_0_bold, E_bold, pk, secparams): """ Algorithm: Checks if a chain of shuffle proofs generated by s different authorities is correct. Args: pi_bold (list of ShuffleProof): Shuffle proof e_0_bold (list): ElGamal Encryptions E_bold (list): Shuffled ElGamal Encryptions pk (mpz): Encryption key pk secparams (SecurityParams): Collection of public security parameters Returns: bool """ AssertList(pi_bold) AssertList(e_0_bold) AssertList(E_bold) AssertMpz(pk) AssertClass(secparams, SecurityParams) N = len(e_0_bold) e_bold_tmp = [] e_bold_tmp.append(e_0_bold) e_bold_tmp.extend(E_bold) for j in range(secparams.s): if not CheckShuffleProof(pi_bold[j], e_bold_tmp[j], e_bold_tmp[j + 1], pk, secparams): return False return True
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
def ToString(x, k, A): """ Algorithm 4.6: Computes a string representation of length k in big-endian order of a given non negative integer x in N Args: x (mpz): Integer x ∈ N k (int) String length k >= log_N (x) A (list) Alphabet A = {c_1, ..., c_N} Returns: string: The string representation of x """ AssertMpz(x) AssertInt(k) AssertList(A) S = "" N = len(A) for i in reversed(range(k)): s_k = A[x % N] x = x // N S = s_k + S return S
def GenShuffle(e_bold, pk, secparams): """ Algorithm 7.41: Generates a random permutation psi and uses it to shuffle a given list e = (e_1, ..., e_n) of ElGamal encryptions e_i = (a_i, b_i) in G_q^2. With psi_N = {(j_1, ..., j_N) : j_i in {1,...,N}, j_i_1 != j_i_2, forAll i_1 != i2} we denote the set of all N! possible permutations of the values {1, ..., N} Args: e_bold (list): ElGamal Encryptions pk (mpz): Encryption key pk secparams (SecurityParams): Collection of public security parameters Returns: tuple (e_prime, r_prime, psi) """ AssertList(e_bold) AssertMpz(pk) psi_bold = GenPermutation(len(e_bold), secparams) e_prime_bold = [] r_prime_bold = [] N = len(e_bold) for i in range(N): (e_prime_i, r_prime_i) = GenReEncryption(e_bold[i], pk, secparams) e_prime_bold.append(e_prime_i) r_prime_bold.append(r_prime_i) e_prime_shuffled = [None] * len(e_prime_bold) for i in range(N): e_prime_shuffled[i] = e_prime_bold[psi_bold[i]] return (e_prime_shuffled, r_prime_bold, psi_bold)
def CheckBallotProof(pi, x_hat, a_bold, pk, secparams): """ Algorithm 7.24: Checks the correctness of a ballot proof Pi generated by Alg. 7.21. The public values of this proof are the public voting credential x_hat and the ElGamal encryption (a,b) Args: pi (BallotProof): Ballot proof pi = (t,s) x_hat (mpz): Voting credential x_hat a_bold (list): OT query a_bold pk (mpz): ElGamal key pk secparams (SecurityParams): Collection of public security parameters Returns: bool: True if (t_1 == t'_1 and t_2 == t'_2 and t_3 == t'_3) holds """ AssertClass(pi, BallotProof) AssertMpz(x_hat) AssertList(a_bold) AssertMpz(pk) AssertClass(secparams, SecurityParams) y = (x_hat, a_bold) t = pi[0] (t_1, t_2, t_3) = t s = pi[1] (s_1, s_2, s_3) = s c = GetNIZKPChallenge(y, t, secparams.tau, secparams) a_1 = mpz(1) a_2 = mpz(1) for j in range(len(a_bold)): a_1 = (a_1 * a_bold[j][0]) % secparams.p a_2 = (a_2 * a_bold[j][1]) % secparams.p # e = (a, b) t_prime_1 = (gmpy2.powmod(x_hat, -c, secparams.p_hat) * gmpy2.powmod( secparams.g_hat, s_1, secparams.p_hat)) % secparams.p_hat t_prime_2 = (gmpy2.powmod(a_1, -c, secparams.p) * s_2 * gmpy2.powmod(pk, s_3, secparams.p)) % secparams.p t_prime_3 = (gmpy2.powmod(a_2, -c, secparams.p) * gmpy2.powmod(secparams.g, s_3, secparams.p)) % secparams.p return t_1 == t_prime_1 and t_2 == t_prime_2 and t_3 == t_prime_3
def GenBallot(X, s, pk, secparams, manipulatedPublicCredential=None, manipulatedPublicKey=None): """ Algorithm 7.18: Generates a ballot based on the selection s and the voting code X. The ballot includes an OT query a and a proof pi. The algorithm also returns the random values used to generate the OT query. These random values are required in Alg. 7.27 to derive the transferred messages from the OT response, which itself is generated by Alg. 7.25. Args: X (str): Voting Code X ∈ A_X^l_X s (list of int): Selection s = (s_1, ... , s_k), 1 <= s_1 < ... < s_k pk (mpz): ElGamal key pk ∈ G_p \ {1} secparams (SecurityParams): Collection of public security parameters Returns: tuple: alpha = (r, Ballot) = (r, (x_hat, a, b, pi)) """ AssertMpz(pk) AssertList(s) AssertClass(secparams, SecurityParams) x = mpz(StringToInteger(X, secparams.A_X)) x_hat = gmpy2.powmod(secparams.g_hat, x, secparams.p_hat) if manipulatedPublicCredential != None: x_hat = mpz(manipulatedPublicCredential) if manipulatedPublicKey != None: pk = mpz(manipulatedPublicKey) q_bold = GetSelectedPrimes(s, secparams) # q = (q_1, ... , q_k) (a_bold, r_bold) = GenQuery(q_bold, pk, secparams) m = mpz(1) for j in range(len(q_bold)): m = m * q_bold[j] if m >= secparams.p: return None #a = mpz(1) #b = mpz(1) r = mpz(0) for j in range(len(q_bold)): #a = (a * a_bold[j][0]) % secparams.p #b = (b * a_bold[j][1]) % secparams.p r = (r + r_bold[j]) % secparams.q #e = (a, b) pi = GenBallotProof(x, m, r, x_hat, a_bold, pk, secparams) alpha = Ballot(x_hat, a_bold, pi) return (alpha, r_bold)
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)
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
def GetPublicVoterData(x, y, y_prime, secparams): """ Algorithm 7.11: Generates the public data for a single voter, which is sent to the bulletin board. Args: x (mpz): Secret voting credential y (mpz): Secret confirmation credential y_prime (mpz): Secret vote validity credential y_prime in Z_p_prime secparams (SecurityParams): Collection of public security parameters Returns: tuple: Public data of a voter """ AssertMpz(x) AssertMpz(y) AssertMpz(y_prime) AssertClass(secparams, SecurityParams) # h = ToInteger(RecHash(y_bold, secparams)) % secparams.q_hat x_hat = gmpy2.powmod(secparams.g_hat, x, secparams.p_hat) y_hat = gmpy2.powmod(secparams.g_hat, (y+y_prime) % secparams.q_hat, secparams.p_hat) return (x_hat, y_hat) # as d_hat
def CheckBallot(v, alpha, pk, k_bold, E_bold, x_hat_bold, B, secparams): """ Algorithm 7.22: Checks if a ballot alpha obtained from voter v is valid. For this, voter i must not have submitted a valid ballot before, pi must be valid, and x_hat must be the public voting credential of voter v. Note that parameter checking |a| ki for ki °tj1 kij is an important initial step of this algorithm. Args: v (int): Voter index alpha (Ballot): Ballot pk (mpz): Public Key k_bold (list): Number of selections E_bold (list): Eligibility matrix E x_hat_bold (list): Public voting credentials B (list): Ballot List secparams (SecurityParams): Collection of public security parameters Returns: bool: True if the ballot is valid, False if not """ AssertInt(v) AssertClass(alpha, Ballot) AssertMpz(pk) assert IsMember(pk, secparams), "pk must be in G_q" AssertList(k_bold) AssertList(x_hat_bold) AssertList(B) AssertClass(secparams, SecurityParams) k_prime = 0 for j in range(len(k_bold)): k_prime = k_prime + E_bold[v][j] * k_bold[ j] # if voter i is eligible to cast a vote in election j, multiply 1 * the number of selections in j hasBallot = HasBallot(v, B, secparams) credentialCheck = x_hat_bold[v] == alpha.x_hat queryLength = len(alpha.a_bold) == k_prime if not hasBallot and credentialCheck and queryLength: ballotProofCheck = CheckBallotProof(alpha.pi, alpha.x_hat, alpha.a_bold, pk, secparams) if ballotProofCheck: return True, [] return (False, [False, hasBallot, credentialCheck, queryLength])
def CheckDecryptionProof(pi_prime, pk_j, e_bold, b_prime_bold, secparams): """ Algorithm 7.52: Checks the correctness of a decryption proof generated by Alg. 7.50. The public values are the ElGamal encryptions e, the partial decryptions b1, and the share pkj of the public encryption key. Args: pi_prime (DecryptionProof): Decryption pk_j (mpz): Encryption key share e_bold (list of ElGamalEncryption): ElGamal encryptions b_prime_bold (list): Partial decryptions secparams (SecurityParams): Collection of public security parameters Returns: bool: (t_0 = t_prime_0) and for i = 1..N: t_i = t_prime_i """ #AssertMpz(pi_prime) AssertMpz(pk_j) AssertList(e_bold) AssertList(b_prime_bold) AssertClass(secparams, SecurityParams) t_0 = pi_prime.t[0] t_1_to_N = pi_prime.t[1] b_bold = [e.b for e in e_bold] y = (pk_j, b_bold, b_prime_bold) c = GetNIZKPChallenge(y, pi_prime.t, secparams.tau, secparams) t_prime_0 = (gmpy2.powmod(pk_j, -c, secparams.p) * gmpy2.powmod( secparams.g, pi_prime.s, secparams.p)) % secparams.p t_prime_bold = [] N = len(e_bold) for i in range(N): t_prime_bold.append( (gmpy2.powmod(b_prime_bold[i], -c, secparams.p) * gmpy2.powmod(b_bold[i], pi_prime.s, secparams.p)) % secparams.p) return (t_0 == t_prime_0 and t_prime_bold == t_1_to_N)
def GetPublicKey(pk_bold, secparams): """ Algorithm 7.16: Computes a public ElGamal encryption key pk ∈ G_q from given shares pk_j ∈ G_q Args: pk_bold (list of mpz): List of public keys = (pk_1, ... , pk_s), pk_j ∈ G_q secparams (SecurityParams): Collection of public security parameters Returns: mpz: Public Key pk """ AssertList(pk_bold) AssertClass(secparams, SecurityParams) resultPk = mpz(1) for j in range(secparams.s): # loop over s (authorities) resultPk = (resultPk * pk_bold[j]) % secparams.p AssertMpz(resultPk) return resultPk
def GetPartialDecryptions(e_bold, sk_j, secparams): """ Algorithm 7.49: Algorithm 7.49: Computes the partial decryptions of a given input list e of ElGamal encryption using a share sk_j of the private decryption key. Args: e_bold (list of ElGamalEncryption): ElGamal encryptions sk_j (mpz): Decryption key share secparams (SecurityParams): Collection of public security parameters Returns: list of mpz Partial decryptions """ AssertList(e_bold) AssertMpz(sk_j) AssertClass(secparams, SecurityParams) b_prime_bold = [] N = len(e_bold) for i in range(N): b_prime_bold.append(gmpy2.powmod(e_bold[i][1], sk_j, secparams.p)) return b_prime_bold
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)
def CheckShuffleProof(pi, e_bold, e_prime_bold, pk, secparams): """ Algorithm 7.48: Checks the correctness of a NIZKP of a shuffle pi generated by Alg. 7.44. The public values are the ElGamal encryptions e and e' and the public encryption key pk. Args: pi (ShuffleProof): Shuffle proof e_bold (list): ElGamal Encryptions e_prime_bold (list): Shuffled ElGamal Encryptions e' pk (mpz): Encryption key pk secparams (SecurityParams): Collection of public security parameters Returns: ShuffleProof """ AssertClass(pi, ShuffleProof) AssertList(e_bold) AssertList(e_prime_bold) AssertMpz(pk) AssertClass(secparams, SecurityParams) N = len(e_bold) c_bold = pi.c_bold c_hat_bold = pi.c_hat_bold s_1 = pi.s[0] s_2 = pi.s[1] s_3 = pi.s[2] s_4 = pi.s[3] s_hat = pi.s[4] # tuple s_prime = pi.s[5] # list t_1 = pi.t[0] t_2 = pi.t[1] t_3 = pi.t[2] t_4_1 = pi.t[3][0] t_4_2 = pi.t[3][1] t_hat = pi.t[4] assert len( e_prime_bold ) == N, "The size of e_prime_bold must be identical to N ( = len(e_bold))" assert len( c_bold ) == N, "The size of c_bold must be identical to N ( = len(e_bold))" assert len( c_hat_bold ) == N, "The size of c_bold must be identical to N ( = len(e_bold))" assert len(pi.t[3]) == 2, "The size of t_4 must be identical to 2" assert len( t_hat ) == N, "The size of t_hat must be identical to N ( = len(e_bold))" assert len( s_hat ) == N, "The size of s_hat must be identical to N ( = len(e_bold))" h_bold = GetGenerators(N, secparams) u_bold = GetNIZKPChallenges(N, (e_bold, e_prime_bold, c_bold), secparams.tau, secparams) y = (e_bold, e_prime_bold, c_bold, c_hat_bold, pk) c = GetNIZKPChallenge(y, pi.t, secparams.tau, secparams) c_product = mpz(1) for i in range(N): c_product = (c_product * pi.c_bold[i]) % secparams.p h_product = mpz(1) for i in range(N): h_product = (h_product * h_bold[i]) % secparams.p c_line = (c_product * gmpy2.invert(h_product, secparams.p)) % secparams.p u = mpz(1) for i in range(N): u = (u * u_bold[i]) % secparams.q c_hat = (c_hat_bold[N - 1] * gmpy2.invert( gmpy2.powmod(secparams.h, u, secparams.p), secparams.p)) % secparams.p c_product2 = mpz(1) for i in range(N): c_product2 = (c_product2 * gmpy2.powmod(c_bold[i], u_bold[i], secparams.p)) % secparams.p c_tilde = c_product2 % secparams.p a_prime = mpz(1) for i in range(N): a_prime = (a_prime * gmpy2.powmod(e_bold[i].a, u_bold[i], secparams.p)) % secparams.p b_prime = mpz(1) for i in range(N): b_prime = (b_prime * gmpy2.powmod(e_bold[i].b, u_bold[i], secparams.p)) % secparams.p t_prime_1 = (gmpy2.powmod(c_line, -c, secparams.p) * gmpy2.powmod(secparams.g, s_1, secparams.p)) % secparams.p t_prime_2 = (gmpy2.powmod(c_hat, -c, secparams.p) * gmpy2.powmod(secparams.g, s_2, secparams.p)) % secparams.p h_product2 = mpz(1) for i in range(N): h_product2 = (h_product2 * gmpy2.powmod(h_bold[i], s_prime[i], secparams.p)) % secparams.p t_prime_3 = (gmpy2.powmod(c_tilde, -c, secparams.p) * gmpy2.powmod( secparams.g, s_3, secparams.p) * h_product2) % secparams.p a_prime_product = mpz(1) for i in range(N): a_prime_product = (a_prime_product * gmpy2.powmod( e_prime_bold[i].a, s_prime[i], secparams.p)) % secparams.p t_prime_4_1 = (gmpy2.powmod(a_prime, -c, secparams.p) * gmpy2.powmod( pk, -s_4, secparams.p) * a_prime_product) % secparams.p b_prime_product = mpz(1) for i in range(N): b_prime_product = (b_prime_product * gmpy2.powmod( e_prime_bold[i].b, s_prime[i], secparams.p)) % secparams.p t_prime_4_2 = (gmpy2.powmod(b_prime, -c, secparams.p) * gmpy2.powmod( secparams.g, -s_4, secparams.p) * b_prime_product) % secparams.p c_hat_bold_tmp = [] c_hat_bold_tmp.append(secparams.h) c_hat_bold_tmp.extend(c_hat_bold) t_hat_prime_bold = [None] * N for i in range(N): t_hat_prime_bold[i] = ( gmpy2.powmod(c_hat_bold_tmp[i + 1], -c, secparams.p) * gmpy2.powmod(secparams.g, s_hat[i], secparams.p) * gmpy2.powmod( c_hat_bold_tmp[i], s_prime[i], secparams.p)) % secparams.p return (t_1 == t_prime_1) and (t_2 == t_prime_2) and ( t_3 == t_prime_3) and (t_4_1 == t_prime_4_1) and ( t_4_2 == t_prime_4_2) and (t_hat == t_hat_prime_bold)
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)
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 testGetNIZKPChallenge(self): for i in range(100): c = GetNIZKPChallenge("Test", "chvote", secparams_l3.tau, secparams_l3) AssertMpz(c) assert c >= 0 and c <= 2 ^ secparams_l3.tau
def publicKeyShare(self, value): AssertMpz(value) self.state.publicKeyShare = value
def secretKeyShare(self, value): AssertMpz(value) self.state.secretKeyShare = value
def publicKey(self, value): AssertMpz(value) self.state.publicKey = value