def test_publish(self) -> None:
        # Arrange
        now = datetime.now(timezone.utc)
        description = ElectionDescription(
            "", ElectionType.unknown, now, now, [], [], [], [], [], []
        )
        context = CiphertextElectionContext(1, 1, ONE_MOD_P, ONE_MOD_Q)
        constants = ElectionConstants()
        devices = []
        coefficients = [CoefficientValidationSet("", [], [])]
        encrypted_ballots = []
        tally = PlaintextTally("", [], [])

        # Act
        publish(
            description,
            context,
            constants,
            devices,
            encrypted_ballots,
            CiphertextTally("", description, context),
            tally,
            coefficients,
        )

        # Assert
        self.assertTrue(path.exists(RESULTS_DIR))

        # Cleanup
        rmtree(RESULTS_DIR)
Exemple #2
0
    def verify_results(self) -> None:
        """Verify results of election"""

        # Deserialize
        description_from_file = ElectionDescription.from_json_file(
            DESCRIPTION_FILE_NAME, RESULTS_DIR
        )
        self.assertEqual(self.description, description_from_file)

        context_from_file = CiphertextElectionContext.from_json_file(
            CONTEXT_FILE_NAME, RESULTS_DIR
        )
        self.assertEqual(self.context, context_from_file)

        constants_from_file = ElectionConstants.from_json_file(
            CONSTANTS_FILE_NAME, RESULTS_DIR
        )
        self.assertEqual(self.constants, constants_from_file)

        device_name = DEVICE_PREFIX + str(self.device.uuid)
        device_from_file = EncryptionDevice.from_json_file(device_name, DEVICES_DIR)
        self.assertEqual(self.device, device_from_file)

        ciphertext_ballots: List[CiphertextAcceptedBallot] = []
        for ballot in self.ballot_store.all():
            ballot_name = BALLOT_PREFIX + ballot.object_id
            ballot_from_file = CiphertextAcceptedBallot.from_json_file(
                ballot_name, BALLOTS_DIR
            )
            self.assertEqual(ballot, ballot_from_file)

        spoiled_ballots: List[CiphertextAcceptedBallot] = []
        for spoiled_ballot in self.ciphertext_tally.spoiled_ballots.values():
            ballot_name = BALLOT_PREFIX + spoiled_ballot.object_id
            spoiled_ballot_from_file = CiphertextAcceptedBallot.from_json_file(
                ballot_name, SPOILED_DIR
            )
            self.assertEqual(spoiled_ballot, spoiled_ballot_from_file)

        ciphertext_tally_from_file = PublishedCiphertextTally.from_json_file(
            ENCRYPTED_TALLY_FILE_NAME, RESULTS_DIR
        )
        self.assertEqual(
            publish_ciphertext_tally(self.ciphertext_tally), ciphertext_tally_from_file
        )

        plainttext_tally_from_file = PlaintextTally.from_json_file(
            TALLY_FILE_NAME, RESULTS_DIR
        )
        self.assertEqual(self.plaintext_tally, plainttext_tally_from_file)

        coefficient_validation_sets: List[CoefficientValidationSet] = []
        for coefficient_validation_set in self.coefficient_validation_sets:
            set_name = COEFFICIENT_PREFIX + coefficient_validation_set.owner_id
            coefficient_validation_set_from_file = CoefficientValidationSet.from_json_file(
                set_name, COEFFICIENTS_DIR
            )
            self.assertEqual(
                coefficient_validation_set, coefficient_validation_set_from_file
            )
    def test_publish(self) -> None:
        # Arrange
        now = datetime.now(timezone.utc)
        manifest = Manifest("", ElectionType.unknown, now, now, [], [], [], [], [], [])
        context = make_ciphertext_election_context(
            1, 1, ONE_MOD_P, ONE_MOD_Q, ONE_MOD_Q
        )
        constants = ElectionConstants()
        devices = []
        guardian_records = [GuardianRecord("", "", ONE_MOD_Q, [], [])]
        encrypted_ballots = []
        spoiled_ballots = []
        plaintext_tally = PlaintextTally("", [])
        ciphertext_tally = CiphertextTally("", manifest, context)

        # Act
        publish(
            manifest,
            context,
            constants,
            devices,
            encrypted_ballots,
            spoiled_ballots,
            ciphertext_tally.publish(),
            plaintext_tally,
            guardian_records,
        )

        # Assert
        self.assertTrue(path.exists(RESULTS_DIR))

        # Cleanup
        rmtree(RESULTS_DIR)
    def verify_results(self) -> None:
        """Verify results of election"""

        # Deserialize
        manifest_from_file = Manifest.from_json_file(MANIFEST_FILE_NAME,
                                                     RESULTS_DIR)
        self.assertEqual(self.manifest, manifest_from_file)

        context_from_file = CiphertextElectionContext.from_json_file(
            CONTEXT_FILE_NAME, RESULTS_DIR)
        self.assertEqual(self.context, context_from_file)

        constants_from_file = ElectionConstants.from_json_file(
            CONSTANTS_FILE_NAME, RESULTS_DIR)
        self.assertEqual(self.constants, constants_from_file)

        device_name = DEVICE_PREFIX + str(self.device.uuid)
        device_from_file = EncryptionDevice.from_json_file(
            device_name, DEVICES_DIR)
        self.assertEqual(self.device, device_from_file)

        for ballot in self.ballot_store.all():
            name = BALLOT_PREFIX + ballot.object_id
            ballot_from_file = SubmittedBallot.from_json_file(
                name, BALLOTS_DIR)
            self.assertEqual(ballot, ballot_from_file)

        for spoiled_ballot in self.plaintext_spoiled_ballots.values():
            name = BALLOT_PREFIX + spoiled_ballot.object_id
            spoiled_ballot_from_file = PlaintextTally.from_json_file(
                name, SPOILED_DIR)
            self.assertEqual(spoiled_ballot, spoiled_ballot_from_file)

        published_ciphertext_tally_from_file = PublishedCiphertextTally.from_json_file(
            ENCRYPTED_TALLY_FILE_NAME, RESULTS_DIR)
        self.assertEqual(self.ciphertext_tally.publish(),
                         published_ciphertext_tally_from_file)

        plainttext_tally_from_file = PlaintextTally.from_json_file(
            TALLY_FILE_NAME, RESULTS_DIR)
        self.assertEqual(self.plaintext_tally, plainttext_tally_from_file)

        for guardian_record in self.guardian_records:
            set_name = COEFFICIENT_PREFIX + guardian_record.guardian_id
            guardian_record_from_file = GuardianRecord.from_json_file(
                set_name, GUARDIAN_DIR)
            self.assertEqual(guardian_record, guardian_record_from_file)
