|
@@ -1,9 +1,16 @@
|
|
|
+#include <iostream>
|
|
|
+
|
|
|
#include "server.hpp"
|
|
|
|
|
|
-extern const scalar_t bn_n;
|
|
|
-const Scalar PrsonaServer::scalarN(bn_n);
|
|
|
extern const curvepoint_fp_t bn_curvegen;
|
|
|
const Curvepoint PrsonaServer::elGamalGenerator(bn_curvegen);
|
|
|
+extern const scalar_t bn_n;
|
|
|
+const Scalar PrsonaServer::scalarN(bn_n);
|
|
|
+const Scalar PrsonaServer::defaultTally(0);
|
|
|
+const Scalar PrsonaServer::defaultVote(0);
|
|
|
+
|
|
|
+bool PrsonaServer::malicious_server = false;
|
|
|
+bool PrsonaServer::malicious_client = false;
|
|
|
|
|
|
PrsonaServer::PrsonaServer()
|
|
|
{
|
|
@@ -15,102 +22,201 @@ PrsonaServer::PrsonaServer()
|
|
|
currentSeed.set_random();
|
|
|
}
|
|
|
|
|
|
+PrsonaServer::PrsonaServer(const BGN& other_bgn, const Curvepoint& other_blind_gen)
|
|
|
+: bgn_system(other_bgn), elGamalBlindGenerator(other_blind_gen)
|
|
|
+{
|
|
|
+ currentSeed.set_random();
|
|
|
+}
|
|
|
+
|
|
|
+void PrsonaServer::set_malicious_server()
|
|
|
+{
|
|
|
+ malicious_server = true;
|
|
|
+}
|
|
|
+
|
|
|
+void PrsonaServer::set_malicious_client()
|
|
|
+{
|
|
|
+ malicious_client = true;
|
|
|
+}
|
|
|
+
|
|
|
+BGNPublicKey PrsonaServer::get_bgn_public_key() const
|
|
|
+{
|
|
|
+ return bgn_system.get_public_key();
|
|
|
+}
|
|
|
+
|
|
|
Curvepoint PrsonaServer::get_blinding_generator() const
|
|
|
{
|
|
|
return elGamalBlindGenerator;
|
|
|
}
|
|
|
|
|
|
-Curvepoint PrsonaServer::get_fresh_generator() const
|
|
|
+Curvepoint PrsonaServer::add_seed_to_generator(Proof& pi, const Curvepoint& currGenerator) const
|
|
|
+{
|
|
|
+ pi = generate_valid_fresh_generator_proof(pi);
|
|
|
+
|
|
|
+ return currGenerator * currentSeed;
|
|
|
+}
|
|
|
+
|
|
|
+std::vector<CurveBipoint> PrsonaServer::get_current_votes_by(Proof& pi, const Curvepoint& shortTermPublicKey) const
|
|
|
{
|
|
|
- return elGamalGenerator * currentSeed;
|
|
|
+ std::vector<CurveBipoint> retval;
|
|
|
+ size_t voteSubmitter = binary_search(shortTermPublicKey);
|
|
|
+ retval = voteMatrix[voteSubmitter];
|
|
|
+
|
|
|
+ pi = generate_votes_valid_proof(retval, shortTermPublicKey);
|
|
|
+
|
|
|
+ return retval;
|
|
|
}
|
|
|
|
|
|
-Curvepoint PrsonaServer::add_new_client(const Curvepoint& longTermPublicKey)
|
|
|
+void PrsonaServer::add_new_client(const Proof& proofOfValidKey, Proof& proofOfValidAddition, const Curvepoint& shortTermPublicKey)
|
|
|
{
|
|
|
- Curvepoint newPseudonym = longTermPublicKey * currentSeed;
|
|
|
- currentPseudonyms.push_back(newPseudonym);
|
|
|
+ if (!verify_valid_key_proof(proofOfValidKey, shortTermPublicKey))
|
|
|
+ {
|
|
|
+ std::cerr << "Could not verify proof of valid key." << std::endl;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ currentPseudonyms.push_back(shortTermPublicKey);
|
|
|
|
|
|
TwistBipoint newTalliedVote;
|
|
|
- encrypt(newTalliedVote, Scalar(0));
|
|
|
+ bgn_system.encrypt(newTalliedVote, Scalar(defaultTally));
|
|
|
previousVoteTally.push_back(newTalliedVote);
|
|
|
|
|
|
- CurveBipoint defaultVote;
|
|
|
- encrypt(defaultVote, Scalar(0));
|
|
|
- vector<CurveBipoint> newRow;
|
|
|
+ CurveBipoint encryptedDefaultVote;
|
|
|
+ bgn_system.encrypt(encryptedDefaultVote, Scalar(defaultVote));
|
|
|
+ std::vector<CurveBipoint> newRow;
|
|
|
for (size_t i = 0; i < voteMatrix.size(); i++)
|
|
|
{
|
|
|
- rerandomize(defaultVote);
|
|
|
- voteMatrix[i].push_back(defaultVote);
|
|
|
- rerandomize(defaultVote);
|
|
|
- newRow.push_back(defaultVote);
|
|
|
+ encryptedDefaultVote = bgn_system.rerandomize(encryptedDefaultVote);
|
|
|
+ voteMatrix[i].push_back(encryptedDefaultVote);
|
|
|
+
|
|
|
+ encryptedDefaultVote = bgn_system.rerandomize(encryptedDefaultVote);
|
|
|
+ newRow.push_back(encryptedDefaultVote);
|
|
|
}
|
|
|
|
|
|
- rerandomize(defaultVote);
|
|
|
- newRow.push_back(defaultVote);
|
|
|
+ encryptedDefaultVote = bgn_system.rerandomize(encryptedDefaultVote);
|
|
|
+ newRow.push_back(encryptedDefaultVote);
|
|
|
voteMatrix.push_back(newRow);
|
|
|
|
|
|
- return newPseudonym;
|
|
|
+ order_data();
|
|
|
+
|
|
|
+ proofOfValidAddition = generate_proof_of_added_user(shortTermPublicKey);
|
|
|
}
|
|
|
|
|
|
-vector<EGCiphertext> PrsonaServer::epoch()
|
|
|
+void PrsonaServer::receive_vote(const Proof& pi, const std::vector<CurveBipoint>& votes, const Curvepoint& shortTermPublicKey)
|
|
|
{
|
|
|
- Scalar inverseSeed = scalarN - currentSeed;
|
|
|
- Scalar nextSeed;
|
|
|
- nextSeed.set_random();
|
|
|
+ if (!verify_vote_proof(pi, votes, shortTermPublicKey))
|
|
|
+ {
|
|
|
+ std::cerr << "Could not verify votes." << std::endl;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ size_t voteSubmitter = binary_search(shortTermPublicKey);
|
|
|
+ voteMatrix[voteSubmitter] = votes;
|
|
|
+}
|
|
|
+
|
|
|
+const BGN& PrsonaServer::get_bgn_details() const
|
|
|
+{
|
|
|
+ return bgn_system;
|
|
|
+}
|
|
|
|
|
|
- vector<Quadripoint> BGNEncryptedTallies;
|
|
|
- vector<Scalar> decryptedTallies;
|
|
|
- vector<EGCiphertext> EGEncryptedTallies(currentPseudonyms.size());
|
|
|
+std::vector<Scalar> PrsonaServer::tally_scores(Proof& pi)
|
|
|
+{
|
|
|
+ std::vector<Quadripoint> BGNEncryptedTallies;
|
|
|
+ std::vector<Scalar> decryptedTallies;
|
|
|
for (size_t i = 0; i < voteMatrix.size(); i++)
|
|
|
{
|
|
|
- vector<Quadripoint> currTally;
|
|
|
+ std::vector<Quadripoint> weightedVotes;
|
|
|
|
|
|
for (size_t j = 0; j < previousVoteTally.size(); j++)
|
|
|
{
|
|
|
- Quadripoint curr;
|
|
|
- homomorphic_multiplication(curr, voteMatrix[j][i], previousVoteTally[j]);
|
|
|
- currTally.push_back(curr);
|
|
|
+ Quadripoint curr = bgn_system.homomorphic_multiplication(voteMatrix[j][i], previousVoteTally[j]);
|
|
|
+ weightedVotes.push_back(curr);
|
|
|
}
|
|
|
|
|
|
- BGNEncryptedTallies.push_back(std::accumulate(currTally.begin(), currTally.end(), Quadripoint()));
|
|
|
+ Quadripoint currEncryptedTally = weightedVotes[0];
|
|
|
+ for (size_t j = 1; j < weightedVotes.size(); j++)
|
|
|
+ currEncryptedTally = bgn_system.homomorphic_addition(currEncryptedTally, weightedVotes[j]);
|
|
|
+
|
|
|
+ currEncryptedTally = bgn_system.rerandomize(currEncryptedTally);
|
|
|
+ decryptedTallies.push_back(bgn_system.decrypt(currEncryptedTally));
|
|
|
}
|
|
|
-
|
|
|
- for (size_t i = 0; i < currentPseudonyms.size(); i++)
|
|
|
+
|
|
|
+ pi = generate_proof_of_correct_tally(BGNEncryptedTallies, decryptedTallies);
|
|
|
+
|
|
|
+ return decryptedTallies;
|
|
|
+}
|
|
|
+
|
|
|
+void PrsonaServer::export_updates(std::vector<TwistBipoint>& otherPreviousVoteTally,
|
|
|
+ std::vector<Curvepoint>& otherCurrentPseudonyms, std::vector<std::vector<CurveBipoint>>& otherVoteMatrix) const
|
|
|
+{
|
|
|
+ otherPreviousVoteTally = previousVoteTally;
|
|
|
+ otherCurrentPseudonyms = currentPseudonyms;
|
|
|
+ otherVoteMatrix = voteMatrix;
|
|
|
+}
|
|
|
+
|
|
|
+void PrsonaServer::import_updates(const Proof& pi, const std::vector<TwistBipoint>& otherPreviousVoteTally,
|
|
|
+ const std::vector<Curvepoint>& otherCurrentPseudonyms, const std::vector<std::vector<CurveBipoint>>& otherVoteMatrix)
|
|
|
+{
|
|
|
+ if (!verify_update_proof(pi, otherPreviousVoteTally, otherCurrentPseudonyms, otherVoteMatrix))
|
|
|
{
|
|
|
- currentPseudonyms[i] = currentPseudonyms[i] * nextSeed;
|
|
|
- decryptedTallies.push_back(decrypt(BGNEncryptedTallies[i]));
|
|
|
+ std::cerr << "Could not verify valid update." << std::endl;
|
|
|
+ return;
|
|
|
}
|
|
|
- shuffle_vote_matrix(decryptedTallies);
|
|
|
-
|
|
|
- Curvepoint nextGenerator = elGamalGenerator * nextSeed;
|
|
|
- for (size_t i = 0; i < currentPseudonyms.size(); i++)
|
|
|
- {
|
|
|
- Scalar currMask;
|
|
|
- currMask.set_random();
|
|
|
|
|
|
- previousVoteTally[i] = encrypt(decryptedTallies[i]);
|
|
|
+ previousVoteTally = otherPreviousVoteTally;
|
|
|
+ currentPseudonyms = otherCurrentPseudonyms;
|
|
|
+ voteMatrix = otherVoteMatrix;
|
|
|
+}
|
|
|
+
|
|
|
+void PrsonaServer::epoch_part_one(Proof& pi, Curvepoint& nextGenerator, std::vector<Scalar>& decryptedTallies)
|
|
|
+{
|
|
|
+ nextSeed.set_random();
|
|
|
+ nextGenerator = nextGenerator * nextSeed;
|
|
|
+
|
|
|
+ for (size_t i = 0; i < currentPseudonyms.size(); i++)
|
|
|
+ currentPseudonyms[i] = currentPseudonyms[i] * nextSeed;
|
|
|
|
|
|
- EGEncryptedTallies[i].mask = currentPseudonyms[i] * currMask;
|
|
|
- EGEncryptedTallies[i].encryptedMessage = (nextGenerator * currMask) + (elGamalBlindGenerator * decryptedTallies[i]);
|
|
|
- }
|
|
|
+ std::vector<size_t> shuffleOrder = order_data();
|
|
|
+ rerandomize_vote_matrix();
|
|
|
+
|
|
|
+ std::vector<Scalar> reorderedTallies;
|
|
|
+ for (size_t i = 0; i < shuffleOrder.size(); i++)
|
|
|
+ reorderedTallies.push_back(decryptedTallies[shuffleOrder[i]]);
|
|
|
+ decryptedTallies = reorderedTallies;
|
|
|
+
|
|
|
+ pi = generate_proof_of_shuffle(shuffleOrder);
|
|
|
+}
|
|
|
+
|
|
|
+void PrsonaServer::epoch_part_two(Proof& pi, std::vector<EGCiphertext>& encryptedTallies)
|
|
|
+{
|
|
|
+ // TOFIX
|
|
|
+ Scalar inverseSeed = scalarN - currentSeed;
|
|
|
|
|
|
for (size_t i = 0; i < currentPseudonyms.size(); i++)
|
|
|
{
|
|
|
currentPseudonyms[i] = currentPseudonyms[i] * inverseSeed;
|
|
|
- EGEncryptedTallies[i].mask = EGEncryptedTallies[i].mask * inverseSeed;
|
|
|
+ encryptedTallies[i].mask = encryptedTallies[i].mask * inverseSeed;
|
|
|
}
|
|
|
- shuffle_vote_matrix(EGEncryptedTallies);
|
|
|
|
|
|
- return EGEncryptedTallies;
|
|
|
+ std::vector<size_t> shuffleOrder = order_data();
|
|
|
+ rerandomize_vote_matrix();
|
|
|
+
|
|
|
+ std::vector<EGCiphertext> reorderedTallies;
|
|
|
+ for (size_t i = 0; i < shuffleOrder.size(); i++)
|
|
|
+ reorderedTallies.push_back(encryptedTallies[shuffleOrder[i]]);
|
|
|
+ encryptedTallies = reorderedTallies;
|
|
|
+
|
|
|
+ pi = generate_proof_of_shuffle(shuffleOrder);
|
|
|
+
|
|
|
+ currentSeed = nextSeed;
|
|
|
}
|
|
|
|
|
|
-template <typename T>
|
|
|
-void PrsonaServer::shuffle_vote_matrix(vector<T>& otherVector)
|
|
|
+std::vector<size_t> PrsonaServer::order_data()
|
|
|
{
|
|
|
- vector<sorting_t> sortTracker;
|
|
|
+ std::vector<size_t> retval;
|
|
|
+ std::vector<SortingType> sortTracker;
|
|
|
for (size_t i = 0; i < currentPseudonyms.size(); i++)
|
|
|
{
|
|
|
- sorting_t curr;
|
|
|
+ SortingType curr;
|
|
|
|
|
|
curr.pseudonym = currentPseudonyms[i];
|
|
|
curr.index = i;
|
|
@@ -120,31 +226,30 @@ void PrsonaServer::shuffle_vote_matrix(vector<T>& otherVector)
|
|
|
|
|
|
std::sort(sortTracker.begin(), sortTracker.end());
|
|
|
|
|
|
- vector<Curvepoint> newPseudonyms;
|
|
|
- vector<TwistBipoint> newVoteTallies;
|
|
|
- vector<vector<CurveBipoint>> newVoteMatrix;
|
|
|
- vector<T> newOtherVector;
|
|
|
+ std::vector<Curvepoint> newPseudonyms;
|
|
|
+ std::vector<TwistBipoint> newVoteTallies;
|
|
|
+ std::vector<std::vector<CurveBipoint>> newVoteMatrix;
|
|
|
|
|
|
- for (size_t i = 0; i < currentPseudonyms.size(); i++)
|
|
|
+ for (size_t i = 0; i < sortTracker.size(); i++)
|
|
|
{
|
|
|
newPseudonyms.push_back(sortTracker[i].pseudonym);
|
|
|
newVoteTallies.push_back(previousVoteTally[sortTracker[i].index]);
|
|
|
- newOtherVector.push_back(otherVector[sortTracker[i].index]);
|
|
|
|
|
|
- vector<CurveBipoint> currNewRow;
|
|
|
+ std::vector<CurveBipoint> currNewRow;
|
|
|
for (size_t j = 0; j < currentPseudonyms.size(); j++)
|
|
|
{
|
|
|
currNewRow.push_back(voteMatrix[sortTracker[i].index][sortTracker[j].index]);
|
|
|
}
|
|
|
newVoteMatrix.push_back(currNewRow);
|
|
|
+
|
|
|
+ retval.push_back(sortTracker[i].index);
|
|
|
}
|
|
|
|
|
|
currentPseudonyms = newPseudonyms;
|
|
|
previousVoteTally = newVoteTallies;
|
|
|
voteMatrix = newVoteMatrix;
|
|
|
- otherVector = newOtherVector;
|
|
|
|
|
|
- rerandomize_vote_matrix();
|
|
|
+ return retval;
|
|
|
}
|
|
|
|
|
|
void PrsonaServer::rerandomize_vote_matrix()
|
|
@@ -153,21 +258,11 @@ void PrsonaServer::rerandomize_vote_matrix()
|
|
|
{
|
|
|
for (size_t j = 0; j < voteMatrix[0].size(); j++)
|
|
|
{
|
|
|
- voteMatrix[i][j] = rerandomize(voteMatrix[i][j]);
|
|
|
+ voteMatrix[i][j] = bgn_system.rerandomize(voteMatrix[i][j]);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void PrsonaServer::receive_vote(const Proof& pi, const vector<CurveBipoint>& votes, const Curvepoint& shortTermPublicKey)
|
|
|
-{
|
|
|
- if (!verify_vote_proof(pi, votes, shortTermPublicKey))
|
|
|
- return;
|
|
|
-
|
|
|
- size_t voteSubmitter = binary_search(shortTermPublicKey);
|
|
|
- voteMatrix[voteSubmitter] = votes;
|
|
|
- rerandomize_vote_matrix();
|
|
|
-}
|
|
|
-
|
|
|
size_t PrsonaServer::binary_search(const Curvepoint& index) const
|
|
|
{
|
|
|
size_t lo, hi;
|
|
@@ -187,7 +282,74 @@ size_t PrsonaServer::binary_search(const Curvepoint& index) const
|
|
|
return lo;
|
|
|
}
|
|
|
|
|
|
-bool PrsonaServer::verify_vote_proof(const Proof& pi, const vector<CurveBipoint>& votes, const Curvepoint& shortTermPublicKey) const
|
|
|
+bool PrsonaServer::verify_valid_key_proof(const Proof& pi, const Curvepoint& shortTermPublicKey) const
|
|
|
+{
|
|
|
+ if (!malicious_client)
|
|
|
+ return pi == "PROOF";
|
|
|
+
|
|
|
+ return pi == "PROOF";
|
|
|
+}
|
|
|
+
|
|
|
+bool PrsonaServer::verify_vote_proof(const Proof& pi, const std::vector<CurveBipoint>& votes, const Curvepoint& shortTermPublicKey) const
|
|
|
+{
|
|
|
+ if (!malicious_client)
|
|
|
+ return pi == "PROOF";
|
|
|
+
|
|
|
+ return pi == "PROOF";
|
|
|
+}
|
|
|
+
|
|
|
+bool PrsonaServer::verify_update_proof(const Proof& pi, const std::vector<TwistBipoint>& otherPreviousVoteTally, const std::vector<Curvepoint>& otherCurrentPseudonyms, const std::vector<std::vector<CurveBipoint>>& otherVoteMatrix) const
|
|
|
+{
|
|
|
+ if (!malicious_server)
|
|
|
+ return pi == "PROOF";
|
|
|
+
|
|
|
+ return pi == "PROOF";
|
|
|
+}
|
|
|
+
|
|
|
+Proof PrsonaServer::generate_valid_fresh_generator_proof(const Proof& oldProof) const
|
|
|
+{
|
|
|
+ if (!malicious_server)
|
|
|
+ return "PROOF";
|
|
|
+
|
|
|
+ return "PROOF";
|
|
|
+}
|
|
|
+
|
|
|
+Proof PrsonaServer::generate_votes_valid_proof(const std::vector<CurveBipoint>& votes, const Curvepoint& voter) const
|
|
|
+{
|
|
|
+ if (!malicious_server)
|
|
|
+ return "PROOF";
|
|
|
+
|
|
|
+ return "PROOF";
|
|
|
+}
|
|
|
+
|
|
|
+Proof PrsonaServer::generate_proof_of_added_user(const Curvepoint& shortTermPublicKey) const
|
|
|
+{
|
|
|
+ if (!malicious_server)
|
|
|
+ return "PROOF";
|
|
|
+
|
|
|
+ return "PROOF";
|
|
|
+}
|
|
|
+
|
|
|
+Proof PrsonaServer::generate_score_proof(const EGCiphertext& score) const
|
|
|
+{
|
|
|
+ if (!malicious_server)
|
|
|
+ return "PROOF";
|
|
|
+
|
|
|
+ return "PROOF";
|
|
|
+}
|
|
|
+
|
|
|
+Proof PrsonaServer::generate_proof_of_correct_tally(const std::vector<Quadripoint>& BGNEncryptedTallies, const std::vector<Scalar>& decryptedTallies) const
|
|
|
+{
|
|
|
+ if (!malicious_server)
|
|
|
+ return "PROOF";
|
|
|
+
|
|
|
+ return "PROOF";
|
|
|
+}
|
|
|
+
|
|
|
+Proof PrsonaServer::generate_proof_of_shuffle(const std::vector<size_t>& shuffle_order) const
|
|
|
{
|
|
|
+ if (!malicious_server)
|
|
|
+ return "PROOF";
|
|
|
|
|
|
+ return "PROOF";
|
|
|
}
|