client.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. #include <iostream>
  2. #include <mutex>
  3. #include <thread>
  4. #include "client.hpp"
  5. /********************
  6. * PUBLIC FUNCTIONS *
  7. ********************/
  8. /*
  9. * CONSTRUCTORS
  10. */
  11. PrsonaClient::PrsonaClient(
  12. const std::vector<Proof>& generatorProof,
  13. const Twistpoint& elGamalBlindGenerator,
  14. const BGNPublicKey& serverPublicKey,
  15. size_t numServers)
  16. : serverPublicKey(serverPublicKey),
  17. numServers(numServers),
  18. max_checked(0)
  19. {
  20. set_EG_blind_generator(generatorProof, elGamalBlindGenerator, numServers);
  21. longTermPrivateKey.set_random();
  22. inversePrivateKey = longTermPrivateKey.curveMultInverse();
  23. std::cout << "LTPrivKey: " << std::hex << longTermPrivateKey << std::endl;
  24. decryption_memoizer[elGamalBlindGenerator * max_checked] = max_checked;
  25. }
  26. /*
  27. * BASIC PUBLIC SYSTEM INFO GETTERS
  28. */
  29. Twistpoint PrsonaClient::get_short_term_public_key() const
  30. {
  31. return currentFreshGenerator * longTermPrivateKey;
  32. }
  33. Twistpoint PrsonaClient::get_short_term_public_key(
  34. Proof &pi) const
  35. {
  36. pi = generate_ownership_proof();
  37. return currentFreshGenerator * longTermPrivateKey;
  38. }
  39. /*
  40. * SERVER INTERACTIONS
  41. */
  42. /* Generate a new vote vector to give to the servers
  43. * @replaces controls which votes are actually being updated and which are not
  44. *
  45. * You may really want to make currentEncryptedVotes a member variable,
  46. * but it doesn't behave correctly when adding new clients after this one. */
  47. std::vector<TwistBipoint> PrsonaClient::make_votes(
  48. std::vector<Proof>& validVoteProof,
  49. const std::vector<Proof>& serverProof,
  50. const std::vector<TwistBipoint>& oldEncryptedVotes,
  51. const std::vector<Scalar>& votes,
  52. const std::vector<bool>& replaces) const
  53. {
  54. if (!verify_valid_vote_row_proof(serverProof, oldEncryptedVotes))
  55. {
  56. std::cerr << "Could not verify proof of valid votes." << std::endl;
  57. return oldEncryptedVotes;
  58. }
  59. std::vector<Scalar> seeds(oldEncryptedVotes.size());
  60. std::vector<TwistBipoint> newEncryptedVotes(oldEncryptedVotes.size());
  61. for (size_t i = 0; i < votes.size(); i++)
  62. {
  63. if (replaces[i])
  64. newEncryptedVotes[i] = serverPublicKey.twistEncrypt(seeds[i], votes[i]);
  65. else
  66. newEncryptedVotes[i] = serverPublicKey.rerandomize(seeds[i], oldEncryptedVotes[i]);
  67. }
  68. validVoteProof = generate_vote_proof(replaces, oldEncryptedVotes, newEncryptedVotes, seeds, votes);
  69. return newEncryptedVotes;
  70. }
  71. // Get a new fresh generator (happens at initialization and during each epoch)
  72. bool PrsonaClient::receive_fresh_generator(
  73. const std::vector<Proof>& pi,
  74. const Twistpoint& freshGenerator)
  75. {
  76. if (!verify_generator_proof(pi, freshGenerator, numServers))
  77. {
  78. std::cerr << "Issue verifying fresh generator proof." << std::endl;
  79. return false;
  80. }
  81. currentFreshGenerator = freshGenerator;
  82. return true;
  83. }
  84. // Receive a new encrypted score from the servers (each epoch)
  85. bool PrsonaClient::receive_vote_tally(
  86. const std::vector<Proof>& pi,
  87. const EGCiphertext& score)
  88. {
  89. if (!verify_valid_user_tally_proof(pi, score))
  90. {
  91. std::cerr << "Could not verify proof of valid tally." << std::endl;
  92. return false;
  93. }
  94. currentEncryptedScore = score;
  95. currentScore = decrypt_score(score);
  96. return true;
  97. }
  98. bool PrsonaClient::receive_new_user_data(
  99. const std::vector<Proof>& mainProof,
  100. const std::vector<Proof>& serverEncryptedScoreProof,
  101. const CurveBipoint& serverEncryptedScore,
  102. const std::vector<Proof>& userEncryptedScoreProof,
  103. const EGCiphertext& userEncryptedScore,
  104. const std::vector<Proof>& voteMatrixProof,
  105. const std::vector<std::vector<TwistBipoint>>& encryptedVoteMatrix,
  106. const std::vector<Proof>& pseudonymsProof,
  107. const std::vector<Twistpoint>& currentPseudonyms)
  108. {
  109. Twistpoint shortTermPublicKey = get_short_term_public_key();
  110. if (!verify_valid_server_tally_proof(serverEncryptedScoreProof, serverEncryptedScore))
  111. {
  112. std::cerr << "Could not verify preliminary proof of server encrypted tally." << std::endl;
  113. return false;
  114. }
  115. if (!verify_valid_user_tally_proof(userEncryptedScoreProof, userEncryptedScore))
  116. {
  117. std::cerr << "Could not verify preliminary proof of user encrypted tally." << std::endl;
  118. return false;
  119. }
  120. if (!verify_valid_vote_matrix_proof(voteMatrixProof, encryptedVoteMatrix))
  121. {
  122. std::cerr << "Could not verify preliminary proof of encrypted votes." << std::endl;
  123. return false;
  124. }
  125. if (!verify_valid_pseudonyms_proof(pseudonymsProof, currentPseudonyms))
  126. {
  127. std::cerr << "Could not verify preliminary proof of pseudonyms." << std::endl;
  128. return false;
  129. }
  130. size_t selfIndex = binary_search(currentPseudonyms, shortTermPublicKey);
  131. if (currentPseudonyms[selfIndex] != shortTermPublicKey)
  132. {
  133. std::cerr << "Was not added to list of pseudonyms." << std::endl;
  134. return false;
  135. }
  136. bool flag = verify_proof_of_added_user(mainProof, currentFreshGenerator, shortTermPublicKey, serverPublicKey.get_bipoint_twistgen(), serverPublicKey.get_bipoint_twist_subgroup_gen(), serverPublicKey.get_bipoint_curvegen(), serverPublicKey.get_bipoint_curve_subgroup_gen(), selfIndex, userEncryptedScore, serverEncryptedScore, encryptedVoteMatrix);
  137. if (!flag)
  138. {
  139. std::cerr << "There was an issue verifying the proof; this user was not properly added." << std::endl;
  140. return false;
  141. }
  142. currentEncryptedScore = userEncryptedScore;
  143. currentScore = decrypt_score(userEncryptedScore);
  144. return true;
  145. }
  146. /*
  147. * REPUTATION PROOFS
  148. */
  149. // A pretty straightforward range proof (generation)
  150. std::vector<Proof> PrsonaClient::generate_reputation_proof(
  151. const Scalar& threshold,
  152. size_t numClients) const
  153. {
  154. Proof ownershipProof = generate_ownership_proof();
  155. return PrsonaBase::generate_reputation_proof(ownershipProof, currentEncryptedScore, currentScore, threshold, inversePrivateKey, numClients);
  156. }
  157. bool PrsonaClient::verify_reputation_proof(
  158. const std::vector<Proof>& pi,
  159. const Twistpoint& shortTermPublicKey,
  160. const Scalar& threshold,
  161. const std::vector<Proof>& encryptedScoreProof,
  162. const EGCiphertext& encryptedScore) const
  163. {
  164. if (!verify_valid_user_tally_proof(encryptedScoreProof, encryptedScore))
  165. {
  166. std::cerr << "Error getting score from server, aborting." << std::endl;
  167. return false;
  168. }
  169. return PrsonaBase::verify_reputation_proof(pi, currentFreshGenerator, shortTermPublicKey, encryptedScore, threshold);
  170. }
  171. Scalar PrsonaClient::get_score() const
  172. {
  173. return currentScore;
  174. }
  175. /*********************
  176. * PRIVATE FUNCTIONS *
  177. *********************/
  178. /*
  179. * SCORE DECRYPTION
  180. */
  181. void alarm_bell(void *mutex, int *value)
  182. {
  183. std::this_thread::sleep_for(std::chrono::seconds(1));
  184. std::mutex *realMtx = (std::mutex *) mutex;
  185. std::unique_lock<std::mutex> lck(*realMtx);
  186. *value = 1;
  187. }
  188. // Basic memoized score decryption
  189. Scalar PrsonaClient::decrypt_score(
  190. const EGCiphertext& score)
  191. {
  192. Twistpoint s, hashedDecrypted;
  193. // Remove the mask portion of the ciphertext
  194. s = score.mask * inversePrivateKey;
  195. hashedDecrypted = score.encryptedMessage - s;
  196. // Check if it's a value we've already seen
  197. auto lookup = decryption_memoizer.find(hashedDecrypted);
  198. if (lookup != decryption_memoizer.end())
  199. return lookup->second;
  200. int alarm = 0;
  201. bool flag = false;
  202. std::mutex alarmMtx;
  203. std::unique_lock<std::mutex> lck(alarmMtx, std::defer_lock);
  204. std::thread alarmThread(alarm_bell, &alarmMtx, &alarm);
  205. // If not, iterate until we find it (adding everything to the memoization)
  206. max_checked++;
  207. Twistpoint decryptionCandidate = elGamalBlindGenerator * max_checked;
  208. lck.lock();
  209. while (!alarm && decryptionCandidate != hashedDecrypted)
  210. {
  211. lck.unlock();
  212. decryption_memoizer[decryptionCandidate] = max_checked;
  213. decryptionCandidate = decryptionCandidate + elGamalBlindGenerator;
  214. max_checked++;
  215. lck.lock();
  216. }
  217. if (alarm)
  218. flag = true;
  219. lck.unlock();
  220. decryption_memoizer[decryptionCandidate] = max_checked;
  221. alarmThread.join();
  222. if (flag)
  223. return Scalar(0);
  224. // Return the value we found
  225. return max_checked;
  226. }
  227. /*
  228. * OWNERSHIP PROOFS
  229. */
  230. // Prove ownership of the short term public key
  231. Proof PrsonaClient::generate_ownership_proof() const
  232. {
  233. Twistpoint shortTermPublicKey = currentFreshGenerator * longTermPrivateKey;
  234. return PrsonaBase::generate_ownership_proof(currentFreshGenerator, shortTermPublicKey, longTermPrivateKey);
  235. }
  236. /*
  237. * VALID VOTE PROOFS
  238. */
  239. std::vector<Proof> PrsonaClient::generate_vote_proof(
  240. const std::vector<bool>& replaces,
  241. const std::vector<TwistBipoint>& oldEncryptedVotes,
  242. const std::vector<TwistBipoint>& newEncryptedVotes,
  243. const std::vector<Scalar>& seeds,
  244. const std::vector<Scalar>& votes) const
  245. {
  246. Proof pi = generate_ownership_proof();
  247. return PrsonaBase::generate_vote_proof(pi, serverPublicKey.get_bipoint_twistgen(), serverPublicKey.get_bipoint_twist_subgroup_gen(), replaces, oldEncryptedVotes, newEncryptedVotes, seeds, votes);
  248. }