def encrypt_ballots(request: EncryptBallotsRequest = Body(...)) -> Any: """ Encrypt one or more ballots """ ballots = [ PlaintextBallot.from_json_object(ballot) for ballot in request.ballots ] description = InternalElectionDescription( ElectionDescription.from_json_object(request.description)) context = CiphertextElectionContext.from_json_object(request.context) seed_hash = read_json_object(request.seed_hash, ElementModQ) nonce: Optional[ElementModQ] = (read_json_object( request.nonce, ElementModQ) if request.nonce else None) encrypted_ballots = [] current_hash = seed_hash for ballot in ballots: encrypted_ballot = encrypt_ballot(ballot, description, context, current_hash, nonce) if not encrypted_ballot: raise HTTPException(status_code=500, detail="Ballot failed to encrypt") encrypted_ballots.append(encrypted_ballot) current_hash = get_optional(encrypted_ballot.tracking_hash) response = EncryptBallotsResponse( encrypted_ballots=[ ballot.to_json_object() for ballot in encrypted_ballots ], next_seed_hash=write_json_object(current_hash), ) return response
def create_backup_challenge(request: BackupChallengeRequest) -> Any: challenge = generate_election_partial_key_challenge( read_json_object(request.election_partial_key_backup, ElectionPartialKeyBackup), read_json_object(request.election_polynomial, ElectionPolynomial), ) if not challenge: raise HTTPException( status_code=500, detail="Backup challenge generation failed" ) return write_json_object(challenge)
def verify_backup(request: BackupVerificationRequest) -> Any: decrypt = identity if request.override_rsa else rsa_decrypt verification = verify_election_partial_key_backup( request.verifier_id, read_json_object(request.election_partial_key_backup, ElectionPartialKeyBackup), read_json_object(request.auxiliary_key_pair, AuxiliaryKeyPair), decrypt, ) if not verification: raise HTTPException( status_code=500, detail="Backup verification process failed" ) return write_json_object(verification)
def create_guardian_backup(request: GuardianBackupRequest) -> GuardianBackup: """ Generate all election partial key backups based on existing public keys :param request: Guardian backup request :return: Guardian backup """ encrypt = identity if request.override_rsa else rsa_encrypt backups: List[Any] = [] for auxiliary_public_key in request.auxiliary_public_keys: backup = generate_election_partial_key_backup( request.guardian_id, read_json_object(request.election_polynomial, ElectionPolynomial), AuxiliaryPublicKey( auxiliary_public_key.owner_id, auxiliary_public_key.sequence_order, auxiliary_public_key.key, ), encrypt, ) if not backup: raise HTTPException(status_code=500, detail="Backup failed to be generated") backups.append(write_json_object(backup)) return GuardianBackup( id=request.guardian_id, election_partial_key_backups=backups, )
def convert_tracker_to_words(request: TrackerWordsRequest = Body(...)) -> Any: """ Convert tracker from hash to human readable / friendly words """ tracker_hash = read_json_object(request.tracker_hash, ElementModQ) tracker_words = tracker_hash_to_words(tracker_hash, request.seperator) return TrackerWords(tracker_words=tracker_words)
def verify_challenge(request: ChallengeVerificationRequest) -> Any: verification = verify_election_partial_key_challenge( request.verifier_id, read_json_object( request.election_partial_key_challenge, ElectionPartialKeyChallenge ), ) if not verification: raise HTTPException( status_code=500, detail="Challenge verification process failed" ) return write_json_object(verification)
def test_read_and_write_json_object(self) -> None: # Act json_object = write_json_object(JSON_DATA) # Assert self.assertEqual(json_object, EXPECTED_JSON_OBJECT) # Act read_json_data = read_json_object(json_object, DataModel) # Assert self.assertEqual(read_json_data, JSON_DATA)
def convert_guardian( api_guardian: Guardian) -> electionguard.guardian.Guardian: """ Convert an API Guardian model to a fully-hydrated SDK Guardian model. """ guardian = electionguard.guardian.Guardian( api_guardian.id, api_guardian.sequence_order, api_guardian.number_of_guardians, api_guardian.quorum, ) guardian._auxiliary_keys = electionguard.key_ceremony.AuxiliaryKeyPair( api_guardian.auxiliary_key_pair.public_key, api_guardian.auxiliary_key_pair.secret_key, ) election_public_key = read_json_object( api_guardian.election_key_pair.public_key, electionguard.group.ElementModP) election_secret_key = read_json_object( api_guardian.election_key_pair.secret_key, electionguard.group.ElementModQ) guardian._election_keys = electionguard.key_ceremony.ElectionKeyPair( electionguard.elgamal.ElGamalKeyPair(election_secret_key, election_public_key), read_json_object(api_guardian.election_key_pair.proof, electionguard.schnorr.SchnorrProof), read_json_object( api_guardian.election_key_pair.polynomial, electionguard.election_polynomial.ElectionPolynomial, ), ) return guardian
def build_election_context(request: ElectionContextRequest = Body(...)) -> Any: """ Build a CiphertextElectionContext for a given election """ description: ElectionDescription = ElectionDescription.from_json_object( request.description) elgamal_public_key: ElementModP = read_json_object( request.elgamal_public_key, ElementModP) number_of_guardians = request.number_of_guardians quorum = request.quorum context = make_ciphertext_election_context(number_of_guardians, quorum, elgamal_public_key, description.crypto_hash()) return write_json_object(context)
def convert_tally( encrypted_tally: PublishedCiphertextTally, description: electionguard.election.InternalElectionDescription, context: electionguard.election.CiphertextElectionContext, ) -> electionguard.tally.CiphertextTally: """ Convert to an SDK CiphertextTally model """ published_tally = read_json_object( encrypted_tally, electionguard.tally.PublishedCiphertextTally ) tally = electionguard.tally.CiphertextTally( published_tally.object_id, description, context ) tally.cast = published_tally.cast return tally
def decrypt_tally(request: DecryptTallyRequest = Body(...)) -> Any: """ Decrypt a tally from a collection of decrypted guardian shares """ description = InternalElectionDescription( ElectionDescription.from_json_object(request.description)) context = CiphertextElectionContext.from_json_object(request.context) tally = convert_tally(request.encrypted_tally, description, context) shares = { guardian_id: read_json_object(share, TallyDecryptionShare) for guardian_id, share in request.shares.items() } full_plaintext_tally = decrypt(tally, shares, context) if not full_plaintext_tally: raise HTTPException( status_code=500, detail="Unable to decrypt tally", ) published_plaintext_tally = publish_plaintext_tally(full_plaintext_tally) return published_plaintext_tally.to_json_object()
def decrypt_ballots(request: DecryptBallotsRequest = Body(...)) -> Any: ballots = [ CiphertextAcceptedBallot.from_json_object(ballot) for ballot in request.encrypted_ballots ] context: CiphertextElectionContext = CiphertextElectionContext.from_json_object( request.context) all_shares: List[BallotDecryptionShare] = [ read_json_object(share, BallotDecryptionShare) for shares in request.shares.values() for share in shares ] shares_by_ballot = index_shares_by_ballot(all_shares) extended_base_hash = context.crypto_extended_base_hash decrypted_ballots = { ballot.object_id: decrypt_ballot(ballot, shares_by_ballot[ballot.object_id], extended_base_hash) for ballot in ballots } return write_json_object(decrypted_ballots)
def deserialize_key(obj): return read_json_object(obj, ElementModP)
def deserialize(obj, type): return read_json_object(obj, type)