server.cpp 46 KB

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