示例#1
0
 def test_in_bounds_q(self, q: ElementModQ):
     self.assertTrue(q.is_in_bounds())
     too_big = q.to_int() + Q
     too_small = q.to_int() - Q
     self.assertFalse(int_to_q_unchecked(too_big).is_in_bounds())
     self.assertFalse(int_to_q_unchecked(too_small).is_in_bounds())
     self.assertEqual(None, int_to_q(too_big))
     self.assertEqual(None, int_to_q(too_small))
示例#2
0
    def test_encrypt_ballot_with_stateful_composer_succeeds(self):
        # Arrange
        keypair = elgamal_keypair_from_secret(int_to_q(2))
        manifest = election_factory.get_fake_manifest()
        internal_manifest, context = election_factory.get_fake_ciphertext_election(
            manifest, keypair.public_key)

        data = election_factory.get_fake_ballot(internal_manifest)
        self.assertTrue(
            data.is_valid(internal_manifest.ballot_styles[0].object_id))

        device = election_factory.get_encryption_device()
        subject = EncryptionMediator(internal_manifest, context, device)

        # Act
        result = subject.encrypt(data)

        # Assert
        self.assertIsNotNone(result)
        self.assertTrue(
            result.is_valid_encryption(
                internal_manifest.manifest_hash,
                keypair.public_key,
                context.crypto_extended_base_hash,
            ))
示例#3
0
    def test_encrypt_simple_ballot_from_files_succeeds(self):
        # Arrange
        keypair = elgamal_keypair_from_secret(int_to_q(2))
        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)

        # Assert
        self.assertIsNotNone(result)
        self.assertEqual(data.object_id, result.object_id)
        self.assertTrue(
            result.is_valid_encryption(
                metadata.description_hash,
                keypair.public_key,
                context.crypto_extended_base_hash,
            )
        )
示例#4
0
    def test_encrypt_ballot_simple_succeeds(self):

        # Arrange
        keypair = elgamal_keypair_from_secret(int_to_q(2))
        manifest = election_factory.get_fake_manifest()
        internal_manifest, context = election_factory.get_fake_ciphertext_election(
            manifest, keypair.public_key)
        nonce_seed = TWO_MOD_Q

        # TODO: Ballot Factory
        subject = election_factory.get_fake_ballot(internal_manifest)
        self.assertTrue(
            subject.is_valid(internal_manifest.ballot_styles[0].object_id))

        # Act
        result = encrypt_ballot(subject, internal_manifest, context, SEED)
        result_from_seed = encrypt_ballot(subject, internal_manifest, context,
                                          SEED, nonce_seed)

        # Assert
        self.assertIsNotNone(result)
        self.assertIsNotNone(result.code)
        self.assertIsNotNone(result_from_seed)
        self.assertTrue(
            result.is_valid_encryption(
                internal_manifest.manifest_hash,
                keypair.public_key,
                context.crypto_extended_base_hash,
            ))
        self.assertTrue(
            result_from_seed.is_valid_encryption(
                internal_manifest.manifest_hash,
                keypair.public_key,
                context.crypto_extended_base_hash,
            ))
    def test_cast_ballot(self):
        # Arrange
        keypair = elgamal_keypair_from_secret(int_to_q(2))
        election = election_factory.get_fake_election()
        metadata, context = election_factory.get_fake_ciphertext_election(
            election, keypair.public_key
        )
        store = BallotStore()
        source = election_factory.get_fake_ballot(metadata)
        self.assertTrue(source.is_valid(metadata.ballot_styles[0].object_id))

        # Act
        data = encrypt_ballot(source, metadata, context, SEED_HASH)
        result = accept_ballot(data, BallotBoxState.CAST, metadata, context, store)

        # Assert
        expected = store.get(source.object_id)
        self.assertEqual(expected.state, BallotBoxState.CAST)
        self.assertEqual(result.state, BallotBoxState.CAST)
        self.assertEqual(expected.object_id, result.object_id)

        # Test failure modes
        self.assertIsNone(
            accept_ballot(data, BallotBoxState.CAST, metadata, context, store)
        )  # cannot cast again
        self.assertIsNone(
            accept_ballot(data, BallotBoxState.SPOILED, metadata, context, store)
        )  # cannot cspoil a ballot already cast
