def reenc_return_r(self): """ Reencryption with fresh randomness, which is returned. """ r = random.mpz_lt(self.pk.q) new_c = self.reenc_with_r(r) return [new_c, r]
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 = (inverse(pow(ciphertext.alpha, self.x, self.pk.p), self.pk.p) * ciphertext.beta) % self.pk.p beta_over_m = (ciphertext.beta * inverse(m, self.pk.p)) % self.pk.p # pick a random w w = 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( SHA1.new(bytes(str(a) + "," + str(b), 'utf-8')).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 encrypt_return_r(self, plaintext): """ Encrypt a plaintext and return the randomness just generated and used. """ r = random.mpz_lt(self.q) ciphertext = self.encrypt_with_r(plaintext, r) return [ciphertext, r]
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 = random.mpz_lt(q) self.pk.y = pow(g, self.sk.x, p) self.sk.public_key = self.pk
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 = 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 simulate_encryption_proof(self, plaintext, challenge=None): # generate a random challenge if not provided if not challenge: challenge = 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 * inverse(plaintext.m, self.pk.p)) % self.pk.p # random response, does not even need to depend on the challenge proof.response = random.mpz_lt(self.pk.q) # now we compute A and B proof.commitment['A'] = ( 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'] = (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 generate_encryption_proof(self, plaintext, randomness, challenge_generator): """ Generate the disjunctive encryption proof of encryption """ # random W w = 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 = 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