|
@@ -15,155 +15,125 @@ using namespace std;
|
|
|
|
|
|
const int MAX_ALLOWED_VOTE = 2;
|
|
|
|
|
|
-// int argparse(
|
|
|
-// int argc,
|
|
|
-// char *argv[],
|
|
|
-// size_t &numServers,
|
|
|
-// size_t &numClients,
|
|
|
-// size_t &numRounds,
|
|
|
-// size_t &numVotes,
|
|
|
-// bool &maliciousServers,
|
|
|
-// bool &maliciousUsers,
|
|
|
-// string &seedStr)
|
|
|
-// {
|
|
|
-// string config_file;
|
|
|
-
|
|
|
-// // Declare a group of options that will be
|
|
|
-// // allowed only on command line
|
|
|
-// po::options_description generic("General options");
|
|
|
-// generic.add_options()
|
|
|
-// ("help", "produce this help message")
|
|
|
-// ("config,c", po::value<string>(&config_file)->default_value(""),
|
|
|
-// "name of a configuration file")
|
|
|
-// ;
|
|
|
-
|
|
|
-// // Declare a group of options that will be
|
|
|
-// // allowed both on command line and in
|
|
|
-// // config file
|
|
|
-// po::options_description config("Configuration");
|
|
|
-// config.add_options()
|
|
|
-// ("malicious-servers,M",
|
|
|
-// "presence of this flag indicates servers will operate in malicious model")
|
|
|
-// ("malicious-users,U",
|
|
|
-// "presence of this flag indicates users will operate in malicious model")
|
|
|
-// ("seed", po::value<string>(&seedStr)->default_value("default"),
|
|
|
-// "the random seed to use for this test")
|
|
|
-// ;
|
|
|
-
|
|
|
-// // Hidden options, will be allowed both on command line and
|
|
|
-// // in config file, but will not be shown to the user.
|
|
|
-// po::options_description hidden("Hidden options");
|
|
|
-// hidden.add_options()
|
|
|
-// ("number-servers,S", po::value<size_t>(&numServers)->default_value(2),
|
|
|
-// "number of servers in test")
|
|
|
-// ("number-users,N", po::value<size_t>(&numClients)->default_value(5),
|
|
|
-// "number of users in test")
|
|
|
-// ("number-rounds,R", po::value<size_t>(&numRounds)->default_value(3),
|
|
|
-// "number of rounds to perform in test")
|
|
|
-// ("number-votes,V", po::value<size_t>(&numVotes)->default_value(3),
|
|
|
-// "number of votes each user makes per round during test")
|
|
|
-// ;
|
|
|
-
|
|
|
-// po::options_description cmdline_options;
|
|
|
-// cmdline_options.add(generic).add(config).add(hidden);
|
|
|
-
|
|
|
-// po::options_description config_file_options;
|
|
|
-// config_file_options.add(config).add(hidden);
|
|
|
-
|
|
|
-// po::options_description visible("Allowed options");
|
|
|
-// visible.add(generic).add(config);
|
|
|
-
|
|
|
-// po::positional_options_description p;
|
|
|
-// p.add("number-servers", 1);
|
|
|
-// p.add("number-users", 1);
|
|
|
-// p.add("number-rounds", 1);
|
|
|
-// p.add("number-votes", 1);
|
|
|
-
|
|
|
-// po::variables_map vm;
|
|
|
-// store(po::command_line_parser(argc, argv).
|
|
|
-// options(cmdline_options).positional(p).run(), vm);
|
|
|
-// notify(vm);
|
|
|
-
|
|
|
-// if (!config_file.empty())
|
|
|
-// {
|
|
|
-// ifstream config(config_file.c_str());
|
|
|
-// if (!config)
|
|
|
-// {
|
|
|
-// cerr << "Cannot open config file: " << config_file << "\n";
|
|
|
-// return 2;
|
|
|
-// }
|
|
|
-// else
|
|
|
-// {
|
|
|
-// store(parse_config_file(config, config_file_options), vm);
|
|
|
-// notify(vm);
|
|
|
-// }
|
|
|
-// }
|
|
|
-
|
|
|
-// if (vm.count("help"))
|
|
|
-// {
|
|
|
-// cout << visible << endl;
|
|
|
-// return 1;
|
|
|
-// }
|
|
|
-
|
|
|
-// maliciousServers = vm.count("malicious-servers");
|
|
|
-// maliciousUsers = vm.count("malicious-users");
|
|
|
-
|
|
|
-// return 0;
|
|
|
-// }
|
|
|
-
|
|
|
// Initialize the classes we use
|
|
|
void initialize_prsona_classes()
|
|
|
{
|
|
|
Scalar::init();
|
|
|
- Curvepoint elGamalBlindGenerator = PrsonaServer::init();
|
|
|
- PrsonaClient::init(elGamalBlindGenerator);
|
|
|
+ PrsonaServer::init();
|
|
|
+ PrsonaClient::init();
|
|
|
+}
|
|
|
+
|
|
|
+// Quick and dirty mean calculation (used for averaging timings)
|
|
|
+double mean(vector<double> xx)
|
|
|
+{
|
|
|
+ return accumulate(xx.begin(), xx.end(), 0.0) / xx.size();
|
|
|
}
|
|
|
|
|
|
-// Do an epoch (including votes, etc.), and return the timing to print out
|
|
|
-double epoch(
|
|
|
+// Time how long it takes to make a proof of valid votes
|
|
|
+vector<double> make_votes(
|
|
|
default_random_engine& generator,
|
|
|
- PrsonaServerEntity& servers,
|
|
|
- vector<PrsonaClient>& users,
|
|
|
+ vector<vector<CurveBipoint>>& newEncryptedVotes,
|
|
|
+ vector<vector<Proof>>& validVoteProofs,
|
|
|
+ const vector<PrsonaClient>& users,
|
|
|
+ const PrsonaServerEntity& servers,
|
|
|
size_t numVotes)
|
|
|
{
|
|
|
- Proof unused;
|
|
|
+ vector<double> retval;
|
|
|
uniform_int_distribution<int> voteDistribution(0, MAX_ALLOWED_VOTE);
|
|
|
size_t numUsers = users.size();
|
|
|
+ newEncryptedVotes.clear();
|
|
|
|
|
|
for (size_t i = 0; i < numUsers; i++)
|
|
|
{
|
|
|
// Make the correct number of new votes, but shuffle where they go
|
|
|
vector<Scalar> votes;
|
|
|
- vector<bool> replace;
|
|
|
+ vector<bool> replaces;
|
|
|
for (size_t j = 0; j < numUsers; j++)
|
|
|
{
|
|
|
votes.push_back(Scalar(voteDistribution(generator)));
|
|
|
- replace.push_back(j < numVotes);
|
|
|
+ replaces.push_back(j < numVotes);
|
|
|
}
|
|
|
- shuffle(replace.begin(), replace.end(), generator);
|
|
|
-
|
|
|
- // Make the actual votes to give to the servers
|
|
|
- Proof pi;
|
|
|
- Curvepoint shortTermPublicKey = users[i].get_short_term_public_key(pi);
|
|
|
- vector<CurveBipoint> encryptedVotes =
|
|
|
- servers.get_current_votes_by(pi, shortTermPublicKey);
|
|
|
- encryptedVotes = users[i].make_votes(
|
|
|
- pi, encryptedVotes, votes, replace);
|
|
|
-
|
|
|
- // Give the servers these new votes
|
|
|
- servers.receive_vote(pi, encryptedVotes, shortTermPublicKey);
|
|
|
+ shuffle(replaces.begin(), replaces.end(), generator);
|
|
|
+
|
|
|
+ Proof ownerProof;
|
|
|
+ Curvepoint shortTermPublicKey =
|
|
|
+ users[i].get_short_term_public_key(ownerProof);
|
|
|
+ vector<CurveBipoint> currEncryptedVotes =
|
|
|
+ servers.get_current_votes_by(ownerProof, shortTermPublicKey);
|
|
|
+ vector<Proof> currVoteProof;
|
|
|
+
|
|
|
+ chrono::high_resolution_clock::time_point t0 =
|
|
|
+ chrono::high_resolution_clock::now();
|
|
|
+ currEncryptedVotes = users[i].make_votes(
|
|
|
+ currVoteProof,
|
|
|
+ ownerProof,
|
|
|
+ currEncryptedVotes,
|
|
|
+ votes,
|
|
|
+ replaces);
|
|
|
+ chrono::high_resolution_clock::time_point t1 =
|
|
|
+ chrono::high_resolution_clock::now();
|
|
|
+
|
|
|
+ newEncryptedVotes.push_back(currEncryptedVotes);
|
|
|
+ validVoteProofs.push_back(currVoteProof);
|
|
|
+
|
|
|
+ chrono::duration<double> time_span =
|
|
|
+ chrono::duration_cast<chrono::duration<double>>(t1 - t0);
|
|
|
+ retval.push_back(time_span.count());
|
|
|
}
|
|
|
|
|
|
+ return retval;
|
|
|
+}
|
|
|
+
|
|
|
+// Time how long it takes to validate a proof of valid votes
|
|
|
+vector<double> transmit_votes_to_servers(
|
|
|
+ const vector<vector<CurveBipoint>>& newEncryptedVotes,
|
|
|
+ const vector<vector<Proof>>& validVoteProofs,
|
|
|
+ const vector<PrsonaClient>& users,
|
|
|
+ PrsonaServerEntity& servers)
|
|
|
+{
|
|
|
+ vector<double> retval;
|
|
|
+ size_t numUsers = users.size();
|
|
|
+ size_t numServers = servers.get_num_servers();
|
|
|
+
|
|
|
+ for (size_t i = 0; i < numUsers; i++)
|
|
|
+ {
|
|
|
+ Proof ownerProof;
|
|
|
+ Curvepoint shortTermPublicKey =
|
|
|
+ users[i].get_short_term_public_key(ownerProof);
|
|
|
+
|
|
|
+ for (size_t j = 0; j < numServers; j++)
|
|
|
+ {
|
|
|
+ chrono::high_resolution_clock::time_point t0 =
|
|
|
+ chrono::high_resolution_clock::now();
|
|
|
+ servers.receive_vote(
|
|
|
+ validVoteProofs[i],
|
|
|
+ newEncryptedVotes[i],
|
|
|
+ shortTermPublicKey,
|
|
|
+ j);
|
|
|
+ chrono::high_resolution_clock::time_point t1 =
|
|
|
+ chrono::high_resolution_clock::now();
|
|
|
+
|
|
|
+ chrono::duration<double> time_span =
|
|
|
+ chrono::duration_cast<chrono::duration<double>>(t1 - t0);
|
|
|
+ retval.push_back(time_span.count());
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ return retval;
|
|
|
+}
|
|
|
+
|
|
|
+// Time how long it takes to do the operations associated with an epoch
|
|
|
+double epoch(PrsonaServerEntity& servers)
|
|
|
+{
|
|
|
+ Proof unused;
|
|
|
+
|
|
|
// Do the epoch server calculations
|
|
|
chrono::high_resolution_clock::time_point t0 =
|
|
|
chrono::high_resolution_clock::now();
|
|
|
servers.epoch(unused);
|
|
|
chrono::high_resolution_clock::time_point t1 =
|
|
|
chrono::high_resolution_clock::now();
|
|
|
-
|
|
|
- // Transmit the results of the epoch to each user
|
|
|
- for (size_t i = 0; i < numUsers; i++)
|
|
|
- servers.transmit_updates(users[i]);
|
|
|
|
|
|
// Return the timing of the epoch server calculations
|
|
|
chrono::duration<double> time_span =
|
|
@@ -171,8 +141,36 @@ double epoch(
|
|
|
return time_span.count();
|
|
|
}
|
|
|
|
|
|
-void reputation_proof_attempt(default_random_engine& generator, const PrsonaClient& a, const PrsonaClient& b)
|
|
|
+// Time how long it takes each user to decrypt their new scores
|
|
|
+vector<double> transmit_epoch_updates(
|
|
|
+ vector<PrsonaClient>& users, const PrsonaServerEntity& servers)
|
|
|
{
|
|
|
+ vector<double> retval;
|
|
|
+ size_t numUsers = users.size();
|
|
|
+
|
|
|
+ for (size_t i = 0; i < numUsers; i++)
|
|
|
+ {
|
|
|
+ chrono::high_resolution_clock::time_point t0 =
|
|
|
+ chrono::high_resolution_clock::now();
|
|
|
+ servers.transmit_updates(users[i]);
|
|
|
+ chrono::high_resolution_clock::time_point t1 =
|
|
|
+ chrono::high_resolution_clock::now();
|
|
|
+
|
|
|
+ chrono::duration<double> time_span =
|
|
|
+ chrono::duration_cast<chrono::duration<double>>(t1 - t0);
|
|
|
+ retval.push_back(time_span.count());
|
|
|
+ }
|
|
|
+
|
|
|
+ return retval;
|
|
|
+}
|
|
|
+
|
|
|
+// Test if the proof of reputation level is working as expected
|
|
|
+void test_reputation_proof(
|
|
|
+ default_random_engine& generator,
|
|
|
+ const PrsonaClient& a,
|
|
|
+ const PrsonaClient& b)
|
|
|
+{
|
|
|
+ bool flag;
|
|
|
mpz_class aScore = a.get_score().toInt();
|
|
|
int i = 0;
|
|
|
while (i < aScore)
|
|
@@ -182,23 +180,92 @@ void reputation_proof_attempt(default_random_engine& generator, const PrsonaClie
|
|
|
Scalar goodThreshold(thresholdDistribution(generator));
|
|
|
Scalar badThreshold(aScore + 1);
|
|
|
|
|
|
- cout << "User A's score: " << aScore << endl;
|
|
|
- cout << "User A's chosen good threshold: " << goodThreshold << endl;
|
|
|
- cout << "User A's chosen bad threshold: " << badThreshold << endl;
|
|
|
-
|
|
|
Proof pi;
|
|
|
Curvepoint shortTermPublicKey = a.get_short_term_public_key(pi);
|
|
|
vector<Proof> goodRepProof = a.generate_reputation_proof(goodThreshold);
|
|
|
- cout << "TEST VALID PROOF: "
|
|
|
- << (b.verify_reputation_proof(goodRepProof, shortTermPublicKey, goodThreshold) ?
|
|
|
- "PASSED (Proof verified)" : "FAILED (Proof not verified)" )
|
|
|
+ flag = b.verify_reputation_proof(
|
|
|
+ goodRepProof, shortTermPublicKey, goodThreshold);
|
|
|
+ cout << "TEST VALID REPUTATION PROOF: "
|
|
|
+ << (flag ? "PASSED (Proof verified)" : "FAILED (Proof not verified)" )
|
|
|
<< endl;
|
|
|
|
|
|
vector<Proof> badRepProof = a.generate_reputation_proof(badThreshold);
|
|
|
- cout << "TEST INVALID PROOF: "
|
|
|
- << (b.verify_reputation_proof(badRepProof, shortTermPublicKey, badThreshold) ?
|
|
|
- "FAILED (Proof verified)" : "PASSED (Proof not verified)" )
|
|
|
+ flag = b.verify_reputation_proof(
|
|
|
+ badRepProof, shortTermPublicKey, badThreshold);
|
|
|
+ cout << "TEST INVALID REPUTATION PROOF: "
|
|
|
+ << (flag ? "FAILED (Proof verified)" : "PASSED (Proof not verified)" )
|
|
|
+ << endl << endl;
|
|
|
+}
|
|
|
+
|
|
|
+// Test if the proof of valid votes is working as expected
|
|
|
+void test_vote_proof(
|
|
|
+ default_random_engine& generator,
|
|
|
+ const PrsonaClient& user,
|
|
|
+ PrsonaServerEntity& servers)
|
|
|
+{
|
|
|
+ size_t numUsers = servers.get_num_clients();
|
|
|
+ vector<Scalar> votes;
|
|
|
+ vector<bool> replaces;
|
|
|
+ bool flag;
|
|
|
+
|
|
|
+ for (size_t i = 0; i < numUsers; i++)
|
|
|
+ {
|
|
|
+ votes.push_back(Scalar(1));
|
|
|
+ replaces.push_back(true);
|
|
|
+ }
|
|
|
+
|
|
|
+ vector<Proof> validVoteProof;
|
|
|
+ Proof ownerProof;
|
|
|
+ Curvepoint shortTermPublicKey =
|
|
|
+ user.get_short_term_public_key(ownerProof);
|
|
|
+ vector<CurveBipoint> encryptedVotes =
|
|
|
+ servers.get_current_votes_by(ownerProof, shortTermPublicKey);
|
|
|
+ encryptedVotes =
|
|
|
+ user.make_votes(
|
|
|
+ validVoteProof, ownerProof, encryptedVotes, votes, replaces);
|
|
|
+
|
|
|
+ flag = servers.receive_vote(
|
|
|
+ validVoteProof, encryptedVotes, shortTermPublicKey);
|
|
|
+ cout << "TEST REPLACE VOTE PROOF: "
|
|
|
+ << (flag ? "PASSED (Proof verified)" : "FAILED (Proof not verified)" )
|
|
|
+ << endl;
|
|
|
+
|
|
|
+ for (size_t i = 0; i < numUsers; i++)
|
|
|
+ {
|
|
|
+ replaces[i] = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ shortTermPublicKey = user.get_short_term_public_key(ownerProof);
|
|
|
+ encryptedVotes =
|
|
|
+ servers.get_current_votes_by(ownerProof, shortTermPublicKey);
|
|
|
+ encryptedVotes =
|
|
|
+ user.make_votes(
|
|
|
+ validVoteProof, ownerProof, encryptedVotes, votes, replaces);
|
|
|
+
|
|
|
+ flag = servers.receive_vote(
|
|
|
+ validVoteProof, encryptedVotes, shortTermPublicKey);
|
|
|
+ cout << "TEST RERANDOMIZE VOTE PROOF: "
|
|
|
+ << (flag ? "PASSED (Proof verified)" : "FAILED (Proof not verified)" )
|
|
|
<< endl;
|
|
|
+
|
|
|
+ for (size_t i = 0; i < numUsers; i++)
|
|
|
+ {
|
|
|
+ votes[i] = Scalar(3);
|
|
|
+ replaces[i] = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ shortTermPublicKey = user.get_short_term_public_key(ownerProof);
|
|
|
+ encryptedVotes =
|
|
|
+ servers.get_current_votes_by(ownerProof, shortTermPublicKey);
|
|
|
+ encryptedVotes =
|
|
|
+ user.make_votes(
|
|
|
+ validVoteProof, ownerProof, encryptedVotes, votes, replaces);
|
|
|
+
|
|
|
+ flag = servers.receive_vote(
|
|
|
+ validVoteProof, encryptedVotes, shortTermPublicKey);
|
|
|
+ cout << "TEST INVALID REPLACE VOTE PROOF: "
|
|
|
+ << (flag ? "FAILED (Proof verified)" : "PASSED (Proof not verified)" )
|
|
|
+ << endl << endl;
|
|
|
}
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
@@ -229,7 +296,7 @@ int main(int argc, char *argv[])
|
|
|
cout << numUsers << " participants (voters/votees)" << endl;
|
|
|
cout << numRounds << " epochs" << endl;
|
|
|
cout << numVotesPerRound << " new (random) votes by each user per epoch"
|
|
|
- << endl;
|
|
|
+ << endl << endl;
|
|
|
|
|
|
// Set malicious flags where necessary
|
|
|
if (maliciousServers)
|
|
@@ -246,12 +313,13 @@ int main(int argc, char *argv[])
|
|
|
// Entities we operate with
|
|
|
PrsonaServerEntity servers(numServers);
|
|
|
BGNPublicKey bgnPublicKey = servers.get_bgn_public_key();
|
|
|
+ Curvepoint elGamalBlindGenerator = servers.get_blinding_generator();
|
|
|
|
|
|
- cout << "Initialization: adding users to system" << endl;
|
|
|
+ cout << "Initialization: adding users to system" << endl << endl;
|
|
|
vector<PrsonaClient> users;
|
|
|
for (size_t i = 0; i < numUsers; i++)
|
|
|
{
|
|
|
- PrsonaClient currUser(bgnPublicKey, &servers);
|
|
|
+ PrsonaClient currUser(bgnPublicKey, elGamalBlindGenerator, &servers);
|
|
|
servers.add_new_client(currUser);
|
|
|
users.push_back(currUser);
|
|
|
}
|
|
@@ -260,21 +328,54 @@ int main(int argc, char *argv[])
|
|
|
seed_seq seed(seedStr.begin(), seedStr.end());
|
|
|
default_random_engine generator(seed);
|
|
|
|
|
|
+ // Do the epoch operations
|
|
|
for (size_t i = 0; i < numRounds; i++)
|
|
|
{
|
|
|
+ vector<double> timings;
|
|
|
+
|
|
|
cout << "Round " << i+1 << " of " << numRounds << ": " << endl;
|
|
|
- double timing = epoch(generator, servers, users, numVotesPerRound);
|
|
|
- cout << "Server computation: " << timing << " seconds" << endl;
|
|
|
+
|
|
|
+ vector<vector<CurveBipoint>> newEncryptedVotes;
|
|
|
+ vector<vector<Proof>> validVoteProofs;
|
|
|
+ timings = make_votes(
|
|
|
+ generator,
|
|
|
+ newEncryptedVotes,
|
|
|
+ validVoteProofs,
|
|
|
+ users,
|
|
|
+ servers,
|
|
|
+ numVotesPerRound);
|
|
|
+
|
|
|
+ cout << "Vote generation (with proofs): " << mean(timings)
|
|
|
+ << " seconds per user" << endl;
|
|
|
+ timings.clear();
|
|
|
+
|
|
|
+ timings = transmit_votes_to_servers(
|
|
|
+ newEncryptedVotes, validVoteProofs, users, servers);
|
|
|
+
|
|
|
+ cout << "Vote validation: " << mean(timings)
|
|
|
+ << " seconds per vote vector/server" << endl;
|
|
|
+ timings.clear();
|
|
|
+
|
|
|
+ timings.push_back(epoch(servers));
|
|
|
+
|
|
|
+ cout << "Epoch computation: " << mean(timings) << " seconds" << endl;
|
|
|
+ timings.clear();
|
|
|
+
|
|
|
+ timings = transmit_epoch_updates(users, servers);
|
|
|
+
|
|
|
+ cout << "Transmit epoch updates: " << mean(timings)
|
|
|
+ << " seconds per user" << endl << endl;
|
|
|
}
|
|
|
|
|
|
- uniform_int_distribution<int> userDistribution(0, numUsers - 1);
|
|
|
- int user_a = userDistribution(generator);
|
|
|
- int user_b = user_a;
|
|
|
+ // Pick random users for our tests
|
|
|
+ uniform_int_distribution<size_t> userDistribution(0, numUsers - 1);
|
|
|
+ size_t user_a = userDistribution(generator);
|
|
|
+ size_t user_b = user_a;
|
|
|
while (user_b == user_a)
|
|
|
user_b = userDistribution(generator);
|
|
|
|
|
|
- cout << "Attempting a proof of reputation" << endl;
|
|
|
- reputation_proof_attempt(generator, users[user_a], users[user_b]);
|
|
|
+ test_reputation_proof(generator, users[user_a], users[user_b]);
|
|
|
+ test_vote_proof(generator, users[user_a], servers);
|
|
|
|
|
|
return 0;
|
|
|
}
|