serverEntity.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. #include <iostream>
  2. #include "serverEntity.hpp"
  3. const int MAX_ALLOWED_VOTE = 2;
  4. /********************
  5. * PUBLIC FUNCTIONS *
  6. ********************/
  7. /*
  8. * CONSTRUCTORS
  9. */
  10. PrsonaServerEntity::PrsonaServerEntity(size_t numServers)
  11. {
  12. if (numServers < 1)
  13. {
  14. std::cerr << "You have to have at least 1 server. "
  15. << "I'm making it anyways." << std::endl;
  16. }
  17. // Make the first server, which makes the BGN parameters
  18. PrsonaServer firstServer;
  19. servers.push_back(firstServer);
  20. // Make the rest of the servers, which take the BGN parameters
  21. const BGN& sharedBGN = firstServer.get_bgn_details();
  22. for (size_t i = 1; i < numServers; i++)
  23. servers.push_back(PrsonaServer(sharedBGN));
  24. // After all servers have made their seeds,
  25. // make sure they have the initial fresh generator
  26. Curvepoint firstGenerator = get_fresh_generator();
  27. for (size_t i = 0; i < numServers; i++)
  28. servers[i].initialize_fresh_generator(firstGenerator);
  29. }
  30. /*
  31. * BASIC PUBLIC SYSTEM INFO GETTERS
  32. */
  33. BGNPublicKey PrsonaServerEntity::get_bgn_public_key() const
  34. {
  35. return servers[0].get_bgn_public_key();
  36. }
  37. Curvepoint PrsonaServerEntity::get_blinding_generator() const
  38. {
  39. return servers[0].get_blinding_generator();
  40. }
  41. Curvepoint PrsonaServerEntity::get_fresh_generator() const
  42. {
  43. Curvepoint retval = PrsonaServer::EL_GAMAL_GENERATOR;
  44. for (size_t j = 0; j < servers.size(); j++)
  45. retval = servers[j].add_curr_seed_to_generator(retval);
  46. return retval;
  47. }
  48. /*
  49. * ENCRYPTED DATA GETTERS
  50. */
  51. /* Call this in order to get the current encrypted votes cast by a given user
  52. * (who is identified by their short term public key).
  53. * In practice, this is intended for clients,
  54. * who need to know their current votes in order to rerandomize them. */
  55. std::vector<CurveBipoint> PrsonaServerEntity::get_current_votes_by(
  56. Proof& pi, const Curvepoint& shortTermPublicKey) const
  57. {
  58. return servers[0].get_current_votes_by(pi, shortTermPublicKey);
  59. }
  60. /* Call this in order to get the current encrypted tally of a given user
  61. * (who is identified by their short term public key).
  62. * In practice, this is intended for clients, so that the servers vouch
  63. * for their ciphertexts being valid as part of their reputation proofs. */
  64. EGCiphertext PrsonaServerEntity::get_current_tally(
  65. Proof& pi, const Curvepoint& shortTermPublicKey) const
  66. {
  67. return servers[0].get_current_tally(pi, shortTermPublicKey);
  68. }
  69. /*
  70. * CLIENT INTERACTIONS
  71. */
  72. /* Add a new client (who is identified only by their short term public key)
  73. * One server does the main work, then other servers import their (proven)
  74. * exported data. */
  75. void PrsonaServerEntity::add_new_client(PrsonaClient& newUser)
  76. {
  77. Proof proofOfValidSTPK, proofOfCorrectAddition, proofOfValidVotes;
  78. Curvepoint freshGenerator = get_fresh_generator();
  79. // Users can't actually announce a short term public key
  80. // if they don't know the fresh generator.
  81. newUser.receive_fresh_generator(freshGenerator);
  82. Curvepoint shortTermPublicKey = newUser.get_short_term_public_key(
  83. proofOfValidSTPK);
  84. // Do the actual work of adding the client to the first server
  85. servers[0].add_new_client(
  86. proofOfValidSTPK, proofOfCorrectAddition, shortTermPublicKey);
  87. // Then, export the data to the rest of the servers
  88. std::vector<TwistBipoint> previousVoteTally;
  89. std::vector<Curvepoint> currentPseudonyms;
  90. std::vector<EGCiphertext> currentUserEncryptedTallies;
  91. std::vector<Proof> currentTallyProofs;
  92. std::vector<std::vector<CurveBipoint>> voteMatrix;
  93. servers[0].export_updates(
  94. previousVoteTally,
  95. currentPseudonyms,
  96. currentUserEncryptedTallies,
  97. currentTallyProofs,
  98. voteMatrix);
  99. for (size_t j = 1; j < servers.size(); j++)
  100. {
  101. servers[j].import_updates(
  102. proofOfCorrectAddition,
  103. previousVoteTally,
  104. currentPseudonyms,
  105. currentUserEncryptedTallies,
  106. currentTallyProofs,
  107. voteMatrix);
  108. }
  109. // Finally, give the user the information it needs
  110. // about its current tally and votes
  111. transmit_updates(newUser);
  112. }
  113. // Receive a new vote row from a user (identified by short term public key).
  114. void PrsonaServerEntity::receive_vote(
  115. const Proof& pi,
  116. const std::vector<CurveBipoint>& votes,
  117. const Curvepoint& shortTermPublicKey)
  118. {
  119. for (size_t j = 0; j < servers.size(); j++)
  120. servers[j].receive_vote(pi, votes, shortTermPublicKey);
  121. }
  122. // After tallying scores and new vote matrix,
  123. // give those to a user for the new epoch
  124. void PrsonaServerEntity::transmit_updates(PrsonaClient& currUser) const
  125. {
  126. Proof proofOfValidSTPK, proofOfScore, proofOfCorrectVotes;
  127. Curvepoint freshGenerator = get_fresh_generator();
  128. // Get users the next fresh generator so they can correctly
  129. // ask for their new scores and vote row
  130. currUser.receive_fresh_generator(freshGenerator);
  131. Curvepoint shortTermPublicKey = currUser.get_short_term_public_key(
  132. proofOfValidSTPK);
  133. EGCiphertext score = get_current_tally(proofOfScore, shortTermPublicKey);
  134. currUser.receive_vote_tally(proofOfScore, score);
  135. std::vector<CurveBipoint> encryptedVotes = get_current_votes_by(
  136. proofOfCorrectVotes, shortTermPublicKey);
  137. currUser.receive_encrypted_votes(proofOfCorrectVotes, encryptedVotes);
  138. }
  139. /*
  140. * EPOCH
  141. */
  142. // Do the epoch process
  143. void PrsonaServerEntity::epoch(Proof& pi)
  144. {
  145. Curvepoint nextGenerator = PrsonaServer::EL_GAMAL_GENERATOR;
  146. std::vector<TwistBipoint> previousVoteTally;
  147. std::vector<Curvepoint> currentPseudonyms;
  148. std::vector<EGCiphertext> currentUserEncryptedTallies;
  149. std::vector<Proof> currentTallyProofs;
  150. std::vector<std::vector<CurveBipoint>> voteMatrix;
  151. // go from A_0 to A_0.5
  152. for (size_t i = 0; i < servers.size(); i++)
  153. {
  154. servers[i].build_up_midway_pseudonyms(pi, nextGenerator);
  155. servers[i].export_updates(
  156. previousVoteTally,
  157. currentPseudonyms,
  158. currentUserEncryptedTallies,
  159. currentTallyProofs,
  160. voteMatrix);
  161. if (i < servers.size() - 1)
  162. {
  163. servers[i + 1].import_updates(
  164. pi,
  165. previousVoteTally,
  166. currentPseudonyms,
  167. currentUserEncryptedTallies,
  168. currentTallyProofs,
  169. voteMatrix);
  170. }
  171. }
  172. /* Imagine that server 0 is encrypting these, then would do a ZKP that it
  173. * knows a secret mask and encrypted the correct value everyone else already
  174. * knows. Everyone else then adds a mask and proves they added a secret mask
  175. * to the committed values. */
  176. currentUserEncryptedTallies = tally_scores(currentTallyProofs, nextGenerator);
  177. servers[0].import_updates(
  178. pi,
  179. previousVoteTally,
  180. currentPseudonyms,
  181. currentUserEncryptedTallies,
  182. currentTallyProofs,
  183. voteMatrix);
  184. // go from A_0.5 to A_1
  185. for (size_t i = 0; i < servers.size(); i++)
  186. {
  187. servers[i].break_down_midway_pseudonyms(pi, nextGenerator);
  188. servers[i].export_updates(
  189. previousVoteTally,
  190. currentPseudonyms,
  191. currentUserEncryptedTallies,
  192. currentTallyProofs,
  193. voteMatrix);
  194. if (i < servers.size() - 1)
  195. {
  196. servers[i + 1].import_updates(
  197. pi,
  198. previousVoteTally,
  199. currentPseudonyms,
  200. currentUserEncryptedTallies,
  201. currentTallyProofs,
  202. voteMatrix);
  203. }
  204. }
  205. // At the end, make sure all servers have same information
  206. for (size_t i = 0; i < servers.size() - 1; i++)
  207. {
  208. servers[i].import_updates(
  209. pi,
  210. previousVoteTally,
  211. currentPseudonyms,
  212. currentUserEncryptedTallies,
  213. currentTallyProofs,
  214. voteMatrix);
  215. }
  216. }
  217. /*********************
  218. * PRIVATE FUNCTIONS *
  219. *********************/
  220. /*
  221. * SCORE TALLYING
  222. */
  223. /* Calculate scores, then scale the values appropriately,
  224. * so they are in the correct range to be used as vote weights.
  225. *
  226. * We're treating it as if we are one server, so that server gets the updated
  227. * weights to be sent to all other servers for the next epoch. */
  228. std::vector<EGCiphertext> PrsonaServerEntity::tally_scores(
  229. std::vector<Proof>& tallyProofs, const Curvepoint& nextGenerator)
  230. {
  231. std::vector<EGCiphertext> retval;
  232. Proof maxScoreProof;
  233. std::vector<Scalar> decryptedTalliedScores = servers[0].tally_scores(
  234. tallyProofs);
  235. mpz_class maxScorePossibleThisRound =
  236. servers[0].get_max_possible_score(maxScoreProof).toInt() *
  237. MAX_ALLOWED_VOTE;
  238. mpz_class topOfScoreRange = retval.size() * MAX_ALLOWED_VOTE;
  239. for (size_t i = 0; i < decryptedTalliedScores.size(); i++)
  240. {
  241. decryptedTalliedScores[i] =
  242. Scalar(
  243. (decryptedTalliedScores[i].toInt() * topOfScoreRange) /
  244. maxScorePossibleThisRound
  245. );
  246. EGCiphertext currCiphertext;
  247. retval.push_back(currCiphertext);
  248. Scalar currMask;
  249. currMask.set_random();
  250. // Give the server the new weights,
  251. // to get passed around to the other servers
  252. servers[0].bgn_system.encrypt(
  253. servers[0].previousVoteTallies[i], decryptedTalliedScores[i]);
  254. retval[i].mask = servers[0].currentPseudonyms[i] * currMask;
  255. retval[i].encryptedMessage =
  256. (nextGenerator * currMask) +
  257. (PrsonaServer::get_blinding_generator() * decryptedTalliedScores[i]);
  258. }
  259. return retval;
  260. }
  261. /*
  262. * BINARY SEARCH
  263. */
  264. // Completely normal binary search
  265. size_t PrsonaServerEntity::binary_search(
  266. const Curvepoint& shortTermPublicKey) const
  267. {
  268. return servers[0].binary_search(shortTermPublicKey);
  269. }