networkClient.cpp 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038
  1. #include <iostream>
  2. #include <fstream>
  3. #include <sstream>
  4. #include "networkClient.hpp"
  5. /********************************************************
  6. ********* *********
  7. ********* client networking public functions *********
  8. ********* *********
  9. ********************************************************/
  10. /*
  11. * CREATOR FOR A NEW CLIENT
  12. */
  13. PrsonaClient *create_client(
  14. std::default_random_engine& rng,
  15. const std::vector<std::string>& serverIPs,
  16. const std::vector<int>& serverPorts,
  17. size_t numServers)
  18. {
  19. // Get the servers' public BGN key
  20. BGNPublicKey publicKey = get_bgn_public_key(rng, serverIPs, serverPorts);
  21. // Get the H point used in ElGamal operations
  22. std::vector<Proof> generatorProof;
  23. Twistpoint blindGenerator = get_generator(rng, serverIPs, serverPorts, false, generatorProof);
  24. // Make the actual client object
  25. PrsonaClient *retval = new PrsonaClient(generatorProof, blindGenerator, publicKey, numServers);
  26. // Get the current fresh generator
  27. generatorProof.clear();
  28. Twistpoint freshGenerator = get_generator(rng, serverIPs, serverPorts, true, generatorProof);
  29. // Load this fresh generator into the client object
  30. retval->receive_fresh_generator(generatorProof, freshGenerator);
  31. // Make the client's current short term public key
  32. Proof proofOfValidSTPK;
  33. Twistpoint shortTermPublicKey = retval->get_short_term_public_key(proofOfValidSTPK);
  34. // Register this client with the servers
  35. register_new_client(rng, retval, serverIPs, serverPorts, proofOfValidSTPK, shortTermPublicKey);
  36. return retval;
  37. }
  38. /*
  39. * FUNCTIONS TO PERFORM OPERATIONS FOR EXPERIMENT
  40. */
  41. void make_vote(
  42. std::default_random_engine& rng,
  43. PrsonaClient* prsonaClient,
  44. const std::vector<std::string>& serverIPs,
  45. const std::vector<int>& serverPorts,
  46. const std::string& target,
  47. int targetPort,
  48. size_t numClients,
  49. const CivetServer& civetServer,
  50. std::mutex& outputMtx,
  51. const std::string& outputFilename)
  52. {
  53. std::uniform_int_distribution<int> voteDistribution(0, PrsonaBase::get_max_allowed_vote());
  54. std::uniform_int_distribution<int> numVoteDistribution(0, numClients);
  55. size_t numVotes = numVoteDistribution(rng);
  56. // Make the correct number of new votes, but shuffle where they go
  57. std::vector<Scalar> votes;
  58. std::vector<bool> replaces;
  59. for (size_t j = 0; j < numClients; j++)
  60. {
  61. votes.push_back(Scalar(voteDistribution(rng)));
  62. replaces.push_back(j < numVotes);
  63. }
  64. shuffle(replaces.begin(), replaces.end(), rng);
  65. std::vector<size_t> bandwidthDataBefore = get_log_data(civetServer.getContext());
  66. std::chrono::high_resolution_clock::time_point wallTimeBefore = std::chrono::high_resolution_clock::now();
  67. clock_t cpuTimeBefore = clock();
  68. // Get current fresh generator (it's not guaranteed we've done this in the current epoch)
  69. std::vector<Proof> generatorProof;
  70. Twistpoint freshGenerator = get_generator(rng, serverIPs, serverPorts, true, generatorProof);
  71. // Load fresh generator into client object
  72. prsonaClient->receive_fresh_generator(generatorProof, freshGenerator);
  73. // Make current short term public key
  74. Twistpoint shortTermPublicKey = prsonaClient->get_short_term_public_key();
  75. // Get this client's current encrypted votes
  76. std::vector<Proof> fullProof;
  77. std::vector<TwistBipoint> encryptedVotes = get_server_committed_val<std::vector<TwistBipoint>>(rng, serverIPs, serverPorts, REQUEST_VOTE_ROW_URI, REQUEST_VOTE_ROW_COMMITMENT_URI, fullProof, shortTermPublicKey);
  78. // Use the client's method to make valid new votes (and their proof)
  79. std::vector<Proof> voteProof;
  80. encryptedVotes = prsonaClient->make_votes(voteProof, fullProof, encryptedVotes, votes, replaces);
  81. // Serialize this data
  82. std::string data = make_vote_string(voteProof, encryptedVotes, shortTermPublicKey);
  83. // Send the new votes (and their proof) to the chosen server
  84. send_item(rng, target, targetPort, SUBMIT_VOTE_URI, data, false);
  85. clock_t cpuTimeAfter = clock();
  86. std::chrono::high_resolution_clock::time_point wallTimeAfter = std::chrono::high_resolution_clock::now();
  87. std::vector<size_t> bandwidthDataAfter = get_log_data(civetServer.getContext());
  88. std::vector<double> timingData(2);
  89. timingData[0] = std::chrono::duration_cast<std::chrono::duration<double>>(wallTimeAfter - wallTimeBefore).count();
  90. timingData[1] = ((double)(cpuTimeAfter - cpuTimeBefore)) / CLOCKS_PER_SEC;
  91. std::vector<size_t> bandwidthData(2);
  92. std::cout << "Bytes read before: " << bandwidthDataBefore[0] << std::endl;
  93. std::cout << "Bytes read after: " << bandwidthDataAfter[0] << std::endl;
  94. bandwidthData[0] = bandwidthDataAfter[0] - bandwidthDataBefore[0];
  95. bandwidthData[1] = bandwidthDataAfter[1] - bandwidthDataBefore[1];
  96. write_log_data(outputMtx, outputFilename, timingData, bandwidthData);
  97. }
  98. bool make_reputation_proof(
  99. std::default_random_engine& rng,
  100. PrsonaClient* prsonaClient,
  101. const std::vector<std::string>& serverIPs,
  102. const std::vector<int>& serverPorts,
  103. const std::string& target,
  104. int targetPort,
  105. size_t numClients,
  106. const CivetServer& civetServer,
  107. std::mutex& outputMtx,
  108. const std::string& outputFilename)
  109. {
  110. std::vector<size_t> bandwidthDataBefore = get_log_data(civetServer.getContext());
  111. std::chrono::high_resolution_clock::time_point wallTimeBefore = std::chrono::high_resolution_clock::now();
  112. clock_t cpuTimeBefore = clock();
  113. // Get current fresh generator (it's not guaranteed we've done this in the current epoch)
  114. std::vector<Proof> generatorProof;
  115. Twistpoint freshGenerator = get_generator(rng, serverIPs, serverPorts, true, generatorProof);
  116. // Load fresh generator into client object
  117. prsonaClient->receive_fresh_generator(generatorProof, freshGenerator);
  118. // Make current short term public key
  119. Twistpoint shortTermPublicKey = prsonaClient->get_short_term_public_key();
  120. // Get this client's current encrypted score
  121. std::vector<Proof> encryptedScoreProof;
  122. EGCiphertext encryptedScore = get_server_committed_val<EGCiphertext>(rng, serverIPs, serverPorts, REQUEST_CLIENT_TALLY_URI, REQUEST_CLIENT_TALLY_COMMITMENT_URI, encryptedScoreProof, shortTermPublicKey);
  123. // Load this current encrypted score into client object
  124. prsonaClient->receive_vote_tally(encryptedScoreProof, encryptedScore);
  125. // Choose a random (valid) threshold to make a proof for
  126. mpz_class maxScore = prsonaClient->get_score().toInt();
  127. int maxScoreInt = 0;
  128. while (maxScoreInt < maxScore)
  129. maxScoreInt++;
  130. std::uniform_int_distribution<int> scoreThresholdDistribution(0, maxScoreInt);
  131. Scalar threshold(scoreThresholdDistribution(rng));
  132. // Use client object to generate a correct reputation proof with the chosen parameters
  133. std::vector<Proof> repProof = prsonaClient->generate_reputation_proof(threshold, numClients);
  134. // Serialize that proof
  135. std::string data = make_rep_proof_string(repProof, shortTermPublicKey, threshold);
  136. // Send that proof to a chosen client (and set up a file to receive whether or not the client accepted the proof)
  137. char *responseFile = send_item(rng, target, targetPort, VERIFY_REPUTATION_PROOF_URI, data, true);
  138. clock_t cpuTimeAfter = clock();
  139. std::chrono::high_resolution_clock::time_point wallTimeAfter = std::chrono::high_resolution_clock::now();
  140. std::vector<size_t> bandwidthDataAfter = get_log_data(civetServer.getContext());
  141. std::vector<double> timingData(2);
  142. timingData[0] = std::chrono::duration_cast<std::chrono::duration<double>>(wallTimeAfter - wallTimeBefore).count();
  143. timingData[1] = ((double)(cpuTimeAfter - cpuTimeBefore)) / CLOCKS_PER_SEC;
  144. std::vector<size_t> bandwidthData(2);
  145. bandwidthData[0] = bandwidthDataAfter[0] - bandwidthDataBefore[0];
  146. bandwidthData[1] = bandwidthDataAfter[1] - bandwidthDataBefore[1];
  147. write_log_data(outputMtx, outputFilename, timingData, bandwidthData);
  148. // The other client will give one byte back, containing whether or not it accepted the proof
  149. std::ifstream response(responseFile);
  150. char passed = response.get();
  151. // Delete the temp file
  152. remove(responseFile);
  153. delete [] responseFile;
  154. return passed == '\x01';
  155. }
  156. /*********************************************************
  157. ********* *********
  158. ********* client networking private functions *********
  159. ********* *********
  160. *********************************************************/
  161. /*
  162. * HELPERS TO ADD THIS CLIENT TO SERVERS
  163. */
  164. void register_new_client(
  165. std::default_random_engine& rng,
  166. PrsonaClient *newUser,
  167. const std::vector<std::string>& serverIPs,
  168. const std::vector<int>& serverPorts,
  169. const Proof& proofOfValidSTPK,
  170. const Twistpoint& shortTermPublicKey)
  171. {
  172. struct synchronization_tool sync;
  173. char *filename = NULL;
  174. struct mg_connection *conn = NULL;
  175. // Serialize the relevant data that needs to be sent
  176. std::stringstream buffer;
  177. std::string data;
  178. buffer << proofOfValidSTPK;
  179. buffer << shortTermPublicKey;
  180. data = buffer.str();
  181. // Set up connection to a server
  182. std::unique_lock<std::mutex> lck(sync.mtx);
  183. sync.val = 0;
  184. while (!conn)
  185. {
  186. // Pick a (pseudo-)random server to register this client with
  187. std::uniform_int_distribution<size_t> distribution(0, serverIPs.size() - 1);
  188. size_t whichServer = distribution(rng);
  189. conn = mg_connect_websocket_client(serverIPs[whichServer].c_str(), serverPorts[whichServer], USE_SSL, NULL, 0, SUBMIT_NEW_CLIENT_URI, "null", file_websocket_data_handler, file_websocket_close_handler, &sync);
  190. if (!conn)
  191. std::cerr << "Couldn't register new client" << std::endl;
  192. }
  193. // Establish a file to receive proof of addition to system at
  194. filename = set_temp_filename(rng, conn);
  195. // Send client data
  196. mg_websocket_client_write(conn, MG_WEBSOCKET_OPCODE_BINARY, data.c_str(), data.length());
  197. mg_websocket_client_write(conn, MG_WEBSOCKET_OPCODE_DATACOMPLETE, "", 0);
  198. // Wait for response
  199. while (!sync.val)
  200. sync.cv.wait(lck);
  201. // Close connection
  202. mg_close_connection(conn);
  203. // Un-serialize proof of addition to system
  204. std::vector<Proof> proofOfValidAddition = get_valid_addition_proof_from_file(filename);
  205. // Remove temp file used to receive serialized data
  206. remove(filename);
  207. delete [] filename;
  208. // Verify that the client was correctly added to the server
  209. verify_valid_addition(rng, newUser, serverIPs, serverPorts, proofOfValidAddition, shortTermPublicKey);
  210. }
  211. void verify_valid_addition(
  212. std::default_random_engine& rng,
  213. PrsonaClient *newUser,
  214. const std::vector<std::string>& serverIPs,
  215. const std::vector<int>& serverPorts,
  216. const std::vector<Proof>& proofOfValidAddition,
  217. const Twistpoint& shortTermPublicKey)
  218. {
  219. // Get general information on state of system from servers
  220. std::vector<Proof> serverEncryptedScoreProof;
  221. CurveBipoint serverEncryptedScore = get_server_committed_val<CurveBipoint>(rng, serverIPs, serverPorts, REQUEST_SERVER_TALLY_URI, REQUEST_SERVER_TALLY_COMMITMENT_URI, serverEncryptedScoreProof, shortTermPublicKey);
  222. std::vector<Proof> userEncryptedScoreProof;
  223. EGCiphertext userEncryptedScore = get_server_committed_val<EGCiphertext>(rng, serverIPs, serverPorts, REQUEST_CLIENT_TALLY_URI, REQUEST_CLIENT_TALLY_COMMITMENT_URI, userEncryptedScoreProof, shortTermPublicKey);
  224. std::vector<Proof> voteMatrixProof;
  225. std::vector<std::vector<TwistBipoint>> voteMatrix = get_server_committed_val<std::vector<std::vector<TwistBipoint>>>(rng, serverIPs, serverPorts, REQUEST_VOTE_MATRIX_URI, REQUEST_VOTE_MATRIX_COMMITMENT_URI, voteMatrixProof, shortTermPublicKey);
  226. std::vector<Proof> pseudonymsProof;
  227. std::vector<Twistpoint> currentPseudonyms = get_server_committed_val<std::vector<Twistpoint>>(rng, serverIPs, serverPorts, REQUEST_PSEUDONYMS_URI, REQUEST_PSEUDONYMS_COMMITMENT_URI, pseudonymsProof, shortTermPublicKey);
  228. // Use client's normal verification method
  229. newUser->receive_new_user_data(proofOfValidAddition, serverEncryptedScoreProof, serverEncryptedScore, userEncryptedScoreProof, userEncryptedScore, voteMatrixProof, voteMatrix, pseudonymsProof, currentPseudonyms);
  230. }
  231. /*
  232. * GETTERS FOR VARIOUS SERVER VALUES
  233. */
  234. Twistpoint get_generator(
  235. std::default_random_engine& rng,
  236. const std::vector<std::string>& serverIPs,
  237. const std::vector<int>& serverPorts,
  238. bool fresh,
  239. std::vector<Proof>& pi)
  240. {
  241. pi.clear();
  242. struct synchronization_tool sync;
  243. char *filename = NULL;
  244. struct mg_connection *conn = NULL;
  245. const char* whichUri = (fresh ? REQUEST_FRESH_GENERATOR_URI : REQUEST_EG_BLIND_GENERATOR_URI);
  246. // Set up connection to a server
  247. std::unique_lock<std::mutex> lck(sync.mtx);
  248. sync.val = 0;
  249. while (!conn)
  250. {
  251. // Pick a (pseudo-)random server to get the generator from
  252. std::uniform_int_distribution<size_t> distribution(0, serverIPs.size() - 1);
  253. size_t whichServer = distribution(rng);
  254. conn = mg_connect_websocket_client(serverIPs[whichServer].c_str(), serverPorts[whichServer], USE_SSL, NULL, 0, whichUri, "null", file_websocket_data_handler, file_websocket_close_handler, &sync);
  255. if (!conn)
  256. std::cerr << "Couldn't connect to servers to get generator" << std::endl;
  257. }
  258. // Establish a file to receive generator at
  259. filename = set_temp_filename(rng, conn);
  260. // Tell server to go ahead with data
  261. mg_websocket_client_write(conn, MG_WEBSOCKET_OPCODE_DATACOMPLETE, "", 0);
  262. // Wait for data
  263. while (!sync.val)
  264. sync.cv.wait(lck);
  265. // Close connection
  266. mg_close_connection(conn);
  267. // Un-serialize generator
  268. Twistpoint retval = get_generator_from_file(filename, pi);
  269. // Remove temp file used to receive serialized data
  270. remove(filename);
  271. delete [] filename;
  272. return retval;
  273. }
  274. BGNPublicKey get_bgn_public_key(
  275. std::default_random_engine& rng,
  276. const std::vector<std::string>& serverIPs,
  277. const std::vector<int>& serverPorts)
  278. {
  279. struct synchronization_tool sync;
  280. char *filename = NULL;
  281. struct mg_connection *conn = NULL;
  282. // Set up connection to a server
  283. std::unique_lock<std::mutex> lck(sync.mtx);
  284. sync.val = 0;
  285. while (!conn)
  286. {
  287. // Pick a (pseudo-)random server to get bgn data from
  288. std::uniform_int_distribution<size_t> distribution(0, serverIPs.size() - 1);
  289. size_t whichServer = distribution(rng);
  290. conn = mg_connect_websocket_client(serverIPs[whichServer].c_str(), serverPorts[whichServer], USE_SSL, NULL, 0, REQUEST_BGN_PUBKEY_URI, "null", file_websocket_data_handler, file_websocket_close_handler, &sync);
  291. if (!conn)
  292. std::cerr << "Couldn't connect to servers to obtain BGN details" << std::endl;
  293. }
  294. // Establish a file to receive BGN public key at
  295. filename = set_temp_filename(rng, conn);
  296. // Tell server to go ahead with data
  297. mg_websocket_client_write(conn, MG_WEBSOCKET_OPCODE_DATACOMPLETE, "", 0);
  298. // Wait for data
  299. while (!sync.val)
  300. sync.cv.wait(lck);
  301. // Close connection
  302. mg_close_connection(conn);
  303. // Un-serialize BGN public key
  304. BGNPublicKey retval = get_bgn_public_key_from_file(filename);
  305. // Remove temp file used to receive serialized data
  306. remove(filename);
  307. delete [] filename;
  308. return retval;
  309. }
  310. template <typename T>
  311. T get_server_committed_val(
  312. std::default_random_engine& rng,
  313. const std::vector<std::string>& serverIPs,
  314. const std::vector<int>& serverPorts,
  315. const char *firstUri,
  316. const char *commitUri,
  317. std::vector<Proof>& pi,
  318. const Twistpoint& shortTermPublicKey)
  319. {
  320. pi.clear();
  321. // Pick a (pseudo-)random server to get a committed-to value from
  322. std::uniform_int_distribution<size_t> distribution(0, serverIPs.size() - 1);
  323. size_t whichServer = distribution(rng);
  324. // Get the value itself
  325. Proof firstProof;
  326. T retval = get_first_committed_val<T>(rng, serverIPs[whichServer], serverPorts[whichServer], firstUri, firstProof, shortTermPublicKey);
  327. // Get all the other server's hashes of the value (to confirm they all agree on it)
  328. pi.push_back(firstProof);
  329. get_additional_commitment(rng, serverIPs, serverPorts, serverIPs[whichServer], serverPorts[whichServer], commitUri, pi, shortTermPublicKey);
  330. return retval;
  331. }
  332. template EGCiphertext get_server_committed_val<EGCiphertext>(std::default_random_engine &, const std::vector<std::string> &, const std::vector<int> &, const char *, const char *, std::vector<Proof> &, const Twistpoint &);
  333. template CurveBipoint get_server_committed_val<CurveBipoint>(std::default_random_engine &, const std::vector<std::string> &, const std::vector<int> &, const char *, const char *, std::vector<Proof> &, const Twistpoint &);
  334. template std::vector<Twistpoint> get_server_committed_val<std::vector<Twistpoint>>(std::default_random_engine &, const std::vector<std::string> &, const std::vector<int> &, const char *, const char *, std::vector<Proof> &, const Twistpoint &);
  335. template std::vector<TwistBipoint> get_server_committed_val<std::vector<TwistBipoint>>(std::default_random_engine &, const std::vector<std::string> &, const std::vector<int> &, const char *, const char *, std::vector<Proof> &, const Twistpoint &);
  336. template std::vector<std::vector<TwistBipoint>> get_server_committed_val<std::vector<std::vector<TwistBipoint>>>(std::default_random_engine &, const std::vector<std::string> &, const std::vector<int> &, const char *, const char *, std::vector<Proof> &, const Twistpoint &);
  337. /*
  338. * HELPERS FOR GENERALIZED GETTER FUNCTION
  339. */
  340. template <typename T>
  341. T get_first_committed_val(
  342. std::default_random_engine& rng,
  343. const std::string& serverIP,
  344. int serverPort,
  345. const char *firstUri,
  346. Proof& pi,
  347. const Twistpoint& shortTermPublicKey)
  348. {
  349. struct synchronization_tool sync;
  350. char *filename = NULL;
  351. struct mg_connection *conn = NULL;
  352. // Serialize the relevant data that needs to be sent
  353. std::stringstream buffer;
  354. std::string data;
  355. buffer << shortTermPublicKey;
  356. data = buffer.str();
  357. // Set up connection to a server
  358. std::unique_lock<std::mutex> lck(sync.mtx);
  359. sync.val = 0;
  360. while (!conn)
  361. {
  362. conn = mg_connect_websocket_client(serverIP.c_str(), serverPort, USE_SSL, NULL, 0, firstUri, "null", file_websocket_data_handler, file_websocket_close_handler, &sync);
  363. if (!conn)
  364. std::cerr << "Trouble getting encrypted score from server at " << serverIP << ":" << serverPort << std::endl;
  365. }
  366. // Establish a file to receive committed-to value at
  367. filename = set_temp_filename(rng, conn);
  368. // Send request data
  369. mg_websocket_client_write(conn, MG_WEBSOCKET_OPCODE_BINARY, data.c_str(), data.length());
  370. mg_websocket_client_write(conn, MG_WEBSOCKET_OPCODE_DATACOMPLETE, "", 0);
  371. // Wait for response
  372. while (!sync.val)
  373. sync.cv.wait(lck);
  374. // Close connection
  375. mg_close_connection(conn);
  376. // Un-serialize committed-to value
  377. T retval = get_committed_val_from_file<T>(filename, pi);
  378. // Remove temp file used to receive serialized data
  379. remove(filename);
  380. delete [] filename;
  381. return retval;
  382. }
  383. void get_additional_commitment(
  384. std::default_random_engine& rng,
  385. const std::vector<std::string>& serverIPs,
  386. const std::vector<int>& serverPorts,
  387. const std::string& skipIP,
  388. int skipPort,
  389. const char *commitUri,
  390. std::vector<Proof>& pi,
  391. const Twistpoint& shortTermPublicKey)
  392. {
  393. std::vector<char *> commitmentFilenames;
  394. std::vector<struct synchronization_tool *> commitmentSyncs;
  395. // Serialize the relevant data that needs to be sent
  396. std::stringstream buffer;
  397. std::string data;
  398. buffer << shortTermPublicKey;
  399. data = buffer.str();
  400. // Ask each server (besides the one we got the value from) what the hash of it is
  401. for (size_t i = 0; i < serverIPs.size(); i++)
  402. {
  403. if (serverIPs[i] == skipIP && serverPorts[i] == skipPort)
  404. continue;
  405. struct synchronization_tool *currSync = new struct synchronization_tool;
  406. commitmentSyncs.push_back(currSync);
  407. struct mg_connection *conn = NULL;
  408. // Set up connection to a server
  409. std::unique_lock<std::mutex> lck(currSync->mtx);
  410. currSync->val = 0;
  411. while (!conn)
  412. {
  413. conn = mg_connect_websocket_client(serverIPs[i].c_str(), serverPorts[i], USE_SSL, NULL, 0, commitUri, "null", file_websocket_data_handler, file_websocket_close_handler, currSync);
  414. if (!conn)
  415. std::cerr << "Trouble getting commitment from server at " << serverIPs[i] << ":" << serverPorts[i] << std::endl;
  416. }
  417. // Establish a file to receive hash at
  418. commitmentFilenames.push_back(set_temp_filename(rng, conn));
  419. // Send request data
  420. mg_websocket_client_write(conn, MG_WEBSOCKET_OPCODE_BINARY, data.c_str(), data.length());
  421. mg_websocket_client_write(conn, MG_WEBSOCKET_OPCODE_DATACOMPLETE, "", 0);
  422. // Wait for response
  423. while (!currSync->val)
  424. currSync->cv.wait(lck);
  425. // Close connection
  426. mg_close_connection(conn);
  427. }
  428. for (size_t i = 0; i < commitmentFilenames.size(); i++)
  429. {
  430. // Un-serialize hash
  431. pi.push_back(get_commitment_from_file(commitmentSyncs[i], commitmentFilenames[i]));
  432. // Clean up the std::mutex used for this hash
  433. delete commitmentSyncs[i];
  434. // Delete temp file used to receive serialized data
  435. remove(commitmentFilenames[i]);
  436. delete [] commitmentFilenames[i];
  437. }
  438. }
  439. /*
  440. * FILE I/O HELPERS FOR ALL GETTERS
  441. */
  442. std::vector<Proof> get_valid_addition_proof_from_file(
  443. const char *filename)
  444. {
  445. std::ifstream additionFile(filename);
  446. std::vector<Proof> retval;
  447. BinarySizeT sizeOfVector;
  448. additionFile >> sizeOfVector;
  449. for (size_t i = 0; i < sizeOfVector.val(); i++)
  450. {
  451. Proof currProof;
  452. additionFile >> currProof;
  453. retval.push_back(currProof);
  454. }
  455. return retval;
  456. }
  457. Twistpoint get_generator_from_file(
  458. const char *filename,
  459. std::vector<Proof>& pi)
  460. {
  461. std::ifstream genFile(filename);
  462. BinarySizeT sizeOfVector;
  463. genFile >> sizeOfVector;
  464. for (size_t i = 0; i < sizeOfVector.val(); i++)
  465. {
  466. Proof currProof;
  467. genFile >> currProof;
  468. pi.push_back(currProof);
  469. }
  470. Twistpoint retval;
  471. genFile >> retval;
  472. return retval;
  473. }
  474. BGNPublicKey get_bgn_public_key_from_file(
  475. const char *filename)
  476. {
  477. std::ifstream bgnFile(filename);
  478. BGNPublicKey publicKey;
  479. bgnFile >> publicKey;
  480. return publicKey;
  481. }
  482. // User-encrytped score
  483. template <>
  484. EGCiphertext get_committed_val_from_file<EGCiphertext>(
  485. const char *filename,
  486. Proof& pi)
  487. {
  488. std::ifstream valFile(filename);
  489. EGCiphertext retval;
  490. valFile >> pi;
  491. valFile >> retval;
  492. return retval;
  493. }
  494. // Server-encrytped score
  495. template <>
  496. CurveBipoint get_committed_val_from_file<CurveBipoint>(
  497. const char *filename,
  498. Proof& pi)
  499. {
  500. std::ifstream valFile(filename);
  501. CurveBipoint retval;
  502. valFile >> pi;
  503. valFile >> retval;
  504. return retval;
  505. }
  506. // Current pseudonyms
  507. template <>
  508. std::vector<Twistpoint> get_committed_val_from_file<std::vector<Twistpoint>>(
  509. const char *filename,
  510. Proof& pi)
  511. {
  512. std::ifstream valFile(filename);
  513. valFile >> pi;
  514. std::vector<Twistpoint> retval;
  515. BinarySizeT sizeOfVector;
  516. valFile >> sizeOfVector;
  517. for (size_t i = 0; i < sizeOfVector.val(); i++)
  518. {
  519. Twistpoint currVote;
  520. valFile >> currVote;
  521. retval.push_back(currVote);
  522. }
  523. return retval;
  524. }
  525. // Vote row
  526. template <>
  527. std::vector<TwistBipoint> get_committed_val_from_file<std::vector<TwistBipoint>>(
  528. const char *filename,
  529. Proof& pi)
  530. {
  531. std::ifstream valFile(filename);
  532. valFile >> pi;
  533. std::vector<TwistBipoint> retval;
  534. BinarySizeT sizeOfVector;
  535. valFile >> sizeOfVector;
  536. for (size_t i = 0; i < sizeOfVector.val(); i++)
  537. {
  538. TwistBipoint currVote;
  539. valFile >> currVote;
  540. retval.push_back(currVote);
  541. }
  542. return retval;
  543. }
  544. // Full vote matrix
  545. template <>
  546. std::vector<std::vector<TwistBipoint>> get_committed_val_from_file<std::vector<std::vector<TwistBipoint>>>(
  547. const char *filename,
  548. Proof& pi)
  549. {
  550. std::ifstream valFile(filename);
  551. valFile >> pi;
  552. std::vector<std::vector<TwistBipoint>> retval;
  553. BinarySizeT sizeOfVector;
  554. valFile >> sizeOfVector;
  555. for (size_t i = 0; i < sizeOfVector.val(); i++)
  556. {
  557. std::vector<TwistBipoint> currRow;
  558. for (size_t j = 0; j < sizeOfVector.val(); j++)
  559. {
  560. TwistBipoint currVote;
  561. valFile >> currVote;
  562. currRow.push_back(currVote);
  563. }
  564. retval.push_back(currRow);
  565. }
  566. return retval;
  567. }
  568. // NOTE: this function is the weird only case in which its usage will not assume you already have possession of the file lock to read from
  569. Proof get_commitment_from_file(
  570. struct synchronization_tool *sync,
  571. const char *filename)
  572. {
  573. std::unique_lock<std::mutex> lck(sync->mtx);
  574. std::ifstream scoreFile(filename);
  575. Proof retval;
  576. scoreFile >> retval;
  577. return retval;
  578. }
  579. /*
  580. * GENERALIZED SENDER FOR ORCHESTRATOR-SIGNALED OPERATIONS
  581. */
  582. char *send_item(
  583. std::default_random_engine& rng,
  584. const std::string& target,
  585. int targetPort,
  586. const char* whichUri,
  587. const std::string& data,
  588. bool responseExpected)
  589. {
  590. struct synchronization_tool sync;
  591. char *retval = NULL;
  592. struct mg_connection *conn = NULL;
  593. // Keep looping until item has been correctly received
  594. std::unique_lock<std::mutex> lck(sync.mtx);
  595. sync.val = 0;
  596. sync.val2 = 0;
  597. while (!sync.val)
  598. {
  599. // Set up connection to a server
  600. while (!conn)
  601. {
  602. if (responseExpected)
  603. conn = mg_connect_websocket_client(target.c_str(), targetPort, USE_SSL, NULL, 0, whichUri, "null", file_websocket_data_handler, file_websocket_close_handler, &sync);
  604. else
  605. conn = mg_connect_websocket_client(target.c_str(), targetPort, USE_SSL, NULL, 0, whichUri, "null", synchro_websocket_data_handler, synchro_websocket_close_handler, &sync);
  606. if (!conn)
  607. std::cerr << "Couldn't connect to server for purposes of sending item." << std::endl;
  608. }
  609. // Set up a file to receive a response at (if it's expected)
  610. if (responseExpected)
  611. retval = set_temp_filename(rng, conn);
  612. // Send request data
  613. mg_websocket_client_write(conn, MG_WEBSOCKET_OPCODE_BINARY, data.c_str(), data.length());
  614. mg_websocket_client_write(conn, MG_WEBSOCKET_OPCODE_DATACOMPLETE, "", 0);
  615. // Wait until the server has closed the connection
  616. while (!sync.val2)
  617. sync.cv.wait(lck);
  618. // Close connection
  619. mg_close_connection(conn);
  620. conn = NULL;
  621. }
  622. return retval;
  623. }
  624. /*
  625. * DATA SERIALIZERS
  626. */
  627. std::string make_vote_string(
  628. const std::vector<Proof>& pi,
  629. const std::vector<TwistBipoint>& newVotes,
  630. const Twistpoint& shortTermPublicKey)
  631. {
  632. std::stringstream buffer;
  633. BinarySizeT sizeOfVector;
  634. sizeOfVector.set(pi.size());
  635. buffer << sizeOfVector;
  636. for (size_t i = 0; i < sizeOfVector.val(); i++)
  637. buffer << pi[i];
  638. sizeOfVector.set(newVotes.size());
  639. buffer << sizeOfVector;
  640. for (size_t i = 0; i < sizeOfVector.val(); i++)
  641. buffer << newVotes[i];
  642. buffer << shortTermPublicKey;
  643. // Clients always tell the server they should share the vote row with other servers; servers never tell other servers to do this
  644. BinaryBool shouldDeal(true);
  645. buffer << shouldDeal;
  646. return buffer.str();
  647. }
  648. std::string make_rep_proof_string(
  649. const std::vector<Proof>& pi,
  650. const Twistpoint& shortTermPublicKey,
  651. const Scalar& threshold)
  652. {
  653. std::stringstream buffer;
  654. BinarySizeT sizeOfVector;
  655. sizeOfVector.set(pi.size());
  656. buffer << sizeOfVector;
  657. for (size_t i = 0; i < sizeOfVector.val(); i++)
  658. buffer << pi[i];
  659. buffer << shortTermPublicKey;
  660. buffer << threshold;
  661. return buffer.str();
  662. }
  663. /*********************************************************
  664. **** ****
  665. **** PrsonaClientWebSocketHandler member functions ****
  666. **** ****
  667. *********************************************************/
  668. /*
  669. * CONSTRUCTOR
  670. */
  671. PrsonaClientWebSocketHandler::PrsonaClientWebSocketHandler(
  672. std::default_random_engine& rng,
  673. PrsonaClient *prsonaClient,
  674. const std::vector<std::string>& serverIPs,
  675. const std::vector<int>& serverPorts,
  676. std::mutex& outputMtx,
  677. const std::string& outputFilename)
  678. : rng(rng), prsonaClient(prsonaClient), serverIPs(serverIPs), serverPorts(serverPorts), outputMtx(outputMtx), outputFilename(outputFilename)
  679. { /* */ }
  680. /*
  681. * REQUIRED BY INHERITED CLASS
  682. */
  683. bool PrsonaClientWebSocketHandler::handleConnection(
  684. CivetServer *server,
  685. const struct mg_connection *conn)
  686. {
  687. const struct mg_request_info *info = mg_get_request_info(conn);
  688. // Check if the request being made is something this client can respond to
  689. bool flag = (info->query_string && info->query_string[0] == PRSONA_VERIFY_REPUTATION_PROOF);
  690. return flag;
  691. }
  692. void PrsonaClientWebSocketHandler::handleReadyState(
  693. CivetServer *server,
  694. struct mg_connection *conn)
  695. {
  696. const struct mg_request_info *info = mg_get_request_info(conn);
  697. // Set filenames for query types that will need to un-serialize data to respond correctly
  698. switch (info->query_string[0])
  699. {
  700. case PRSONA_VERIFY_REPUTATION_PROOF:
  701. set_temp_filename(rng, conn);
  702. break;
  703. default:
  704. mg_set_user_connection_data(conn, NULL);
  705. break;
  706. }
  707. }
  708. bool PrsonaClientWebSocketHandler::handleData(
  709. CivetServer *server,
  710. struct mg_connection *conn,
  711. int bits,
  712. char *data,
  713. size_t data_len)
  714. {
  715. char *filename = (char *) mg_get_user_connection_data(conn);
  716. FILE *currFile = NULL;
  717. switch (bits & 0xf)
  718. {
  719. // Requester has indicated they have sent all relevant data
  720. case MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE:
  721. case MG_WEBSOCKET_OPCODE_DATACOMPLETE:
  722. generate_response(server, conn, filename);
  723. break;
  724. // Requester has sent more data (which may theoretically be broken up into multiple packets)
  725. case MG_WEBSOCKET_OPCODE_BINARY:
  726. case MG_WEBSOCKET_OPCODE_CONTINUATION:
  727. currFile = fopen(filename, "ab");
  728. fwrite(data, sizeof(char), data_len, currFile);
  729. fclose(currFile);
  730. return true;
  731. // Something strange has happened
  732. default:
  733. std::cerr << "Unknown packet type received. Failing." << std::endl;
  734. break;
  735. }
  736. return false;
  737. }
  738. void PrsonaClientWebSocketHandler::handleClose(
  739. CivetServer *server,
  740. const struct mg_connection *conn)
  741. {
  742. char *filename = (char *) mg_get_user_connection_data(conn);
  743. // If we didn't have a temp file for this request, don't do anything
  744. if (!filename)
  745. return;
  746. // If we did, delete it
  747. remove(filename);
  748. delete [] filename;
  749. }
  750. /*
  751. * RESPONSE ROUTER FUNCTION
  752. */
  753. void PrsonaClientWebSocketHandler::generate_response(
  754. CivetServer *server,
  755. struct mg_connection *conn,
  756. const char *filename)
  757. {
  758. const struct mg_request_info *info = mg_get_request_info(conn);
  759. // Select the correct response for this type of request
  760. switch (info->query_string[0])
  761. {
  762. case PRSONA_VERIFY_REPUTATION_PROOF:
  763. verify_reputation_proof(server, conn, filename);
  764. break;
  765. default:
  766. break;
  767. }
  768. }
  769. /*
  770. * REPUTATION PROOF RESPONSE
  771. */
  772. void PrsonaClientWebSocketHandler::verify_reputation_proof(
  773. CivetServer *civetServer,
  774. struct mg_connection *conn,
  775. const char *filename)
  776. {
  777. std::vector<Proof> pi;
  778. Twistpoint shortTermPublicKey;
  779. Scalar threshold;
  780. // Un-serialize the reputation proof
  781. std::ifstream file(filename);
  782. file.ignore(std::numeric_limits<std::streamsize>::max());
  783. std::streamsize bandwidthRcv = file.gcount();
  784. file.clear();
  785. file.seekg(0, std::ios_base::beg);
  786. BinarySizeT sizeOfVector;
  787. file >> sizeOfVector;
  788. for (size_t i = 0; i < sizeOfVector.val(); i++)
  789. {
  790. Proof currProof;
  791. file >> currProof;
  792. pi.push_back(currProof);
  793. }
  794. file >> shortTermPublicKey;
  795. file >> threshold;
  796. std::vector<size_t> bandwidthDataBefore = get_log_data(civetServer->getContext());
  797. std::chrono::high_resolution_clock::time_point wallTimeBefore = std::chrono::high_resolution_clock::now();
  798. clock_t cpuTimeBefore = clock();
  799. // Get current fresh generator (it's not guaranteed we've done this in the current epoch)
  800. std::vector<Proof> generatorProof;
  801. Twistpoint freshGenerator = get_generator(rng, serverIPs, serverPorts, true, generatorProof);
  802. // Load fresh generator into client object
  803. prsonaClient->receive_fresh_generator(generatorProof, freshGenerator);
  804. // Get what the servers say is this user's encrypted score
  805. std::vector<Proof> encryptedScoreProof;
  806. EGCiphertext encryptedScore = get_server_committed_val<EGCiphertext>(rng, serverIPs, serverPorts, REQUEST_CLIENT_TALLY_URI, REQUEST_CLIENT_TALLY_COMMITMENT_URI, encryptedScoreProof, shortTermPublicKey);
  807. // Check if the proof verifies correctly
  808. bool flag = prsonaClient->verify_reputation_proof(pi, shortTermPublicKey, threshold, encryptedScoreProof, encryptedScore);
  809. clock_t cpuTimeAfter = clock();
  810. std::chrono::high_resolution_clock::time_point wallTimeAfter = std::chrono::high_resolution_clock::now();
  811. std::vector<size_t> bandwidthDataAfter = get_log_data(civetServer->getContext());
  812. std::vector<double> timingData(2);
  813. timingData[0] = std::chrono::duration_cast<std::chrono::duration<double>>(wallTimeAfter - wallTimeBefore).count();
  814. timingData[1] = ((double)(cpuTimeAfter - cpuTimeBefore)) / CLOCKS_PER_SEC;
  815. std::vector<size_t> bandwidthData(2);
  816. bandwidthData[0] = bandwidthDataAfter[0] - bandwidthDataBefore[0] + bandwidthRcv;
  817. bandwidthData[1] = bandwidthDataAfter[1] - bandwidthDataBefore[1] + 1;
  818. write_log_data(outputMtx, outputFilename, timingData, bandwidthData);
  819. // Tell the prover whether or not we accept the proof
  820. std::string data = flag ? "\x01" : "\x00";
  821. mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_BINARY, data.c_str(), 1);
  822. mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_DATACOMPLETE, "", 0);
  823. }