|
2 | 2 |
|
3 | 3 | from .ballot import CiphertextAcceptedBallot, CiphertextSelection |
4 | 4 | from .decryption_share import ( |
5 | | - TallyDecryptionShare, |
| 5 | + BallotDecryptionShare, |
6 | 6 | CiphertextDecryptionSelection, |
7 | | - get_spoiled_shares_for_selection, |
| 7 | + TallyDecryptionShare, |
| 8 | + get_ballot_shares_for_selection, |
8 | 9 | get_tally_shares_for_selection, |
9 | 10 | ) |
10 | 11 | from .dlog import discrete_log |
@@ -156,28 +157,52 @@ def decrypt_spoiled_ballots( |
156 | 157 | ] = {} |
157 | 158 |
|
158 | 159 | for spoiled_ballot in spoiled_ballots.values(): |
159 | | - contests: Dict[CONTEST_ID, PlaintextTallyContest] = {} |
160 | | - for contest in spoiled_ballot.contests: |
161 | | - selections: Dict[SELECTION_ID, PlaintextTallySelection] = {} |
162 | | - for selection in contest.ballot_selections: |
163 | | - spoiled_shares = get_spoiled_shares_for_selection( |
164 | | - spoiled_ballot.object_id, selection.object_id, shares |
165 | | - ) |
166 | | - plaintext_selection = decrypt_selection_with_decryption_shares( |
167 | | - selection, spoiled_shares, extended_base_hash |
168 | | - ) |
| 160 | + ballot_shares: Dict[AVAILABLE_GUARDIAN_ID, BallotDecryptionShare] = { |
| 161 | + guardian_id: share.spoiled_ballots[spoiled_ballot.object_id] |
| 162 | + for guardian_id, share in shares.items() |
| 163 | + } |
| 164 | + |
| 165 | + decrypted_ballot = decrypt_ballot( |
| 166 | + spoiled_ballot, ballot_shares, extended_base_hash |
| 167 | + ) |
| 168 | + if decrypted_ballot: |
| 169 | + plaintext_spoiled_ballots[spoiled_ballot.object_id] = decrypted_ballot |
| 170 | + else: |
| 171 | + return None |
| 172 | + |
| 173 | + return plaintext_spoiled_ballots |
169 | 174 |
|
170 | | - # verify the plaintext values are received and add them to the collection |
171 | | - if plaintext_selection is None: |
172 | | - log_warning( |
173 | | - f"could not decrypt spoiled ballot {spoiled_ballot.object_id} for contest {contest.object_id} selection {selection.object_id}" |
174 | | - ) |
175 | | - return None |
176 | | - selections[plaintext_selection.object_id] = plaintext_selection |
177 | 175 |
|
178 | | - contests[contest.object_id] = PlaintextTallyContest( |
179 | | - contest.object_id, selections |
| 176 | +def decrypt_ballot( |
| 177 | + ballot: CiphertextAcceptedBallot, |
| 178 | + shares: Dict[AVAILABLE_GUARDIAN_ID, BallotDecryptionShare], |
| 179 | + extended_base_hash: ElementModQ, |
| 180 | +) -> Optional[Dict[CONTEST_ID, PlaintextTallyContest]]: |
| 181 | + """ |
| 182 | + Try to decrypt a single ballot using the provided decryption shares |
| 183 | + """ |
| 184 | + |
| 185 | + contests: Dict[CONTEST_ID, PlaintextTallyContest] = {} |
| 186 | + for contest in ballot.contests: |
| 187 | + selections: Dict[SELECTION_ID, PlaintextTallySelection] = {} |
| 188 | + for selection in contest.ballot_selections: |
| 189 | + selection_shares = get_ballot_shares_for_selection( |
| 190 | + selection.object_id, shares |
| 191 | + ) |
| 192 | + plaintext_selection = decrypt_selection_with_decryption_shares( |
| 193 | + selection, selection_shares, extended_base_hash |
180 | 194 | ) |
181 | | - plaintext_spoiled_ballots[spoiled_ballot.object_id] = contests |
182 | 195 |
|
183 | | - return plaintext_spoiled_ballots |
| 196 | + # verify the plaintext values are received and add them to the collection |
| 197 | + if plaintext_selection is None: |
| 198 | + log_warning( |
| 199 | + f"could not decrypt ballot {ballot.object_id} for contest {contest.object_id} selection {selection.object_id}" |
| 200 | + ) |
| 201 | + return None |
| 202 | + selections[plaintext_selection.object_id] = plaintext_selection |
| 203 | + |
| 204 | + contests[contest.object_id] = PlaintextTallyContest( |
| 205 | + contest.object_id, selections |
| 206 | + ) |
| 207 | + |
| 208 | + return contests |
0 commit comments