Example #1
0
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
Example #2
0
    def build_election(self, election_creation: dict):
        self.election = ElectionDescription.from_json_object(
            complete_election_description(election_creation['description']))

        if not self.election.is_valid():
            raise InvalidElectionDescription()

        self.number_of_guardians = len(election_creation['trustees'])
        self.quorum = election_creation['scheme']['parameters']['quorum']
        self.election_builder = ElectionBuilder(self.number_of_guardians,
                                                self.quorum, self.election)
Example #3
0
def handle_ballot(request: AcceptBallotRequest, state: BallotBoxState) -> Any:
    ballot = CiphertextBallot.from_json_object(request.ballot)
    description = ElectionDescription.from_json_object(request.description)
    internal_description = InternalElectionDescription(description)
    context = CiphertextElectionContext.from_json_object(request.context)

    accepted_ballot = accept_ballot(
        ballot,
        state,
        internal_description,
        context,
        BallotStore(),
    )

    return accepted_ballot
Example #4
0
def _parse_tally_request(
    request: StartTallyRequest,
) -> Tuple[List[CiphertextAcceptedBallot], InternalElectionDescription,
           CiphertextElectionContext, ]:
    """
    Deserialize common tally request values
    """
    ballots = [
        CiphertextAcceptedBallot.from_json_object(ballot)
        for ballot in request.ballots
    ]
    description = ElectionDescription.from_json_object(request.description)
    internal_description = InternalElectionDescription(description)
    context = CiphertextElectionContext.from_json_object(request.context)

    return (ballots, internal_description, context)
Example #5
0
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)
Example #6
0
def decrypt_share(
    request: DecryptTallyShareRequest = Body(...),
    scheduler: Scheduler = Depends(get_scheduler),
) -> Any:
    """
    Decrypt a single guardian's share of a tally
    """
    description = InternalElectionDescription(
        ElectionDescription.from_json_object(request.description)
    )
    context = CiphertextElectionContext.from_json_object(request.context)
    guardian = convert_guardian(request.guardian)
    tally = convert_tally(request.encrypted_tally, description, context)

    share = compute_decryption_share(guardian, tally, context, scheduler)

    return write_json_object(share)
Example #7
0
def validate_election_description(
        request: ValidateElectionDescriptionRequest = Body(...),
        schema: Any = Depends(get_description_schema),
) -> Any:
    """
    Validate an Election description or manifest for a given election
    """

    success = True
    message = "Election description successfully validated"
    details = ""

    # Check schema
    schema = request.schema_override if request.schema_override else schema
    (schema_success,
     error_details) = validate_json_schema(request.description, schema)
    if not schema_success:
        success = schema_success
        message = "Election description did not match schema"
        details = error_details

    # Check object parse
    description: Optional[ElectionDescription] = None
    if success:
        try:
            description = ElectionDescription.from_json_object(
                request.description)
        except Exception:  # pylint: disable=broad-except
            success = False
            message = "Election description could not be read from JSON"

    if success:
        if description:
            valid_success = description.is_valid()
            if not valid_success:
                message = "Election description was not valid well formed data"

    # Check
    return ValidationResponse(success=success,
                              message=message,
                              details=details)
Example #8
0
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()