Skip to content

Commit 39b0366

Browse files
Bug/cleanup output data (#138)
* ✨ Implement Scheduler for multi processing - Add scheduler singleton to handle creating pools an closing pools. - Remove Pool references and replace scheduler - Update tests and benchmarks * Modify scheduler to include only one method add tally methods to tally in batches * fix naming * Adjust proof fields to reflect new output requirements also, fix a bug where the tally did not include the decryption shares, and where a few of the CP proofs were not using the crypto_extended_base_hash in their challenge inputs * fix unused inports * return int * increase the deadline on slow tests * fix imports * fix CI Errors * Address PR Feedback * fix lint error Co-authored-by: Keith Fung <keith.fung@infernored.com> Co-authored-by: Keith Fung <keithrfung@users.noreply.github.com>
1 parent c87d602 commit 39b0366

16 files changed

+444
-201
lines changed

bench/bench_chaum_pedersen.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
ElGamalKeyPair,
1111
elgamal_encrypt,
1212
)
13-
from electionguard.group import ElementModQ, int_to_q_unchecked
13+
from electionguard.group import ElementModQ, int_to_q_unchecked, ONE_MOD_Q
1414
from electionguard.nonces import Nonces
1515
from electionguard.scheduler import Scheduler
1616
from electionguard.utils import get_optional
@@ -30,9 +30,11 @@ def chaum_pedersen_bench(bi: BenchInput) -> Tuple[float, float]:
3030
(keypair, r, s) = bi
3131
ciphertext = get_optional(elgamal_encrypt(0, r, keypair.public_key))
3232
start1 = timer()
33-
proof = make_disjunctive_chaum_pedersen_zero(ciphertext, r, keypair.public_key, s)
33+
proof = make_disjunctive_chaum_pedersen_zero(
34+
ciphertext, r, keypair.public_key, ONE_MOD_Q, s
35+
)
3436
end1 = timer()
35-
valid = proof.is_valid(ciphertext, keypair.public_key)
37+
valid = proof.is_valid(ciphertext, keypair.public_key, ONE_MOD_Q)
3638
end2 = timer()
3739
if not valid:
3840
raise Exception("Wasn't expecting an invalid proof during a benchmark!")

