serverEntity.cpp 9.5 KB

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