This repository has been archived by the owner on Jun 7, 2024. It is now read-only.
forked from Election-Tech-Initiative/electionguard-python
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathverify.py
93 lines (77 loc) · 2.77 KB
/
verify.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
from dataclasses import dataclass
from typing import Dict, Optional, List
from electionguard.ballot import CiphertextBallot, SubmittedBallot
from electionguard.election import CiphertextElectionContext
from electionguard.key_ceremony import ElectionPublicKey
from electionguard.manifest import (
InternalManifest,
Manifest,
)
from electionguard.type import GuardianId
from electionguard.tally import PlaintextTally, CiphertextTally
@dataclass
class Verification:
"""
Representation of a verification result with an optional message
"""
verified: bool
"""Verification successful?"""
message: Optional[str]
def verify_ballot(
ballot: CiphertextBallot,
manifest: Manifest,
context: CiphertextElectionContext,
) -> Verification:
"""
Method to verify the validity of a ballot
"""
if not ballot.is_valid_encryption(
manifest.crypto_hash(),
context.elgamal_public_key,
context.crypto_extended_base_hash,
):
return Verification(
False,
message=f"verify_ballot: mismatching ballot encryption {ballot.object_id}",
)
return Verification(True, message=None)
def verify_decryption(
tally: PlaintextTally,
election_public_keys: Dict[GuardianId, ElectionPublicKey],
context: CiphertextElectionContext,
) -> Verification:
for _, contest in tally.contests.items():
for selection_id, selection in contest.selections.items():
for share in selection.shares:
election_public_key = election_public_keys.get(share.guardian_id).key
if not share.proof.is_valid(
selection.message,
election_public_key,
share.share,
context.crypto_extended_base_hash,
):
return Verification(
False,
message=f"verify_decryption: {selection_id} selection is not valid",
)
return Verification(True, message=None)
def verify_aggregation(
submitted_ballots: List[SubmittedBallot],
tally: CiphertextTally,
manifest: Manifest,
context: CiphertextElectionContext,
) -> Verification:
new_tally = CiphertextTally("verify", InternalManifest(manifest), context)
for ballot in submitted_ballots:
new_tally.append(ballot, True)
if (
isinstance(tally, CiphertextTally)
and new_tally.cast_ballot_ids == tally.cast_ballot_ids
and new_tally.spoiled_ballot_ids == tally.spoiled_ballot_ids
and new_tally.contests == tally.contests
):
return Verification(True, message=None)
return Verification(
False,
message="verify_aggregation: aggregated value of ballots doesn't matches with tally",
)