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 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 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 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 CheckConfirmationProof(pi, y_hat, secparams): """ Algorithm 7.36: Checks the correctness of a NIZKP pi generated by Alg. 7.33. The public value of this proof is the public confirmation credential y_hat. Args: pi: The NIZKP to check y_hat: The public confirmation credential secparams (SecurityParams): Collection of public security parameters Returns: bool: True if the NIZKP is correct, False otherwise. """ AssertClass(secparams, SecurityParams) (t, s) = pi c = GetNIZKPChallenge(y_hat, t, secparams.tau, secparams) t_prime = (gmpy2.powmod(y_hat, -c, secparams.p_hat) * gmpy2.powmod( secparams.g_hat, s, secparams.p_hat)) % secparams.p_hat return t == t_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 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