client.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. #include <iostream>
  2. #include "client.hpp"
  3. #include "serverEntity.hpp"
  4. /********************
  5. * PUBLIC FUNCTIONS *
  6. ********************/
  7. /*
  8. * CONSTRUCTORS
  9. */
  10. PrsonaClient::PrsonaClient(
  11. const std::vector<Proof>& generatorProof,
  12. const Curvepoint& elGamalBlindGenerator,
  13. const BGNPublicKey& serverPublicKey,
  14. const PrsonaServerEntity* servers)
  15. : serverPublicKey(serverPublicKey),
  16. servers(servers),
  17. max_checked(0)
  18. {
  19. set_EG_blind_generator(
  20. generatorProof, elGamalBlindGenerator, servers->get_num_servers());
  21. longTermPrivateKey.set_random();
  22. inversePrivateKey = longTermPrivateKey.curveInverse();
  23. decryption_memoizer[elGamalBlindGenerator * max_checked] = max_checked;
  24. }
  25. /*
  26. * BASIC PUBLIC SYSTEM INFO GETTERS
  27. */
  28. Curvepoint PrsonaClient::get_short_term_public_key() const
  29. {
  30. return currentFreshGenerator * longTermPrivateKey;
  31. }
  32. Curvepoint PrsonaClient::get_short_term_public_key(Proof &pi) const
  33. {
  34. pi = generate_ownership_proof();
  35. return currentFreshGenerator * longTermPrivateKey;
  36. }
  37. /*
  38. * SERVER INTERACTIONS
  39. */
  40. /* Generate a new vote vector to give to the servers
  41. * @replaces controls which votes are actually being updated and which are not
  42. *
  43. * You may really want to make currentEncryptedVotes a member variable,
  44. * but it doesn't behave correctly when adding new clients after this one. */
  45. std::vector<CurveBipoint> PrsonaClient::make_votes(
  46. std::vector<Proof>& validVoteProof,
  47. const Proof& serverProof,
  48. const std::vector<CurveBipoint>& oldEncryptedVotes,
  49. const std::vector<Scalar>& votes,
  50. const std::vector<bool>& replaces) const
  51. {
  52. Curvepoint shortTermPublicKey = get_short_term_public_key();
  53. if (!verify_valid_vote_row_proof(serverProof, shortTermPublicKey, oldEncryptedVotes))
  54. {
  55. std::cerr << "Could not verify proof of valid votes." << std::endl;
  56. return oldEncryptedVotes;
  57. }
  58. std::vector<Scalar> seeds(oldEncryptedVotes.size());
  59. std::vector<CurveBipoint> newEncryptedVotes(oldEncryptedVotes.size());
  60. for (size_t i = 0; i < votes.size(); i++)
  61. {
  62. if (replaces[i])
  63. {
  64. newEncryptedVotes[i] =
  65. serverPublicKey.curveEncrypt(seeds[i], votes[i]);
  66. }
  67. else
  68. {
  69. newEncryptedVotes[i] =
  70. serverPublicKey.rerandomize(seeds[i], oldEncryptedVotes[i]);
  71. }
  72. }
  73. validVoteProof = generate_vote_proof(
  74. replaces, oldEncryptedVotes, newEncryptedVotes, seeds, votes);
  75. return newEncryptedVotes;
  76. }
  77. // Get a new fresh generator (happens at initialization and during each epoch)
  78. bool PrsonaClient::receive_fresh_generator(
  79. const std::vector<Proof>& pi, const Curvepoint& freshGenerator)
  80. {
  81. if (!verify_generator_proof(pi, freshGenerator, servers->get_num_servers()))
  82. {
  83. std::cerr << "Issue verifying fresh generator proof." << std::endl;
  84. return false;
  85. }
  86. currentFreshGenerator = freshGenerator;
  87. return true;
  88. }
  89. // Receive a new encrypted score from the servers (each epoch)
  90. bool PrsonaClient::receive_vote_tally()
  91. {
  92. Proof pi;
  93. Curvepoint shortTermPublicKey = get_short_term_public_key();
  94. EGCiphertext score =
  95. servers->get_current_user_encrypted_tally(pi, shortTermPublicKey);
  96. if (!verify_valid_user_tally_proof(pi, shortTermPublicKey, score))
  97. {
  98. std::cerr << "Could not verify proof of valid tally." << std::endl;
  99. return false;
  100. }
  101. currentEncryptedScore = score;
  102. currentScore = decrypt_score(score);
  103. return true;
  104. }
  105. bool PrsonaClient::receive_new_user_data(const std::vector<Proof>& mainProof)
  106. {
  107. Proof currProof;
  108. Curvepoint shortTermPublicKey = get_short_term_public_key();
  109. TwistBipoint serverEncryptedScore =
  110. servers->get_current_server_encrypted_tally(currProof, shortTermPublicKey);
  111. if (!verify_valid_server_tally_proof(currProof, shortTermPublicKey, serverEncryptedScore))
  112. {
  113. std::cerr << "Could not verify preliminary proof of server encrypted tally." << std::endl;
  114. return false;
  115. }
  116. EGCiphertext userEncryptedScore =
  117. servers->get_current_user_encrypted_tally(currProof, shortTermPublicKey);
  118. if (!verify_valid_user_tally_proof(currProof, shortTermPublicKey, userEncryptedScore))
  119. {
  120. std::cerr << "Could not verify preliminary proof of user encrypted tally." << std::endl;
  121. return false;
  122. }
  123. std::vector<std::vector<CurveBipoint>> encryptedVoteMatrix =
  124. servers->get_all_current_votes(currProof);
  125. if (!verify_valid_vote_matrix_proof(currProof, encryptedVoteMatrix))
  126. {
  127. std::cerr << "Could not verify preliminary proof of encrypted votes." << std::endl;
  128. return false;
  129. }
  130. std::vector<Curvepoint> currentPseudonyms =
  131. servers->get_current_pseudonyms(currProof);
  132. if (!verify_valid_pseudonyms_proof(currProof, currentPseudonyms))
  133. {
  134. std::cerr << "Could not verify preliminary proof of pseudonyms." << std::endl;
  135. return false;
  136. }
  137. size_t selfIndex = binary_search(currentPseudonyms, shortTermPublicKey);
  138. if (currentPseudonyms[selfIndex] != shortTermPublicKey)
  139. {
  140. std::cerr << "Was not added to list of pseudonyms." << std::endl;
  141. return false;
  142. }
  143. bool flag = verify_proof_of_added_user(
  144. mainProof,
  145. currentFreshGenerator,
  146. shortTermPublicKey,
  147. elGamalBlindGenerator,
  148. serverPublicKey.get_bipoint_curvegen(),
  149. serverPublicKey.get_bipoint_curve_subgroup_gen(),
  150. serverPublicKey.get_bipoint_twistgen(),
  151. serverPublicKey.get_bipoint_twist_subgroup_gen(),
  152. selfIndex,
  153. userEncryptedScore,
  154. serverEncryptedScore,
  155. encryptedVoteMatrix);
  156. if (!flag)
  157. {
  158. std::cerr << "There was an issue verifying the proof; this user was not properly added." << std::endl;
  159. return false;
  160. }
  161. currentEncryptedScore = userEncryptedScore;
  162. currentScore = decrypt_score(userEncryptedScore);
  163. // std::cout << "g^r: " << std::hex << currentFreshGenerator << std::dec << std::endl;
  164. return true;
  165. }
  166. /*
  167. * REPUTATION PROOFS
  168. */
  169. // A pretty straightforward range proof (generation)
  170. std::vector<Proof> PrsonaClient::generate_reputation_proof(
  171. const Scalar& threshold) const
  172. {
  173. Proof ownershipProof = generate_ownership_proof();
  174. return PrsonaBase::generate_reputation_proof(
  175. ownershipProof,
  176. currentEncryptedScore,
  177. currentScore,
  178. threshold,
  179. inversePrivateKey,
  180. servers->get_num_clients());
  181. }
  182. bool PrsonaClient::verify_reputation_proof(
  183. const std::vector<Proof>& pi,
  184. const Curvepoint& shortTermPublicKey,
  185. const Scalar& threshold) const
  186. {
  187. Proof serverProof;
  188. EGCiphertext encryptedScore =
  189. servers->get_current_user_encrypted_tally(serverProof, shortTermPublicKey);
  190. if (!verify_valid_user_tally_proof(serverProof, shortTermPublicKey, encryptedScore))
  191. {
  192. std::cerr << "Error getting score from server, aborting." << std::endl;
  193. return false;
  194. }
  195. return PrsonaBase::verify_reputation_proof(
  196. pi, currentFreshGenerator, shortTermPublicKey, encryptedScore, threshold);
  197. }
  198. Scalar PrsonaClient::get_score() const
  199. {
  200. return currentScore;
  201. }
  202. /*********************
  203. * PRIVATE FUNCTIONS *
  204. *********************/
  205. /*
  206. * SCORE DECRYPTION
  207. */
  208. // Basic memoized score decryption
  209. Scalar PrsonaClient::decrypt_score(const EGCiphertext& score)
  210. {
  211. Curvepoint s, hashedDecrypted;
  212. // Remove the mask portion of the ciphertext
  213. s = score.mask * inversePrivateKey;
  214. hashedDecrypted = score.encryptedMessage - s;
  215. // Check if it's a value we've already seen
  216. auto lookup = decryption_memoizer.find(hashedDecrypted);
  217. if (lookup != decryption_memoizer.end())
  218. return lookup->second;
  219. // If not, iterate until we find it (adding everything to the memoization)
  220. max_checked++;
  221. Curvepoint decryptionCandidate = elGamalBlindGenerator * max_checked;
  222. while (decryptionCandidate != hashedDecrypted)
  223. {
  224. decryption_memoizer[decryptionCandidate] = max_checked;
  225. decryptionCandidate = decryptionCandidate + elGamalBlindGenerator;
  226. max_checked++;
  227. }
  228. decryption_memoizer[decryptionCandidate] = max_checked;
  229. // Return the value we found
  230. return max_checked;
  231. }
  232. /*
  233. * OWNERSHIP PROOFS
  234. */
  235. // Prove ownership of the short term public key
  236. Proof PrsonaClient::generate_ownership_proof() const
  237. {
  238. Curvepoint shortTermPublicKey = currentFreshGenerator * longTermPrivateKey;
  239. return PrsonaBase::generate_ownership_proof(
  240. currentFreshGenerator, shortTermPublicKey, longTermPrivateKey);
  241. }
  242. /*
  243. * VALID VOTE PROOFS
  244. */
  245. std::vector<Proof> PrsonaClient::generate_vote_proof(
  246. const std::vector<bool>& replaces,
  247. const std::vector<CurveBipoint>& oldEncryptedVotes,
  248. const std::vector<CurveBipoint>& newEncryptedVotes,
  249. const std::vector<Scalar>& seeds,
  250. const std::vector<Scalar>& votes) const
  251. {
  252. Proof pi = generate_ownership_proof();
  253. return PrsonaBase::generate_vote_proof(
  254. pi,
  255. serverPublicKey.get_bipoint_curvegen(),
  256. serverPublicKey.get_bipoint_curve_subgroup_gen(),
  257. replaces,
  258. oldEncryptedVotes,
  259. newEncryptedVotes,
  260. seeds,
  261. votes);
  262. }
  263. /*
  264. * SERVER AGREEMENT PROOFS
  265. */
  266. bool PrsonaClient::verify_valid_vote_row_proof(
  267. const Proof& pi,
  268. const Curvepoint& shortTermPublicKey,
  269. const std::vector<CurveBipoint>& commitment) const
  270. {
  271. std::vector<Proof> fullProof;
  272. fullProof.push_back(pi);
  273. servers->get_other_vote_row_commitments(fullProof, shortTermPublicKey);
  274. return PrsonaBase::verify_valid_vote_row_proof(fullProof, commitment);
  275. }
  276. bool PrsonaClient::verify_valid_vote_matrix_proof(
  277. const Proof& pi,
  278. const std::vector<std::vector<CurveBipoint>>& commitment) const
  279. {
  280. std::vector<Proof> fullProof;
  281. fullProof.push_back(pi);
  282. servers->get_other_vote_matrix_commitments(fullProof);
  283. return PrsonaBase::verify_valid_vote_matrix_proof(fullProof, commitment);
  284. }
  285. bool PrsonaClient::verify_valid_user_tally_proof(
  286. const Proof& pi,
  287. const Curvepoint& shortTermPublicKey,
  288. const EGCiphertext& commitment) const
  289. {
  290. std::vector<Proof> fullProof;
  291. fullProof.push_back(pi);
  292. servers->get_other_user_tally_commitments(fullProof, shortTermPublicKey);
  293. return PrsonaBase::verify_valid_user_tally_proof(fullProof, commitment);
  294. }
  295. bool PrsonaClient::verify_valid_server_tally_proof(
  296. const Proof& pi,
  297. const Curvepoint& shortTermPublicKey,
  298. const TwistBipoint& commitment) const
  299. {
  300. std::vector<Proof> fullProof;
  301. fullProof.push_back(pi);
  302. servers->get_other_server_tally_commitments(fullProof, shortTermPublicKey);
  303. return PrsonaBase::verify_valid_server_tally_proof(fullProof, commitment);
  304. }
  305. bool PrsonaClient::verify_valid_pseudonyms_proof(
  306. const Proof& pi,
  307. const std::vector<Curvepoint>& commitment) const
  308. {
  309. std::vector<Proof> fullProof;
  310. fullProof.push_back(pi);
  311. servers->get_other_pseudonyms_commitments(fullProof);
  312. return PrsonaBase::verify_valid_pseudonyms_proof(fullProof, commitment);
  313. }