client.cpp 8.3 KB

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