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
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
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
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
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