server.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
  1. #include <iostream>
  2. #include "server.hpp"
  3. extern const curvepoint_fp_t bn_curvegen;
  4. extern const scalar_t bn_n;
  5. const int MAX_ALLOWED_VOTE = 2;
  6. /* These lines need to be here so these static variables are defined,
  7. * but in C++ putting code here doesn't actually execute
  8. * (or at least, with g++, whenever it would execute is not at a useful time)
  9. * so we have an init() function to actually put the correct values in them. */
  10. Curvepoint PrsonaServer::EL_GAMAL_GENERATOR = Curvepoint();
  11. Curvepoint PrsonaServer::EL_GAMAL_BLIND_GENERATOR = Curvepoint();
  12. Scalar PrsonaServer::SCALAR_N = Scalar();
  13. Scalar PrsonaServer::DEFAULT_TALLY = Scalar();
  14. Scalar PrsonaServer::DEFAULT_VOTE = Scalar();
  15. bool PrsonaServer::SERVER_IS_MALICIOUS = false;
  16. bool PrsonaServer::CLIENT_IS_MALICIOUS = false;
  17. /********************
  18. * PUBLIC FUNCTIONS *
  19. ********************/
  20. /*
  21. * CONSTRUCTORS
  22. */
  23. // Used to generate the first server; instantiates BGN for the first time
  24. PrsonaServer::PrsonaServer()
  25. {
  26. currentSeed.set_random();
  27. }
  28. // Used for all other servers, so they have the same BGN parameters
  29. PrsonaServer::PrsonaServer(const BGN& other_bgn)
  30. : bgn_system(other_bgn)
  31. {
  32. currentSeed.set_random();
  33. }
  34. /*
  35. * SETUP FUNCTIONS
  36. */
  37. // Must be called once before any usage of this class
  38. Curvepoint PrsonaServer::init()
  39. {
  40. Scalar lambda;
  41. lambda.set_random();
  42. EL_GAMAL_GENERATOR = Curvepoint(bn_curvegen);
  43. EL_GAMAL_BLIND_GENERATOR = EL_GAMAL_GENERATOR * lambda;
  44. SCALAR_N = Scalar(bn_n);
  45. DEFAULT_TALLY = Scalar(1);
  46. DEFAULT_VOTE = Scalar(1);
  47. return EL_GAMAL_BLIND_GENERATOR;
  48. }
  49. // Call this (once) if using malicious-security servers
  50. void PrsonaServer::set_server_malicious()
  51. {
  52. SERVER_IS_MALICIOUS = true;
  53. }
  54. // Call this (once) if using malicious-security clients
  55. void PrsonaServer::set_client_malicious()
  56. {
  57. CLIENT_IS_MALICIOUS = true;
  58. }
  59. /*
  60. * BASIC PUBLIC SYSTEM INFO GETTERS
  61. */
  62. Curvepoint PrsonaServer::get_blinding_generator()
  63. {
  64. return EL_GAMAL_BLIND_GENERATOR;
  65. }
  66. BGNPublicKey PrsonaServer::get_bgn_public_key() const
  67. {
  68. return bgn_system.get_public_key();
  69. }
  70. /*
  71. * FRESH GENERATOR CALCULATION
  72. */
  73. // To calculate the current epoch's generator, start from the base generator,
  74. // then have every server call this function on it iteratively (in any order).
  75. Curvepoint PrsonaServer::add_curr_seed_to_generator(
  76. const Curvepoint& currGenerator) const
  77. {
  78. return currGenerator * currentSeed;
  79. }
  80. // To calculate the next epoch's generator, start from the base generator,
  81. // then have every server call this function on it iteratively (in any order).
  82. Curvepoint PrsonaServer::add_next_seed_to_generator(
  83. const Curvepoint& currGenerator) const
  84. {
  85. return currGenerator * nextSeed;
  86. }
  87. /*
  88. * ENCRYPTED DATA GETTERS
  89. */
  90. /* Call this in order to get the current encrypted votes cast by a given user
  91. * (who is identified by their short term public key).
  92. * In practice, this is intended for clients,
  93. * who need to know their current votes in order to rerandomize them. */
  94. std::vector<CurveBipoint> PrsonaServer::get_current_votes_by(
  95. Proof& pi, const Curvepoint& shortTermPublicKey) const
  96. {
  97. std::vector<CurveBipoint> retval;
  98. size_t voteSubmitter = binary_search(shortTermPublicKey);
  99. retval = voteMatrix[voteSubmitter];
  100. pi = generate_votes_valid_proof(retval, shortTermPublicKey);
  101. return retval;
  102. }
  103. /* Call this in order to get the current encrypted tally of a given user
  104. * (who is identified by their short term public key).
  105. * In practice, this is intended for clients, so that the servers vouch
  106. * for their ciphertexts being valid as part of their reputation proofs. */
  107. EGCiphertext PrsonaServer::get_current_tally(
  108. Proof& pi, const Curvepoint& shortTermPublicKey) const
  109. {
  110. EGCiphertext retval;
  111. size_t tallyOwner = binary_search(shortTermPublicKey);
  112. retval = currentUserEncryptedTallies[tallyOwner];
  113. pi = currentTallyProofs[tallyOwner];
  114. return retval;
  115. }
  116. /*
  117. * CLIENT INTERACTIONS
  118. */
  119. /* Add a new client (who is identified only by their short term public key)
  120. * One server will do this, then ask all other servers to import their
  121. * (proven) exported data. */
  122. void PrsonaServer::add_new_client(
  123. const Proof& proofOfValidKey,
  124. Proof& proofOfValidAddition,
  125. const Curvepoint& shortTermPublicKey)
  126. {
  127. if (!verify_valid_key_proof(proofOfValidKey, shortTermPublicKey))
  128. {
  129. std::cerr << "Could not verify proof of valid key." << std::endl;
  130. return;
  131. }
  132. currentPseudonyms.push_back(shortTermPublicKey);
  133. // The first epoch's score for a new user will be low,
  134. // but will typically converge on an average score quickly
  135. TwistBipoint encryptedDefaultTally;
  136. bgn_system.encrypt(encryptedDefaultTally, DEFAULT_TALLY);
  137. previousVoteTallies.push_back(encryptedDefaultTally);
  138. Scalar mask;
  139. mask.set_random();
  140. EGCiphertext newUserEncryptedTally;
  141. newUserEncryptedTally.mask = shortTermPublicKey * mask;
  142. newUserEncryptedTally.encryptedMessage =
  143. currentFreshGenerator * mask +
  144. get_blinding_generator() * DEFAULT_TALLY;
  145. currentUserEncryptedTallies.push_back(newUserEncryptedTally);
  146. currentTallyProofs.push_back(
  147. generate_valid_default_tally_proof(newUserEncryptedTally, mask));
  148. // Users are defaulted to casting a neutral vote for others.
  149. CurveBipoint encryptedDefaultVote, encryptedSelfVote;
  150. bgn_system.encrypt(encryptedDefaultVote, DEFAULT_VOTE);
  151. bgn_system.encrypt(encryptedSelfVote, Scalar(MAX_ALLOWED_VOTE));
  152. std::vector<CurveBipoint> newRow;
  153. for (size_t i = 0; i < voteMatrix.size(); i++)
  154. {
  155. encryptedDefaultVote = bgn_system.rerandomize(encryptedDefaultVote);
  156. voteMatrix[i].push_back(encryptedDefaultVote);
  157. encryptedDefaultVote = bgn_system.rerandomize(encryptedDefaultVote);
  158. newRow.push_back(encryptedDefaultVote);
  159. }
  160. // Because we are adding the new user to the end (and then sorting it),
  161. // this last element (bottom right corner) is always the self vote.
  162. newRow.push_back(encryptedSelfVote);
  163. voteMatrix.push_back(newRow);
  164. order_data(proofOfValidAddition);
  165. proofOfValidAddition = generate_proof_of_added_user(shortTermPublicKey);
  166. }
  167. // Receive a new vote row from a user (identified by short term public key).
  168. void PrsonaServer::receive_vote(
  169. const Proof& pi,
  170. const std::vector<CurveBipoint>& votes,
  171. const Curvepoint& shortTermPublicKey)
  172. {
  173. if (!verify_vote_proof(pi, votes, shortTermPublicKey))
  174. {
  175. std::cerr << "Could not verify votes." << std::endl;
  176. return;
  177. }
  178. size_t voteSubmitter = binary_search(shortTermPublicKey);
  179. voteMatrix[voteSubmitter] = votes;
  180. }
  181. /*********************
  182. * PRIVATE FUNCTIONS *
  183. *********************/
  184. /*
  185. * CONSTRUCTOR HELPERS
  186. */
  187. const BGN& PrsonaServer::get_bgn_details() const
  188. {
  189. return bgn_system;
  190. }
  191. void PrsonaServer::initialize_fresh_generator(const Curvepoint& firstGenerator)
  192. {
  193. currentFreshGenerator = firstGenerator;
  194. }
  195. /*
  196. * SCORE TALLYING
  197. */
  198. /* Calculate scores homomorphically (as an individual server would normally)
  199. * and then decrypt them (which the servers would normally work together to do).
  200. *
  201. * Note that since these calculations are just for us, we don't need to do any
  202. * expensive rerandomizations of intermediate values. */
  203. std::vector<Scalar> PrsonaServer::tally_scores(std::vector<Proof>& tallyProofs)
  204. {
  205. std::vector<Quadripoint> BGNEncryptedTallies;
  206. std::vector<Scalar> decryptedTallies;
  207. for (size_t i = 0; i < voteMatrix.size(); i++)
  208. {
  209. std::vector<Quadripoint> weightedVotes;
  210. // ZIP
  211. for (size_t j = 0; j < previousVoteTallies.size(); j++)
  212. {
  213. Quadripoint curr =
  214. bgn_system.homomorphic_multiplication_no_rerandomize(
  215. voteMatrix[j][i], previousVoteTallies[j]);
  216. weightedVotes.push_back(curr);
  217. }
  218. // FOLDL
  219. Quadripoint currEncryptedTally = weightedVotes[0];
  220. for (size_t j = 1; j < weightedVotes.size(); j++)
  221. {
  222. currEncryptedTally =
  223. bgn_system.homomorphic_addition_no_rerandomize(
  224. currEncryptedTally, weightedVotes[j]);
  225. }
  226. // DECRYPT
  227. decryptedTallies.push_back(bgn_system.decrypt(currEncryptedTally));
  228. tallyProofs.push_back(
  229. generate_proof_of_correct_tally(
  230. currEncryptedTally, decryptedTallies[i]));
  231. }
  232. return decryptedTallies;
  233. }
  234. /* Calculate what the maximum possible score this round was (that is,
  235. * given the current user weights, what was the highest possible score?).
  236. *
  237. * As with individual scores, this also does the decryption that servers
  238. * would ordinarily work together to form. */
  239. Scalar PrsonaServer::get_max_possible_score(Proof& pi)
  240. {
  241. // FOLDL
  242. TwistBipoint currEncryptedVal = previousVoteTallies[0];
  243. for (size_t i = 1; i < previousVoteTallies.size(); i++)
  244. {
  245. currEncryptedVal =
  246. bgn_system.homomorphic_addition_no_rerandomize(
  247. currEncryptedVal, previousVoteTallies[i]);
  248. }
  249. // DECRYPT
  250. Scalar retval = bgn_system.decrypt(currEncryptedVal);
  251. pi = generate_proof_of_correct_sum(currEncryptedVal, retval);
  252. return retval;
  253. }
  254. /*
  255. * EPOCH ROUNDS
  256. */
  257. // The first round, going from A_0 to A_0.5
  258. void PrsonaServer::build_up_midway_pseudonyms(
  259. Proof& pi, Curvepoint& nextGenerator)
  260. {
  261. nextSeed.set_random();
  262. nextGenerator = nextGenerator * nextSeed;
  263. currentUserEncryptedTallies.clear();
  264. currentTallyProofs.clear();
  265. for (size_t i = 0; i < currentPseudonyms.size(); i++)
  266. currentPseudonyms[i] = currentPseudonyms[i] * nextSeed;
  267. rerandomize_data();
  268. order_data(pi);
  269. }
  270. // In between these rounds, scores are tallied, decrypted,
  271. // and encrypted to fresh user pseudonyms (possible through weird math)
  272. // The second round, going from A_0.5 to A_1
  273. void PrsonaServer::break_down_midway_pseudonyms(
  274. Proof& pi, const Curvepoint& nextGenerator)
  275. {
  276. Scalar inverseSeed = currentSeed.curveInverse();
  277. for (size_t i = 0; i < currentPseudonyms.size(); i++)
  278. {
  279. currentPseudonyms[i] = currentPseudonyms[i] * inverseSeed;
  280. currentUserEncryptedTallies[i].mask =
  281. currentUserEncryptedTallies[i].mask * inverseSeed;
  282. }
  283. currentSeed = nextSeed;
  284. currentFreshGenerator = nextGenerator;
  285. rerandomize_data();
  286. order_data(pi);
  287. }
  288. /*
  289. * DATA MAINTENANCE
  290. */
  291. void PrsonaServer::import_updates(
  292. const Proof& pi,
  293. const std::vector<TwistBipoint>& otherPreviousVoteTallies,
  294. const std::vector<Curvepoint>& otherCurrentPseudonyms,
  295. const std::vector<EGCiphertext>& otherCurrentUserEncryptedTallies,
  296. const std::vector<Proof>& otherCurrentTallyProofs,
  297. const std::vector<std::vector<CurveBipoint>>& otherVoteMatrix)
  298. {
  299. if (!verify_update_proof(pi))
  300. {
  301. std::cerr << "Could not verify valid update." << std::endl;
  302. return;
  303. }
  304. previousVoteTallies = otherPreviousVoteTallies;
  305. currentPseudonyms = otherCurrentPseudonyms;
  306. currentUserEncryptedTallies = otherCurrentUserEncryptedTallies;
  307. currentTallyProofs = otherCurrentTallyProofs;
  308. voteMatrix = otherVoteMatrix;
  309. }
  310. void PrsonaServer::export_updates(
  311. std::vector<TwistBipoint>& otherPreviousVoteTallies,
  312. std::vector<Curvepoint>& otherCurrentPseudonyms,
  313. std::vector<EGCiphertext>& otherCurrentUserEncryptedTallies,
  314. std::vector<Proof>& otherCurrentTallyProofs,
  315. std::vector<std::vector<CurveBipoint>>& otherVoteMatrix) const
  316. {
  317. otherPreviousVoteTallies = previousVoteTallies;
  318. otherCurrentPseudonyms = currentPseudonyms;
  319. otherCurrentUserEncryptedTallies = currentUserEncryptedTallies;
  320. otherCurrentTallyProofs = currentTallyProofs;
  321. otherVoteMatrix = voteMatrix;
  322. }
  323. /*
  324. * DATA SAFEKEEPING
  325. */
  326. // Everything needs to be rerandomized during epoch rounds
  327. // NOTE: this may need to add something about proofs later?
  328. void PrsonaServer::rerandomize_data()
  329. {
  330. for (size_t i = 0; i < voteMatrix.size(); i++)
  331. {
  332. for (size_t j = 0; j < voteMatrix[0].size(); j++)
  333. voteMatrix[i][j] = bgn_system.rerandomize(voteMatrix[i][j]);
  334. bgn_system.rerandomize(previousVoteTallies[i]);
  335. if (!currentUserEncryptedTallies.empty())
  336. {
  337. Scalar rerandomizer;
  338. rerandomizer.set_random();
  339. currentUserEncryptedTallies[i].mask =
  340. currentUserEncryptedTallies[i].mask +
  341. currentPseudonyms[i] * rerandomizer;
  342. currentUserEncryptedTallies[i].encryptedMessage =
  343. currentUserEncryptedTallies[i].encryptedMessage +
  344. currentFreshGenerator * rerandomizer;
  345. }
  346. }
  347. }
  348. /* This is what powers the "shuffle"; really, as pseudonyms get updated,
  349. * the pseudonyms are no longer in the order prescribed by operator<().
  350. * So, we put them (and everything else) back into that order,
  351. * effectively shuffling them (and making lookups easier later on). */
  352. std::vector<size_t> PrsonaServer::order_data(Proof& pi)
  353. {
  354. std::vector<size_t> retval;
  355. // SortingType's index member allows us to replicate the "sort" across
  356. std::vector<SortingType> sortTracker;
  357. for (size_t i = 0; i < currentPseudonyms.size(); i++)
  358. {
  359. SortingType curr;
  360. curr.pseudonym = currentPseudonyms[i];
  361. curr.index = i;
  362. sortTracker.push_back(curr);
  363. }
  364. std::sort(sortTracker.begin(), sortTracker.end());
  365. // Order all other data in the same way, for consistency
  366. std::vector<Curvepoint> newPseudonyms;
  367. std::vector<TwistBipoint> newVoteTallies;
  368. std::vector<EGCiphertext> newUserEncryptedTallies;
  369. std::vector<Proof> newTallyProofs;
  370. std::vector<std::vector<CurveBipoint>> newVoteMatrix;
  371. for (size_t i = 0; i < sortTracker.size(); i++)
  372. {
  373. newPseudonyms.push_back(sortTracker[i].pseudonym);
  374. newVoteTallies.push_back(previousVoteTallies[sortTracker[i].index]);
  375. if (!currentUserEncryptedTallies.empty())
  376. {
  377. newUserEncryptedTallies.push_back(
  378. currentUserEncryptedTallies[sortTracker[i].index]);
  379. }
  380. if (!currentTallyProofs.empty())
  381. {
  382. newTallyProofs.push_back(
  383. currentTallyProofs[sortTracker[i].index]);
  384. }
  385. std::vector<CurveBipoint> currNewRow;
  386. for (size_t j = 0; j < currentPseudonyms.size(); j++)
  387. {
  388. currNewRow.push_back(
  389. voteMatrix[sortTracker[i].index][sortTracker[j].index]);
  390. }
  391. newVoteMatrix.push_back(currNewRow);
  392. retval.push_back(sortTracker[i].index);
  393. }
  394. previousVoteTallies = newVoteTallies;
  395. currentPseudonyms = newPseudonyms;
  396. currentUserEncryptedTallies = newUserEncryptedTallies;
  397. currentTallyProofs = newTallyProofs;
  398. voteMatrix = newVoteMatrix;
  399. pi = generate_proof_of_shuffle(retval);
  400. return retval;
  401. }
  402. /*
  403. * BINARY SEARCH
  404. */
  405. /* Completely normal binary search
  406. * There might be a standard function for this in <algorithms>?
  407. * But it returns an iterator, not a size_t, so less useful. */
  408. size_t PrsonaServer::binary_search(const Curvepoint& index) const
  409. {
  410. size_t lo, hi;
  411. lo = 0;
  412. hi = currentPseudonyms.size() - 1;
  413. while (lo < hi)
  414. {
  415. size_t mid = (lo + hi) / 2;
  416. if (currentPseudonyms[mid] < index)
  417. lo = mid + 1;
  418. else if (index == currentPseudonyms[mid])
  419. return mid;
  420. else hi = mid - 1;
  421. }
  422. return lo;
  423. }
  424. /*
  425. * PROOF VERIFICATION
  426. */
  427. bool PrsonaServer::verify_valid_key_proof(
  428. const Proof& pi,
  429. const Curvepoint& shortTermPublicKey) const
  430. {
  431. if (!CLIENT_IS_MALICIOUS)
  432. return pi.basic == "PROOF";
  433. return pi.basic == "PROOF";
  434. }
  435. bool PrsonaServer::verify_vote_proof(
  436. const Proof& pi,
  437. const std::vector<CurveBipoint>& votes,
  438. const Curvepoint& shortTermPublicKey) const
  439. {
  440. if (!CLIENT_IS_MALICIOUS)
  441. return pi.basic == "PROOF";
  442. return pi.basic == "PROOF";
  443. }
  444. bool PrsonaServer::verify_update_proof(
  445. const Proof& pi) const
  446. {
  447. if (!SERVER_IS_MALICIOUS)
  448. return pi.basic == "PROOF";
  449. return pi.basic == "PROOF";
  450. }
  451. /*
  452. * PROOF GENERATION
  453. */
  454. Proof PrsonaServer::generate_valid_default_tally_proof(
  455. const EGCiphertext& newUserEncryptedTally, const Scalar& mask) const
  456. {
  457. Proof retval;
  458. if (!SERVER_IS_MALICIOUS)
  459. {
  460. retval.basic = "PROOF";
  461. return retval;
  462. }
  463. retval.basic = "PROOF";
  464. return retval;
  465. }
  466. Proof PrsonaServer::generate_valid_fresh_generator_proof(
  467. const Proof& oldProof) const
  468. {
  469. Proof retval;
  470. if (!SERVER_IS_MALICIOUS)
  471. {
  472. retval.basic = "PROOF";
  473. return retval;
  474. }
  475. retval.basic = "PROOF";
  476. return retval;
  477. }
  478. Proof PrsonaServer::generate_votes_valid_proof(
  479. const std::vector<CurveBipoint>& votes, const Curvepoint& voter) const
  480. {
  481. Proof retval;
  482. if (!SERVER_IS_MALICIOUS)
  483. {
  484. retval.basic = "PROOF";
  485. return retval;
  486. }
  487. retval.basic = "PROOF";
  488. return retval;
  489. }
  490. Proof PrsonaServer::generate_proof_of_added_user(
  491. const Curvepoint& shortTermPublicKey) const
  492. {
  493. Proof retval;
  494. if (!SERVER_IS_MALICIOUS)
  495. {
  496. retval.basic = "PROOF";
  497. return retval;
  498. }
  499. retval.basic = "PROOF";
  500. return retval;
  501. }
  502. Proof PrsonaServer::generate_score_proof(const EGCiphertext& score) const
  503. {
  504. Proof retval;
  505. if (!SERVER_IS_MALICIOUS)
  506. {
  507. retval.basic = "PROOF";
  508. return retval;
  509. }
  510. retval.basic = "PROOF";
  511. return retval;
  512. }
  513. Proof PrsonaServer::generate_proof_of_correct_tally(
  514. const Quadripoint& BGNEncryptedTally,
  515. const Scalar& decryptedTally) const
  516. {
  517. Proof retval;
  518. if (!SERVER_IS_MALICIOUS)
  519. {
  520. retval.basic = "PROOF";
  521. return retval;
  522. }
  523. retval.basic = "PROOF";
  524. return retval;
  525. }
  526. Proof PrsonaServer::generate_proof_of_correct_sum(
  527. const TwistBipoint& BGNEncryptedSum, const Scalar& decryptedSum) const
  528. {
  529. Proof retval;
  530. if (!SERVER_IS_MALICIOUS)
  531. {
  532. retval.basic = "PROOF";
  533. return retval;
  534. }
  535. retval.basic = "PROOF";
  536. return retval;
  537. }
  538. Proof PrsonaServer::generate_proof_of_shuffle(
  539. const std::vector<size_t>& shuffle_order) const
  540. {
  541. Proof retval;
  542. if (!SERVER_IS_MALICIOUS)
  543. {
  544. retval.basic = "PROOF";
  545. return retval;
  546. }
  547. retval.basic = "PROOF";
  548. return retval;
  549. }