def test_ccp_proof( self, keypair: ElGamalKeyPair, nonce: ElementModQ, seed: ElementModQ, constant: int, bad_constant: int, ): if constant == bad_constant: bad_constant = constant + 1 message = get_optional(elgamal_encrypt(constant, nonce, keypair.public_key)) decryption = message.partial_decrypt(keypair.secret_key) proof = make_chaum_pedersen( message, keypair.secret_key, decryption, seed, ONE_MOD_Q ) bad_proof = make_chaum_pedersen( message, keypair.secret_key, int_to_p(bad_constant), seed, ONE_MOD_Q ) self.assertTrue( proof.is_valid(message, keypair.public_key, decryption, ONE_MOD_Q) ) self.assertFalse( bad_proof.is_valid(message, keypair.public_key, decryption, ONE_MOD_Q) )
def test_cp_proofs_simple(self): keypair = elgamal_keypair_from_secret(TWO_MOD_Q) nonce = ONE_MOD_Q seed = TWO_MOD_Q message = get_optional(elgamal_encrypt(0, nonce, keypair.public_key)) decryption = message.partial_decrypt(keypair.secret_key) proof = make_chaum_pedersen(message, keypair.secret_key, decryption, seed, ONE_MOD_Q) bad_proof = make_chaum_pedersen(message, keypair.secret_key, TWO_MOD_Q, seed, ONE_MOD_Q) self.assertTrue( proof.is_valid(message, keypair.public_key, decryption, ONE_MOD_Q)) self.assertFalse( bad_proof.is_valid(message, keypair.public_key, decryption, ONE_MOD_Q))
def partially_decrypt( guardian_keys: ElectionKeyPair, elgamal: ElGamalCiphertext, extended_base_hash: ElementModQ, nonce_seed: ElementModQ = None, ) -> Tuple[ElementModP, ChaumPedersenProof]: """ Compute a partial decryption of an elgamal encryption :param elgamal: the `ElGamalCiphertext` that will be partially decrypted :param extended_base_hash: the extended base hash of the election that was used to generate t he ElGamal Ciphertext :param nonce_seed: an optional value used to generate the `ChaumPedersenProof` if no value is provided, a random number will be used. :return: a `Tuple[ElementModP, ChaumPedersenProof]` of the decryption and its proof """ if nonce_seed is None: nonce_seed = rand_q() # TODO: ISSUE #47: Decrypt the election secret key # 𝑀_i = 𝐴^𝑠𝑖 mod 𝑝 partial_decryption = elgamal.partial_decrypt( guardian_keys.key_pair.secret_key) # 𝑀_i = 𝐴^𝑠𝑖 mod 𝑝 and 𝐾𝑖 = 𝑔^𝑠𝑖 mod 𝑝 proof = make_chaum_pedersen( message=elgamal, s=guardian_keys.key_pair.secret_key, m=partial_decryption, seed=nonce_seed, hash_header=extended_base_hash, ) return (partial_decryption, proof)
def compensate_decrypt( guardian_auxiliary_keys: AuxiliaryKeyPair, missing_guardian_backup: ElectionPartialKeyBackup, ciphertext: ElGamalCiphertext, extended_base_hash: ElementModQ, nonce_seed: ElementModQ = None, decrypt: AuxiliaryDecrypt = rsa_decrypt, ) -> Optional[Tuple[ElementModP, ChaumPedersenProof]]: """ Compute a compensated partial decryption of an elgamal encryption on behalf of the missing guardian :param guardian_auxiliary_keys: Auxiliary key pair for guardian decrypting :param missing_guardian_backup: Missing guardians backup :param ciphertext: the `ElGamalCiphertext` that will be partially decrypted :param extended_base_hash: the extended base hash of the election that was used to generate t he ElGamal Ciphertext :param nonce_seed: an optional value used to generate the `ChaumPedersenProof` if no value is provided, a random number will be used. :param decrypt: an `AuxiliaryDecrypt` function to decrypt the missing guardina private key backup :return: a `Tuple[ElementModP, ChaumPedersenProof]` of the decryption and its proof """ if nonce_seed is None: nonce_seed = rand_q() decrypted_value = decrypt(missing_guardian_backup.encrypted_value, guardian_auxiliary_keys.secret_key) if decrypted_value is None: log_warning( (f"compensate decrypt guardian {guardian_auxiliary_keys.owner_id}" f" failed decryption for {missing_guardian_backup.owner_id}")) return None partial_secret_key = get_optional(hex_to_q(decrypted_value)) # 𝑀_{𝑖,l} = 𝐴^P𝑖_{l} partial_decryption = ciphertext.partial_decrypt(partial_secret_key) # 𝑀_{𝑖,l} = 𝐴^𝑠𝑖 mod 𝑝 and 𝐾𝑖 = 𝑔^𝑠𝑖 mod 𝑝 proof = make_chaum_pedersen( ciphertext, partial_secret_key, partial_decryption, nonce_seed, extended_base_hash, ) return (partial_decryption, proof)