src/electionguard/ballot.py

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,10 @@ class CiphertextBallotSelection(
203203
"""encrypted representation of the extended_data field"""
204204

205205
def is_valid_encryption(
206-
self, seed_hash: ElementModQ, elgamal_public_key: ElementModP
206+
self,
207+
seed_hash: ElementModQ,
208+
elgamal_public_key: ElementModP,
209+
crypto_extended_base_hash: ElementModQ,
207210
) -> bool:
208211
"""
209212
Given an encrypted BallotSelection, validates the encryption state against a specific seed hash and public key.
@@ -233,7 +236,9 @@ def is_valid_encryption(
233236
log_warning(f"no proof exists for: {self.object_id}")
234237
return False
235238

236-
return self.proof.is_valid(self.ciphertext, elgamal_public_key)
239+
return self.proof.is_valid(
240+
self.ciphertext, elgamal_public_key, crypto_extended_base_hash
241+
)
237242

238243
def crypto_hash_with(self, seed_hash: ElementModQ) -> ElementModQ:
239244
"""
@@ -262,6 +267,7 @@ def make_ciphertext_ballot_selection(
262267
description_hash: ElementModQ,
263268
ciphertext: ElGamalCiphertext,
264269
elgamal_public_key: ElementModP,
270+
crypto_extended_base_hash: ElementModQ,
265271
proof_seed: ElementModQ,
266272
selection_representation: int,
267273
is_placeholder_selection: bool = False,
@@ -285,7 +291,12 @@ def make_ciphertext_ballot_selection(
285291
proof = flatmap_optional(
286292
nonce,
287293
lambda n: make_disjunctive_chaum_pedersen(
288-
ciphertext, n, elgamal_public_key, proof_seed, selection_representation
294+
ciphertext,
295+
n,
296+
elgamal_public_key,
297+
crypto_extended_base_hash,
298+
proof_seed,
299+
selection_representation,
289300
),
290301
)
291302

@@ -443,7 +454,10 @@ def elgamal_accumulate(self) -> ElGamalCiphertext:
443454
return _ciphertext_ballot_elgamal_accumulate(self.ballot_selections)
444455

445456
def is_valid_encryption(
446-
self, seed_hash: ElementModQ, elgamal_public_key: ElementModP
457+
self,
458+
seed_hash: ElementModQ,
459+
elgamal_public_key: ElementModP,
460+
crypto_extended_base_hash: ElementModQ,
447461
) -> bool:
448462
"""
449463
Given an encrypted BallotContest, validates the encryption state against a specific seed hash and public key
@@ -475,7 +489,9 @@ def is_valid_encryption(
475489

476490
# Verify the sum of the selections matches the proof
477491
elgamal_accumulation = self.elgamal_accumulate()
478-
return self.proof.is_valid(elgamal_accumulation, elgamal_public_key)
492+
return self.proof.is_valid(
493+
elgamal_accumulation, elgamal_public_key, crypto_extended_base_hash
494+
)
479495

480496

481497
def _ciphertext_ballot_elgamal_accumulate(
@@ -521,6 +537,7 @@ def make_ciphertext_ballot_contest(
521537
description_hash: ElementModQ,
522538
ballot_selections: List[CiphertextBallotSelection],
523539
elgamal_public_key: ElementModP,
540+
crypto_extended_base_hash: ElementModQ,
524541
proof_seed: ElementModQ,
525542
number_elected: int,
526543
crypto_hash: Optional[ElementModQ] = None,
@@ -548,6 +565,7 @@ def make_ciphertext_ballot_contest(
548565
r=ag,
549566
k=elgamal_public_key,
550567
seed=proof_seed,
568+
hash_header=crypto_extended_base_hash,
551569
),
552570
)
553571
return CiphertextBallotContest(
@@ -606,7 +624,7 @@ class CiphertextBallot(ElectionObjectBase, CryptoHashCheckable):
606624
When a ballot is in it's complete, encrypted state, the `nonce` is the master nonce
607625
from which all other nonces can be derived to encrypt the ballot. Allong with the `nonce`
608626
fields on `Ballotcontest` and `BallotSelection`, this value is sensitive.
609-
:field object_id: A unique Ballot ID that is relevant to the external system
627+
:field object_id: A unique Ballot ID that is relevant to the external system
610628
"""
611629

612630
ballot_style: str
@@ -638,7 +656,16 @@ def __post_init__(self) -> None:
638656
self.timestamp = to_ticks(datetime.utcnow())
639657
self.generate_tracking(self.previous_tracking_hash)
640658

641-
@property
659+
@staticmethod
660+
def nonce_seed(
661+
description_hash: ElementModQ, object_id: str, nonce: ElementModQ
662+
) -> ElementModQ:
663+
"""
664+
:return: a representation of the election and the external Id in the nonce's used
665+
to derive other nonce values on the ballot
666+
"""
667+
return hash_elems(description_hash, object_id, nonce)
668+
642669
def hashed_ballot_nonce(self) -> Optional[ElementModQ]:
643670
"""
644671
:return: a hash value derived from the description hash, the object id, and the nonce value
@@ -651,7 +678,7 @@ def hashed_ballot_nonce(self) -> Optional[ElementModQ]:
651678
)
652679
return None
653680

654-
return hash_elems(self.description_hash, self.object_id, self.nonce)
681+
return self.nonce_seed(self.description_hash, self.object_id, self.nonce)
655682

656683
def generate_tracking(self, seed_hash: ElementModQ) -> None:
657684
"""
@@ -691,7 +718,10 @@ def crypto_hash_with(self, seed_hash: ElementModQ) -> ElementModQ:
691718
return hash_elems(self.object_id, seed_hash, *contest_hashes)
692719

693720
def is_valid_encryption(
694-
self, seed_hash: ElementModQ, elgamal_public_key: ElementModP
721+
self,
722+
seed_hash: ElementModQ,
723+
elgamal_public_key: ElementModP,
724+
crypto_extended_base_hash: ElementModQ,
695725
) -> bool:
696726
"""
697727
Given an encrypted Ballot, validates the encryption state against a specific seed hash and public key
@@ -723,12 +753,16 @@ def is_valid_encryption(
723753
for selection in contest.ballot_selections:
724754
valid_proofs.append(
725755
selection.is_valid_encryption(
726-
selection.description_hash, elgamal_public_key
756+
selection.description_hash,
757+
elgamal_public_key,
758+
crypto_extended_base_hash,
727759
)
728760
)
729761
valid_proofs.append(
730762
contest.is_valid_encryption(
731-
contest.description_hash, elgamal_public_key
763+
contest.description_hash,
764+
elgamal_public_key,
765+
crypto_extended_base_hash,
732766
)
733767
)
734768
return all(valid_proofs)

src/electionguard/ballot_validator.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ def ballot_is_valid_for_election(
2222
return False
2323

2424
if not ballot.is_valid_encryption(
25-
context.crypto_extended_base_hash, context.elgamal_public_key,
25+
metadata.description_hash,
26+
context.elgamal_public_key,
27+
context.crypto_extended_base_hash,
2628
):
2729
log_warning(
2830
f"ballot_is_valid_for_election: mismatching ballot encryption {ballot.object_id}"

0 commit comments

Comments
 (0)