Exemple #5
0
    def get_hamilton_election_with_encryption_context(
        self, ) -> Tuple[AllPublicElectionData, AllPrivateElectionData]:
        guardians: List[Guardian] = []
        coefficient_validation_sets: List[CoefficientValidationSet] = []

        # Configure the election builder
        description = self.get_hamilton_election_from_file()
        builder = ElectionBuilder(NUMBER_OF_GUARDIANS, QUORUM, description)

        # Setup Guardians
        for i in range(NUMBER_OF_GUARDIANS):
            guardians.append(
                Guardian(
                    "hamilton-county-canvass-board-member-" + str(i),
                    i,
                    NUMBER_OF_GUARDIANS,
                    QUORUM,
                ))

        # Run the key ceremony
        mediator = KeyCeremonyMediator(guardians[0].ceremony_details)
        for guardian in guardians:
            mediator.announce(guardian)
        mediator.orchestrate()
        mediator.verify()

        # Joint Key
        joint_key = mediator.publish_joint_key()

        # Save Validation Keys
        for guardian in guardians:
            coefficient_validation_sets.append(
                guardian.share_coefficient_validation_set())

        builder.set_public_key(get_optional(joint_key).joint_public_key)
        builder.set_commitment_hash(get_optional(joint_key).commitment_hash)
        metadata, context = get_optional(builder.build())
        constants = ElectionConstants()

        return (
            AllPublicElectionData(description, metadata, context, constants,
                                  coefficient_validation_sets),
            AllPrivateElectionData(guardians),
        )