示例#6
0
    def test_electionguard_basics(self) -> None:
        plaintexts = range(0, 1000)
        nonces = Nonces(int_to_q(3))
        keypair = elgamal_keypair_random()
        r_public_key = ray.put(keypair.public_key)

        start = timer()
        serial_ciphertexts: List[ElGamalCiphertext] = [
            elgamal_encrypt(p, n, keypair.public_key)
            for p, n in zip(plaintexts, nonces)
        ]
        serial_time = timer()

        # List[ObjectRef[ElGamalCiphertext]
        parallel_ciphertext_objects: List[ObjectRef] = [
            r_encrypt.remote(p, n, r_public_key) for p, n in zip(plaintexts, nonces)
        ]
        parallel_ciphertexts: List[ElGamalCiphertext] = ray.get(
            parallel_ciphertext_objects
        )

        parallel_time = timer()

        self.assertEqual(serial_ciphertexts, parallel_ciphertexts)
        print(
            f"Parallel speedup: {(serial_time - start) / (parallel_time - serial_time):.3f}x"
        )
示例#7
0
    def test_reduce_with_ray_wait_with_progress(
            self, counters: List[int], keypair: ElGamalKeyPair) -> None:
        nonces = Nonces(int_to_q(3))[0:len(counters)]
        pbar = ProgressBar({
            "Ballots": len(counters),
            "Tallies": len(counters),
            "Iterations": 0
        })

        ciphertexts: List[ObjectRef] = [
            r_encrypt.remote(pbar.actor, p, n, keypair.public_key)
            for p, n in zip(counters, nonces)
        ]

        # compute in parallel
        ptotal = ray.get(
            ray_reduce_with_ray_wait(
                inputs=ciphertexts,
                shard_size=3,
                reducer_first_arg=pbar.actor,
                reducer=r_elgamal_add.remote,
                progressbar=pbar,
                progressbar_key="Tallies",
                timeout=None,
                verbose=False,
            ))

        # recompute serially
        stotal = elgamal_add(*ray.get(ciphertexts))

        self.assertEqual(stotal, ptotal)
    def test_encrypt_ballot_simple_succeeds(self):

        # Arrange
        keypair = elgamal_keypair_from_secret(int_to_q(2))
        election = election_factory.get_fake_election()
        metadata, context = election_factory.get_fake_ciphertext_election(
            election, keypair.public_key)
        nonce_seed = TWO_MOD_Q

        # TODO: Ballot Factory
        subject = election_factory.get_fake_ballot(metadata)
        self.assertTrue(subject.is_valid(metadata.ballot_styles[0].object_id))

        # Act
        result = encrypt_ballot(subject, metadata, context, SEED_HASH)
        tracker_code = result.get_tracker_code()
        result_from_seed = encrypt_ballot(subject, metadata, context,
                                          SEED_HASH, nonce_seed)

        # Assert
        self.assertIsNotNone(result)
        self.assertIsNotNone(result.tracking_id)
        self.assertIsNotNone(tracker_code)
        self.assertIsNotNone(result_from_seed)
        self.assertTrue(
            result.is_valid_encryption(context.crypto_extended_base_hash,
                                       keypair.public_key))
        self.assertTrue(
            result_from_seed.is_valid_encryption(
                context.crypto_extended_base_hash, keypair.public_key))
    def test_encrypt_simple_selection_malformed_data_fails(self):

        # Arrange
        keypair = elgamal_keypair_from_secret(int_to_q(2))
        nonce = randbelow(Q)
        metadata = SelectionDescription("some-selection-object-id",
                                        "some-candidate-id", 1)
        hash_context = metadata.crypto_hash()

        subject = selection_from(metadata)
        self.assertTrue(subject.is_valid(metadata.object_id))

        # Act
        result = encrypt_selection(subject, metadata, keypair.public_key,
                                   nonce)

        # tamper with the description_hash
        malformed_description_hash = deepcopy(result)
        malformed_description_hash.description_hash = TWO_MOD_Q

        # remove the proof
        missing_proof = deepcopy(result)
        missing_proof.proof = None

        # Assert
        self.assertFalse(
            malformed_description_hash.is_valid_encryption(
                hash_context, keypair.public_key))
        self.assertFalse(
            missing_proof.is_valid_encryption(hash_context,
                                              keypair.public_key))
