123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669 |
- #include <iostream>
- #include "serverEntity.hpp"
- /********************
- * PUBLIC FUNCTIONS *
- ********************/
- /*
- * CONSTRUCTORS
- */
- PrsonaServerEntity::PrsonaServerEntity(size_t numServers)
- {
- if (numServers < 1)
- {
- std::cerr << "You have to have at least 1 server. "
- << "I'm making it anyways." << std::endl;
- }
- // Make the first server, which makes the BGN parameters
- PrsonaServer firstServer(numServers);
- servers.push_back(firstServer);
- // Make the rest of the servers, which take the BGN parameters
- const BGN& sharedBGN = firstServer.get_bgn_details();
- for (size_t i = 1; i < numServers; i++)
- servers.push_back(PrsonaServer(numServers, sharedBGN));
- // After all servers have made their seeds,
- // make sure they have the initial fresh generator
- std::vector<Proof> pi;
- Curvepoint firstGenerator = get_fresh_generator(pi);
- for (size_t i = 0; i < numServers; i++)
- servers[i].initialize_fresh_generator(pi, firstGenerator);
- pi.clear();
- // It's important that no server knows the DLOG between g and h for ElGamal,
- // so have each server collaborate to make h.
- Curvepoint blindGenerator = PrsonaServer::EL_GAMAL_GENERATOR;
- for (size_t i = 0; i < numServers; i++)
- {
- blindGenerator =
- servers[i].add_rand_seed_to_generator(pi, blindGenerator);
- }
- for (size_t i = 0; i < numServers; i++)
- servers[i].set_EG_blind_generator(pi, blindGenerator);
- }
- /*
- * BASIC PUBLIC SYSTEM INFO GETTERS
- */
- BGNPublicKey PrsonaServerEntity::get_bgn_public_key() const
- {
- return get_bgn_public_key(0);
- }
- BGNPublicKey PrsonaServerEntity::get_bgn_public_key(size_t which) const
- {
- return servers[which].get_bgn_public_key();
- }
- Curvepoint PrsonaServerEntity::get_blinding_generator() const
- {
- return get_blinding_generator(0);
- }
- Curvepoint PrsonaServerEntity::get_blinding_generator(size_t which) const
- {
- std::vector<Proof> pi;
- Curvepoint retval = get_blinding_generator(pi, which);
- if (!servers[which].verify_generator_proof(
- pi, retval, servers[which].get_num_servers()))
- {
- std::cerr << "Error making the generator, aborting." << std::endl;
- return Curvepoint();
- }
- return retval;
- }
- Curvepoint PrsonaServerEntity::get_blinding_generator(
- std::vector<Proof>& pi) const
- {
- return get_blinding_generator(pi, 0);
- }
- Curvepoint PrsonaServerEntity::get_blinding_generator(
- std::vector<Proof>& pi, size_t which) const
- {
- return servers[which].get_blinding_generator(pi);
- }
- Curvepoint PrsonaServerEntity::get_fresh_generator() const
- {
- return get_fresh_generator(0);
- }
- Curvepoint PrsonaServerEntity::get_fresh_generator(size_t which) const
- {
- std::vector<Proof> pi;
- Curvepoint retval = get_fresh_generator(pi, which);
- if (!servers[which].verify_generator_proof(
- pi, retval, servers[which].get_num_servers()))
- {
- std::cerr << "Error making the generator, aborting." << std::endl;
- return Curvepoint();
- }
- return retval;
- }
- Curvepoint PrsonaServerEntity::get_fresh_generator(
- std::vector<Proof>& pi) const
- {
- return get_fresh_generator(pi, 0);
- }
- Curvepoint PrsonaServerEntity::get_fresh_generator(
- std::vector<Proof>& pi, size_t which) const
- {
- Curvepoint retval = PrsonaServer::EL_GAMAL_GENERATOR;
- pi.clear();
- for (size_t j = 0; j < servers[which].get_num_servers(); j++)
- {
- size_t index = (which + j) % servers[which].get_num_servers();
- retval = servers[index].add_curr_seed_to_generator(pi, retval);
- }
- return retval;
- }
- size_t PrsonaServerEntity::get_num_clients() const
- {
- return get_num_clients(0);
- }
- size_t PrsonaServerEntity::get_num_clients(size_t which) const
- {
- return servers[which].get_num_clients();
- }
- size_t PrsonaServerEntity::get_num_servers() const
- {
- return get_num_servers(0);
- }
- size_t PrsonaServerEntity::get_num_servers(size_t which) const
- {
- return servers[which].get_num_servers();
- }
- /*
- * ENCRYPTED DATA GETTERS
- */
- std::vector<CurveBipoint> PrsonaServerEntity::get_current_votes_by(
- Proof& pi, const Curvepoint& shortTermPublicKey) const
- {
- return get_current_votes_by(pi, shortTermPublicKey, 0);
- }
- /* Call this in order to get the current encrypted votes cast by a given user
- * (who is identified by their short term public key).
- * In practice, this is intended for clients,
- * who need to know their current votes in order to rerandomize them. */
- std::vector<CurveBipoint> PrsonaServerEntity::get_current_votes_by(
- Proof& pi, const Curvepoint& shortTermPublicKey, size_t which) const
- {
- return servers[which].get_current_votes_by(pi, shortTermPublicKey);
- }
- std::vector<std::vector<CurveBipoint>> PrsonaServerEntity::get_all_current_votes(
- Proof& pi) const
- {
- return get_all_current_votes(pi, 0);
- }
- std::vector<std::vector<CurveBipoint>> PrsonaServerEntity::get_all_current_votes(
- Proof& pi, size_t which) const
- {
- return servers[which].get_all_current_votes(pi);
- }
- EGCiphertext PrsonaServerEntity::get_current_user_encrypted_tally(
- Proof& pi, const Curvepoint& shortTermPublicKey) const
- {
- return get_current_user_encrypted_tally(pi, shortTermPublicKey, 0);
- }
- EGCiphertext PrsonaServerEntity::get_current_user_encrypted_tally(
- Proof& pi, const Curvepoint& shortTermPublicKey, size_t which) const
- {
- return servers[which].get_current_user_encrypted_tally(
- pi, shortTermPublicKey);
- }
- TwistBipoint PrsonaServerEntity::get_current_server_encrypted_tally(
- Proof& pi, const Curvepoint& shortTermPublicKey) const
- {
- return get_current_server_encrypted_tally(pi, shortTermPublicKey, 0);
- }
- TwistBipoint PrsonaServerEntity::get_current_server_encrypted_tally(
- Proof& pi, const Curvepoint& shortTermPublicKey, size_t which) const
- {
- return servers[which].get_current_server_encrypted_tally(
- pi, shortTermPublicKey);
- }
- std::vector<Curvepoint> PrsonaServerEntity::get_current_pseudonyms(
- Proof& pi) const
- {
- return get_current_pseudonyms(pi, 0);
- }
- std::vector<Curvepoint> PrsonaServerEntity::get_current_pseudonyms(
- Proof& pi, size_t which) const
- {
- return servers[which].get_current_pseudonyms(pi);
- }
- /*
- * PROOF COMMITMENT GETTERS
- */
- void PrsonaServerEntity::get_other_vote_row_commitments(
- std::vector<Proof>& pi, const Curvepoint& request) const
- {
- get_other_vote_row_commitments(pi, request, 0);
- }
- void PrsonaServerEntity::get_other_vote_row_commitments(
- std::vector<Proof>& pi, const Curvepoint& request, size_t whichNot) const
- {
- for (size_t i = 0; i < servers.size(); i++)
- {
- if (i == whichNot)
- continue;
- pi.push_back(servers[i].get_vote_row_commitment(request));
- }
- }
- void PrsonaServerEntity::get_other_vote_matrix_commitments(
- std::vector<Proof>& pi) const
- {
- get_other_vote_matrix_commitments(pi, 0);
- }
- void PrsonaServerEntity::get_other_vote_matrix_commitments(
- std::vector<Proof>& pi, size_t whichNot) const
- {
- for (size_t i = 0; i < servers.size(); i++)
- {
- if (i == whichNot)
- continue;
- pi.push_back(servers[i].get_vote_matrix_commitment());
- }
- }
- void PrsonaServerEntity::get_other_user_tally_commitments(
- std::vector<Proof>& pi, const Curvepoint& request) const
- {
- get_other_user_tally_commitments(pi, request, 0);
- }
- void PrsonaServerEntity::get_other_user_tally_commitments(
- std::vector<Proof>& pi, const Curvepoint& request, size_t whichNot) const
- {
- for (size_t i = 0; i < servers.size(); i++)
- {
- if (i == whichNot)
- continue;
- pi.push_back(servers[i].get_user_tally_commitment(request));
- }
- }
- void PrsonaServerEntity::get_other_server_tally_commitments(
- std::vector<Proof>& pi, const Curvepoint& request) const
- {
- get_other_server_tally_commitments(pi, request, 0);
- }
- void PrsonaServerEntity::get_other_server_tally_commitments(
- std::vector<Proof>& pi, const Curvepoint& request, size_t whichNot) const
- {
- for (size_t i = 0; i < servers.size(); i++)
- {
- if (i == whichNot)
- continue;
- pi.push_back(servers[i].get_server_tally_commitment(request));
- }
- }
- void PrsonaServerEntity::get_other_pseudonyms_commitments(
- std::vector<Proof>& pi) const
- {
- get_other_pseudonyms_commitments(pi, 0);
- }
- void PrsonaServerEntity::get_other_pseudonyms_commitments(
- std::vector<Proof>& pi, size_t whichNot) const
- {
- for (size_t i = 0; i < servers.size(); i++)
- {
- if (i == whichNot)
- continue;
- pi.push_back(servers[i].get_pseudonyms_commitment());
- }
- }
- /*
- * CLIENT INTERACTIONS
- */
- void PrsonaServerEntity::add_new_client(PrsonaClient& newUser)
- {
- add_new_client(newUser, 0);
- }
- /* Add a new client (who is identified only by their short term public key)
- * One server does the main work, then other servers import their (proven)
- * exported data. */
- void PrsonaServerEntity::add_new_client(PrsonaClient& newUser, size_t which)
- {
- Proof proofOfValidSTPK, proofOfValidVotes;
- std::vector<Proof> proofOfValidGenerator, proofOfCorrectAddition;
- Curvepoint freshGenerator =
- get_fresh_generator(proofOfValidGenerator, which);
- // Users can't actually announce a short term public key
- // if they don't know the fresh generator.
- newUser.receive_fresh_generator(proofOfValidGenerator, freshGenerator);
- Curvepoint shortTermPublicKey = newUser.get_short_term_public_key(
- proofOfValidSTPK);
- // Do the actual work of adding the client to the first server
- servers[which].add_new_client(
- proofOfCorrectAddition, proofOfValidSTPK, shortTermPublicKey);
- // Then, export the data to the rest of the servers
- std::vector<TwistBipoint> previousVoteTallies;
- std::vector<Curvepoint> currentPseudonyms;
- std::vector<EGCiphertext> currentUserEncryptedTallies;
- std::vector<std::vector<CurveBipoint>> voteMatrix;
- previousVoteTallies = servers[which].previousVoteTallies;
- currentPseudonyms = servers[which].currentPseudonyms;
- currentUserEncryptedTallies = servers[which].currentUserEncryptedTallies;
- voteMatrix = servers[which].voteMatrix;
- for (size_t j = 1; j < servers[which].get_num_servers(); j++)
- {
- size_t index = (which + j) % servers[which].get_num_servers();
- servers[index].import_new_user_update(
- proofOfCorrectAddition,
- previousVoteTallies,
- currentPseudonyms,
- currentUserEncryptedTallies,
- voteMatrix);
- }
- // Finally, give the user the information it needs
- // about its current tally and votes
- transmit_new_user_data(proofOfCorrectAddition, newUser);
- }
- // Receive a new vote row from a user (identified by short term public key).
- bool PrsonaServerEntity::receive_vote(
- const std::vector<Proof>& pi,
- const std::vector<CurveBipoint>& newVotes,
- const Curvepoint& shortTermPublicKey)
- {
- return receive_vote(pi, newVotes, shortTermPublicKey, 0);
- }
- bool PrsonaServerEntity::receive_vote(
- const std::vector<Proof>& pi,
- const std::vector<CurveBipoint>& newVotes,
- const Curvepoint& shortTermPublicKey,
- size_t which)
- {
- bool retval = true;
- for (size_t i = 0; i < servers[which].get_num_servers(); i++)
- {
- size_t index = (i + which) % servers[which].get_num_servers();
- retval = retval &&
- servers[index].receive_vote(pi, newVotes, shortTermPublicKey);
- }
- return retval;
- }
- void PrsonaServerEntity::transmit_new_user_data(
- const std::vector<Proof>& pi, PrsonaClient& newUser) const
- {
- newUser.receive_new_user_data(pi);
- }
- void PrsonaServerEntity::transmit_updates(PrsonaClient& currUser) const
- {
- transmit_updates(currUser, 0);
- }
- // After tallying scores and new vote matrix,
- // give those to a user for the new epoch
- void PrsonaServerEntity::transmit_updates(
- PrsonaClient& currUser, size_t which) const
- {
- Proof proofOfValidSTPK, proofOfScore, proofOfCorrectVotes;
- std::vector<Proof> proofOfValidGenerator;
- Curvepoint freshGenerator =
- get_fresh_generator(proofOfValidGenerator, which);
- // Get users the next fresh generator so they can correctly
- // ask for their new scores and vote row
- currUser.receive_fresh_generator(proofOfValidGenerator, freshGenerator);
- currUser.receive_vote_tally();
- }
- /*
- * EPOCH
- */
- void PrsonaServerEntity::epoch()
- {
- epoch(0);
- }
- // Do the epoch process
- void PrsonaServerEntity::epoch(size_t which)
- {
- Curvepoint nextGenerator = PrsonaServer::EL_GAMAL_GENERATOR;
-
- std::vector<std::vector<std::vector<Proof>>> pi;
- std::vector<std::vector<std::vector<Curvepoint>>> permutationCommits;
- std::vector<std::vector<std::vector<Curvepoint>>> freshPseudonymCommits;
- std::vector<std::vector<std::vector<Curvepoint>>> freshPseudonymPowerCommits;
- std::vector<std::vector<std::vector<Curvepoint>>> freshPseudonymSeedCommits;
- std::vector<std::vector<std::vector<TwistBipoint>>> serverTallyCommits;
- std::vector<std::vector<std::vector<std::vector<std::vector<CurveBipoint>>>>> voteMatrixCommits;
- std::vector<std::vector<std::vector<std::vector<Curvepoint>>>> userTallyCommits;
- std::vector<std::vector<std::vector<Curvepoint>>> userTallyMaskPowerCommits;
- std::vector<std::vector<std::vector<Curvepoint>>> userTallyMaskSeedCommits;
- std::vector<std::vector<Proof>> generator_proof_holder(1);
- pi.push_back(generator_proof_holder);
- // go from A_0 to A_0.5
- for (size_t i = 0; i < servers[which].get_num_servers(); i++)
- {
- if (i > 0)
- continue;
- size_t realI = (which + i) % servers[which].get_num_servers();
- std::cout << "Building up on server " << realI << "." << std::endl;
- servers[realI].build_up_midway_pseudonyms(
- pi,
- permutationCommits,
- freshPseudonymCommits,
- freshPseudonymPowerCommits,
- freshPseudonymSeedCommits,
- serverTallyCommits,
- voteMatrixCommits,
- nextGenerator);
- for (size_t j = 1; j < servers[which].get_num_servers(); j++)
- {
- std::vector<std::vector<std::vector<Curvepoint>>> currUserTallyCommits;
- std::vector<std::vector<Curvepoint>> currUserTallyMaskPowerCommits;
- std::vector<std::vector<Curvepoint>> currUserTallyMaskSeedCommits;
- size_t realJ = (which + j) % servers[which].get_num_servers();
- std::cout << "Giving to server " << realJ << "." << std::endl;
- servers[realJ].accept_epoch_updates(
- pi[i + 1],
- permutationCommits[i],
- freshPseudonymCommits[i],
- freshPseudonymPowerCommits[i],
- freshPseudonymSeedCommits[i],
- serverTallyCommits[i],
- voteMatrixCommits[i],
- currUserTallyCommits,
- currUserTallyMaskPowerCommits,
- currUserTallyMaskSeedCommits,
- false);
- }
- }
- std::vector<Proof> generator_proof = pi[0][0];
- pi.clear();
- permutationCommits.clear();
- freshPseudonymCommits.clear();
- freshPseudonymPowerCommits.clear();
- freshPseudonymSeedCommits.clear();
- serverTallyCommits.clear();
- voteMatrixCommits.clear();
- std::cout << "Tallying scores." << std::endl;
- /* Imagine that server 0 is encrypting these, then would do a ZKP that it
- * knows a secret mask and encrypted the correct value everyone else already
- * knows. Everyone else then adds a mask and proves they added a secret mask
- * to the committed values. */
- std::vector<EGCiphertext> currentUserEncryptedTallies =
- tally_scores(nextGenerator, which);
- distribute_tallied_scores(currentUserEncryptedTallies);
-
- // go from A_0.5 to A_1
- for (size_t i = 0; i < servers[which].get_num_servers(); i++)
- {
- size_t realI = (which + i) % servers[which].get_num_servers();
- std::cout << "Breaking down on server " << realI << "." << std::endl;
-
- servers[realI].break_down_midway_pseudonyms(
- generator_proof,
- pi,
- permutationCommits,
- freshPseudonymCommits,
- freshPseudonymPowerCommits,
- freshPseudonymSeedCommits,
- serverTallyCommits,
- voteMatrixCommits,
- userTallyCommits,
- userTallyMaskPowerCommits,
- userTallyMaskSeedCommits,
- nextGenerator);
-
- for (size_t j = 1; j < servers[which].get_num_servers(); j++)
- {
- size_t realJ = (which + j) % servers[which].get_num_servers();
- std::cout << "Giving to server " << realJ << "." << std::endl;
- servers[realJ].accept_epoch_updates(
- pi[i],
- permutationCommits[i],
- freshPseudonymCommits[i],
- freshPseudonymPowerCommits[i],
- freshPseudonymSeedCommits[i],
- serverTallyCommits[i],
- voteMatrixCommits[i],
- userTallyCommits[i],
- userTallyMaskPowerCommits[i],
- userTallyMaskSeedCommits[i],
- true);
- }
- }
- }
- void PrsonaServerEntity::print_scores() const
- {
- BGN bgnSystem = servers[0].bgnSystem;
- std::vector<TwistBipoint> scores = servers[0].previousVoteTallies;
- std::cout << "[";
- for (size_t i = 0; i < scores.size(); i++)
- {
- std::cout << bgnSystem.decrypt(scores[i])
- << (i == scores.size() - 1 ? "]" : " ");
- }
- std::cout << std::endl;
- }
- void PrsonaServerEntity::print_votes() const
- {
- BGN bgnSystem = servers[0].bgnSystem;
- std::vector<std::vector<CurveBipoint>> voteMatrix = servers[0].voteMatrix;
- for (size_t i = 0; i < voteMatrix.size(); i++)
- {
- std::cout << (i == 0 ? "[[" : " [");
- for (size_t j = 0; j < voteMatrix[i].size(); j++)
- {
- std::cout << bgnSystem.decrypt(voteMatrix[i][j])
- << (j == voteMatrix[i].size() - 1 ? "]" : " ");
- }
- std::cout << (i == voteMatrix.size() - 1 ? "]" : " ") << std::endl;
- }
- }
- /*********************
- * PRIVATE FUNCTIONS *
- *********************/
- /*
- * SCORE TALLYING
- */
- /* Calculate scores, then scale the values appropriately,
- * so they are in the correct range to be used as vote weights.
- *
- * We're treating it as if we are one server, so that server gets the updated
- * weights to be sent to all other servers for the next epoch. */
- std::vector<EGCiphertext> PrsonaServerEntity::tally_scores(
- const Curvepoint& nextGenerator,
- size_t which)
- {
- std::vector<EGCiphertext> retval;
- std::vector<Scalar> decryptedTalliedScores = servers[which].tally_scores();
- mpz_class maxScorePossibleThisRound =
- servers[which].get_max_possible_score().toInt() *
- PrsonaBase::get_max_allowed_vote();
- mpz_class topOfScoreRange =
- decryptedTalliedScores.size() * PrsonaBase::get_max_allowed_vote();
- for (size_t i = 0; i < decryptedTalliedScores.size(); i++)
- {
- decryptedTalliedScores[i] =
- Scalar(
- (decryptedTalliedScores[i].toInt() * topOfScoreRange) /
- maxScorePossibleThisRound
- );
- EGCiphertext currCiphertext;
- retval.push_back(currCiphertext);
- Scalar currMask;
- currMask.set_random();
- // Give the server the new weights,
- // to get passed around to the other servers
- servers[which].bgnSystem.encrypt(
- servers[which].previousVoteTallies[i], decryptedTalliedScores[i]);
-
- retval[i].mask = servers[which].currentPseudonyms[i] * currMask;
- retval[i].encryptedMessage =
- (nextGenerator * currMask) +
- (servers[which].get_blinding_generator() * decryptedTalliedScores[i]);
- }
- return retval;
- }
- void PrsonaServerEntity::distribute_tallied_scores(
- const std::vector<EGCiphertext>& scores)
- {
- for (size_t i = 0; i < servers[0].get_num_servers(); i++)
- servers[i].currentUserEncryptedTallies = scores;
- }
- /*
- * BINARY SEARCH
- */
- // Completely normal binary search
- size_t PrsonaServerEntity::binary_search(
- const Curvepoint& shortTermPublicKey, size_t which) const
- {
- return servers[which].binary_search(shortTermPublicKey);
- }
|