Exemple #6
0
    def is_valid(self) -> bool:
        if self.constants != ElectionConstants():
            log_error("Mismatching election constants!")
            return False

        # super-cheesy unit test to make sure keypair works

        m1 = randbelow(5)
        m2 = randbelow(5)
        nonce1 = rand_q()
        nonce2 = rand_q()

        c1 = get_optional(elgamal_encrypt(m1, nonce1, self.keypair.public_key))
        c2 = get_optional(elgamal_encrypt(m2, nonce2, self.keypair.public_key))
        csum = elgamal_add(c1, c2)

        psum = csum.decrypt(self.keypair.secret_key)

        if psum != m1 + m2:
            log_error("The given keypair didn't work for basic ElGamal math")
            return False

        return True
    def process_message(
        self,
        message_type: Literal["key_ceremony.trustee_verification"],
        message: Content,
        context: BulletinBoardContext,
    ) -> Tuple[List[Content], Optional[ElectionStep]]:
        content = deserialize(message["content"], TrusteeVerification)
        self.verifications_received.add(content.guardian_id)
        # TO-DO: check verifications?

        if len(self.verifications_received) < context.number_of_guardians:
            return [], None

        sorted_trustee_elections_keys = sorted(
            context.trustee_election_keys.items())

        election_joint_key = combine_election_public_keys(
            trustee_election_key.public_key_set.election for guardian_id,
            trustee_election_key in sorted_trustee_elections_keys)
        context.election_builder.set_public_key(
            get_optional(election_joint_key.joint_public_key))
        context.election_builder.set_commitment_hash(
            get_optional(election_joint_key.commitment_hash))
        context.election_metadata, context.election_context = get_optional(
            context.election_builder.build())

        return [{
            "message_type":
            "end_key_ceremony",
            "content":
            serialize(
                KeyCeremonyResults(
                    election_joint_key=election_joint_key,
                    constants=ElectionConstants(),
                    context=context.election_context,
                )),
        }], ProcessStartVote()
    def get_hamilton_manifest_with_encryption_context(
        self, ) -> Tuple[AllPublicElectionData, AllPrivateElectionData]:
        guardians: List[Guardian] = []
        guardian_records: List[GuardianRecord] = []

        # Configure the election builder
        manifest = self.get_hamilton_manifest_from_file()
        builder = ElectionBuilder(NUMBER_OF_GUARDIANS, QUORUM, manifest)

        # Run the Key Ceremony
        ceremony_details = CeremonyDetails(NUMBER_OF_GUARDIANS, QUORUM)
        guardians = KeyCeremonyHelper.create_guardians(ceremony_details)
        mediator = KeyCeremonyMediator("key-ceremony-mediator",
                                       ceremony_details)
        KeyCeremonyHelper.perform_full_ceremony(guardians, mediator)

        # Final: Joint Key
        joint_key = mediator.publish_joint_key()

        # Publish Guardian Records
        guardian_records = [guardian.publish() for guardian in guardians]

        builder.set_public_key(get_optional(joint_key).joint_public_key)
        builder.set_commitment_hash(get_optional(joint_key).commitment_hash)
        internal_manifest, context = get_optional(builder.build())
        constants = ElectionConstants()

        return (
            AllPublicElectionData(
                manifest,
                internal_manifest,
                context,
                constants,
                guardian_records,
            ),
            AllPrivateElectionData(guardians),
        )
Exemple #9
0
def make_fresh_election_admin() -> ElectionAdmin:
    return ElectionAdmin(elgamal_keypair_random(), ElectionConstants())
    def step_1_key_ceremony(self) -> None:
        """
        Using the NUMBER_OF_GUARDIANS, generate public-private keypairs and share
        representations of those keys with QUORUM of other Guardians.  Then, combine
        the public election keys to make a joint election key that is used to encrypt ballots
        """

        # Setup Guardians
        for i in range(self.NUMBER_OF_GUARDIANS):
            self.guardians.append(
                Guardian(
                    "guardian_" + str(i + 1),
                    i + 1,
                    self.NUMBER_OF_GUARDIANS,
                    self.QUORUM,
                ))

        # Setup Mediator
        self.mediator = KeyCeremonyMediator("mediator_1",
                                            self.guardians[0].ceremony_details)

        # ROUND 1: Public Key Sharing
        # Announce
        for guardian in self.guardians:
            self.mediator.announce(guardian.share_public_keys())

        # Share Keys
        for guardian in self.guardians:
            announced_keys = self.mediator.share_announced()
            for key_set in announced_keys:
                if guardian.id is not key_set.election.owner_id:
                    guardian.save_guardian_public_keys(key_set)

        self._assert_message(
            KeyCeremonyMediator.all_guardians_announced.__qualname__,
            "Confirms all guardians have shared their public keys",
            self.mediator.all_guardians_announced(),
        )

        # ROUND 2: Election Partial Key Backup Sharing
        # Share Backups
        for sending_guardian in self.guardians:
            sending_guardian.generate_election_partial_key_backups(
                identity_auxiliary_encrypt)
            backups = []
            for designated_guardian in self.guardians:
                if designated_guardian.id != sending_guardian.id:
                    backups.append(
                        sending_guardian.share_election_partial_key_backup(
                            designated_guardian.id))
            self.mediator.receive_backups(backups)
            self._assert_message(
                KeyCeremonyMediator.receive_backups.__qualname__,
                "Receive election partial key backups from key owning guardian",
                len(backups) == NUMBER_OF_GUARDIANS - 1,
            )

        self._assert_message(
            KeyCeremonyMediator.all_backups_available.__qualname__,
            "Confirm all guardians have shared their election partial key backups",
            self.mediator.all_backups_available(),
        )

        # Receive Backups
        for designated_guardian in self.guardians:
            backups = self.mediator.share_backups(designated_guardian.id)
            self._assert_message(
                KeyCeremonyMediator.share_backups.__qualname__,
                "Share election partial key backups for the designated guardian",
                len(backups) == NUMBER_OF_GUARDIANS - 1,
            )
            for backup in backups:
                designated_guardian.save_election_partial_key_backup(backup)

        # ROUND 3: Verification of Backups
        # Verify Backups
        for designated_guardian in self.guardians:
            verifications = []
            for backup_owner in self.guardians:
                if designated_guardian.id is not backup_owner.id:
                    verification = (
                        designated_guardian.verify_election_partial_key_backup(
                            backup_owner.id, identity_auxiliary_encrypt))
                    verifications.append(verification)
            self.mediator.receive_backup_verifications(verifications)

        self._assert_message(
            KeyCeremonyMediator.all_backups_verified.__qualname__,
            "Confirms all guardians have verified the backups of all other guardians",
            self.mediator.all_backups_verified(),
        )

        # FINAL: Publish Joint Key
        joint_key = self.mediator.publish_joint_key()
        self._assert_message(
            KeyCeremonyMediator.publish_joint_key.__qualname__,
            "Publishes the Joint Election Key",
            joint_key is not None,
        )

        # Build the Election
        self.election_builder.set_public_key(
            get_optional(joint_key).joint_public_key)
        self.election_builder.set_commitment_hash(
            get_optional(joint_key).commitment_hash)
        self.internal_manifest, self.context = get_optional(
            self.election_builder.build())
        self.constants = ElectionConstants()
