예제 #1
0
def plaintext_voted_ballot(draw: _DrawType,
                           metadata: InternalElectionDescription):
    """
    Given an `InternalElectionDescription` object, generates an arbitrary `PlaintextBallot` with the
    choices made randomly.
    :param draw: Hidden argument, used by Hypothesis.
    :param metadata: Any `InternalElectionDescription`
    """

    num_ballot_styles = len(metadata.ballot_styles)
    assert num_ballot_styles > 0, "invalid election with no ballot styles"

    # pick a ballot style at random
    ballot_style = metadata.ballot_styles[draw(
        integers(0, num_ballot_styles - 1))]

    contests = metadata.get_contests_for(ballot_style.object_id)
    assert len(contests) > 0, "invalid ballot style with no contests in it"

    voted_contests: List[PlaintextBallotContest] = []
    for contest in contests:
        assert contest.is_valid(), "every contest needs to be valid"
        n = contest.number_elected  # we need exactly this many 1's, and the rest 0's
        ballot_selections = contest.ballot_selections
        assert len(ballot_selections) >= n

        random = Random(draw(integers()))
        random.shuffle(ballot_selections)
        cut_point = draw(integers(0, n))
        yes_votes = ballot_selections[:cut_point]
        no_votes = ballot_selections[cut_point:]

        voted_selections = [
            selection_from(
                description, is_placeholder=False, is_affirmative=True)
            for description in yes_votes
        ] + [
            selection_from(
                description, is_placeholder=False, is_affirmative=False)
            for description in no_votes
        ]

        voted_contests.append(
            PlaintextBallotContest(contest.object_id, voted_selections))

    return PlaintextBallot(str(draw(uuids())), ballot_style.object_id,
                           voted_contests)
    def generate_fake_plaintext_ballots_for_election(
        self, election: InternalElectionDescription, number_of_ballots: int
    ) -> List[PlaintextBallot]:
        ballots: List[PlaintextBallot] = []
        for _i in range(number_of_ballots):

            style_index = randint(0, len(election.ballot_styles) - 1)
            ballot_style = election.ballot_styles[style_index]
            ballot_id = f"ballot-{uuid.uuid1()}"

            contests: List[PlaintextBallotContest] = []
            for contest in election.get_contests_for(ballot_style.object_id):
                contests.append(
                    self.get_random_contest_from(contest, Random(), with_trues=True)
                )

            ballots.append(PlaintextBallot(ballot_id, ballot_style.object_id, contests))

        return ballots
예제 #3
0
def ballot_from_json(ballot: dict) -> PlaintextBallot:
    # TODO: Ballot validation

    voted_contests: List[PlaintextBallotContest] = []
    for contest in ballot['contests']:
        voted_selections: List[PlaintextBallotSelection] = []

        for selection in contest['ballotSelections']:
            voted_selections.append(
                PlaintextBallotSelection(
                    selection['objectId'],
                    plaintext=selection['plaintext'],
                    is_placeholder_selection=False,
                ))

        voted_contests.append(
            PlaintextBallotContest(contest['objectId'], voted_selections))

    return PlaintextBallot(ballot['objectId'], ballot['ballotStyle'],
                           voted_contests)
    def test_publish_private_data(self) -> None:
        # Arrange
        plaintext_ballots = [PlaintextBallot("", "", [])]
        encrypted_ballots = [
            make_ciphertext_ballot("", "", int_to_q_unchecked(0),
                                   int_to_q_unchecked(0), [])
        ]
        guardians = [Guardian("", 1, 1, 1)]

        # Act
        publish_private_data(
            plaintext_ballots,
            encrypted_ballots,
            guardians,
        )

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

        # Cleanup
        rmtree(RESULTS_DIR)
    def get_fake_ballot(self,
                        election: ElectionDescription = None,
                        ballot_id: str = None) -> PlaintextBallot:
        """
        Get a single Fake Ballot object that is manually constructed with default vaules
        """
        if election is None:
            election = self.get_fake_election()

        if ballot_id is None:
            ballot_id = "some-unique-ballot-id-123"

        fake_ballot = PlaintextBallot(
            ballot_id,
            election.ballot_styles[0].object_id,
            [
                contest_from(election.contests[0]),
                contest_from(election.contests[1])
            ],
        )

        return fake_ballot
예제 #6
0
    def get_fake_ballot(self,
                        manifest: Manifest = None,
                        ballot_id: str = None) -> PlaintextBallot:
        """
        Get a single Fake Ballot object that is manually constructed with default vaules
        """
        if manifest is None:
            manifest = self.get_fake_manifest()

        if ballot_id is None:
            ballot_id = "some-unique-ballot-id-123"

        fake_ballot = PlaintextBallot(
            ballot_id,
            manifest.ballot_styles[0].object_id,
            [
                contest_from(manifest.contests[0]),
                contest_from(manifest.contests[1])
            ],
        )

        return fake_ballot
예제 #7
0
    def row_to_plaintext_ballot(self, row: Dict[str, Any]) -> PlaintextBallot:
        ballot_type = row["BallotType"]
        ballot_id = row["BallotId"]
        pbcontests: List[PlaintextBallotContest] = []

        contest_titles: Set[str] = self.style_map[ballot_type]
        for title in contest_titles:
            # This is insanely complicated. The challenge is that we have the Dominion data structures,
            # which has its own column names, but we have to connect that with all of the ElectionGuard
            # structures, which don't just let you follow from one to the other. Instead, it's a twisty
            # world of object_ids. Thus, we need mappings to go from one to the next, and have to do all
            # this extra bookkeeping, in Python dictionaries, to make all the connections.

            contest = self.contest_map[title]
            candidate_ids = [s.candidate_id for s in contest.ballot_selections]
            column_names = [
                self.all_candidate_ids_to_columns[c] for c in candidate_ids
            ]
            voter_intents = [row[x] > 0 for x in column_names]
            selections: List[SelectionDescription] = contest.ballot_selections
            plaintexts = [
                selection_from(
                    description=selections[i],
                    is_placeholder=False,
                    is_affirmative=voter_intents[i],
                ) for i in range(0, len(selections))
            ]
            pbcontests.append(
                PlaintextBallotContest(
                    object_id=contest.object_id,
                    ballot_selections=plaintexts,
                ))

        return PlaintextBallot(
            object_id=ballot_id,
            ballot_style=self.ballotstyle_map[ballot_type].object_id,
            contests=pbcontests,
        )
    def get_fake_ballot(
        self,
        election: InternalElectionDescription,
        ballot_id: str = None,
        with_trues=True,
    ) -> PlaintextBallot:
        """
        Get a single Fake Ballot object that is manually constructed with default vaules
        """

        if ballot_id is None:
            ballot_id = "some-unique-ballot-id-123"

        contests: List[PlaintextBallotContest] = []
        for contest in election.get_contests_for(election.ballot_styles[0].object_id):
            contests.append(
                self.get_random_contest_from(contest, Random(), with_trues=with_trues)
            )

        fake_ballot = PlaintextBallot(
            ballot_id, election.ballot_styles[0].object_id, contests
        )

        return fake_ballot
 def _get_ballot_from_file(filename: str) -> PlaintextBallot:
     with open(os.path.join(data, filename), "r") as subject:
         result = subject.read()
         target = PlaintextBallot.from_json(result)
     return target
예제 #10
0
 def _get_ballot_from_file(self, filename: str) -> PlaintextBallot:
     with open(os.path.join(here, "data", filename), "r") as subject:
         data = subject.read()
         target = PlaintextBallot.from_json(data)
     return target