Skip to content

Commit 7dccd17

Browse files
authored
🔧 Lock cryptography version (#235)
* 🔧 Lock cryptography version * 🔧Lock black package version This is due to build fails * ✅ Auto Correct with Black v20
1 parent 5cab8c9 commit 7dccd17

33 files changed

+563
-428
lines changed

Pipfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ verify_ssl = true
55

66
[dev-packages]
77
atomicwrites = "*"
8-
black = "*"
8+
black = "20.8b1"
99
coverage = "*"
1010
docutils = "*"
1111
hypothesis = ">=5.15.1"
@@ -24,7 +24,7 @@ typish = '*'
2424
numpy = '>=1.18.2'
2525
jsons = '>=1.1.2'
2626
psutil = '>=5.7.2'
27-
cryptography = "*"
27+
cryptography = ">=3.2"
2828

2929
[requires]
3030
python_version = "3.8"

Pipfile.lock

Lines changed: 394 additions & 319 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/electionguard/ballot.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,13 @@ class CiphertextBallotSelection(
158158
After construction, the `crypto_hash` field is populated automatically in the `__post_init__` cycle
159159
160160
A consumer of this object has the option to discard the `nonce` and/or discard the `proof`,
161-
or keep both values.
162-
161+
or keep both values.
162+
163163
By discarding the `nonce`, the encrypted representation and `proof`
164164
can only be regenerated if the nonce was derived from the ballot's master nonce. If the nonce
165165
used for this selection is truly random, and it is discarded, then the proofs cannot be regenerated.
166166
167-
By keeping the `nonce`, or deriving the selection nonce from the ballot nonce, an external system can
167+
By keeping the `nonce`, or deriving the selection nonce from the ballot nonce, an external system can
168168
regenerate the proofs on demand. This is useful for storage or memory constrained systems.
169169
170170
By keeping the `proof` the nonce is not required fotor verify the encrypted selection.
@@ -202,9 +202,9 @@ def is_valid_encryption(
202202
Given an encrypted BallotSelection, validates the encryption state against a specific seed hash and public key.
203203
Calling this function expects that the object is in a well-formed encrypted state
204204
with the elgamal encrypted `message` field populated along with the DisjunctiveChaumPedersenProof `proof` populated.
205-
the ElementModQ `description_hash` and the ElementModQ `crypto_hash` are also checked.
205+
the ElementModQ `description_hash` and the ElementModQ `crypto_hash` are also checked.
206206
207-
:param seed_hash: the hash of the SelectionDescription, or
207+
:param seed_hash: the hash of the SelectionDescription, or
208208
whatever `ElementModQ` was used to populate the `description_hash` field.
209209
:param elgamal_public_key: The election public key
210210
"""
@@ -310,10 +310,10 @@ class PlaintextBallotContest(ElectionObjectBase):
310310
this class can be either a partial or a complete representation of a contest dataset. Specifically,
311311
a partial representation must include at a minimum the "affirmative" selections of a contest.
312312
A complete representation of a ballot must include both affirmative and negative selections of
313-
the contest, AND the placeholder selections necessary to satisfy the ConstantChaumPedersen proof
313+
the contest, AND the placeholder selections necessary to satisfy the ConstantChaumPedersen proof
314314
in the CiphertextBallotContest.
315315
316-
Typically partial contests are passed into Electionguard for memory constrained systems,
316+
Typically partial contests are passed into Electionguard for memory constrained systems,
317317
while complete contests are passed into ElectionGuard when running encryption on an existing dataset.
318318
"""
319319

@@ -385,12 +385,12 @@ class CiphertextBallotContest(ElectionObjectBase, CryptoHashCheckable):
385385
386386
CiphertextBallotContest can only be a complete representation of a contest dataset. While
387387
PlaintextBallotContest supports a partial representation, a CiphertextBallotContest includes all data
388-
necessary for a verifier to verify the contest. Specifically, it includes both explicit affirmative
388+
necessary for a verifier to verify the contest. Specifically, it includes both explicit affirmative
389389
and negative selections of the contest, as well as the placeholder selections that satisfy
390390
the ConstantChaumPedersen proof.
391391
392392
Similar to `CiphertextBallotSelection` the consuming application can choose to discard or keep both
393-
the `nonce` and the `proof` in some circumstances. For deterministic nonce's derived from the
393+
the `nonce` and the `proof` in some circumstances. For deterministic nonce's derived from the
394394
master nonce, both values can be regenerated. If the `nonce` for this contest is completely random,
395395
then it is required in order to regenerate the proof.
396396
"""
@@ -468,8 +468,8 @@ def is_valid_encryption(
468468
by verifying the accumulated sum of selections match the proof.
469469
Calling this function expects that the object is in a well-formed encrypted state
470470
with the `ballot_selections` populated with valid encrypted ballot selections,
471-
the ElementModQ `description_hash`, the ElementModQ `crypto_hash`, and the ConstantChaumPedersenProof all populated.
472-
Specifically, the seed hash in this context is the hash of the ContestDescription,
471+
the ElementModQ `description_hash`, the ElementModQ `crypto_hash`, and the ConstantChaumPedersenProof all populated.
472+
Specifically, the seed hash in this context is the hash of the ContestDescription,
473473
or whatever `ElementModQ` was used to populate the `description_hash` field.
474474
"""
475475
if seed_hash != self.description_hash:
@@ -737,7 +737,7 @@ def is_valid_encryption(
737737
Calling this function expects that the object is in a well-formed encrypted state
738738
with the `contests` populated with valid encrypted ballot selections,
739739
and the ElementModQ `description_hash` also populated.
740-
Specifically, the seed hash in this context is the hash of the Election Manifest,
740+
Specifically, the seed hash in this context is the hash of the Election Manifest,
741741
or whatever `ElementModQ` was used to populate the `description_hash` field.
742742
"""
743743

src/electionguard/chaum_pedersen.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ def is_valid(
139139
@dataclass(frozen=True)
140140
class ChaumPedersenProof(Proof):
141141
"""
142-
Representation of a generic Chaum-Pedersen Zero Knowledge proof
142+
Representation of a generic Chaum-Pedersen Zero Knowledge proof
143143
"""
144144

145145
pad: ElementModP
@@ -170,9 +170,9 @@ def is_valid(
170170
- The given values 𝑎𝑖 and 𝑏𝑖 are both in the set Z𝑞^𝑟
171171
- The challenge value 𝑐 satisfies 𝑐 = 𝐻(𝑄, (𝐴, 𝐵), (𝑎 , 𝑏 ), 𝑀 ).
172172
- that the equations 𝑔^𝑣𝑖 = 𝑎𝑖𝐾^𝑐𝑖 mod 𝑝 and 𝐴^𝑣𝑖 = 𝑏𝑖𝑀𝑖^𝑐𝑖 mod 𝑝 are satisfied.
173-
173+
174174
:param message: The ciphertext message
175-
:param k: The public key corresponding to the private key used to encrypt
175+
:param k: The public key corresponding to the private key used to encrypt
176176
(e.g. the Guardian public election key)
177177
:param m: The value being checked for validity
178178
:param q: The extended base hash of the election
@@ -380,7 +380,7 @@ def make_disjunctive_chaum_pedersen(
380380
:param message: An ElGamal ciphertext
381381
:param r: The nonce used creating the ElGamal ciphertext
382382
:param k: The ElGamal public key for the election
383-
:param q: A value used when generating the challenge,
383+
:param q: A value used when generating the challenge,
384384
usually the election extended base hash (𝑄')
385385
:param seed: Used to generate other random values here
386386
:param plaintext: Zero or one
@@ -408,7 +408,7 @@ def make_disjunctive_chaum_pedersen_zero(
408408
:param message: An ElGamal ciphertext
409409
:param r: The nonce used creating the ElGamal ciphertext
410410
:param k: The ElGamal public key for the election
411-
:param q: A value used when generating the challenge,
411+
:param q: A value used when generating the challenge,
412412
usually the election extended base hash (𝑄')
413413
:param seed: Used to generate other random values here
414414
"""
@@ -443,7 +443,7 @@ def make_disjunctive_chaum_pedersen_one(
443443
:param message: An ElGamal ciphertext
444444
:param r: The nonce used creating the ElGamal ciphertext
445445
:param k: The ElGamal public key for the election
446-
:param q: A value used when generating the challenge,
446+
:param q: A value used when generating the challenge,
447447
usually the election extended base hash (𝑄')
448448
:param seed: Used to generate other random values here
449449
"""
@@ -480,7 +480,7 @@ def make_chaum_pedersen(
480480
:param s: The nonce or secret used to derive the value
481481
:param m: The value we are trying to prove
482482
:param seed: Used to generate other random values here
483-
:param hash_header: A value used when generating the challenge,
483+
:param hash_header: A value used when generating the challenge,
484484
usually the election extended base hash (𝑄')
485485
"""
486486
(alpha, beta) = message

src/electionguard/data_store.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class DataStore(Generic[_T, _U], Iterable):
2020
"""
2121
A lightweight convenience wrapper around a dictionary for data storage.
2222
This implementation defines the common interface used to access stored
23-
state elements.
23+
state elements.
2424
"""
2525

2626
_store: Dict[_T, _U]

src/electionguard/decryption.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,10 @@ def compute_decryption_share_for_ballot(
267267
selections[decryption.object_id] = decryption
268268

269269
contests[contest.object_id] = CiphertextDecryptionContest(
270-
contest.object_id, guardian.object_id, contest.description_hash, selections,
270+
contest.object_id,
271+
guardian.object_id,
272+
contest.description_hash,
273+
selections,
271274
)
272275
return BallotDecryptionShare(
273276
guardian.object_id,
@@ -472,7 +475,8 @@ def compute_lagrange_coefficients_for_guardian(
472475
if g.owner_id != guardian_keys.owner_id
473476
]
474477
return compute_lagrange_coefficient(
475-
guardian_keys.sequence_order, *other_guardian_orders,
478+
guardian_keys.sequence_order,
479+
*other_guardian_orders,
476480
)
477481

478482

@@ -578,7 +582,10 @@ def reconstruct_decryption_contests(
578582
}
579583

580584
selections: Dict[SELECTION_ID, CiphertextDecryptionSelection] = {}
581-
for (selection_id, tally_selection,) in tally_contest.tally_selections.items():
585+
for (
586+
selection_id,
587+
tally_selection,
588+
) in tally_contest.tally_selections.items():
582589

583590
# collect all of the shares generated for each selection
584591
compensated_selection_shares: Dict[
@@ -604,7 +611,10 @@ def reconstruct_decryption_contests(
604611
compensated_selection_shares,
605612
)
606613
contests[contest_id] = CiphertextDecryptionContest(
607-
contest_id, missing_guardian_id, tally_contest.description_hash, selections,
614+
contest_id,
615+
missing_guardian_id,
616+
tally_contest.description_hash,
617+
selections,
608618
)
609619

610620
return contests
@@ -706,5 +716,8 @@ def reconstruct_decryption_ballot(
706716
selections,
707717
)
708718
return BallotDecryptionShare(
709-
missing_guardian_id, public_key.key, ballot.object_id, contests,
719+
missing_guardian_id,
720+
public_key.key,
721+
ballot.object_id,
722+
contests,
710723
)

src/electionguard/decryption_mediator.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
@dataclass
3636
class DecryptionMediator:
3737
"""
38-
The Decryption Mediator composes partial decryptions from each Guardian
38+
The Decryption Mediator composes partial decryptions from each Guardian
3939
to form a decrypted representation of an election tally
4040
"""
4141

@@ -81,7 +81,7 @@ class DecryptionMediator:
8181

8282
def announce(self, guardian: Guardian) -> Optional[TallyDecryptionShare]:
8383
"""
84-
Announce that a Guardian is present and participating in the decryption.
84+
Announce that a Guardian is present and participating in the decryption.
8585
A Decryption Share will be generated for the Guardian
8686
8787
:param guardian: The guardian who will participate in the decryption.
@@ -208,7 +208,7 @@ def get_plaintext_tally(
208208
self, recompute: bool = False, decrypt: AuxiliaryDecrypt = rsa_decrypt
209209
) -> Optional[PlaintextTally]:
210210
"""
211-
Get the plaintext tally for the election by composing each Guardian's
211+
Get the plaintext tally for the election by composing each Guardian's
212212
decrypted representation of each selection into a decrypted representation
213213
214214
:param recompute: Specify if the function should recompute the result, even if one already exists.

src/electionguard/decryption_share.py

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,9 @@ def is_valid(
106106
extended_base_hash: ElementModQ,
107107
) -> bool:
108108
"""
109-
Verify that this CiphertextDecryptionSelection is valid for a
109+
Verify that this CiphertextDecryptionSelection is valid for a
110110
specific ElGamal key pair, public key, and election context.
111-
111+
112112
:param message: the `ElGamalCiphertext` to compare
113113
:param election_public_key: the `ElementModP Election Public Key for the Guardian
114114
:param extended_base_hash: The `ElementModQ` election extended base hash.
@@ -127,17 +127,26 @@ def is_valid(
127127
return False
128128

129129
if self.proof is not None and not self.proof.is_valid(
130-
message, election_public_key, self.share, extended_base_hash,
130+
message,
131+
election_public_key,
132+
self.share,
133+
extended_base_hash,
131134
):
132135
log_warning(
133136
f"CiphertextDecryptionSelection is_valid failed for guardian: {self.guardian_id} selection: {self.object_id} with invalid proof"
134137
)
135138
return False
136139

137140
if self.recovered_parts is not None:
138-
for (compensating_guardian_id, part,) in self.recovered_parts.items():
141+
for (
142+
compensating_guardian_id,
143+
part,
144+
) in self.recovered_parts.items():
139145
if not part.proof.is_valid(
140-
message, part.recovery_key, part.share, extended_base_hash,
146+
message,
147+
part.recovery_key,
148+
part.share,
149+
extended_base_hash,
141150
):
142151

143152
log_warning(
@@ -179,7 +188,10 @@ def create_ciphertext_decryption_selection(
179188
else:
180189
log_warning(f"decryption share cannot assign {proof_or_recovery}")
181190
return CiphertextDecryptionSelection(
182-
object_id, guardian_id, description_hash, share,
191+
object_id,
192+
guardian_id,
193+
description_hash,
194+
share,
183195
)
184196

185197

@@ -262,7 +274,7 @@ class BallotDecryptionShare:
262274
@dataclass
263275
class CompensatedBallotDecryptionShare:
264276
"""
265-
A Compensated Partial Decryption Share generated by
277+
A Compensated Partial Decryption Share generated by
266278
an available guardian on behalf of a missing guardian
267279
"""
268280

@@ -322,7 +334,7 @@ class TallyDecryptionShare:
322334
@dataclass
323335
class CompensatedTallyDecryptionShare:
324336
"""
325-
A Compensated Partial Decryption Share generated by
337+
A Compensated Partial Decryption Share generated by
326338
an available guardian on behalf of a missing guardian
327339
"""
328340

@@ -353,7 +365,8 @@ class CompensatedTallyDecryptionShare:
353365

354366

355367
def get_tally_shares_for_selection(
356-
selection_id: str, shares: Dict[GUARDIAN_ID, TallyDecryptionShare],
368+
selection_id: str,
369+
shares: Dict[GUARDIAN_ID, TallyDecryptionShare],
357370
) -> Dict[GUARDIAN_ID, Tuple[ELECTION_PUBLIC_KEY, CiphertextDecryptionSelection]]:
358371
"""
359372
Get all of the cast shares for a specific selection
@@ -371,7 +384,9 @@ def get_tally_shares_for_selection(
371384

372385

373386
def get_spoiled_shares_for_selection(
374-
ballot_id: str, selection_id: str, shares: Dict[GUARDIAN_ID, TallyDecryptionShare],
387+
ballot_id: str,
388+
selection_id: str,
389+
shares: Dict[GUARDIAN_ID, TallyDecryptionShare],
375390
) -> Dict[GUARDIAN_ID, Tuple[ELECTION_PUBLIC_KEY, CiphertextDecryptionSelection]]:
376391
"""
377392
Get the spoiled shares for a given selection
@@ -393,7 +408,8 @@ def get_spoiled_shares_for_selection(
393408

394409

395410
def get_ballot_shares_for_selection(
396-
selection_id: str, shares: Dict[GUARDIAN_ID, BallotDecryptionShare],
411+
selection_id: str,
412+
shares: Dict[GUARDIAN_ID, BallotDecryptionShare],
397413
) -> Dict[GUARDIAN_ID, Tuple[ELECTION_PUBLIC_KEY, CiphertextDecryptionSelection]]:
398414
"""
399415
Get the ballot shares for a given selection, in the context of a specific ballot

0 commit comments

Comments
 (0)