Exemple #11
0
def get_election_constants() -> Any:
    """
    Return the constants defined for an election
    """
    constants = ElectionConstants()
    return constants.to_json_object()
Exemple #12
0
    def step_1_key_ceremony(self) -> None:
        """
        Using the NUMBER_OF_GUARDIANS, generate public-private keypairs and share
        representations of those keys with QUORUM of other Guardians.  Then, combine
        the public election keys to make a joint election key that is used to encrypt ballots
        """

        # Setup Guardians
        for i in range(self.NUMBER_OF_GUARDIANS):
            self.guardians.append(
                Guardian("guardian_" + str(i), i, self.NUMBER_OF_GUARDIANS,
                         self.QUORUM))

        # Setup Mediator
        self.mediator = KeyCeremonyMediator(self.guardians[0].ceremony_details)

        # Attendance (Public Key Share)
        for guardian in self.guardians:
            self.mediator.announce(guardian)

        self._assert_message(
            KeyCeremonyMediator.all_guardians_in_attendance.__qualname__,
            "Confirms all guardians have shared their public keys",
            self.mediator.all_guardians_in_attendance(),
        )

        # Run the Key Ceremony process,
        # Which shares the keys among the guardians
        orchestrated = self.mediator.orchestrate()
        self._assert_message(
            KeyCeremonyMediator.orchestrate.__qualname__,
            "Executes the key exchange between guardians",
            orchestrated is not None,
        )

        self._assert_message(
            KeyCeremonyMediator.all_election_partial_key_backups_available.
            __qualname__,
            "Confirm sall guardians have shared their partial key backups",
            self.mediator.all_election_partial_key_backups_available(),
        )

        # Verification
        verified = self.mediator.verify()
        self._assert_message(
            KeyCeremonyMediator.verify.__qualname__,
            "Confirms all guardians truthfully executed the ceremony",
            verified,
        )

        self._assert_message(
            KeyCeremonyMediator.
            all_election_partial_key_verifications_received.__qualname__,
            "Confirms all guardians have submitted a verification of the backups of all other guardians",
            self.mediator.all_election_partial_key_verifications_received(),
        )

        self._assert_message(
            KeyCeremonyMediator.all_election_partial_key_backups_verified.
            __qualname__,
            "Confirms all guardians have verified the backups of all other guardians",
            self.mediator.all_election_partial_key_backups_verified(),
        )

        # Joint Key
        joint_key = self.mediator.publish_joint_key()
        self._assert_message(
            KeyCeremonyMediator.publish_joint_key.__qualname__,
            "Publishes the Joint Election Key",
            joint_key is not None,
        )

        # Save Validation Keys
        for guardian in self.guardians:
            self.coefficient_validation_sets.append(
                guardian.share_coefficient_validation_set())

        # Build the Election
        self.election_builder.set_public_key(get_optional(joint_key))
        self.metadata, self.context = get_optional(
            self.election_builder.build())
        self.constants = ElectionConstants()