def GetNIZKPChallenges(n, y, kappa, secparams): """ Algorithm 7.5: Computes n challenges c ∈ Z_q for a given of public value y. The domain Y of the input value is unspecified. The results in c = (c_1, ..., c_n) are identical to c_i = RecHash(y, i), but precomputing H makes the algorithm more efficient. Args: y (unspecified): Public value t (unspecified): Commitment kappa (int): Soundness strength 1 <= kappa <= 8L secparams (SecurityParams): Collection of public security parameters Retuns: list of mpz: List containing n computed challenges (mpz) """ AssertInt(n) AssertInt(kappa) assert kappa >= 1 and kappa <= 8 * secparams.L, "Constraint for kappa: 1 <= kappa <= 8L" AssertClass(secparams, SecurityParams) H = RecHash(y, secparams) c = [] for i in range(1, n + 1): I = RecHash(i, secparams) c.append(mpz(ToInteger(secparams.hash(H + I)) % 2 ^ kappa)) return c
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 GetFinalization(v, P_bold, B, secparams): """ Algorithm 7.36: Computes the finalization code F_v for voter v from the given points p_i and returns F_v together with the randomizations r_v used in the OT response. Args: v (int): Voter index p_bold (list of points): Points B (list): Ballot list secparams (SecurityParams): Collection of public security parameters Returns: tuple: delta (F_v, r_bold_v) """ AssertInt(v) AssertList(P_bold) AssertList(B) AssertClass(secparams, SecurityParams) p_bold_v = P_bold[v] F = Truncate(RecHash(p_bold_v, secparams), secparams.L_F) for i in range(len(B)): if (B[i].voterId == v): z_i = B[i].randomizations delta = (F, z_i) return delta
def GetReturnCodes(s_bold, P_s_bold, secparams): """ Algorithm 7.28: Computes the k return codes rcs = (RC_s_1, ... , RC_s_k) for the selected candidates by combining the hash values of the transferred points p_ij in P_s from different authorities. Args: s_bold (list of int): Selections P_s_bold (list of Point): Points secparams (SecurityParams): Collection of public security parameters Returns: list Points """ AssertList(s_bold) AssertList(P_s_bold) AssertClass(secparams, SecurityParams) rc_s_bold = [] k = len(s_bold) s = len(P_s_bold) for i in range(k): R_j = [] for j in range(s): R_j.append(Truncate(RecHash(P_s_bold[j][i], secparams), secparams.L_R)) R = MarkByteArray(XorByteArray(R_j), s_bold[i], secparams.n_max) rc_s_bold.append(ByteArrayToString(R, secparams.A_R)) return rc_s_bold
def testGetNIZKPChallenges(self): # The results in c should be identical to c_i = ToInteger(RecHash(y,i)): c = GetNIZKPChallenges(50, mpz(1234), secparams_l3.tau, secparams_l3) self.assertEqual(len(c), 50) for i in range(1, len(c) + 1): self.assertEqual( c[i - 1], ToInteger(RecHash([mpz(1234), i], secparams_l3)) % 2 ^ secparams_l3.tau)
def GetPoints(beta, s_bold, r_bold, secparams): """ Algorithm 7.26: Computes the k-by-s matrix P_s = (P_ij)k x s of the points obtained from the s authorities for the selection s. The points are derived from the messages included in the OT responses beta = (beta_1, ..., beta_s) Args: beta (Response): Oblivious Transfer Response s_bold (list of int): Selections r_bold (list of mpz): Randomizations secparams (SecurityParams): Collection of public security parameters Returns: list Points """ AssertClass(beta, Response) AssertList(s_bold) AssertList(r_bold) AssertClass(secparams, SecurityParams) (b_bold, C_bold, d) = beta k = len(s_bold) l_M = ceil(secparams.L_M // secparams.L) p_bold = [] for j in range(k): k_j = (b_bold[j] * gmpy2.powmod(d, -r_bold[j], secparams.p)) % secparams.p K_j = bytearray() for c in range(l_M): K_j += RecHash([k_j, c], secparams) K_j = Truncate(K_j, secparams.L_M) M_j = XorByteArray([C_bold[s_bold[j]][j], K_j]) x_j = ToInteger(Truncate(M_j, secparams.L_M // 2)) y_j = ToInteger(Skip(M_j, secparams.L_M // 2)) if x_j >= secparams.p_prime or y_j >= secparams.p_prime: return None p_bold.append(Point(x_j, y_j)) return p_bold
def GetNIZKPChallenge(y, t, kappa, secparams): """ Algorithm 7.4: Computes a NIZKP challenge c ∈ Z_q for a given public value y and a public commitment t. The domains Y and T of the input values are unspecified. Args: y (unspecified): Public value t (unspecified): Commitment kappa (int): Soundness strength 1 <= kappa <= 8L secparams (SecurityParams): Collection of public security parameters Returns: mpz: The NIZKP challenge """ AssertInt(kappa) assert kappa >= 1 and kappa <= 8 * secparams.L, "Constraint for kappa: 1 <= kappa <= 8L" AssertClass(secparams, SecurityParams) c = mpz(ToInteger(RecHash([y, t], secparams)) % 2 ^ kappa) return c
def GetGenerators(n, secparams): """ Algorithm 7.3: Computes n independent generators of G_q. The algorithm is an adaption of the NIST standard FIPS PUB 186-4 [1, Appendix A.2.3]. The string "chVote" guarantees that the resulting values are specific for chVote. In a more efficient implementation of this algorithm, the list of resulting generators is accumulated in a cache or precomputed for the largest expected value n_max >= n. Args: n (int): The number of primes to be calculated secparams (SecurityParams): Collection of public security parameters Returns: list of mpz: a list with independent generators of G_p (mpz) """ AssertInt(n) AssertClass(secparams, SecurityParams) assert n >= 0, "n must be greater than or equal 0" generators = [] for i in range(n): x = 0 while True: x += 1 h = mpz( ToInteger(RecHash(["chVote", "ggen", i, x], secparams)) % secparams.p) h = (h**2) % secparams.p if h not in (0, 1): break generators.append(h) return generators
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)