last changed: April 12, 2022
The election manifest and each input plaintext ballot are expected to be validated before being passed to the electionguard library. Both the encrypted and decrypted tallies may also be validated against the manifest, and against each other for consistency. This document summarizes the expected (non-crypto) validations.
A specific validation is referenced as, eg, Manifest.B.5 and Ballot.A.2.1
-
Referential integrity of BallotStyle's geopoliticalUnitIds.
- For each BallotStyle, all geopoliticalUnitIds reference a GeopoliticalUnit in Manifest.geopoliticalUnitIds
-
Referential integrity of Candidate partyId.
- For each Candidate, the partyId is null or references a Party in Manifest.parties
-
Referential integrity of ContestDescription geopoliticalUnitId.
- For each ContestDescription, the geopoliticalUnitId references a GeopoliticalUnit in Manifest.geopoliticalUnitIds
-
Referential integrity of SelectionDescription candidateId.
- For each SelectionDescription, the candidateId references a Candidate in Manifest.candidates
-
Every ContestDescription geopoliticalUnitId exists in some BallotStyle
- For each ContestDescription, the geopoliticalUnitId exists in at least one Manifest.ballotStyles.geopoliticalUnitIds
-
All ContestDescription have a unique object_id.
-
All ContestDescription have a unique sequence_order.
-
Within a ContestDescription, all SelectionDescription have a unique selectionId.
-
Within a ContestDescription, all SelectionDescription have a unique sequenceOrder.
-
Within a ContestDescription, all SelectionDescription have a unique candidateIdd.
-
All SelectionDescription have a unique object_id within the election (see get_shares_for_selection in decryption_share)
-
A ContestDescription has VoteVariationType = n_of_m, one_of_m, or approval.
-
For all contests, votes_allowed == number_elected.
-
A one_of_m contest has votes_allowed == 1.
-
A n_of_m contest has 0 < votes_allowed <= number of selections in the contest.
-
An approval contest has votes_allowed == number of selections in the contest.
-
A PlaintextBallot's ballotStyleId must match a BallotStyle in Manifest.ballotStyles.
-
For each PlaintextBallotContest on the ballot, the contestId must match a ContestDescription.contestId in Manifest.contests.
2.1 Within the PlaintextBallotContest and matching ContestDescription, each PlaintextBallotSelection.selectionId must match a SelectionDescription.selectionId.
-
PlaintextBallot.Contest's geopoliticalUnitId must be listed in the PlaintextBallot's BallotStyle geopoliticalUnitIds.
-
All PlaintextBallotContest have a unique contest_id.
-
Within a PlaintextBallotContest, all PlaintextBallotSelection have a unique selectionId.
3Within a PlaintextBallotContest, all PlaintextBallotSelection have a unique sequenceOrder.
-
All PlaintextBallotSelection must have a vote whose value is 0 or 1.
-
Within a PlaintextBallotContest, the sum of the PlaintextBallotSelection votes must be <= ContestDescription.votes_allowed.
-
For each CiphertextTally.Contest in the tally, the contestId must match a ContestDescription.contestId in Manifest.contests.
1.1 CiphertextTally.Contest description_hash must match the ContestDescription.crypto_hash.
-
Within the CiphertextTally.Contest and matching ContestDescription, each CiphertextTally.Selection.selectionId must match a SelectionDescription.selectionId.
2.1 CiphertextTally.Selection description_hash must match the SelectionDescription.crypto_hash.
-
All CiphertextTally.Contest must have a unique contestId.
1.1 In the contests map, the key must match the value.object_id. (JSON only)
-
Within a CiphertextTally.Contest, all CiphertextTally.Selection have a unique object_id.
2.1 In the selections map, the key must match the value.object_id. (JSON only)
-
For each PlaintextTally.Contest in the tally, the object_id must match a ContestDescription.object_id in Manifest.contests.
-
Within the PlaintextTally.Contest and matching ContestDescription, each PlaintextTally.Selection.object_id must match a SelectionDescription.object_id.
-
For each PlaintextTally.Contest in the tally, the contestId must match a CiphertextTally.Contest.contestId.
-
Within the PlaintextTally.Contest and matching CiphertextTally.Contest, each PlaintextTally.Selection.selectionId must match a CiphertextTally.Selection.selectionId.
2.1 The PlaintextTally.Selection.message must match the CiphertextTally.Selection.message.
-
All PlaintextTally.Contest must have a unique contest_id. In the contests map, the key must match the value.object_id.
-
Within a PlaintextTally.Contest, all PlaintextTally.Selection have a unique object_id. In the selections map, the key must match the value.object_id.
-
All Selection shares have an object_id matching the Selection object_id.
-
Within a selection, the selection shares have a unique guardian_id.
3 There are nguardian shares.
-
For each CiphertextDecryptionSelection share with recovered_parts, each recovered_part has an object_id matching the share object_id.
-
Each recovered_part has a unique guardian_id, matching the key in the share's map.
-
There are navailable recovered_parts. Note that navailable may be greater than quorum.
-
Each recovered_part has a missing_guardian_id matching the share's guardian_id