示例#10
0
    def test_ballot_box_spoil_ballot(self):
        # Arrange
        keypair = elgamal_keypair_from_secret(int_to_q(2))
        manifest = election_factory.get_fake_manifest()
        internal_manifest, context = election_factory.get_fake_ciphertext_election(
            manifest, keypair.public_key)
        store = DataStore()
        source = election_factory.get_fake_ballot(internal_manifest)
        self.assertTrue(
            source.is_valid(internal_manifest.ballot_styles[0].object_id))

        # Act
        data = encrypt_ballot(source, internal_manifest, context, SEED)
        subject = BallotBox(internal_manifest, context, store)
        result = subject.spoil(data)

        # Assert
        expected = store.get(source.object_id)
        self.assertEqual(expected.state, BallotBoxState.SPOILED)
        self.assertEqual(result.state, BallotBoxState.SPOILED)
        self.assertEqual(expected.object_id, result.object_id)

        # Test failure modes
        self.assertIsNone(subject.spoil(data))  # cannot spoil again
        self.assertIsNone(
            subject.cast(data))  # cannot cast a ballot alraedy spoiled
示例#11
0
    def test_encrypt_simple_contest_referendum_succeeds(self):
        # Arrange
        keypair = elgamal_keypair_from_secret(int_to_q(2))
        nonce = randbelow(Q)
        ballot_selections = [
            SelectionDescription(
                "some-object-id-affirmative", "some-candidate-id-affirmative", 0
            ),
            SelectionDescription(
                "some-object-id-negative", "some-candidate-id-negative", 1
            ),
        ]
        placeholder_selections = [
            SelectionDescription(
                "some-object-id-placeholder", "some-candidate-id-placeholder", 2
            )
        ]
        metadata = ContestDescriptionWithPlaceholders(
            "some-contest-object-id",
            "some-electoral-district-id",
            0,
            VoteVariationType.one_of_m,
            1,
            1,
            "some-referendum-contest-name",
            ballot_selections,
            None,
            None,
            placeholder_selections,
        )
        hash_context = metadata.crypto_hash()

        subject = contest_from(metadata)
        self.assertTrue(
            subject.is_valid(
                metadata.object_id,
                len(metadata.ballot_selections),
                metadata.number_elected,
                metadata.votes_allowed,
            )
        )

        # Act
        result = encrypt_contest(
            subject, metadata, keypair.public_key, ONE_MOD_Q, nonce
        )

        # Assert
        self.assertIsNotNone(result)
        self.assertTrue(
            result.is_valid_encryption(hash_context, keypair.public_key, ONE_MOD_Q)
        )
    def test_encrypt_simple_selection_succeeds(self):

        # Arrange
        keypair = elgamal_keypair_from_secret(int_to_q(2))
        nonce = randbelow(Q)
        metadata = SelectionDescription("some-selection-object-id",
                                        "some-candidate-id", 1)
        hash_context = metadata.crypto_hash()

        subject = selection_from(metadata)
        self.assertTrue(subject.is_valid(metadata.object_id))

        # Act
        result = encrypt_selection(subject, metadata, keypair.public_key,
                                   nonce)

        # Assert
        self.assertIsNotNone(result)
        self.assertIsNotNone(result.message)
        self.assertTrue(
            result.is_valid_encryption(hash_context, keypair.public_key))
示例#13
0
    def setUp(self) -> None:
        # Election setup
        election_factory = ElectionFactory()
        keypair = elgamal_keypair_from_secret(int_to_q(2))
        manifest = election_factory.get_fake_manifest()
        (
            self.internal_manifest,
            self.context,
        ) = election_factory.get_fake_ciphertext_election(
            manifest, keypair.public_key)
        device_hash = ElectionFactory.get_encryption_device().get_hash()

        # Arrange ballots
        self.plaintext_ballot = election_factory.get_fake_ballot(
            self.internal_manifest)
        ciphertext_ballot = encrypt_ballot(self.plaintext_ballot,
                                           self.internal_manifest,
                                           self.context, device_hash)
        self.ballot_nonce = ciphertext_ballot.nonce
        self.submitted_ballot = from_ciphertext_ballot(ciphertext_ballot,
                                                       BallotBoxState.CAST)
