123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378 |
- #include <iostream>
- #include "client.hpp"
- #include "serverEntity.hpp"
- /********************
- * PUBLIC FUNCTIONS *
- ********************/
- /*
- * CONSTRUCTORS
- */
- PrsonaClient::PrsonaClient(
- const std::vector<Proof>& generatorProof,
- const Curvepoint& elGamalBlindGenerator,
- const BGNPublicKey& serverPublicKey,
- const PrsonaServerEntity* servers)
- : serverPublicKey(serverPublicKey),
- servers(servers),
- max_checked(0)
- {
- set_EG_blind_generator(
- generatorProof, elGamalBlindGenerator, servers->get_num_servers());
- longTermPrivateKey.set_random();
- inversePrivateKey = longTermPrivateKey.curveMultInverse();
- decryption_memoizer[elGamalBlindGenerator * max_checked] = max_checked;
- }
- /*
- * BASIC PUBLIC SYSTEM INFO GETTERS
- */
- Curvepoint PrsonaClient::get_short_term_public_key() const
- {
- return currentFreshGenerator * longTermPrivateKey;
- }
- Curvepoint PrsonaClient::get_short_term_public_key(Proof &pi) const
- {
- pi = generate_ownership_proof();
- return currentFreshGenerator * longTermPrivateKey;
- }
- /*
- * SERVER INTERACTIONS
- */
- /* Generate a new vote vector to give to the servers
- * @replaces controls which votes are actually being updated and which are not
- *
- * You may really want to make currentEncryptedVotes a member variable,
- * but it doesn't behave correctly when adding new clients after this one. */
- std::vector<CurveBipoint> PrsonaClient::make_votes(
- std::vector<Proof>& validVoteProof,
- const Proof& serverProof,
- const std::vector<CurveBipoint>& oldEncryptedVotes,
- const std::vector<Scalar>& votes,
- const std::vector<bool>& replaces) const
- {
- Curvepoint shortTermPublicKey = get_short_term_public_key();
- if (!verify_valid_vote_row_proof(serverProof, shortTermPublicKey, oldEncryptedVotes))
- {
- std::cerr << "Could not verify proof of valid votes." << std::endl;
- return oldEncryptedVotes;
- }
- std::vector<Scalar> seeds(oldEncryptedVotes.size());
- std::vector<CurveBipoint> newEncryptedVotes(oldEncryptedVotes.size());
- for (size_t i = 0; i < votes.size(); i++)
- {
- if (replaces[i])
- {
- newEncryptedVotes[i] =
- serverPublicKey.curveEncrypt(seeds[i], votes[i]);
- }
- else
- {
- newEncryptedVotes[i] =
- serverPublicKey.rerandomize(seeds[i], oldEncryptedVotes[i]);
- }
- }
- validVoteProof = generate_vote_proof(
- replaces, oldEncryptedVotes, newEncryptedVotes, seeds, votes);
- return newEncryptedVotes;
- }
- // Get a new fresh generator (happens at initialization and during each epoch)
- bool PrsonaClient::receive_fresh_generator(
- const std::vector<Proof>& pi, const Curvepoint& freshGenerator)
- {
- if (!verify_generator_proof(pi, freshGenerator, servers->get_num_servers()))
- {
- std::cerr << "Issue verifying fresh generator proof." << std::endl;
- return false;
- }
- currentFreshGenerator = freshGenerator;
- return true;
- }
- // Receive a new encrypted score from the servers (each epoch)
- bool PrsonaClient::receive_vote_tally()
- {
- Proof pi;
- Curvepoint shortTermPublicKey = get_short_term_public_key();
- EGCiphertext score =
- servers->get_current_user_encrypted_tally(pi, shortTermPublicKey);
- if (!verify_valid_user_tally_proof(pi, shortTermPublicKey, score))
- {
- std::cerr << "Could not verify proof of valid tally." << std::endl;
- return false;
- }
- currentEncryptedScore = score;
- currentScore = decrypt_score(score);
- return true;
- }
- bool PrsonaClient::receive_new_user_data(const std::vector<Proof>& mainProof)
- {
- Proof currProof;
- Curvepoint shortTermPublicKey = get_short_term_public_key();
- TwistBipoint serverEncryptedScore =
- servers->get_current_server_encrypted_tally(currProof, shortTermPublicKey);
- if (!verify_valid_server_tally_proof(currProof, shortTermPublicKey, serverEncryptedScore))
- {
- std::cerr << "Could not verify preliminary proof of server encrypted tally." << std::endl;
- return false;
- }
- EGCiphertext userEncryptedScore =
- servers->get_current_user_encrypted_tally(currProof, shortTermPublicKey);
- if (!verify_valid_user_tally_proof(currProof, shortTermPublicKey, userEncryptedScore))
- {
- std::cerr << "Could not verify preliminary proof of user encrypted tally." << std::endl;
- return false;
- }
- std::vector<std::vector<CurveBipoint>> encryptedVoteMatrix =
- servers->get_all_current_votes(currProof);
- if (!verify_valid_vote_matrix_proof(currProof, encryptedVoteMatrix))
- {
- std::cerr << "Could not verify preliminary proof of encrypted votes." << std::endl;
- return false;
- }
- std::vector<Curvepoint> currentPseudonyms =
- servers->get_current_pseudonyms(currProof);
- if (!verify_valid_pseudonyms_proof(currProof, currentPseudonyms))
- {
- std::cerr << "Could not verify preliminary proof of pseudonyms." << std::endl;
- return false;
- }
- size_t selfIndex = binary_search(currentPseudonyms, shortTermPublicKey);
- if (currentPseudonyms[selfIndex] != shortTermPublicKey)
- {
- std::cerr << "Was not added to list of pseudonyms." << std::endl;
- return false;
- }
- bool flag = verify_proof_of_added_user(
- mainProof,
- currentFreshGenerator,
- shortTermPublicKey,
- serverPublicKey.get_bipoint_curvegen(),
- serverPublicKey.get_bipoint_curve_subgroup_gen(),
- serverPublicKey.get_bipoint_twistgen(),
- serverPublicKey.get_bipoint_twist_subgroup_gen(),
- selfIndex,
- userEncryptedScore,
- serverEncryptedScore,
- encryptedVoteMatrix);
- if (!flag)
- {
- std::cerr << "There was an issue verifying the proof; this user was not properly added." << std::endl;
- return false;
- }
- currentEncryptedScore = userEncryptedScore;
- currentScore = decrypt_score(userEncryptedScore);
- return true;
- }
- /*
- * REPUTATION PROOFS
- */
- // A pretty straightforward range proof (generation)
- std::vector<Proof> PrsonaClient::generate_reputation_proof(
- const Scalar& threshold) const
- {
- Proof ownershipProof = generate_ownership_proof();
-
- return PrsonaBase::generate_reputation_proof(
- ownershipProof,
- currentEncryptedScore,
- currentScore,
- threshold,
- inversePrivateKey,
- servers->get_num_clients());
- }
- bool PrsonaClient::verify_reputation_proof(
- const std::vector<Proof>& pi,
- const Curvepoint& shortTermPublicKey,
- const Scalar& threshold) const
- {
- Proof serverProof;
- EGCiphertext encryptedScore =
- servers->get_current_user_encrypted_tally(serverProof, shortTermPublicKey);
- if (!verify_valid_user_tally_proof(serverProof, shortTermPublicKey, encryptedScore))
- {
- std::cerr << "Error getting score from server, aborting." << std::endl;
- return false;
- }
- return PrsonaBase::verify_reputation_proof(
- pi, currentFreshGenerator, shortTermPublicKey, encryptedScore, threshold);
- }
- Scalar PrsonaClient::get_score() const
- {
- return currentScore;
- }
- /*********************
- * PRIVATE FUNCTIONS *
- *********************/
- /*
- * SCORE DECRYPTION
- */
- // Basic memoized score decryption
- Scalar PrsonaClient::decrypt_score(const EGCiphertext& score)
- {
- Curvepoint s, hashedDecrypted;
- // Remove the mask portion of the ciphertext
- s = score.mask * inversePrivateKey;
- hashedDecrypted = score.encryptedMessage - s;
-
- // Check if it's a value we've already seen
- auto lookup = decryption_memoizer.find(hashedDecrypted);
- if (lookup != decryption_memoizer.end())
- return lookup->second;
- // If not, iterate until we find it (adding everything to the memoization)
- max_checked++;
- Curvepoint decryptionCandidate = elGamalBlindGenerator * max_checked;
- while (decryptionCandidate != hashedDecrypted)
- {
- decryption_memoizer[decryptionCandidate] = max_checked;
- decryptionCandidate = decryptionCandidate + elGamalBlindGenerator;
- max_checked++;
- }
- decryption_memoizer[decryptionCandidate] = max_checked;
- // Return the value we found
- return max_checked;
- }
- /*
- * OWNERSHIP PROOFS
- */
- // Prove ownership of the short term public key
- Proof PrsonaClient::generate_ownership_proof() const
- {
- Curvepoint shortTermPublicKey = currentFreshGenerator * longTermPrivateKey;
- return PrsonaBase::generate_ownership_proof(
- currentFreshGenerator, shortTermPublicKey, longTermPrivateKey);
- }
- /*
- * VALID VOTE PROOFS
- */
- std::vector<Proof> PrsonaClient::generate_vote_proof(
- const std::vector<bool>& replaces,
- const std::vector<CurveBipoint>& oldEncryptedVotes,
- const std::vector<CurveBipoint>& newEncryptedVotes,
- const std::vector<Scalar>& seeds,
- const std::vector<Scalar>& votes) const
- {
- Proof pi = generate_ownership_proof();
- return PrsonaBase::generate_vote_proof(
- pi,
- serverPublicKey.get_bipoint_curvegen(),
- serverPublicKey.get_bipoint_curve_subgroup_gen(),
- replaces,
- oldEncryptedVotes,
- newEncryptedVotes,
- seeds,
- votes);
- }
- /*
- * SERVER AGREEMENT PROOFS
- */
- bool PrsonaClient::verify_valid_vote_row_proof(
- const Proof& pi,
- const Curvepoint& shortTermPublicKey,
- const std::vector<CurveBipoint>& commitment) const
- {
- std::vector<Proof> fullProof;
- fullProof.push_back(pi);
- servers->get_other_vote_row_commitments(fullProof, shortTermPublicKey);
- return PrsonaBase::verify_valid_vote_row_proof(fullProof, commitment);
- }
- bool PrsonaClient::verify_valid_vote_matrix_proof(
- const Proof& pi,
- const std::vector<std::vector<CurveBipoint>>& commitment) const
- {
- std::vector<Proof> fullProof;
- fullProof.push_back(pi);
- servers->get_other_vote_matrix_commitments(fullProof);
- return PrsonaBase::verify_valid_vote_matrix_proof(fullProof, commitment);
- }
- bool PrsonaClient::verify_valid_user_tally_proof(
- const Proof& pi,
- const Curvepoint& shortTermPublicKey,
- const EGCiphertext& commitment) const
- {
- std::vector<Proof> fullProof;
- fullProof.push_back(pi);
- servers->get_other_user_tally_commitments(fullProof, shortTermPublicKey);
- return PrsonaBase::verify_valid_user_tally_proof(fullProof, commitment);
- }
- bool PrsonaClient::verify_valid_server_tally_proof(
- const Proof& pi,
- const Curvepoint& shortTermPublicKey,
- const TwistBipoint& commitment) const
- {
- std::vector<Proof> fullProof;
- fullProof.push_back(pi);
- servers->get_other_server_tally_commitments(fullProof, shortTermPublicKey);
- return PrsonaBase::verify_valid_server_tally_proof(fullProof, commitment);
- }
- bool PrsonaClient::verify_valid_pseudonyms_proof(
- const Proof& pi,
- const std::vector<Curvepoint>& commitment) const
- {
- std::vector<Proof> fullProof;
- fullProof.push_back(pi);
- servers->get_other_pseudonyms_commitments(fullProof);
- return PrsonaBase::verify_valid_pseudonyms_proof(fullProof, commitment);
- }
|