server.cpp 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488
  1. #include <iostream>
  2. #include "server.hpp"
  3. /********************
  4. * PUBLIC FUNCTIONS *
  5. ********************/
  6. /*
  7. * CONSTRUCTORS
  8. */
  9. // Used to generate the first server; instantiates BGN for the first time
  10. PrsonaServer::PrsonaServer(size_t numServers)
  11. : numServers(numServers)
  12. {
  13. currentSeed.set_random();
  14. }
  15. // Used for all other servers, so they have the same BGN parameters
  16. PrsonaServer::PrsonaServer(size_t numServers, const BGN& otherBgn)
  17. : numServers(numServers), bgnSystem(otherBgn)
  18. {
  19. currentSeed.set_random();
  20. }
  21. /*
  22. * BASIC PUBLIC SYSTEM INFO GETTERS
  23. */
  24. BGNPublicKey PrsonaServer::get_bgn_public_key() const
  25. {
  26. return bgnSystem.get_public_key();
  27. }
  28. size_t PrsonaServer::get_num_clients() const
  29. {
  30. return currentPseudonyms.size();
  31. }
  32. size_t PrsonaServer::get_num_servers() const
  33. {
  34. return numServers;
  35. }
  36. Twistpoint PrsonaServer::get_fresh_generator(std::vector<Proof>& pi) const
  37. {
  38. pi = currentGeneratorProof;
  39. return currentFreshGenerator;
  40. }
  41. /*
  42. * FRESH GENERATOR CALCULATION
  43. */
  44. // To calculate the current epoch's generator, start from the base generator,
  45. // then have every server call this function on it iteratively (in any order).
  46. Twistpoint PrsonaServer::add_curr_seed_to_generator(
  47. std::vector<Proof>& pi,
  48. const Twistpoint& currGenerator) const
  49. {
  50. pi.push_back(add_to_generator_proof(currGenerator, currentSeed));
  51. return currGenerator * currentSeed;
  52. }
  53. // To calculate the next epoch's generator, start from the base generator,
  54. // then have every server call this function on it iteratively (in any order).
  55. Twistpoint PrsonaServer::add_next_seed_to_generator(
  56. std::vector<Proof>& pi,
  57. const Twistpoint& currGenerator) const
  58. {
  59. pi.push_back(add_to_generator_proof(currGenerator, nextSeed));
  60. return currGenerator * nextSeed;
  61. }
  62. /*
  63. * ENCRYPTED DATA GETTERS
  64. */
  65. /* Call this in order to get the current encrypted votes cast by a given user
  66. * (who is identified by their short term public key).
  67. * In practice, this is intended for clients,
  68. * who need to know their current votes in order to rerandomize them. */
  69. std::vector<TwistBipoint> PrsonaServer::get_current_votes_by(
  70. Proof& pi, const Twistpoint& shortTermPublicKey) const
  71. {
  72. std::vector<TwistBipoint> retval;
  73. size_t voteSubmitter = binary_search(shortTermPublicKey);
  74. retval = voteMatrix[voteSubmitter];
  75. pi = generate_valid_vote_row_proof(retval);
  76. return retval;
  77. }
  78. std::vector<std::vector<TwistBipoint>> PrsonaServer::get_all_current_votes(
  79. Proof& pi) const
  80. {
  81. pi = generate_valid_vote_matrix_proof(voteMatrix);
  82. return voteMatrix;
  83. }
  84. /* Call this in order to get the current encrypted tally of a given user
  85. * (who is identified by their short term public key).
  86. * In practice, this is intended for clients, so that the servers vouch
  87. * for their ciphertexts being valid as part of their reputation proofs. */
  88. EGCiphertext PrsonaServer::get_current_user_encrypted_tally(
  89. Proof& pi, const Twistpoint& shortTermPublicKey) const
  90. {
  91. EGCiphertext retval;
  92. size_t tallyOwner = binary_search(shortTermPublicKey);
  93. retval = currentUserEncryptedTallies[tallyOwner];
  94. pi = generate_valid_user_tally_proof(retval);
  95. return retval;
  96. }
  97. CurveBipoint PrsonaServer::get_current_server_encrypted_tally(
  98. Proof& pi, const Twistpoint& shortTermPublicKey) const
  99. {
  100. CurveBipoint retval;
  101. size_t tallyOwner = binary_search(shortTermPublicKey);
  102. retval = previousVoteTallies[tallyOwner];
  103. pi = generate_valid_server_tally_proof(retval);
  104. return retval;
  105. }
  106. std::vector<Twistpoint> PrsonaServer::get_current_pseudonyms(Proof& pi) const
  107. {
  108. pi = generate_valid_pseudonyms_proof(currentPseudonyms);
  109. return currentPseudonyms;
  110. }
  111. std::vector<Twistpoint> PrsonaServer::get_current_pseudonyms() const
  112. {
  113. return currentPseudonyms;
  114. }
  115. /*
  116. * PROOF COMMITMENT GETTERS
  117. */
  118. Proof PrsonaServer::get_vote_row_commitment(const Twistpoint& request) const
  119. {
  120. size_t requestID = binary_search(request);
  121. return generate_valid_vote_row_proof(voteMatrix[requestID]);
  122. }
  123. Proof PrsonaServer::get_vote_matrix_commitment() const
  124. {
  125. return generate_valid_vote_matrix_proof(voteMatrix);
  126. }
  127. Proof PrsonaServer::get_user_tally_commitment(const Twistpoint& request) const
  128. {
  129. size_t requestID = binary_search(request);
  130. return generate_valid_user_tally_proof(currentUserEncryptedTallies[requestID]);
  131. }
  132. Proof PrsonaServer::get_server_tally_commitment(const Twistpoint& request) const
  133. {
  134. size_t requestID = binary_search(request);
  135. return generate_valid_server_tally_proof(previousVoteTallies[requestID]);
  136. }
  137. Proof PrsonaServer::get_pseudonyms_commitment() const
  138. {
  139. return generate_valid_pseudonyms_proof(currentPseudonyms);
  140. }
  141. void PrsonaServer::print_current_commitments() const
  142. {
  143. std::stringstream helper;
  144. std::cout << "Commitments:\n";
  145. std::cout << "User tallies:\n";
  146. for (size_t i = 0; i < currentUserEncryptedTallies.size(); i++)
  147. {
  148. helper.str("");
  149. helper << currentUserEncryptedTallies[i];
  150. std::cout << "Tally " << i + 1 << " of " << currentUserEncryptedTallies.size() << ": " << std::hex << oracle(helper.str()) << std::dec << "\n";
  151. }
  152. std::cout << "Server tallies:\n";
  153. for (size_t i = 0; i < previousVoteTallies.size(); i++)
  154. {
  155. helper.str("");
  156. helper << previousVoteTallies[i];
  157. std::cout << "Tally " << i + 1 << " of " << previousVoteTallies.size() << ": " << std::hex << oracle(helper.str()) << std::dec << "\n";
  158. }
  159. }
  160. /*
  161. * CLIENT INTERACTIONS
  162. */
  163. /* Add a new client (who is identified only by their short term public key)
  164. * One server will do this, then ask all other servers to import their
  165. * (proven) exported data. */
  166. void PrsonaServer::add_new_client(
  167. std::vector<Proof>& proofOfValidAddition,
  168. const Proof& proofOfValidKey,
  169. const Twistpoint& shortTermPublicKey)
  170. {
  171. if (!verify_ownership_proof(
  172. proofOfValidKey, currentFreshGenerator, shortTermPublicKey))
  173. {
  174. std::cerr << "Could not verify proof of valid key." << std::endl;
  175. return;
  176. }
  177. currentPseudonyms.push_back(shortTermPublicKey);
  178. // The first epoch's score for a new user will be low,
  179. // but will typically converge on an average score quickly
  180. Scalar tallySeed;
  181. CurveBipoint encryptedDefaultTally =
  182. bgnSystem.get_public_key().curveEncrypt(tallySeed, DEFAULT_TALLY);
  183. previousVoteTallies.push_back(encryptedDefaultTally);
  184. Scalar seedForUserTally;
  185. seedForUserTally.set_random();
  186. EGCiphertext newUserEncryptedTally;
  187. newUserEncryptedTally.mask = shortTermPublicKey * seedForUserTally;
  188. newUserEncryptedTally.encryptedMessage =
  189. currentFreshGenerator * seedForUserTally +
  190. elGamalBlindGenerator * DEFAULT_TALLY;
  191. currentUserEncryptedTallies.push_back(newUserEncryptedTally);
  192. // Users are defaulted to casting a neutral vote for others.
  193. TwistBipoint encryptedDefaultVote, encryptedSelfVote;
  194. Scalar currDefaultSeed, currSelfSeed;
  195. encryptedDefaultVote =
  196. bgnSystem.get_public_key().twistEncrypt(currDefaultSeed, DEFAULT_VOTE);
  197. encryptedSelfVote =
  198. bgnSystem.get_public_key().twistEncrypt(currSelfSeed, Scalar(MAX_ALLOWED_VOTE));
  199. std::vector<TwistBipoint> newRow;
  200. std::vector<Scalar> userVoteSeeds;
  201. std::vector<Scalar> otherVoteSeeds;
  202. for (size_t i = 0; i < voteMatrix.size(); i++)
  203. {
  204. Scalar addedSeed;
  205. encryptedDefaultVote = bgnSystem.get_public_key().rerandomize(addedSeed, encryptedDefaultVote);
  206. currDefaultSeed = currDefaultSeed + addedSeed;
  207. otherVoteSeeds.push_back(Scalar());
  208. otherVoteSeeds[i] = currDefaultSeed;
  209. voteMatrix[i].push_back(encryptedDefaultVote);
  210. encryptedDefaultVote = bgnSystem.get_public_key().rerandomize(addedSeed, encryptedDefaultVote);
  211. currDefaultSeed = currDefaultSeed + addedSeed;
  212. userVoteSeeds.push_back(Scalar());
  213. userVoteSeeds[i] = currDefaultSeed;
  214. newRow.push_back(encryptedDefaultVote);
  215. }
  216. // Because we are adding the new user to the end (and then sorting it),
  217. // this last element (bottom right corner) is always the self vote.
  218. userVoteSeeds.push_back(Scalar());
  219. userVoteSeeds[newRow.size()] = currSelfSeed;
  220. otherVoteSeeds.push_back(Scalar());
  221. otherVoteSeeds[newRow.size()] = currSelfSeed;
  222. newRow.push_back(encryptedSelfVote);
  223. voteMatrix.push_back(newRow);
  224. std::vector<size_t> sortOrder = order_data();
  225. std::vector<Scalar> newUserVoteSeeds;
  226. std::vector<Scalar> newOtherVoteSeeds;
  227. for (size_t i = 0; i < sortOrder.size(); i++)
  228. {
  229. newUserVoteSeeds.push_back(userVoteSeeds[sortOrder[i]]);
  230. newOtherVoteSeeds.push_back(otherVoteSeeds[sortOrder[i]]);
  231. }
  232. proofOfValidAddition = generate_proof_of_added_user(
  233. tallySeed,
  234. seedForUserTally,
  235. newUserVoteSeeds,
  236. newOtherVoteSeeds);
  237. }
  238. // Receive a new vote row from a user (identified by short term public key).
  239. bool PrsonaServer::receive_vote(
  240. const std::vector<Proof>& pi,
  241. const std::vector<TwistBipoint>& newVotes,
  242. const Twistpoint& shortTermPublicKey)
  243. {
  244. size_t voteSubmitter = binary_search(shortTermPublicKey);
  245. std::vector<TwistBipoint> oldVotes = voteMatrix[voteSubmitter];
  246. if (!verify_vote_proof(pi, oldVotes, newVotes, shortTermPublicKey))
  247. return false;
  248. voteMatrix[voteSubmitter] = newVotes;
  249. return true;
  250. }
  251. /*********************
  252. * PRIVATE FUNCTIONS *
  253. *********************/
  254. /*
  255. * CONSTRUCTOR HELPERS
  256. */
  257. const BGN& PrsonaServer::get_bgn_details() const
  258. {
  259. return bgnSystem;
  260. }
  261. bool PrsonaServer::initialize_fresh_generator(
  262. const std::vector<Proof>& pi,
  263. const Twistpoint& firstGenerator)
  264. {
  265. if (!verify_generator_proof(pi, firstGenerator, numServers))
  266. {
  267. std::cerr << "Could not verify generator proof, aborting." << std::endl;
  268. return false;
  269. }
  270. currentGeneratorProof = pi;
  271. currentFreshGenerator = firstGenerator;
  272. return true;
  273. }
  274. // To calculate the blind generator for ElGamal, start from the base generator,
  275. // then have every server call this function on it iteratively (in any order).
  276. Twistpoint PrsonaServer::add_rand_seed_to_generator(
  277. std::vector<Proof>& pi,
  278. const Twistpoint& currGenerator) const
  279. {
  280. Scalar lambda;
  281. lambda.set_random();
  282. pi.push_back(add_to_generator_proof(currGenerator, lambda));
  283. return currGenerator * lambda;
  284. }
  285. bool PrsonaServer::set_EG_blind_generator(
  286. const std::vector<Proof>& pi,
  287. const Twistpoint& currGenerator)
  288. {
  289. return PrsonaBase::set_EG_blind_generator(pi, currGenerator, numServers);
  290. }
  291. /*
  292. * SCORE TALLYING
  293. */
  294. /* Calculate scores homomorphically (as an individual server would normally)
  295. * and then decrypt them (which the servers would normally work together to do).
  296. *
  297. * Note that since these calculations are just for us, we don't need to do any
  298. * expensive rerandomizations of intermediate values. */
  299. std::vector<Scalar> PrsonaServer::tally_scores()
  300. {
  301. std::vector<Quadripoint> BGNEncryptedTallies;
  302. std::vector<Scalar> decryptedTallies;
  303. for (size_t i = 0; i < voteMatrix.size(); i++)
  304. {
  305. std::vector<Quadripoint> weightedVotes;
  306. // ZIP
  307. for (size_t j = 0; j < previousVoteTallies.size(); j++)
  308. {
  309. Quadripoint curr =
  310. bgnSystem.homomorphic_multiplication_no_rerandomize(
  311. previousVoteTallies[j], voteMatrix[j][i]);
  312. weightedVotes.push_back(curr);
  313. }
  314. // FOLDL
  315. Quadripoint currEncryptedTally = weightedVotes[0];
  316. for (size_t j = 1; j < weightedVotes.size(); j++)
  317. {
  318. currEncryptedTally =
  319. bgnSystem.homomorphic_addition_no_rerandomize(
  320. currEncryptedTally, weightedVotes[j]);
  321. }
  322. // DECRYPT
  323. decryptedTallies.push_back(bgnSystem.decrypt(currEncryptedTally));
  324. }
  325. return decryptedTallies;
  326. }
  327. /* Calculate what the maximum possible score this round was (that is,
  328. * given the current user weights, what was the highest possible score?).
  329. *
  330. * As with individual scores, this also does the decryption that servers
  331. * would ordinarily work together to form. */
  332. Scalar PrsonaServer::get_max_possible_score()
  333. {
  334. // FOLDL
  335. CurveBipoint currEncryptedVal = previousVoteTallies[0];
  336. for (size_t i = 1; i < previousVoteTallies.size(); i++)
  337. {
  338. currEncryptedVal =
  339. bgnSystem.homomorphic_addition_no_rerandomize(
  340. currEncryptedVal, previousVoteTallies[i]);
  341. }
  342. // DECRYPT
  343. Scalar retval = bgnSystem.decrypt(currEncryptedVal);
  344. return retval;
  345. }
  346. void PrsonaServer::receive_tallied_scores(
  347. const std::vector<EGCiphertext>& userTallyScores,
  348. const std::vector<CurveBipoint>& serverTallyScores)
  349. {
  350. currentUserEncryptedTallies = userTallyScores;
  351. previousVoteTallies = serverTallyScores;
  352. }
  353. void PrsonaServer::encrypt(
  354. CurveBipoint& element,
  355. const Scalar& value)
  356. {
  357. bgnSystem.encrypt(element, value);
  358. }
  359. /*
  360. * EPOCH ROUNDS
  361. */
  362. // The first round, going from A_0 to A_0.5
  363. void PrsonaServer::build_up_midway_pseudonyms(
  364. std::vector<std::vector<std::vector<Proof>>>& pi,
  365. std::vector<std::vector<std::vector<Twistpoint>>>& permutationCommits,
  366. std::vector<std::vector<std::vector<Twistpoint>>>& freshPseudonymCommits,
  367. std::vector<std::vector<std::vector<Twistpoint>>>& freshPseudonymSeedCommits,
  368. std::vector<std::vector<std::vector<CurveBipoint>>>& serverTallyCommits,
  369. std::vector<std::vector<std::vector<std::vector<TwistBipoint>>>>& partwayVoteMatrixCommits,
  370. std::vector<std::vector<std::vector<std::vector<TwistBipoint>>>>& finalVoteMatrixCommits,
  371. Twistpoint& nextGenerator)
  372. {
  373. nextSeed.set_random();
  374. std::vector<std::vector<Twistpoint>> currPermutationCommits;
  375. std::vector<std::vector<Twistpoint>> currFreshPseudonymCommits;
  376. std::vector<std::vector<Twistpoint>> currFreshPseudonymSeedCommits;
  377. std::vector<std::vector<CurveBipoint>> currServerTallyCommits;
  378. std::vector<std::vector<std::vector<TwistBipoint>>> currPartwayVoteMatrixCommits;
  379. std::vector<std::vector<std::vector<TwistBipoint>>> currFinalVoteMatrixCommits;
  380. std::vector<std::vector<Twistpoint>> currUserTallyMaskCommits;
  381. std::vector<std::vector<Twistpoint>> currUserTallyMessageCommits;
  382. std::vector<std::vector<Twistpoint>> currUserTallySeedCommits;
  383. pi.push_back(epoch_calculations(
  384. currPermutationCommits,
  385. currFreshPseudonymCommits,
  386. currFreshPseudonymSeedCommits,
  387. currServerTallyCommits,
  388. currPartwayVoteMatrixCommits,
  389. currFinalVoteMatrixCommits,
  390. currUserTallyMaskCommits,
  391. currUserTallyMessageCommits,
  392. currUserTallySeedCommits,
  393. nextSeed,
  394. nextGenerator,
  395. false));
  396. permutationCommits.push_back(currPermutationCommits);
  397. freshPseudonymCommits.push_back(currFreshPseudonymCommits);
  398. freshPseudonymSeedCommits.push_back(currFreshPseudonymSeedCommits);
  399. serverTallyCommits.push_back(currServerTallyCommits);
  400. partwayVoteMatrixCommits.push_back(currPartwayVoteMatrixCommits);
  401. finalVoteMatrixCommits.push_back(currFinalVoteMatrixCommits);
  402. pi[0][0].push_back(
  403. add_to_generator_proof(nextGenerator, nextSeed));
  404. nextGenerator = nextGenerator * nextSeed;
  405. }
  406. // In between these rounds, scores are tallied, decrypted,
  407. // and encrypted to fresh user pseudonyms (possible through weird math)
  408. // The second round, going from A_0.5 to A_1
  409. void PrsonaServer::break_down_midway_pseudonyms(
  410. const std::vector<Proof>& generatorProof,
  411. std::vector<std::vector<std::vector<Proof>>>& pi,
  412. std::vector<std::vector<std::vector<Twistpoint>>>& permutationCommits,
  413. std::vector<std::vector<std::vector<Twistpoint>>>& freshPseudonymCommits,
  414. std::vector<std::vector<std::vector<Twistpoint>>>& freshPseudonymSeedCommits,
  415. std::vector<std::vector<std::vector<CurveBipoint>>>& serverTallyCommits,
  416. std::vector<std::vector<std::vector<std::vector<TwistBipoint>>>>& partwayVoteMatrixCommits,
  417. std::vector<std::vector<std::vector<std::vector<TwistBipoint>>>>& finalVoteMatrixCommits,
  418. std::vector<std::vector<std::vector<Twistpoint>>>& userTallyMaskCommits,
  419. std::vector<std::vector<std::vector<Twistpoint>>>& userTallyMessageCommits,
  420. std::vector<std::vector<std::vector<Twistpoint>>>& userTallySeedCommits,
  421. const Twistpoint& nextGenerator)
  422. {
  423. if (!initialize_fresh_generator(generatorProof, nextGenerator))
  424. {
  425. std::cerr << "New fresh generator could not be verified." << std::endl;
  426. return;
  427. }
  428. Scalar inverseSeed = currentSeed.curveMultInverse();
  429. std::vector<std::vector<Twistpoint>> currPermutationCommits;
  430. std::vector<std::vector<Twistpoint>> currFreshPseudonymCommits;
  431. std::vector<std::vector<Twistpoint>> currFreshPseudonymSeedCommits;
  432. std::vector<std::vector<CurveBipoint>> currServerTallyCommits;
  433. std::vector<std::vector<std::vector<TwistBipoint>>> currPartwayVoteMatrixCommits;
  434. std::vector<std::vector<std::vector<TwistBipoint>>> currFinalVoteMatrixCommits;
  435. std::vector<std::vector<Twistpoint>> currUserTallyMaskCommits;
  436. std::vector<std::vector<Twistpoint>> currUserTallyMessageCommits;
  437. std::vector<std::vector<Twistpoint>> currUserTallySeedCommits;
  438. pi.push_back(epoch_calculations(
  439. currPermutationCommits,
  440. currFreshPseudonymCommits,
  441. currFreshPseudonymSeedCommits,
  442. currServerTallyCommits,
  443. currPartwayVoteMatrixCommits,
  444. currFinalVoteMatrixCommits,
  445. currUserTallyMaskCommits,
  446. currUserTallyMessageCommits,
  447. currUserTallySeedCommits,
  448. inverseSeed,
  449. nextGenerator,
  450. true));
  451. permutationCommits.push_back(currPermutationCommits);
  452. freshPseudonymCommits.push_back(currFreshPseudonymCommits);
  453. freshPseudonymSeedCommits.push_back(currFreshPseudonymSeedCommits);
  454. serverTallyCommits.push_back(currServerTallyCommits);
  455. partwayVoteMatrixCommits.push_back(currPartwayVoteMatrixCommits);
  456. finalVoteMatrixCommits.push_back(currFinalVoteMatrixCommits);
  457. userTallyMaskCommits.push_back(currUserTallyMaskCommits);
  458. userTallyMessageCommits.push_back(currUserTallyMessageCommits);
  459. userTallySeedCommits.push_back(currUserTallySeedCommits);
  460. currentSeed = nextSeed;
  461. }
  462. /*
  463. * EPOCH HELPERS
  464. */
  465. std::vector<std::vector<Proof>> PrsonaServer::epoch_calculations(
  466. std::vector<std::vector<Twistpoint>>& permutationCommits,
  467. std::vector<std::vector<Twistpoint>>& freshPseudonymCommits,
  468. std::vector<std::vector<Twistpoint>>& freshPseudonymSeedCommits,
  469. std::vector<std::vector<CurveBipoint>>& serverTallyCommits,
  470. std::vector<std::vector<std::vector<TwistBipoint>>>& partwayVoteMatrixCommits,
  471. std::vector<std::vector<std::vector<TwistBipoint>>>& finalVoteMatrixCommits,
  472. std::vector<std::vector<Twistpoint>>& userTallyMaskCommits,
  473. std::vector<std::vector<Twistpoint>>& userTallyMessageCommits,
  474. std::vector<std::vector<Twistpoint>>& userTallySeedCommits,
  475. const Scalar& power,
  476. const Twistpoint& nextGenerator,
  477. bool doUserTallies)
  478. {
  479. std::vector<std::vector<Proof>> retval;
  480. std::vector<std::vector<Scalar>> permutations =
  481. generate_permutation_matrix(power);
  482. std::vector<std::vector<Scalar>> permutationSeeds;
  483. permutationCommits.clear();
  484. permutationCommits =
  485. generate_commitment_matrix(permutations, permutationSeeds);
  486. retval.push_back(generate_valid_permutation_proof(
  487. permutations, permutationSeeds, permutationCommits));
  488. std::vector<std::vector<Scalar>> freshPseudonymSeeds;
  489. freshPseudonymSeedCommits.clear();
  490. freshPseudonymCommits.clear();
  491. freshPseudonymCommits =
  492. generate_pseudonym_matrix(
  493. permutations,
  494. power,
  495. freshPseudonymSeeds,
  496. freshPseudonymSeedCommits);
  497. retval.push_back(
  498. generate_proof_of_reordering_plus_power(
  499. permutations,
  500. power,
  501. permutationSeeds,
  502. freshPseudonymSeeds,
  503. currentPseudonyms,
  504. permutationCommits,
  505. freshPseudonymCommits,
  506. freshPseudonymSeedCommits));
  507. std::vector<std::vector<Scalar>> serverTallySeeds;
  508. serverTallyCommits.clear();
  509. serverTallyCommits =
  510. generate_server_tally_matrix(
  511. permutations,
  512. serverTallySeeds);
  513. retval.push_back(
  514. generate_proof_of_reordering<CurveBipoint>(
  515. permutations,
  516. permutationSeeds,
  517. serverTallySeeds,
  518. previousVoteTallies,
  519. permutationCommits,
  520. serverTallyCommits,
  521. bgnSystem.get_public_key().get_bipoint_curvegen(),
  522. bgnSystem.get_public_key().get_bipoint_curve_subgroup_gen()));
  523. std::vector<std::vector<std::vector<Scalar>>> partwayVoteMatrixSeeds;
  524. std::vector<std::vector<std::vector<Scalar>>> finalVoteMatrixSeeds;
  525. partwayVoteMatrixCommits.clear();
  526. partwayVoteMatrixCommits = generate_vote_tensor(
  527. permutations,
  528. voteMatrix,
  529. partwayVoteMatrixSeeds,
  530. false);
  531. std::vector<std::vector<TwistBipoint>> partialVoteMatrix =
  532. calculate_next_vote_matrix(partwayVoteMatrixCommits);
  533. finalVoteMatrixCommits.clear();
  534. finalVoteMatrixCommits = generate_vote_tensor(
  535. permutations,
  536. partialVoteMatrix,
  537. finalVoteMatrixSeeds,
  538. true);
  539. generate_vote_tensor_proofs(
  540. retval,
  541. permutations,
  542. permutationSeeds,
  543. partwayVoteMatrixSeeds,
  544. voteMatrix,
  545. permutationCommits,
  546. partwayVoteMatrixCommits,
  547. false);
  548. generate_vote_tensor_proofs(
  549. retval,
  550. permutations,
  551. permutationSeeds,
  552. finalVoteMatrixSeeds,
  553. partialVoteMatrix,
  554. permutationCommits,
  555. finalVoteMatrixCommits,
  556. true);
  557. if (doUserTallies)
  558. {
  559. std::vector<Twistpoint> userTallyMasks;
  560. std::vector<Twistpoint> userTallyMessages;
  561. std::vector<std::vector<Scalar>> userTallySeeds;
  562. userTallyMaskCommits.clear();
  563. userTallyMessageCommits.clear();
  564. userTallySeedCommits.clear();
  565. generate_user_tally_matrix(
  566. permutations,
  567. power,
  568. nextGenerator,
  569. currentPseudonyms,
  570. userTallyMasks,
  571. userTallyMaskCommits,
  572. userTallyMessages,
  573. userTallyMessageCommits,
  574. userTallySeeds,
  575. userTallySeedCommits);
  576. retval.push_back(
  577. generate_user_tally_proofs(
  578. permutations,
  579. power,
  580. nextGenerator,
  581. permutationSeeds,
  582. userTallySeeds,
  583. currentPseudonyms,
  584. userTallyMasks,
  585. userTallyMessages,
  586. permutationCommits,
  587. userTallyMaskCommits,
  588. userTallyMessageCommits,
  589. userTallySeedCommits));
  590. }
  591. // Replace internal values
  592. update_data(
  593. freshPseudonymCommits,
  594. serverTallyCommits,
  595. finalVoteMatrixCommits,
  596. userTallyMaskCommits,
  597. userTallyMessageCommits);
  598. return retval;
  599. }
  600. bool PrsonaServer::accept_epoch_updates(
  601. const std::vector<std::vector<Proof>>& pi,
  602. const std::vector<std::vector<Twistpoint>>& permutationCommits,
  603. const std::vector<std::vector<Twistpoint>>& freshPseudonymCommits,
  604. const std::vector<std::vector<Twistpoint>>& freshPseudonymSeedCommits,
  605. const std::vector<std::vector<CurveBipoint>>& serverTallyCommits,
  606. const std::vector<std::vector<std::vector<TwistBipoint>>>& partwayVoteMatrixCommits,
  607. const std::vector<std::vector<std::vector<TwistBipoint>>>& finalVoteMatrixCommits,
  608. const std::vector<std::vector<Twistpoint>>& userTallyMaskCommits,
  609. const std::vector<std::vector<Twistpoint>>& userTallyMessageCommits,
  610. const std::vector<std::vector<Twistpoint>>& userTallySeedCommits,
  611. const Twistpoint& nextGenerator,
  612. bool doUserTallies)
  613. {
  614. bool verification;
  615. if ((userTallyMaskCommits.empty() && doUserTallies) || (!userTallyMaskCommits.empty() && !doUserTallies))
  616. {
  617. std::cerr << "user tallies are not in expected state." << std::endl;
  618. return false;
  619. }
  620. if (pi.empty())
  621. return false;
  622. size_t currOffset = 0;
  623. verification =
  624. verify_valid_permutation_proof(pi[currOffset], permutationCommits);
  625. currOffset++;
  626. if (!verification)
  627. {
  628. std::cerr << "Could not verify valid permutation matrix." << std::endl;
  629. return false;
  630. }
  631. verification =
  632. verify_proof_of_reordering_plus_power(
  633. pi[currOffset],
  634. currentPseudonyms,
  635. permutationCommits,
  636. freshPseudonymCommits,
  637. freshPseudonymSeedCommits);
  638. currOffset++;
  639. if (!verification)
  640. {
  641. std::cerr << "Could not verify valid pseudonym vector." << std::endl;
  642. return false;
  643. }
  644. verification =
  645. verify_proof_of_reordering<CurveBipoint>(
  646. pi[currOffset],
  647. previousVoteTallies,
  648. permutationCommits,
  649. serverTallyCommits,
  650. bgnSystem.get_public_key().get_bipoint_curvegen(),
  651. bgnSystem.get_public_key().get_bipoint_curve_subgroup_gen());
  652. currOffset++;
  653. if (!verification)
  654. {
  655. std::cerr << "Could not verify valid server tally vector." << std::endl;
  656. return false;
  657. }
  658. verification = verify_vote_tensor_proofs(
  659. pi,
  660. currOffset,
  661. voteMatrix,
  662. permutationCommits,
  663. partwayVoteMatrixCommits,
  664. false);
  665. currOffset += voteMatrix.size();
  666. if (!verification)
  667. {
  668. std::cerr << "Could not verify first half vote matrix." << std::endl;
  669. return false;
  670. }
  671. std::vector<std::vector<TwistBipoint>> partialVoteMatrix =
  672. calculate_next_vote_matrix(partwayVoteMatrixCommits);
  673. verification = verify_vote_tensor_proofs(
  674. pi,
  675. currOffset,
  676. partialVoteMatrix,
  677. permutationCommits,
  678. finalVoteMatrixCommits,
  679. true);
  680. currOffset += voteMatrix.size();
  681. if (!verification)
  682. {
  683. std::cerr << "Could not verify second half vote matrix." << std::endl;
  684. return false;
  685. }
  686. if (doUserTallies)
  687. {
  688. std::vector<Twistpoint> userTallyMasks;
  689. std::vector<Twistpoint> userTallyMessages;
  690. for (size_t i = 0; i < currentUserEncryptedTallies.size(); i++)
  691. {
  692. userTallyMasks.push_back(currentUserEncryptedTallies[i].mask);
  693. userTallyMessages.push_back(currentUserEncryptedTallies[i].encryptedMessage);
  694. }
  695. verification = verify_user_tally_proofs(
  696. pi[currOffset],
  697. nextGenerator,
  698. currentPseudonyms,
  699. userTallyMasks,
  700. userTallyMessages,
  701. permutationCommits,
  702. userTallyMaskCommits,
  703. userTallyMessageCommits,
  704. userTallySeedCommits);
  705. currOffset++;
  706. if (!verification)
  707. {
  708. std::cerr << "Could not verify user tallies." << std::endl;
  709. return false;
  710. }
  711. }
  712. verification = update_data(
  713. freshPseudonymCommits,
  714. serverTallyCommits,
  715. finalVoteMatrixCommits,
  716. userTallyMaskCommits,
  717. userTallyMessageCommits);
  718. return verification;
  719. }
  720. std::vector<std::vector<Scalar>> PrsonaServer::generate_permutation_matrix(
  721. const Scalar& reorderSeed) const
  722. {
  723. std::vector<std::vector<Scalar>> retval;
  724. for (size_t i = 0; i < currentPseudonyms.size(); i++)
  725. {
  726. std::vector<Scalar> currRow;
  727. for (size_t j = 0; j < currentPseudonyms.size(); j++)
  728. currRow.push_back(Scalar(0));
  729. retval.push_back(currRow);
  730. }
  731. std::vector<Twistpoint> nextPseudonyms;
  732. for (size_t i = 0; i < currentPseudonyms.size(); i++)
  733. nextPseudonyms.push_back(currentPseudonyms[i] * reorderSeed);
  734. std::vector<size_t> order = sort_data(nextPseudonyms);
  735. for (size_t i = 0; i < order.size(); i++)
  736. retval[order[i]][i] = Scalar(1);
  737. return retval;
  738. }
  739. std::vector<std::vector<Twistpoint>> PrsonaServer::generate_commitment_matrix(
  740. const std::vector<std::vector<Scalar>>& permutations,
  741. std::vector<std::vector<Scalar>>& seeds) const
  742. {
  743. std::vector<std::vector<Twistpoint>> retval;
  744. Twistpoint g = EL_GAMAL_GENERATOR;
  745. Twistpoint h = elGamalBlindGenerator;
  746. seeds.clear();
  747. for (size_t i = 0; i < permutations.size(); i++)
  748. {
  749. std::vector<Scalar> currSeeds;
  750. for (size_t j = 0; j < permutations[i].size(); j++)
  751. currSeeds.push_back(Scalar(0));
  752. seeds.push_back(currSeeds);
  753. }
  754. for (size_t i = 0; i < permutations.size(); i++)
  755. {
  756. std::vector<Twistpoint> currRow;
  757. size_t last = permutations[i].size() - 1;
  758. for (size_t j = 0; j < permutations[i].size(); j++)
  759. {
  760. Twistpoint element;
  761. if (j != last)
  762. {
  763. seeds[i][j].set_random();
  764. seeds[i][last] = seeds[i][last] - seeds[i][j];
  765. }
  766. element = g * permutations[i][j] + h * seeds[i][j];
  767. currRow.push_back(element);
  768. }
  769. retval.push_back(currRow);
  770. }
  771. return retval;
  772. }
  773. std::vector<std::vector<Twistpoint>> PrsonaServer::generate_pseudonym_matrix(
  774. const std::vector<std::vector<Scalar>>& permutations,
  775. const Scalar& power,
  776. std::vector<std::vector<Scalar>>& seeds,
  777. std::vector<std::vector<Twistpoint>>& seedCommits) const
  778. {
  779. return generate_reordered_plus_power_matrix<Twistpoint>(
  780. permutations,
  781. power,
  782. currentPseudonyms,
  783. seeds,
  784. seedCommits,
  785. elGamalBlindGenerator);
  786. }
  787. std::vector<std::vector<CurveBipoint>> PrsonaServer::generate_server_tally_matrix(
  788. const std::vector<std::vector<Scalar>>& permutations,
  789. std::vector<std::vector<Scalar>>& seeds) const
  790. {
  791. return generate_reordered_matrix<CurveBipoint>(
  792. permutations,
  793. previousVoteTallies,
  794. seeds,
  795. bgnSystem.get_public_key().get_bipoint_curve_subgroup_gen(),
  796. false);
  797. }
  798. std::vector<std::vector<std::vector<TwistBipoint>>> PrsonaServer::generate_vote_tensor(
  799. const std::vector<std::vector<Scalar>>& permutations,
  800. const std::vector<std::vector<TwistBipoint>>& currVoteMatrix,
  801. std::vector<std::vector<std::vector<Scalar>>>& seeds,
  802. bool inverted) const
  803. {
  804. std::vector<std::vector<std::vector<TwistBipoint>>> retval;
  805. for (size_t i = 0; i < currVoteMatrix.size(); i++)
  806. {
  807. std::vector<std::vector<Scalar>> currSeeds;
  808. std::vector<TwistBipoint> inputRow;
  809. if (inverted)
  810. {
  811. for (size_t j = 0; j < currVoteMatrix.size(); j++)
  812. inputRow.push_back(currVoteMatrix[j][i]);
  813. }
  814. else
  815. {
  816. inputRow = currVoteMatrix[i];
  817. }
  818. retval.push_back(generate_reordered_matrix<TwistBipoint>(
  819. permutations,
  820. inputRow,
  821. currSeeds,
  822. bgnSystem.get_public_key().get_bipoint_twist_subgroup_gen(),
  823. false));
  824. seeds.push_back(currSeeds);
  825. }
  826. return retval;
  827. }
  828. std::vector<std::vector<TwistBipoint>> PrsonaServer::calculate_next_vote_matrix(
  829. const std::vector<std::vector<std::vector<TwistBipoint>>>& voteTensor) const
  830. {
  831. std::vector<std::vector<TwistBipoint>> retval;
  832. for (size_t i = 0; i < voteTensor.size(); i++)
  833. {
  834. std::vector<TwistBipoint> currRow;
  835. for (size_t j = 0; j < voteTensor[i].size(); j++)
  836. {
  837. TwistBipoint sum = voteTensor[i][j][0];
  838. for (size_t k = 1; k < voteTensor[i][j].size(); k++)
  839. sum = sum + voteTensor[i][j][k];
  840. currRow.push_back(sum);
  841. }
  842. retval.push_back(currRow);
  843. }
  844. return retval;
  845. }
  846. void PrsonaServer::generate_vote_tensor_proofs(
  847. std::vector<std::vector<Proof>>& pi,
  848. const std::vector<std::vector<Scalar>>& permutations,
  849. const std::vector<std::vector<Scalar>>& permutationSeeds,
  850. const std::vector<std::vector<std::vector<Scalar>>>& matrixSeeds,
  851. const std::vector<std::vector<TwistBipoint>>& currMatrix,
  852. const std::vector<std::vector<Twistpoint>>& permutationCommits,
  853. const std::vector<std::vector<std::vector<TwistBipoint>>>& matrixCommits,
  854. bool inverted) const
  855. {
  856. for (size_t i = 0; i < currMatrix.size(); i++)
  857. {
  858. std::vector<TwistBipoint> inputRow;
  859. if (inverted)
  860. {
  861. for (size_t j = 0; j < currMatrix.size(); j++)
  862. inputRow.push_back(currMatrix[j][i]);
  863. }
  864. else
  865. {
  866. inputRow = currMatrix[i];
  867. }
  868. pi.push_back(generate_proof_of_reordering<TwistBipoint>(
  869. permutations,
  870. permutationSeeds,
  871. matrixSeeds[i],
  872. inputRow,
  873. permutationCommits,
  874. matrixCommits[i],
  875. bgnSystem.get_public_key().get_bipoint_twistgen(),
  876. bgnSystem.get_public_key().get_bipoint_twist_subgroup_gen()));
  877. }
  878. }
  879. bool PrsonaServer::verify_vote_tensor_proofs(
  880. const std::vector<std::vector<Proof>>& pi,
  881. size_t start_offset,
  882. const std::vector<std::vector<TwistBipoint>>& currMatrix,
  883. const std::vector<std::vector<Twistpoint>>& permutationCommits,
  884. const std::vector<std::vector<std::vector<TwistBipoint>>>& matrixCommits,
  885. bool inverted) const
  886. {
  887. bool retval = true;
  888. for (size_t i = 0; i < currMatrix.size(); i++)
  889. {
  890. std::vector<TwistBipoint> inputRow;
  891. if (inverted)
  892. {
  893. for (size_t j = 0; j < currMatrix.size(); j++)
  894. inputRow.push_back(currMatrix[j][i]);
  895. }
  896. else
  897. {
  898. inputRow = currMatrix[i];
  899. }
  900. size_t whichProof = i + start_offset;
  901. retval = retval && verify_proof_of_reordering<TwistBipoint>(
  902. pi[whichProof],
  903. inputRow,
  904. permutationCommits,
  905. matrixCommits[i],
  906. bgnSystem.get_public_key().get_bipoint_twistgen(),
  907. bgnSystem.get_public_key().get_bipoint_twist_subgroup_gen());
  908. }
  909. return retval;
  910. }
  911. void PrsonaServer::generate_user_tally_matrix(
  912. const std::vector<std::vector<Scalar>>& permutations,
  913. const Scalar& power,
  914. const Twistpoint& nextGenerator,
  915. const std::vector<Twistpoint>& currPseudonyms,
  916. std::vector<Twistpoint>& masks,
  917. std::vector<std::vector<Twistpoint>>& maskCommits,
  918. std::vector<Twistpoint>& messages,
  919. std::vector<std::vector<Twistpoint>>& messageCommits,
  920. std::vector<std::vector<Scalar>>& userTallySeeds,
  921. std::vector<std::vector<Twistpoint>>& userTallySeedCommits) const
  922. {
  923. masks.clear();
  924. messages.clear();
  925. for (size_t i = 0; i < currentUserEncryptedTallies.size(); i++)
  926. {
  927. masks.push_back(currentUserEncryptedTallies[i].mask);
  928. messages.push_back(currentUserEncryptedTallies[i].encryptedMessage);
  929. }
  930. maskCommits.clear();
  931. messageCommits.clear();
  932. userTallySeeds.clear();
  933. userTallySeedCommits.clear();
  934. for (size_t i = 0; i < permutations.size(); i++)
  935. {
  936. std::vector<Scalar> currSeeds;
  937. std::vector<Twistpoint> currRow;
  938. for (size_t j = 0; j < permutations[i].size(); j++)
  939. {
  940. currSeeds.push_back(Scalar(0));
  941. currRow.push_back(Twistpoint());
  942. }
  943. userTallySeeds.push_back(currSeeds);
  944. maskCommits.push_back(currRow);
  945. messageCommits.push_back(currRow);
  946. userTallySeedCommits.push_back(currRow);
  947. }
  948. for (size_t i = 0; i < permutations.size(); i++)
  949. {
  950. size_t last = permutations[i].size() - 1;
  951. for (size_t j = 0; j < permutations[i].size(); j++)
  952. {
  953. if (j != last)
  954. {
  955. userTallySeeds[i][j].set_random();
  956. userTallySeeds[i][last] =
  957. userTallySeeds[i][last] -
  958. userTallySeeds[i][j];
  959. }
  960. maskCommits[i][j] =
  961. masks[j] * permutations[j][i] * power +
  962. currPseudonyms[j] * power * permutations[j][i] * userTallySeeds[i][j] +
  963. elGamalBlindGenerator * userTallySeeds[i][j];
  964. messageCommits[i][j] =
  965. messages[j] * permutations[j][i] +
  966. nextGenerator * permutations[j][i] * userTallySeeds[i][j] +
  967. elGamalBlindGenerator * userTallySeeds[i][j];
  968. userTallySeedCommits[i][j] =
  969. EL_GAMAL_GENERATOR * userTallySeeds[i][j];
  970. }
  971. }
  972. }
  973. template <typename T>
  974. std::vector<std::vector<T>> PrsonaServer::generate_reordered_plus_power_matrix(
  975. const std::vector<std::vector<Scalar>>& permutations,
  976. const Scalar& power,
  977. const std::vector<T>& oldValues,
  978. std::vector<std::vector<Scalar>>& seeds,
  979. std::vector<std::vector<Twistpoint>>& seedCommits,
  980. const T& h) const
  981. {
  982. std::vector<std::vector<Scalar>> permutation_plus_power;
  983. seedCommits.clear();
  984. for (size_t i = 0; i < permutations.size(); i++)
  985. {
  986. std::vector<Scalar> currPermutations;
  987. std::vector<Twistpoint> currSeedCommits;
  988. for (size_t j = 0; j < permutations[i].size(); j++)
  989. {
  990. currPermutations.push_back(permutations[i][j] * power);
  991. currSeedCommits.push_back(Twistpoint());
  992. }
  993. permutation_plus_power.push_back(currPermutations);
  994. seedCommits.push_back(currSeedCommits);
  995. }
  996. std::vector<std::vector<T>> retval =
  997. generate_reordered_matrix<T>(
  998. permutation_plus_power,
  999. oldValues,
  1000. seeds,
  1001. h,
  1002. true);
  1003. for (size_t i = 0; i < permutations.size(); i++)
  1004. for (size_t j = 0; j < permutations[i].size(); j++)
  1005. seedCommits[i][j] = EL_GAMAL_GENERATOR * seeds[i][j];
  1006. return retval;
  1007. }
  1008. template <typename T>
  1009. std::vector<std::vector<T>> PrsonaServer::generate_reordered_matrix(
  1010. const std::vector<std::vector<Scalar>>& permutations,
  1011. const std::vector<T>& oldValues,
  1012. std::vector<std::vector<Scalar>>& seeds,
  1013. const T& h,
  1014. bool cancelOut) const
  1015. {
  1016. std::vector<std::vector<T>> retval;
  1017. seeds.clear();
  1018. for (size_t i = 0; i < permutations.size(); i++)
  1019. {
  1020. std::vector<Scalar> currSeeds;
  1021. std::vector<T> currRow;
  1022. for (size_t j = 0; j < permutations[i].size(); j++)\
  1023. {
  1024. currSeeds.push_back(Scalar(0));
  1025. currRow.push_back(T());
  1026. }
  1027. seeds.push_back(currSeeds);
  1028. retval.push_back(currRow);
  1029. }
  1030. for (size_t i = 0; i < permutations.size(); i++)
  1031. {
  1032. size_t last = permutations[i].size() - 1;
  1033. for (size_t j = 0; j < permutations[i].size(); j++)
  1034. {
  1035. if (!cancelOut)
  1036. {
  1037. seeds[i][j].set_random();
  1038. }
  1039. else if (j != last)
  1040. {
  1041. seeds[i][j].set_random();
  1042. seeds[i][last] = seeds[i][last] - seeds[i][j];
  1043. }
  1044. retval[i][j] = oldValues[j] * permutations[j][i] + h * seeds[i][j];
  1045. }
  1046. }
  1047. return retval;
  1048. }
  1049. std::vector<size_t> PrsonaServer::sort_data(const std::vector<Twistpoint>& inputs) const
  1050. {
  1051. std::vector<size_t> retval;
  1052. // SortingType's index member allows us to replicate the "sort" across
  1053. std::vector<SortingType> sortTracker;
  1054. for (size_t i = 0; i < inputs.size(); i++)
  1055. {
  1056. SortingType curr;
  1057. curr.pseudonym = inputs[i];
  1058. curr.index = i;
  1059. sortTracker.push_back(curr);
  1060. }
  1061. std::sort(sortTracker.begin(), sortTracker.end());
  1062. for (size_t i = 0; i < inputs.size(); i++)
  1063. retval.push_back(sortTracker[i].index);
  1064. return retval;
  1065. }
  1066. bool PrsonaServer::update_data(
  1067. const std::vector<std::vector<Twistpoint>>& freshPseudonymCommits,
  1068. const std::vector<std::vector<CurveBipoint>>& serverTallyCommits,
  1069. const std::vector<std::vector<std::vector<TwistBipoint>>>& voteMatrixCommits,
  1070. const std::vector<std::vector<Twistpoint>>& userTallyMaskCommits,
  1071. const std::vector<std::vector<Twistpoint>>& userTallyMessageCommits)
  1072. {
  1073. std::vector<Twistpoint> newPseudonyms;
  1074. std::vector<CurveBipoint> newVoteTallies;
  1075. std::vector<EGCiphertext> newUserTallies;
  1076. for (size_t i = 0; i < freshPseudonymCommits.size(); i++)
  1077. {
  1078. Twistpoint pseudonymSum = freshPseudonymCommits[i][0];
  1079. CurveBipoint voteTallySum = serverTallyCommits[i][0];
  1080. Twistpoint userTallyMask, userTallyMessage;
  1081. if (!userTallyMaskCommits.empty())
  1082. {
  1083. userTallyMask = userTallyMaskCommits[i][0];
  1084. userTallyMessage = userTallyMessageCommits[i][0];
  1085. }
  1086. for (size_t j = 1; j < freshPseudonymCommits[i].size(); j++)
  1087. {
  1088. pseudonymSum = pseudonymSum + freshPseudonymCommits[i][j];
  1089. voteTallySum = voteTallySum + serverTallyCommits[i][j];
  1090. if (!userTallyMaskCommits.empty())
  1091. {
  1092. userTallyMask = userTallyMask +
  1093. userTallyMaskCommits[i][j];
  1094. userTallyMessage = userTallyMessage +
  1095. userTallyMessageCommits[i][j];
  1096. }
  1097. }
  1098. newPseudonyms.push_back(pseudonymSum);
  1099. newVoteTallies.push_back(voteTallySum);
  1100. if (!userTallyMaskCommits.empty())
  1101. {
  1102. newUserTallies.push_back(
  1103. EGCiphertext(userTallyMask, userTallyMessage));
  1104. }
  1105. }
  1106. if (!pseudonyms_sorted(newPseudonyms))
  1107. {
  1108. std::cerr << "Pseudonyms not sorted correctly." << std::endl;
  1109. return false;
  1110. }
  1111. currentPseudonyms = newPseudonyms;
  1112. previousVoteTallies = newVoteTallies;
  1113. voteMatrix = calculate_next_vote_matrix(voteMatrixCommits);
  1114. currentUserEncryptedTallies = newUserTallies;
  1115. return true;
  1116. }
  1117. bool PrsonaServer::pseudonyms_sorted(
  1118. const std::vector<Twistpoint> newPseudonyms) const
  1119. {
  1120. bool retval = true;
  1121. for (size_t i = 0; i < newPseudonyms.size() - 1; i++)
  1122. retval = retval && (newPseudonyms[i] < newPseudonyms[i + 1]);
  1123. return retval;
  1124. }
  1125. /*
  1126. * DATA MAINTENANCE
  1127. */
  1128. void PrsonaServer::export_new_user_update(
  1129. std::vector<CurveBipoint>& otherPreviousVoteTallies,
  1130. std::vector<Twistpoint>& otherCurrentPseudonyms,
  1131. std::vector<EGCiphertext>& otherCurrentUserEncryptedTallies,
  1132. std::vector<std::vector<TwistBipoint>>& otherVoteMatrix) const
  1133. {
  1134. otherPreviousVoteTallies = previousVoteTallies;
  1135. otherCurrentPseudonyms = currentPseudonyms;
  1136. otherCurrentUserEncryptedTallies = currentUserEncryptedTallies;
  1137. otherVoteMatrix = voteMatrix;
  1138. }
  1139. bool PrsonaServer::import_new_user_update(
  1140. const std::vector<Proof>& pi,
  1141. const std::vector<CurveBipoint>& otherPreviousVoteTallies,
  1142. const std::vector<Twistpoint>& otherCurrentPseudonyms,
  1143. const std::vector<EGCiphertext>& otherCurrentUserEncryptedTallies,
  1144. const std::vector<std::vector<TwistBipoint>>& otherVoteMatrix)
  1145. {
  1146. size_t newIndex = 0;
  1147. if (!currentPseudonyms.empty())
  1148. while (otherCurrentPseudonyms[newIndex] == currentPseudonyms[newIndex])
  1149. newIndex++;
  1150. Twistpoint shortTermPublicKey = otherCurrentPseudonyms[newIndex];
  1151. bool flag = verify_proof_of_added_user(
  1152. pi,
  1153. currentFreshGenerator,
  1154. shortTermPublicKey,
  1155. bgnSystem.get_public_key().get_bipoint_twistgen(),
  1156. bgnSystem.get_public_key().get_bipoint_twist_subgroup_gen(),
  1157. bgnSystem.get_public_key().get_bipoint_curvegen(),
  1158. bgnSystem.get_public_key().get_bipoint_curve_subgroup_gen(),
  1159. newIndex,
  1160. otherCurrentUserEncryptedTallies[newIndex],
  1161. otherPreviousVoteTallies[newIndex],
  1162. otherVoteMatrix);
  1163. if (!flag)
  1164. {
  1165. std::cerr << "Other server added new user invalidly, aborting." << std::endl;
  1166. return false;
  1167. }
  1168. for (size_t i = 0; i < otherCurrentPseudonyms.size(); i++)
  1169. {
  1170. if (i == newIndex)
  1171. continue;
  1172. size_t otherI = (i > newIndex ? i - 1 : i);
  1173. flag = flag && otherCurrentPseudonyms[i] ==
  1174. currentPseudonyms[otherI];
  1175. flag = flag && otherCurrentUserEncryptedTallies[i] ==
  1176. currentUserEncryptedTallies[otherI];
  1177. flag = flag && otherPreviousVoteTallies[i] ==
  1178. previousVoteTallies[otherI];
  1179. for (size_t j = 0; j < otherCurrentPseudonyms.size(); j++)
  1180. {
  1181. if (j == newIndex)
  1182. continue;
  1183. size_t otherJ = (j > newIndex ? j - 1 : j);
  1184. flag = flag && otherVoteMatrix[i][j] ==
  1185. voteMatrix[otherI][otherJ];
  1186. }
  1187. }
  1188. if (!flag)
  1189. {
  1190. std::cerr << "Other server illicitly changed other value during new user add." << std::endl;
  1191. return false;
  1192. }
  1193. previousVoteTallies = otherPreviousVoteTallies;
  1194. currentPseudonyms = otherCurrentPseudonyms;
  1195. currentUserEncryptedTallies = otherCurrentUserEncryptedTallies;
  1196. voteMatrix = otherVoteMatrix;
  1197. return true;
  1198. }
  1199. /*
  1200. * DATA SAFEKEEPING
  1201. */
  1202. /* This is what powers the "shuffle"; really, as pseudonyms get updated,
  1203. * the pseudonyms are no longer in the order prescribed by operator<().
  1204. * So, we put them (and everything else) back into that order,
  1205. * effectively shuffling them (and making lookups easier later on). */
  1206. std::vector<size_t> PrsonaServer::order_data()
  1207. {
  1208. std::vector<size_t> retval = sort_data(currentPseudonyms);
  1209. // Order all other data in the same way, for consistency
  1210. std::vector<Twistpoint> newPseudonyms;
  1211. std::vector<CurveBipoint> newVoteTallies;
  1212. std::vector<EGCiphertext> newUserEncryptedTallies;
  1213. std::vector<std::vector<TwistBipoint>> newVoteMatrix;
  1214. for (size_t i = 0; i < retval.size(); i++)
  1215. {
  1216. newPseudonyms.push_back(currentPseudonyms[retval[i]]);
  1217. newVoteTallies.push_back(previousVoteTallies[retval[i]]);
  1218. if (!currentUserEncryptedTallies.empty())
  1219. {
  1220. newUserEncryptedTallies.push_back(
  1221. currentUserEncryptedTallies[retval[i]]);
  1222. }
  1223. std::vector<TwistBipoint> currNewRow;
  1224. for (size_t j = 0; j < currentPseudonyms.size(); j++)
  1225. {
  1226. currNewRow.push_back(
  1227. voteMatrix[retval[i]][retval[j]]);
  1228. }
  1229. newVoteMatrix.push_back(currNewRow);
  1230. }
  1231. previousVoteTallies = newVoteTallies;
  1232. currentPseudonyms = newPseudonyms;
  1233. currentUserEncryptedTallies = newUserEncryptedTallies;
  1234. voteMatrix = newVoteMatrix;
  1235. return retval;
  1236. }
  1237. /*
  1238. * BINARY SEARCH
  1239. */
  1240. // Completely normal binary search
  1241. size_t PrsonaServer::binary_search(const Twistpoint& index) const
  1242. {
  1243. return PrsonaBase::binary_search(currentPseudonyms, index);
  1244. }
  1245. /*
  1246. * VALID VOTE PROOFS
  1247. */
  1248. bool PrsonaServer::verify_vote_proof(
  1249. const std::vector<Proof>& pi,
  1250. const std::vector<TwistBipoint>& oldVotes,
  1251. const std::vector<TwistBipoint>& newVotes,
  1252. const Twistpoint& shortTermPublicKey) const
  1253. {
  1254. const BGNPublicKey& pubKey = bgnSystem.get_public_key();
  1255. return PrsonaBase::verify_vote_proof(
  1256. pubKey.get_bipoint_twistgen(),
  1257. pubKey.get_bipoint_twist_subgroup_gen(),
  1258. pi,
  1259. oldVotes,
  1260. newVotes,
  1261. currentFreshGenerator,
  1262. shortTermPublicKey);
  1263. }
  1264. void PrsonaServer::print_scores(const std::vector<CurveBipoint>& scores)
  1265. {
  1266. std::cout << "[";
  1267. for (size_t i = 0; i < scores.size(); i++)
  1268. {
  1269. std::cout << bgnSystem.decrypt(scores[i])
  1270. << (i == scores.size() - 1 ? "]" : " ");
  1271. }
  1272. std::cout << std::endl;
  1273. }