def test_decrypt_selection_valid_input_succeeds(
        self,
        selection_description: Tuple[str, SelectionDescription],
        keypair: ElGamalKeyPair,
        nonce_seed: ElementModQ,
        random_seed: int,
    ):

        # Arrange
        random = Random(random_seed)
        _, description = selection_description
        data = ballot_factory.get_random_selection_from(description, random)

        # Act
        subject = encrypt_selection(data, description, keypair.public_key, nonce_seed)
        self.assertIsNotNone(subject)

        result_from_key = decrypt_selection_with_secret(
            subject, description, keypair.public_key, keypair.secret_key
        )
        result_from_nonce = decrypt_selection_with_nonce(
            subject, description, keypair.public_key
        )
        result_from_nonce_seed = decrypt_selection_with_nonce(
            subject, description, keypair.public_key, nonce_seed
        )

        # Assert
        self.assertIsNotNone(result_from_key)
        self.assertIsNotNone(result_from_nonce)
        self.assertIsNotNone(result_from_nonce_seed)
        self.assertEqual(data.plaintext, result_from_key.plaintext)
        self.assertEqual(data.plaintext, result_from_nonce.plaintext)
        self.assertEqual(data.plaintext, result_from_nonce_seed.plaintext)
    def test_decrypt_selection_valid_input_tampered_fails(
        self,
        selection_description: Tuple[str, SelectionDescription],
        keypair: ElGamalKeyPair,
        seed: ElementModQ,
        random_seed: int,
    ):

        # Arrange
        _, description = selection_description
        random = Random(random_seed)
        data = ballot_factory.get_random_selection_from(description, random)

        # Act
        subject = encrypt_selection(data, description, keypair.public_key,
                                    seed)

        # tamper with the encryption
        malformed_encryption = deepcopy(subject)
        malformed_message = malformed_encryption.ciphertext._replace(
            pad=mult_p(subject.ciphertext.pad, TWO_MOD_P))
        malformed_encryption.ciphertext = malformed_message

        # tamper with the proof
        malformed_proof = deepcopy(subject)
        altered_a0 = mult_p(subject.proof.a0, TWO_MOD_P)
        malformed_disjunctive = DisjunctiveChaumPedersenProof(
            altered_a0,
            malformed_proof.proof.b0,
            malformed_proof.proof.a1,
            malformed_proof.proof.b1,
            malformed_proof.proof.c0,
            malformed_proof.proof.c1,
            malformed_proof.proof.v0,
            malformed_proof.proof.v1,
        )
        malformed_proof.proof = malformed_disjunctive

        result_from_key_malformed_encryption = decrypt_selection_with_secret(
            malformed_encryption, description, keypair.public_key,
            keypair.secret_key)

        result_from_key_malformed_proof = decrypt_selection_with_secret(
            malformed_proof, description, keypair.public_key,
            keypair.secret_key)

        result_from_nonce_malformed_encryption = decrypt_selection_with_nonce(
            malformed_encryption, description, keypair.public_key)
        result_from_nonce_malformed_proof = decrypt_selection_with_nonce(
            malformed_proof, description, keypair.public_key)

        # Assert
        self.assertIsNone(result_from_key_malformed_encryption)
        self.assertIsNone(result_from_key_malformed_proof)
        self.assertIsNone(result_from_nonce_malformed_encryption)
        self.assertIsNone(result_from_nonce_malformed_proof)
    def test_decrypt_selection_tampered_nonce_fails(
        self,
        selection_description: Tuple[str, SelectionDescription],
        keypair: ElGamalKeyPair,
        nonce_seed: ElementModQ,
        random_seed: int,
    ):

        # Arrange
        random = Random(random_seed)
        _, description = selection_description
        data = ballot_factory.get_random_selection_from(description, random)

        # Act
        subject = encrypt_selection(data, description, keypair.public_key, nonce_seed)
        self.assertIsNotNone(subject)

        # Tamper with the nonce by setting it to an aribtrary value
        subject.nonce = nonce_seed

        result_from_nonce_seed = decrypt_selection_with_nonce(
            subject, description, keypair.public_key, nonce_seed
        )

        # Assert
        self.assertIsNone(result_from_nonce_seed)