def test_ccp_proof( self, keypair: ElGamalKeyPair, nonce: ElementModQ, seed: ElementModQ, constant: int, bad_constant: int, ): # assume() slows down the test-case generation # so assume(constant != bad_constant) if constant == bad_constant: bad_constant = constant + 1 message = get_optional(elgamal_encrypt(constant, nonce, keypair.public_key)) message_bad = get_optional( elgamal_encrypt(bad_constant, nonce, keypair.public_key) ) proof = make_constant_chaum_pedersen( message, constant, nonce, keypair.public_key, seed ) self.assertTrue(proof.is_valid(message, keypair.public_key)) proof_bad1 = make_constant_chaum_pedersen( message_bad, constant, nonce, keypair.public_key, seed ) self.assertFalse(proof_bad1.is_valid(message_bad, keypair.public_key)) proof_bad2 = make_constant_chaum_pedersen( message, bad_constant, nonce, keypair.public_key, seed ) self.assertFalse(proof_bad2.is_valid(message, keypair.public_key)) proof_bad3 = proof._replace(constant=-1) self.assertFalse(proof_bad3.is_valid(message, keypair.public_key))
def test_ccp_proofs_simple_encryption_of_one(self): keypair = elgamal_keypair_from_secret(TWO_MOD_Q) nonce = ONE_MOD_Q seed = TWO_MOD_Q message = get_optional(elgamal_encrypt(1, nonce, keypair.public_key)) proof = make_constant_chaum_pedersen(message, 1, nonce, keypair.public_key, seed) bad_proof = make_constant_chaum_pedersen(message, 0, nonce, keypair.public_key, seed) self.assertTrue(proof.is_valid(message, keypair.public_key)) self.assertFalse(bad_proof.is_valid(message, keypair.public_key))
def test_encrypt_ballot_with_derivative_nonces_regenerates_valid_proofs( self, keypair: ElGamalKeyPair): """ This test verifies that we can regenerate the contest and selection proofs from the cached nonce values """ # TODO: Hypothesis test instead # Arrange election = election_factory.get_simple_election_from_file() metadata, context = election_factory.get_fake_ciphertext_election( election, keypair.public_key) data = ballot_factory.get_simple_ballot_from_file() self.assertTrue(data.is_valid(metadata.ballot_styles[0].object_id)) device = EncryptionDevice("Location") subject = EncryptionMediator(metadata, context, device) # Act result = subject.encrypt(data) self.assertTrue( result.is_valid_encryption(context.crypto_extended_base_hash, keypair.public_key)) # Assert for contest in result.contests: # Find the contest description contest_description = list( filter(lambda i: i.object_id == contest.object_id, metadata.contests))[0] # Homomorpically accumulate the selection encryptions elgamal_accumulation = elgamal_add( * [selection.message for selection in contest.ballot_selections]) # accumulate the selection nonce's aggregate_nonce = add_q( *[selection.nonce for selection in contest.ballot_selections]) regenerated_constant = make_constant_chaum_pedersen( elgamal_accumulation, contest_description.number_elected, aggregate_nonce, keypair.public_key, add_q(contest.nonce, TWO_MOD_Q), ) self.assertTrue( regenerated_constant.is_valid(elgamal_accumulation, keypair.public_key)) for selection in contest.ballot_selections: # Since we know the nonce, we can decrypt the plaintext representation = selection.message.decrypt_known_nonce( keypair.public_key, selection.nonce) # one could also decrypt with the secret key: # representation = selection.message.decrypt(keypair.secret_key) regenerated_disjuctive = make_disjunctive_chaum_pedersen( selection.message, selection.nonce, keypair.public_key, add_q(selection.nonce, TWO_MOD_Q), representation, ) self.assertTrue( regenerated_disjuctive.is_valid(selection.message, keypair.public_key))