示例#14
0
    def test_reduce_with_rounds_without_progress(
            self, counters: List[int], keypair: ElGamalKeyPair) -> None:
        nonces = Nonces(int_to_q(3))[0:len(counters)]

        ciphertexts: List[ObjectRef] = [
            r_encrypt.remote(None, p, n, keypair.public_key)
            for p, n in zip(counters, nonces)
        ]

        # compute in parallel
        ptotal = ray.get(
            ray_reduce_with_rounds(
                inputs=ciphertexts,
                shard_size=3,
                reducer_first_arg=None,
                reducer=r_elgamal_add.remote,
                progressbar=None,
                verbose=True,
            ))

        # recompute serially
        stotal = elgamal_add(*ray.get(ciphertexts))

        self.assertEqual(stotal, ptotal)
示例#15
0
 def test_large_values_rejected_by_int_to_q(self, q: ElementModQ):
     oversize = q.to_int() + Q
     self.assertEqual(None, int_to_q(oversize))
示例#16
0
    def test_ballot_store(self):

        # Arrange
        keypair = elgamal_keypair_from_secret(int_to_q(2))
        election = election_factory.get_fake_election()
        metadata, context = election_factory.get_fake_ciphertext_election(
            election, keypair.public_key)

        # get an encrypted fake ballot to work with
        fake_ballot = election_factory.get_fake_ballot(metadata)
        encrypted_ballot = encrypt_ballot(fake_ballot, metadata, context,
                                          SEED_HASH)

        # Set up the ballot store
        subject = BallotStore()
        data_cast = CiphertextAcceptedBallot(
            encrypted_ballot.object_id,
            encrypted_ballot.ballot_style,
            encrypted_ballot.description_hash,
            encrypted_ballot.previous_tracking_hash,
            encrypted_ballot.contests,
            encrypted_ballot.tracking_hash,
            encrypted_ballot.timestamp,
        )
        data_cast.state = BallotBoxState.CAST

        data_spoiled = CiphertextAcceptedBallot(
            encrypted_ballot.object_id,
            encrypted_ballot.ballot_style,
            encrypted_ballot.description_hash,
            encrypted_ballot.previous_tracking_hash,
            encrypted_ballot.contests,
            encrypted_ballot.tracking_hash,
            encrypted_ballot.timestamp,
        )
        data_spoiled.state = BallotBoxState.SPOILED

        self.assertIsNone(subject.get("cast"))
        self.assertIsNone(subject.get("spoiled"))

        # try to set a ballot with an unknown state
        self.assertFalse(
            subject.set(
                "unknown",
                CiphertextAcceptedBallot(
                    encrypted_ballot.object_id,
                    encrypted_ballot.ballot_style,
                    encrypted_ballot.description_hash,
                    encrypted_ballot.previous_tracking_hash,
                    encrypted_ballot.contests,
                    encrypted_ballot.tracking_hash,
                    encrypted_ballot.timestamp,
                ),
            ))

        # Act
        self.assertTrue(subject.set("cast", data_cast))
        self.assertTrue(subject.set("spoiled", data_spoiled))

        self.assertEqual(subject.get("cast"), data_cast)
        self.assertEqual(subject.get("spoiled"), data_spoiled)

        self.assertEqual(subject.exists("cast"), (True, data_cast))
        self.assertEqual(subject.exists("spoiled"), (True, data_spoiled))

        # test mutate state
        data_cast.state = BallotBoxState.UNKNOWN
        self.assertEqual(subject.exists("cast"), (False, data_cast))

        # test remove
        self.assertTrue(subject.set("cast", None))
        self.assertEqual(subject.exists("cast"), (False, None))
示例#17
0
    def test_cached(self, exp: int):
        plaintext = get_optional(int_to_q(exp))
        exp_plaintext = g_pow_p(plaintext)
        plaintext_again = discrete_log(exp_plaintext)

        self.assertEqual(exp, plaintext_again)