def prove_decrypt_batched(self, ciphertext_batch): """Batched version of `prove_decrypt()` Arguments: ciphertext_batch (list): the ciphertexts (PaillierCiphertext) to be decrypted in a verifiable manner Returns: tuple: `partial_decryption_batch`, `proof` where `partial_decryption_batch` is a list of the partial decryptions (int) of the ciphertexts, and `proof` is a proof (int) that they are indeed so """ pk = self.public_key partial_decryption_batch = [ self.decrypt(ciphertext) for ciphertext in ciphertext_batch ] # run protocol in the Fiat-Shamir heuristic # to aggregate ZKPs, the verifier provides λ_i *after* the plaintexts # have been provided; then combined_ciphertext = ∏ ciphertext^{λ_i} # and combined_plaintext = ∏ m^{λ_i} (not needed for prover) lambda_batch = [ util.H([ciphertext.raw_value, partial_decryption]) for ciphertext, partial_decryption in zip( ciphertext_batch, partial_decryption_batch) ] combined_plaintext = util.prod( util.powmod(plaintext, lambda_, pk.n) for plaintext, lambda_ in zip(partial_decryption_batch, lambda_batch)) combined_ciphertext = util.prod( util.powmod(ciphertext.raw_value, lambda_, pk.n) for ciphertext, lambda_ in zip(ciphertext_batch, lambda_batch)) try: # raises IndexError if not enough precomputations were forecast r, t1 = self.precomputed_values.pop() except AttributeError: # no pre-computations r = random.SystemRandom().randrange(pk.n << (2 * pk.security_parameter)) t1 = util.powmod(self.verification_base, r, pk.n) # prove knowledge of key_share such that: # * v_i = v**key_share # * combined_plaintext**2 = (combined_ciphertext**2)**(2*key_share) t2 = util.powmod(combined_ciphertext, _CP * _QR * r, pk.n) h = util.H([ combined_ciphertext, combined_plaintext, t1, self.verification_base, self.verification, t2, ]) w = r + h * self.key_share proof = t1, t2, w return partial_decryption_batch, proof
def f2(pa): # called after getting (s, B) B, I, s, v, g, a, A = int(pa[0][1]), pa[1], int( pa[0][0]), pa[3], pa[4], pa[5], pa[6] u = util.H([A, B]) % util.N x = util.H(list(itertools.chain([ord(c) for c in util.p], [s]))) Kclient = pow((B - util.k * v), a + u * x, util.N) pa.append(Kclient) m1 = util.H([A, B, Kclient]) pa.append(m1) pa[0] = [m1] return pa
def check_challenge(m1, clientMap): # m1 - client's response, assuming just 1 client and called in right order for key in clientMap: m = clientMap[key] A = m[2] v = m[1] b = m[3] B = m[5] u = util.H([A, B]) % util.N Kserv = pow(A * (pow(v, u, util.N)), b, util.N) m[4] = Kserv m0 = util.H([A, B, Kserv]) return int(m1[0]) == m0 return None
def verify_decrypt_batched(self, ciphertext_batch, partial_decryption_batch, proof): """Batched version of `verify_decrypt()` Arguments: ciphertext_batch (list): the ciphertexts (PaillierCiphertext) to be decrypted in a verifiable manner partial_decryption_batch (list): the corresponding partial decryptions (int) proof: a proof that each element of `partial_decryption_batch` is indeed a partial decryption of the corresponding element in `ciphertext_batch` under the secret key corresponding to self """ pk = self.public_key # run protocol in the Fiat-Shamir heuristic t1, t2, w = proof # generate random λ_i *after* decryption shares have been provided lambda_batch = [ util.H([ciphertext.raw_value, partial_decryption]) for ciphertext, partial_decryption in zip( ciphertext_batch, partial_decryption_batch) ] # compute combined plaintext and ciphertext for verification combined_plaintext = util.prod( util.powmod(plaintext, lambda_, pk.n) for plaintext, lambda_ in zip(partial_decryption_batch, lambda_batch)) combined_ciphertext = util.prod( util.powmod(ciphertext.raw_value, lambda_, pk.n) for ciphertext, lambda_ in zip(ciphertext_batch, lambda_batch)) h = util.H([ combined_ciphertext, combined_plaintext, t1, self.verification_base, self.verification, t2, ]) # verify proof # check that v^s = t_1 * v_i^c if util.powmod(self.verification_base, w, pk.n) != \ t1 * util.powmod(self.verification, h, pk.n) % pk.n: raise InvalidProof # check that (x^2)^s = t_2 * (m^2)^c if util.powmod(combined_ciphertext, _CP*_QR*w, pk.n) != \ t2 * util.powmod(combined_plaintext, _CP*h, pk.n) % pk.n: raise InvalidProof
def verify_decrypt(self, ciphertext, partial_decryption, proof): """Check the proof of decryption of the corresponding secret key Arguments: ciphertext (PaillierCiphertext): the ciphertext to be decrypted in a verifiable manner partial_decryption (int): the corresponding partial decryption proof (int): a proof that `partial_decryption` is indeed a partial decryption of `ciphertext` under the corresponding secret key """ pk = self.public_key # run Chaum-Pedersen protocol in the Fiat-Shamir heuristic t1, t2, w = proof h = util.H([ ciphertext.raw_value, partial_decryption, t1, self.verification_base, self.verification, t2, ]) # verify proof # check that v^s = t_1 * v_i^c if util.powmod(self.verification_base, w, pk.n) != \ t1 * util.powmod(self.verification, h, pk.n) % pk.n: raise InvalidProof # check that (x^2)^s = t_2 * (m^2)^c if util.powmod(ciphertext.raw_value, _CP*_QR*w, pk.n) != \ t2 * util.powmod(partial_decryption, _CP*h, pk.n) % pk.n: raise InvalidProof
def Verify(m, p, q, g, pubKey, r, s): # 驗證簽章 assert r >= 0 and r < q and s >= 0 and s < q w = util.ModInv(s, q) u1 = (util.H(m) * w) % q u2 = (r * w) % q v = ((util.SQandMU(g, u1, p) * util.SQandMU(pubKey, u2, p)) % p) % q return v % q == r % q
def f0( pa ): # NOTE: The first element in the returned array will be used for sending and receiving server messages. util.q, util.N, util.g, util.k, util.nL = int(pa[0][0]), int( pa[0][1]), int(pa[0][2]), int(pa[0][3]), int(pa[0][4]) s = util.getSalt() x = util.H(list(itertools.chain([ord(c) for c in util.p], [s]))) v = pow(util.g, x, util.N) del x return [(util.I, s, v), util.I, s, v, util.g]
def f3(pa): global fmt fmt = "" m2, A, Kclient, m1 = pa[0], pa[6], pa[-2], pa[-1] if util.H([A, m1, Kclient]) == int(m2[0]): print("Client: Success") pa[0] = [util.encryptFile(plaintext_filename, Kclient)] return pa[0] else: print("Client: Not Success") exit(1)
def verify_private_multiply_batched(self, cx, cy_list, cz_list, proof): """Check the proof of multiplication of a ciphertext with a plaintext Arguments: cx (PaillierCiphertext): the encrypted left operand cy_list (list): the encrypted right operands (PaillierCiphertext) cz_list (list): the encrypted products (PaillierCiphertext) of x*y for each y in `cy_list` proof (int): a proof that z = x*y for each y, z in cy_list, cz_list """ n2 = self.nsquare # generate random λ_i *after* ciphertexts have been provided cu, cyu, w, rs, rys = proof lambda_list = [ util.H([cx, cy, cz]) for cy, cz in zip(cy_list, cz_list) ] # compute combined ciphertexts cy = util.prod( util.powmod(cy, lambda_, self.nsquare) for cy, lambda_ in zip(cy_list, lambda_list)) cz = util.prod( util.powmod(cz, lambda_, self.nsquare) for cz, lambda_ in zip(cz_list, lambda_list)) # run private multiply protocol in the Fiat-Shamir heuristic h = util.H([cx, cy, cz, cu, cyu]) # verify proofs cs, _ = self.raw_multiply(self.g, w, rs) # ⟦s⟧ = ⟦u + xe⟧ cys, _ = self.raw_multiply(cy, w, rys) # ⟦ys⟧ = ⟦y(u + xe)⟧ # ⟦u⟧ * ⟦x⟧**e = ⟦u + xe⟧ = ⟦s⟧ if cs != cu * util.powmod(cx, h, n2) % n2: raise InvalidProof # ⟦yu⟧ * ⟦z⟧**e = ⟦yu + yxe⟧ = ⟦ys⟧ if cys != cyu * util.powmod(cz, h, n2) % n2: raise InvalidProof
def Sign(m, p, q, g, priKey): # 簽章 r, s = 0, 0 while 1: k = random.randrange(1, q) r = util.SQandMU(g, k, p) % q if (r == 0): continue # 發生R=0的情況,試另一組k dk = util.ModInv(k, q) s = (dk * (util.H(m) + priKey * r)) % q if (s != 0): break return r, s
def verify_knowledge(self, proof): """Check the proof of knowledge of the corresponding secret key Arguments: proof (int): a proof of knowledge of the secret key """ pk = self.public_key # run Schnorr protocol in the Fiat-Shamir heuristic t, w = proof h = util.H([self.verification_base, self.verification, t]) # verify proof if util.powmod(self.verification_base, w, pk.n) != \ t * util.powmod(self.verification, h, pk.n) % pk.n: raise InvalidProof
def prove_private_multiply(self, x, cy): """Multiply a ciphertext with a plaintext in a verifiable manner Arguments: x (int): the clear operand cy (PaillierCiphertext): the encrypted operand Returns: tuple: `cx`, `cz`, `proof` where `cx` is an encryption (PaillierCiphertext) of x, `cz` is an encryption (PaillierCiphertext) of x*y and `proof` is a proof (int) that z = x * y """ n2 = self.nsquare # precomputable values try: # raises IndexError if not enough precomputations were forecast x_, (cx, rx), u, (cu, ru) = self.precomputed_values.pop() except AttributeError: # no pre-computations u = random.SystemRandom().randrange(self.n) cx, rx = self.raw_multiply(self.g, x) # ⟦x⟧ cu, ru = self.raw_multiply(self.g, u) # ⟦u⟧ else: # ensure consistency with arguments if x is None: x = x_ elif x != x_: raise ValueError # other encrypted values cz, rz = self.raw_multiply(cy, x) # ⟦z⟧ = ⟦xy⟧ cyu, ryu = self.raw_multiply(cy, u) # ⟦yu⟧ # run protocol in the Fiat-Shamir heuristic h = util.H([cx, cy, cz, cu, cyu]) rs = ru * util.powmod(rx, h, self.n) % self.n rys = ryu * util.powmod(rz, h, self.n) % self.n w = u + x * h proof = cu, cyu, w, rs, rys return cx, cz, proof
def prove_decrypt(self, ciphertext): """(Partially) decrypt a ciphertext in a verifiable manner Arguments: ciphertext (PaillierCiphertext): the ciphertext to be decrypted Returns: tuple: `partial_decryption`, `proof` where `partial_decryption` is the partial decryption (int) of the ciphertext, and `proof` is a proof (int) that it is indeed so """ pk = self.public_key partial_decryption = self.decrypt(ciphertext) try: # raises IndexError if not enough precomputations were forecast r, t1 = self.precomputed_values.pop() except AttributeError: # no pre-computations r = random.SystemRandom().randrange(pk.n << (2 * pk.security_parameter)) t1 = util.powmod(self.verification_base, r, pk.n) # prove knowledge of key_share such that: # * v_i = v**key_share # * (partial_decryption**2) = (ciphertext**2)**(2*key_share) t2 = util.powmod(ciphertext.raw_value, _CP * _QR * r, pk.n) # run Chaum-Pedersen protocol in the Fiat-Shamir heuristic h = util.H([ ciphertext.raw_value, partial_decryption, t1, self.verification_base, self.verification, t2, ]) w = r + h * self.key_share proof = t1, t2, w return partial_decryption, proof
def prove_knowledge(self): """Proves knowldege of the secret key share Returns: int: the proof """ pk = self.public_key try: # raises IndexError if not enough precomputations were forecast r, t = self.precomputed_values.pop() except AttributeError: # no pre-computations r = random.SystemRandom().randrange(pk.n << (2 * pk.security_parameter)) t = util.powmod(self.verification_base, r, pk.n) # run Schnorr protocol in the Fiat-Shamir heuristic h = util.H([self.verification_base, self.verification, t]) w = r + h * self.key_share proof = t, w return proof
def verify_private_multiply(self, cx, cy, cz, proof): """Check the proof of multiplication of a ciphertext with a plaintext Arguments: cx (int): the encrypted left operand cy (int): the encrypted right operand cz (int): the encrypted result proof (int): a proof that z = x*y """ n2 = self.nsquare # run protocol in the Fiat-Shamir heuristic cu, cyu, w, rs, rys = proof h = util.H([cx, cy, cz, cu, cyu]) # verify proofs cs, _ = self.raw_multiply(self.g, w, rs) # ⟦s⟧ = ⟦u + xe⟧ cys, _ = self.raw_multiply(cy, w, rys) # ⟦ys⟧ = ⟦y(u + xe)⟧ # ⟦u⟧ * ⟦x⟧**e = ⟦u + xe⟧ = ⟦s⟧ if cs != cu * util.powmod(cx, h, n2) % n2: raise InvalidProof # ⟦yu⟧ * ⟦z⟧**e = ⟦yu + yxe⟧ = ⟦ys⟧ if cys != cyu * util.powmod(cz, h, n2) % n2: raise InvalidProof
def auth_successful(m1, clientMap): for key in clientMap: m = clientMap[key] return util.numbersToByteArr([util.H([m[2], int(m1[0]), m[4]])]) return None
def prove_private_multiply_batched(self, x, cy_list): """Multiply a secret with several ciphertexts in a verifiable manner Arguments: x (int): the secret operand (plaintext) cy_list (list): the list of encrypted operands (PaillierCiphertext) Returns: tuple: `cx`, `cz_list`, `proof` where `cx` is an encryption (PaillierCiphertext) of x, `cz_list` is a list of encryptions (PaillierCiphertext) of x*y for each y in `cy_list`, and `proof` (int) is a proof that z = x*y for each y, z in cy_list, cz_list """ n2 = self.nsquare # precomputable values try: # raises IndexError if not enough precomputations were forecast x_, (cx, rx), u, (cu, ru) = self.precomputed_values.pop() except AttributeError: # no pre-computations u = random.SystemRandom().randrange(self.n) cx, rx = self.raw_multiply(self.g, x) # ⟦x⟧ cu, ru = self.raw_multiply(self.g, u) # ⟦u⟧ else: # ensure consistency with arguments if x is None: x = x_ elif x != x_: raise ValueError # encrypted result cz_rz_list = [self.raw_multiply(cy, x) for cy in cy_list] # ⟦z⟧ = ⟦xy⟧ cz_list = [cz for cz, rz in cz_rz_list] rz_list = [rz for cz, rz in cz_rz_list] lambda_list = [ util.H([cx, cy, cz]) for cy, cz in zip(cy_list, cz_list) ] # compute combined ciphertexts cy = util.prod( util.powmod(cy, lambda_, self.nsquare) for cy, lambda_ in zip(cy_list, lambda_list)) cz = util.prod( util.powmod(cz, lambda_, self.nsquare) for cz, lambda_ in zip(cz_list, lambda_list)) rz = util.prod( util.powmod(rz, lambda_, self.n) for rz, lambda_ in zip(rz_list, lambda_list)) # other encrypted values cyu, ryu = self.raw_multiply(cy, u) # ⟦yu⟧ # run private multiply protocol in the Fiat-Shamir heuristic h = util.H([cx, cy, cz, cu, cyu]) rs = ru * util.powmod(rx, h, self.n) % self.n rys = ryu * util.powmod(rz, h, self.n) % self.n w = u + x * h proof = cu, cyu, w, rs, rys return cx, cz_list, proof
def register(): s = random.randrange(1000, 9999) # needs to be cryptographically suitable random x = util.H(list(itertools.chain([ord(c) for c in util.p], [s]))) v = pow(util.g, x, util.N)