def prove_decryption(self, ciphertext): """ given g, y, alpha, beta/(encoded m), prove equality of discrete log with Chaum Pedersen, and that discrete log is x, the secret key. Prover sends a=g^w, b=alpha^w for random w Challenge c = sha1(a,b) with and b in decimal form Prover sends t = w + xc Verifier will check that g^t = a * y^c and alpha^t = b * beta/m ^ c """ m = (Utils.inverse(pow(ciphertext.alpha, self.x, self.pk.p), self.pk.p) * ciphertext.beta) % self.pk.p beta_over_m = (ciphertext.beta * Utils.inverse(m, self.pk.p)) % self.pk.p # pick a random w w = Utils.random_mpz_lt(self.pk.q) a = pow(self.pk.g, w, self.pk.p) b = pow(ciphertext.alpha, w, self.pk.p) c = int(hashlib.sha1(str(a) + "," + str(b)).hexdigest(),16) t = (w + self.x * c) % self.pk.q return m, { 'commitment' : {'A' : str(a), 'B': str(b)}, 'challenge' : str(c), 'response' : str(t) }
def reenc_return_r(self): """ Reencryption with fresh randomness, which is returned. """ r = Utils.random_mpz_lt(self.pk.q) new_c = self.reenc_with_r(r) return [new_c, r]
def encrypt_return_r(self, plaintext): """ Encrypt a plaintext and return the randomness just generated and used. """ r = Utils.random_mpz_lt(self.q) ciphertext = self.encrypt_with_r(plaintext, r) return [ciphertext, r]
def decrypt(self, decryption_factors, public_key): """ decrypt a ciphertext given a list of decryption factors (from multiple trustees) For now, no support for threshold """ running_decryption = self.beta for dec_factor in decryption_factors: running_decryption = (running_decryption * Utils.inverse(dec_factor, public_key.p)) % public_key.p return running_decryption
def simulate_encryption_proof(self, plaintext, challenge=None): # generate a random challenge if not provided if not challenge: challenge = Utils.random_mpz_lt(self.pk.q) proof = ZKProof() proof.challenge = challenge # compute beta/plaintext, the completion of the DH tuple beta_over_plaintext = (self.beta * Utils.inverse(plaintext.m, self.pk.p)) % self.pk.p # random response, does not even need to depend on the challenge proof.response = Utils.random_mpz_lt(self.pk.q); # now we compute A and B proof.commitment['A'] = (Utils.inverse(pow(self.alpha, proof.challenge, self.pk.p), self.pk.p) * pow(self.pk.g, proof.response, self.pk.p)) % self.pk.p proof.commitment['B'] = (Utils.inverse(pow(beta_over_plaintext, proof.challenge, self.pk.p), self.pk.p) * pow(self.pk.y, proof.response, self.pk.p)) % self.pk.p return proof
def __init__(self, c0=None, scheme=None, EG=None): self.coeff = [] self.coeff.append(c0) self.EG = EG self.scheme = scheme self.grade = self.scheme.k - 1 p = self.EG.p for i in range(self.grade): # Dit moet p zijn!!? werkt niet met p..? fout? self.coeff.append(Utils.random_mpz_lt(p))
def generate(self, p, q, g): """ Generate an ElGamal keypair """ self.pk.g = g self.pk.p = p self.pk.q = q self.sk.x = Utils.random_mpz_lt(p) self.pk.y = pow(g, self.sk.x, p) self.sk.public_key = self.pk
def generate(cls, n_bits): """ generate an El-Gamal environment. Returns an instance of ElGamal(), with prime p, group size q, and generator g """ EG = cls() # find a prime p such that (p-1)/2 is prime q EG.p = Utils.random_safe_prime(n_bits) # q is the order of the group # FIXME: not always p-1/2 EG.q = (EG.p-1)/2 # find g that generates the q-order subgroup while True: EG.g = Utils.random_mpz_lt(EG.p) if pow(EG.g, EG.q, EG.p) == 1: break return EG
def prove_sk(self, challenge_generator): """ Generate a PoK of the secret key Prover generates w, a random integer modulo q, and computes commitment = g^w mod p. Verifier provides challenge modulo q. Prover computes response = w + x*challenge mod q, where x is the secret key. """ w = Utils.random_mpz_lt(self.pk.q) commitment = pow(self.pk.g, w, self.pk.p) challenge = challenge_generator(commitment) % self.pk.q response = (w + (self.x * challenge)) % self.pk.q return DLogProof(commitment, challenge, response)
def verify_encryption_proof(self, plaintext, proof): """ Checks for the DDH tuple g, y, alpha, beta/plaintext. (PoK of randomness r.) Proof contains commitment = {A, B}, challenge, response """ # check that g^response = A * alpha^challenge first_check = (pow(self.pk.g, proof.response, self.pk.p) == ((pow(self.alpha, proof.challenge, self.pk.p) * proof.commitment['A']) % self.pk.p)) # check that y^response = B * (beta/m)^challenge beta_over_m = (self.beta * Utils.inverse(plaintext.m, self.pk.p)) % self.pk.p second_check = (pow(self.pk.y, proof.response, self.pk.p) == ((pow(beta_over_m, proof.challenge, self.pk.p) * proof.commitment['B']) % self.pk.p)) # print "1,2: %s %s " % (first_check, second_check) return (first_check and second_check)
def decrypt(self, ciphertext, dec_factor=None, decode_m=False): """ Decrypt a ciphertext. Optional parameter decides whether to encode the message into the proper subgroup. """ if not dec_factor: dec_factor = self.decryption_factor(ciphertext) m = (Utils.inverse(dec_factor, self.pk.p) * ciphertext.beta) % self.pk.p if decode_m: # get m back from the q-order subgroup if m < self.pk.q: y = m else: y = -m % self.pk.p return Plaintext(y-1, self.pk) else: return Plaintext(m, self.pk)
def decrypt(self, ciphertext, dec_factor = None, decode_m=False): """ Decrypt a ciphertext. Optional parameter decides whether to encode the message into the proper subgroup. """ if not dec_factor: dec_factor = self.decryption_factor(ciphertext) m = (Utils.inverse(dec_factor, self.pk.p) * ciphertext.beta) % self.pk.p if decode_m: # get m back from the q-order subgroup if m < self.pk.q: y = m else: y = -m % self.pk.p return Plaintext(y-1, self.pk) else: return Plaintext(m, self.pk)
def generate_encryption_proof(self, plaintext, randomness, challenge_generator): """ Generate the disjunctive encryption proof of encryption """ # random W w = Utils.random_mpz_lt(self.pk.q) # build the proof proof = ZKProof() # compute A=g^w, B=y^w proof.commitment['A'] = pow(self.pk.g, w, self.pk.p) proof.commitment['B'] = pow(self.pk.y, w, self.pk.p) # generate challenge proof.challenge = challenge_generator(proof.commitment); # Compute response = w + randomness * challenge proof.response = (w + (randomness * proof.challenge)) % self.pk.q; return proof;
def generate(cls, little_g, little_h, x, p, q, challenge_generator): """ generate a DDH tuple proof, where challenge generator is almost certainly EG_fiatshamir_challenge_generator """ # generate random w w = Utils.random_mpz_lt(q) # create proof instance proof = cls() # compute A = little_g^w, B=little_h^w proof.commitment['A'] = pow(little_g, w, p) proof.commitment['B'] = pow(little_h, w, p) # get challenge proof.challenge = challenge_generator(proof.commitment) # compute response proof.response = (w + (x * proof.challenge)) % q # return proof return proof