base.cpp 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881
  1. #include <iostream>
  2. #include <fstream>
  3. #include "base.hpp"
  4. extern const scalar_t bn_n;
  5. extern const twistpoint_fp2_t bn_twistgen;
  6. /* These lines need to be here so these static variables are defined,
  7. * but in C++ putting code here doesn't actually execute
  8. * (or at least, with g++, whenever it would execute is not at a useful time)
  9. * so we have an init() function to actually put the correct values in them. */
  10. Twistpoint PrsonaBase::EL_GAMAL_GENERATOR = Twistpoint();
  11. Scalar PrsonaBase::SCALAR_N = Scalar();
  12. Scalar PrsonaBase::DEFAULT_TALLY = Scalar();
  13. Scalar PrsonaBase::DEFAULT_VOTE = Scalar();
  14. bool PrsonaBase::SERVER_IS_MALICIOUS = false;
  15. bool PrsonaBase::CLIENT_IS_MALICIOUS = false;
  16. size_t PrsonaBase::MAX_ALLOWED_VOTE = 2;
  17. // Quick and dirty function to calculate ceil(log base 2) with mpz_class
  18. mpz_class log2(mpz_class x)
  19. {
  20. mpz_class retval = 0;
  21. while (x > 0)
  22. {
  23. retval++;
  24. x = x >> 1;
  25. }
  26. return retval;
  27. }
  28. mpz_class bit(mpz_class x)
  29. {
  30. return x > 0 ? 1 : 0;
  31. }
  32. /********************
  33. * PUBLIC FUNCTIONS *
  34. ********************/
  35. /*
  36. * SETUP FUNCTIONS
  37. */
  38. // Must be called once before any usage of this class
  39. void PrsonaBase::init()
  40. {
  41. EL_GAMAL_GENERATOR = Twistpoint(bn_twistgen);
  42. SCALAR_N = Scalar(bn_n);
  43. DEFAULT_TALLY = Scalar(1);
  44. DEFAULT_VOTE = Scalar(1);
  45. }
  46. // Call this (once) if using malicious-security servers
  47. void PrsonaBase::set_server_malicious()
  48. {
  49. SERVER_IS_MALICIOUS = true;
  50. }
  51. // Call this (once) if using malicious-security clients
  52. void PrsonaBase::set_client_malicious()
  53. {
  54. CLIENT_IS_MALICIOUS = true;
  55. }
  56. /*
  57. * CONST GETTERS
  58. */
  59. size_t PrsonaBase::get_max_allowed_vote()
  60. {
  61. return MAX_ALLOWED_VOTE;
  62. }
  63. Twistpoint PrsonaBase::get_blinding_generator() const
  64. {
  65. return elGamalBlindGenerator;
  66. }
  67. Twistpoint PrsonaBase::get_blinding_generator(
  68. std::vector<Proof>& pi) const
  69. {
  70. pi = elGamalBlindGeneratorProof;
  71. return elGamalBlindGenerator;
  72. }
  73. /***********************
  74. * PROTECTED FUNCTIONS *
  75. ***********************/
  76. /*
  77. * PRIVATE ELEMENT SETTER
  78. */
  79. bool PrsonaBase::set_EG_blind_generator(
  80. const std::vector<Proof>& pi,
  81. const Twistpoint& currGenerator,
  82. size_t numServers)
  83. {
  84. if (!verify_generator_proof(pi, currGenerator, numServers))
  85. {
  86. std::cerr << "Could not set EG blind generator correctly." << std::endl;
  87. return false;
  88. }
  89. elGamalBlindGeneratorProof = pi;
  90. elGamalBlindGenerator = currGenerator;
  91. return true;
  92. }
  93. /*
  94. * BINARY SEARCH
  95. */
  96. /* Completely normal binary search
  97. * There might be a standard function for this in <algorithms>?
  98. * But it returns an iterator, not a size_t, so less useful. */
  99. size_t PrsonaBase::binary_search(
  100. const std::vector<Twistpoint> list,
  101. const Twistpoint& index) const
  102. {
  103. size_t lo, hi;
  104. lo = 0;
  105. hi = list.size() - 1;
  106. while (lo < hi)
  107. {
  108. size_t mid = (lo + hi) / 2;
  109. if (list[mid] < index)
  110. lo = mid + 1;
  111. else if (index == list[mid])
  112. return mid;
  113. else if (mid == lo)
  114. return lo;
  115. else hi = mid - 1;
  116. }
  117. return lo;
  118. }
  119. /*
  120. * SCHNORR PROOFS
  121. */
  122. Proof PrsonaBase::schnorr_generation(
  123. const Twistpoint& generator,
  124. const Twistpoint& commitment,
  125. const Scalar& log) const
  126. {
  127. Proof retval;
  128. std::stringstream oracleInput;
  129. Scalar u;
  130. u.set_random();
  131. Twistpoint U = generator * u;
  132. oracleInput << generator << commitment << U;
  133. Scalar x = oracle(oracleInput.str());
  134. Scalar z = log * x + u;
  135. retval.challengeParts.push_back(x);
  136. retval.responseParts.push_back(z);
  137. return retval;
  138. }
  139. bool PrsonaBase::schnorr_verification(
  140. const Twistpoint& generator,
  141. const Twistpoint& commitment,
  142. const Scalar& x,
  143. const Scalar& z) const
  144. {
  145. Twistpoint U = generator * z - commitment * x;
  146. std::stringstream oracleInput;
  147. oracleInput << generator << commitment << U;
  148. return x == oracle(oracleInput.str());
  149. }
  150. /*
  151. * OWNERSHIP PROOFS
  152. */
  153. // Prove ownership of the short term public key
  154. Proof PrsonaBase::generate_ownership_proof(
  155. const Twistpoint& generator,
  156. const Twistpoint& commitment,
  157. const Scalar& log) const
  158. {
  159. if (!CLIENT_IS_MALICIOUS)
  160. {
  161. Proof retval;
  162. retval.hbc = "PROOF";
  163. return retval;
  164. }
  165. return schnorr_generation(generator, commitment, log);
  166. }
  167. bool PrsonaBase::verify_ownership_proof(
  168. const Proof& pi,
  169. const Twistpoint& generator,
  170. const Twistpoint& commitment) const
  171. {
  172. if (!CLIENT_IS_MALICIOUS)
  173. return pi.hbc == "PROOF";
  174. Scalar c = pi.challengeParts[0];
  175. Scalar z = pi.responseParts[0];
  176. return schnorr_verification(generator, commitment, c, z);
  177. }
  178. /*
  179. * ITERATED SCHNORR PROOFS
  180. */
  181. Proof PrsonaBase::add_to_generator_proof(
  182. const Twistpoint& currGenerator,
  183. const Scalar& seed) const
  184. {
  185. Proof retval;
  186. if (!SERVER_IS_MALICIOUS)
  187. {
  188. retval.hbc = "PROOF";
  189. return retval;
  190. }
  191. Twistpoint nextGenerator = currGenerator * seed;
  192. retval = schnorr_generation(currGenerator, nextGenerator, seed);
  193. retval.curvepointUniversals.push_back(currGenerator);
  194. return retval;
  195. }
  196. bool PrsonaBase::verify_generator_proof(
  197. const std::vector<Proof>& pi,
  198. const Twistpoint& currGenerator,
  199. size_t numServers) const
  200. {
  201. if (pi.size() != numServers || numServers == 0)
  202. return false;
  203. bool retval = true;
  204. if (!SERVER_IS_MALICIOUS)
  205. {
  206. for (size_t i = 0; i < pi.size(); i++)
  207. retval = retval && pi[i].hbc == "PROOF";
  208. return retval;
  209. }
  210. if (pi[0].curvepointUniversals[0] != EL_GAMAL_GENERATOR)
  211. return false;
  212. for (size_t i = 0; i < pi.size(); i++)
  213. {
  214. Twistpoint generator = pi[i].curvepointUniversals[0];
  215. Twistpoint commitment = (i == pi.size() - 1 ? currGenerator : pi[i + 1].curvepointUniversals[0]);
  216. Scalar c = pi[i].challengeParts[0];
  217. Scalar z = pi[i].responseParts[0];
  218. retval = retval && schnorr_verification(generator, commitment, c, z);
  219. if (!retval)
  220. std::cerr << "Error in index " << i+1 << " of " << pi.size() << std::endl;
  221. }
  222. return retval;
  223. }
  224. /*
  225. * REPUTATION PROOFS
  226. */
  227. // A pretty straightforward range proof (generation)
  228. std::vector<Proof> PrsonaBase::generate_reputation_proof(
  229. const Proof& ownershipProof,
  230. const EGCiphertext& commitment,
  231. const Scalar& currentScore,
  232. const Scalar& threshold,
  233. const Scalar& inverseKey,
  234. size_t numClients) const
  235. {
  236. std::vector<Proof> retval;
  237. // Base case
  238. if (!CLIENT_IS_MALICIOUS)
  239. {
  240. retval.push_back(Proof("PROOF"));
  241. return retval;
  242. }
  243. // Don't even try if the user asks to make an illegitimate proof
  244. if (threshold.toInt() > (numClients * MAX_ALLOWED_VOTE))
  245. return retval;
  246. // We really have two consecutive proofs in a junction.
  247. // The first is to prove that we are the stpk we claim we are
  248. retval.push_back(ownershipProof);
  249. // The value we're actually using in our proof
  250. mpz_class proofVal = (currentScore - threshold).toInt();
  251. // Top of the range in our proof determined by what scores are even possible
  252. mpz_class proofBits = log2(numClients * MAX_ALLOWED_VOTE - threshold.toInt());
  253. // Don't risk a situation that would divulge our private key
  254. if (proofBits <= 1)
  255. proofBits = 2;
  256. // This seems weird, but remember our base is A_t^r, not g^t
  257. std::vector<Scalar> masksPerBit;
  258. masksPerBit.push_back(inverseKey);
  259. for (size_t i = 1; i < proofBits; i++)
  260. {
  261. Scalar currMask;
  262. currMask.set_random();
  263. masksPerBit.push_back(currMask);
  264. masksPerBit[0] = masksPerBit[0] - (currMask * Scalar(1 << i));
  265. }
  266. // Taken from Fig. 1 in https://eprint.iacr.org/2014/764.pdf
  267. for (size_t i = 0; i < proofBits; i++)
  268. {
  269. Proof currProof;
  270. Twistpoint g, h, C, C_a, C_b;
  271. g = commitment.mask;
  272. h = elGamalBlindGenerator;
  273. mpz_class currBit = bit(proofVal & (1 << i));
  274. Scalar a, s, t, m, r;
  275. a.set_random();
  276. s.set_random();
  277. t.set_random();
  278. m = Scalar(currBit);
  279. r = masksPerBit[i];
  280. C = g * r + h * m;
  281. currProof.curvepointUniversals.push_back(C);
  282. C_a = g * s + h * a;
  283. C_b = g * t + h * a * m;
  284. std::stringstream oracleInput;
  285. oracleInput << g << h << C << C_a << C_b;
  286. Scalar x = oracle(oracleInput.str());
  287. currProof.challengeParts.push_back(x);
  288. Scalar f, z_a, z_b;
  289. f = m * x + a;
  290. z_a = r * x + s;
  291. z_b = r * (x - f) + t;
  292. currProof.responseParts.push_back(f);
  293. currProof.responseParts.push_back(z_a);
  294. currProof.responseParts.push_back(z_b);
  295. retval.push_back(currProof);
  296. }
  297. return retval;
  298. }
  299. // A pretty straightforward range proof (verification)
  300. bool PrsonaBase::verify_reputation_proof(
  301. const std::vector<Proof>& pi,
  302. const Twistpoint& generator,
  303. const Twistpoint& owner,
  304. const EGCiphertext& commitment,
  305. const Scalar& threshold) const
  306. {
  307. // Reject outright if there's no proof to check
  308. if (pi.empty())
  309. {
  310. std::cerr << "Proof was empty, aborting." << std::endl;
  311. return false;
  312. }
  313. // If the range is so big that it wraps around mod n,
  314. // there's a chance the user actually made a proof for a very low reputation
  315. if (pi.size() > 256)
  316. {
  317. std::cerr << "Proof was too big, prover could have cheated." << std::endl;
  318. return false;
  319. }
  320. if (!CLIENT_IS_MALICIOUS)
  321. return pi[0].hbc == "PROOF";
  322. Scalar ownerChallenge, ownerResponse;
  323. ownerChallenge = pi[0].challengeParts[0];
  324. ownerResponse = pi[0].responseParts[0];
  325. // User should be able to prove they are who they say they are
  326. if (!schnorr_verification(generator, owner, ownerChallenge, ownerResponse))
  327. {
  328. std::cerr << "Schnorr proof failed, aborting." << std::endl;
  329. return false;
  330. }
  331. // X is the thing we're going to be checking in on throughout
  332. // to try to get our score commitment back in the end.
  333. Twistpoint X;
  334. for (size_t i = 1; i < pi.size(); i++)
  335. {
  336. Twistpoint C, g, h;
  337. C = pi[i].curvepointUniversals[0];
  338. g = commitment.mask;
  339. h = elGamalBlindGenerator;
  340. X = X + C * Scalar(1 << (i - 1));
  341. Scalar x, f, z_a, z_b;
  342. x = pi[i].challengeParts[0];
  343. f = pi[i].responseParts[0];
  344. z_a = pi[i].responseParts[1];
  345. z_b = pi[i].responseParts[2];
  346. // Taken from Fig. 1 in https://eprint.iacr.org/2014/764.pdf
  347. Twistpoint C_a, C_b;
  348. C_a = g * z_a + h * f - C * x;
  349. C_b = g * z_b - C * (x - f);
  350. std::stringstream oracleInput;
  351. oracleInput << g << h << C << C_a << C_b;
  352. if (oracle(oracleInput.str()) != x)
  353. {
  354. std::cerr << "0 or 1 proof failed at index " << i << " of " << pi.size() - 1 << ", aborting." << std::endl;
  355. return false;
  356. }
  357. }
  358. Twistpoint scoreCommitment = commitment.encryptedMessage + elGamalBlindGenerator * -threshold;
  359. return X == scoreCommitment;
  360. }
  361. /*
  362. * VALID VOTE PROOFS
  363. */
  364. std::vector<Proof> PrsonaBase::generate_vote_proof(
  365. const Proof& ownershipProof,
  366. const TwistBipoint& g,
  367. const TwistBipoint& h,
  368. const std::vector<bool>& replaces,
  369. const std::vector<TwistBipoint>& oldEncryptedVotes,
  370. const std::vector<TwistBipoint>& newEncryptedVotes,
  371. const std::vector<Scalar>& seeds,
  372. const std::vector<Scalar>& votes) const
  373. {
  374. std::vector<Proof> retval;
  375. // Base case
  376. if (!CLIENT_IS_MALICIOUS)
  377. {
  378. retval.push_back(Proof("PROOF"));
  379. return retval;
  380. }
  381. // The first need is to prove that we are the stpk we claim we are
  382. retval.push_back(ownershipProof);
  383. // Then, we iterate over all votes for the proofs that they are correct
  384. for (size_t i = 0; i < replaces.size(); i++)
  385. {
  386. std::stringstream oracleInput;
  387. oracleInput << g << h << oldEncryptedVotes[i] << newEncryptedVotes[i];
  388. Scalar m = votes[i];
  389. Scalar r = seeds[i];
  390. /* This proof structure is documented in my notes.
  391. * It's inspired by the proof in Fig. 1 at
  392. * https://eprint.iacr.org/2014/764.pdf, but adapted so that you prove
  393. * m(m-1)(m-2) = 0 instead of m(m-1) = 0.
  394. *
  395. * The rerandomization part is just a slight variation on an
  396. * ordinary Schnorr proof, so that part's less scary. */
  397. if (replaces[i]) // CASE: Make new vote
  398. {
  399. Proof currProof;
  400. Scalar x_r, z_r, a, s, t_1, t_2;
  401. x_r.set_random();
  402. z_r.set_random();
  403. a.set_random();
  404. s.set_random();
  405. t_1.set_random();
  406. t_2.set_random();
  407. TwistBipoint U = h * z_r +
  408. oldEncryptedVotes[i] * x_r -
  409. newEncryptedVotes[i] * x_r;
  410. TwistBipoint C_a = g * a + h * s;
  411. Scalar power = ((a + a) * m * m - (a + a + a) * m);
  412. TwistBipoint C_b = g * power + h * t_1;
  413. currProof.curveBipointUniversals.push_back(C_b);
  414. TwistBipoint C_c = g * (a * a * m) + h * t_2;
  415. oracleInput << U << C_a << C_b << C_c;
  416. Scalar x = oracle(oracleInput.str());
  417. Scalar x_n = x - x_r;
  418. currProof.challengeParts.push_back(x_r);
  419. currProof.challengeParts.push_back(x_n);
  420. Scalar f = m * x_n + a;
  421. Scalar z_na = r * x_n + s;
  422. Scalar z_nb = r * (f - x_n) * (x_n + x_n - f) + t_1 * x_n + t_2;
  423. currProof.responseParts.push_back(z_r);
  424. currProof.responseParts.push_back(f);
  425. currProof.responseParts.push_back(z_na);
  426. currProof.responseParts.push_back(z_nb);
  427. retval.push_back(currProof);
  428. }
  429. else // CASE: Rerandomize existing vote
  430. {
  431. Proof currProof;
  432. Scalar u, commitmentLambda_1, commitmentLambda_2, x_n, z_na, z_nb, f;
  433. u.set_random();
  434. commitmentLambda_1.set_random();
  435. commitmentLambda_2.set_random();
  436. x_n.set_random();
  437. z_na.set_random();
  438. z_nb.set_random();
  439. f.set_random();
  440. TwistBipoint U = h * u;
  441. TwistBipoint C_a = g * f +
  442. h * z_na -
  443. newEncryptedVotes[i] * x_n;
  444. TwistBipoint C_b = g * commitmentLambda_1 + h * commitmentLambda_2;
  445. currProof.curveBipointUniversals.push_back(C_b);
  446. TwistBipoint C_c = h * z_nb -
  447. newEncryptedVotes[i] * ((f - x_n) * (x_n + x_n - f)) -
  448. C_b * x_n;
  449. oracleInput << U << C_a << C_b << C_c;
  450. Scalar x = oracle(oracleInput.str());
  451. Scalar x_r = x - x_n;
  452. currProof.challengeParts.push_back(x_r);
  453. currProof.challengeParts.push_back(x_n);
  454. Scalar z_r = r * x_r + u;
  455. currProof.responseParts.push_back(z_r);
  456. currProof.responseParts.push_back(f);
  457. currProof.responseParts.push_back(z_na);
  458. currProof.responseParts.push_back(z_nb);
  459. retval.push_back(currProof);
  460. }
  461. }
  462. return retval;
  463. }
  464. bool PrsonaBase::verify_vote_proof(
  465. const TwistBipoint& g,
  466. const TwistBipoint& h,
  467. const std::vector<Proof>& pi,
  468. const std::vector<TwistBipoint>& oldEncryptedVotes,
  469. const std::vector<TwistBipoint>& newEncryptedVotes,
  470. const Twistpoint& freshGenerator,
  471. const Twistpoint& owner) const
  472. {
  473. // Reject outright if there's no proof to check
  474. if (pi.empty())
  475. {
  476. std::cerr << "Proof was empty, aborting." << std::endl;
  477. return false;
  478. }
  479. // Base case
  480. if (!CLIENT_IS_MALICIOUS)
  481. return pi[0].hbc == "PROOF";
  482. // User should be able to prove they are who they say they are
  483. if (!verify_ownership_proof(pi[0], freshGenerator, owner))
  484. {
  485. std::cerr << "Schnorr proof failed, aborting." << std::endl;
  486. return false;
  487. }
  488. /* This proof structure is documented in my notes.
  489. * It's inspired by the proof in Fig. 1 at
  490. * https://eprint.iacr.org/2014/764.pdf, but adapted so that you prove
  491. * m(m-1)(m-2) = 0 instead of m(m-1) = 0.
  492. *
  493. * The rerandomization part is just a slight variation on an
  494. * ordinary Schnorr proof, so that part's less scary. */
  495. for (size_t i = 1; i < pi.size(); i++)
  496. {
  497. size_t voteIndex = i - 1;
  498. TwistBipoint C_b;
  499. C_b = pi[i].curveBipointUniversals[0];
  500. Scalar x_r, x_n, z_r, f, z_na, z_nb;
  501. x_r = pi[i].challengeParts[0];
  502. x_n = pi[i].challengeParts[1];
  503. z_r = pi[i].responseParts[0];
  504. f = pi[i].responseParts[1];
  505. z_na = pi[i].responseParts[2];
  506. z_nb = pi[i].responseParts[3];
  507. TwistBipoint U, C_a, C_c;
  508. U = h * z_r +
  509. oldEncryptedVotes[voteIndex] * x_r -
  510. newEncryptedVotes[voteIndex] * x_r;
  511. C_a = g * f + h * z_na - newEncryptedVotes[voteIndex] * x_n;
  512. C_c = h * z_nb -
  513. newEncryptedVotes[voteIndex] * ((f - x_n) * (x_n + x_n - f)) -
  514. C_b * x_n;
  515. std::stringstream oracleInput;
  516. oracleInput << g << h << oldEncryptedVotes[voteIndex] << newEncryptedVotes[voteIndex] << U << C_a << C_b << C_c;
  517. if (oracle(oracleInput.str()) != x_r + x_n)
  518. return false;
  519. }
  520. return true;
  521. }
  522. /*
  523. * NEW USER PROOFS
  524. */
  525. std::vector<Proof> PrsonaBase::generate_proof_of_added_user(
  526. const Scalar& twistBipointSeed,
  527. const Scalar& EGCiphertextSeed,
  528. const std::vector<Scalar>& curveBipointSelfSeeds,
  529. const std::vector<Scalar>& curveBipointOtherSeeds) const
  530. {
  531. std::vector<Proof> retval;
  532. if (!SERVER_IS_MALICIOUS)
  533. {
  534. retval.push_back(Proof("PROOF"));
  535. return retval;
  536. }
  537. Proof currProof;
  538. currProof.responseParts.push_back(twistBipointSeed);
  539. retval.push_back(currProof);
  540. currProof.responseParts.clear();
  541. currProof.responseParts.push_back(EGCiphertextSeed);
  542. retval.push_back(currProof);
  543. currProof.responseParts.clear();
  544. for (size_t i = 0; i < curveBipointSelfSeeds.size(); i++)
  545. currProof.responseParts.push_back(curveBipointSelfSeeds[i]);
  546. retval.push_back(currProof);
  547. currProof.responseParts.clear();
  548. for (size_t i = 0; i < curveBipointOtherSeeds.size(); i++)
  549. currProof.responseParts.push_back(curveBipointOtherSeeds[i]);
  550. retval.push_back(currProof);
  551. return retval;
  552. }
  553. bool PrsonaBase::verify_proof_of_added_user(
  554. const std::vector<Proof>& pi,
  555. const Twistpoint& currentFreshGenerator,
  556. const Twistpoint& shortTermPublicKey,
  557. const TwistBipoint& curveG,
  558. const TwistBipoint& curveH,
  559. const CurveBipoint& twistG,
  560. const CurveBipoint& twistH,
  561. size_t selfIndex,
  562. const EGCiphertext& userEncryptedScore,
  563. const CurveBipoint& serverEncryptedScore,
  564. const std::vector<std::vector<TwistBipoint>> encryptedVoteMatrix) const
  565. {
  566. if (pi.empty())
  567. {
  568. std::cerr << "Proof empty." << std::endl;
  569. return false;
  570. }
  571. if (!SERVER_IS_MALICIOUS)
  572. return pi[0].hbc == "PROOF";
  573. Scalar currSeed = pi[0].responseParts[0];
  574. if (serverEncryptedScore !=
  575. twistG * DEFAULT_TALLY + twistH * currSeed)
  576. {
  577. std::cerr << "Issue in server encrypted score." << std::endl;
  578. return false;
  579. }
  580. currSeed = pi[1].responseParts[0];
  581. if (userEncryptedScore.mask != shortTermPublicKey * currSeed)
  582. {
  583. std::cerr << "Issue in user encrypted score: mask." << std::endl;
  584. return false;
  585. }
  586. if (userEncryptedScore.encryptedMessage !=
  587. currentFreshGenerator * currSeed + elGamalBlindGenerator * DEFAULT_TALLY)
  588. {
  589. std::cerr << "Issue in user encrypted score: value." << std::endl;
  590. return false;
  591. }
  592. for (size_t i = 0; i < pi[2].responseParts.size(); i++)
  593. {
  594. TwistBipoint currVote = encryptedVoteMatrix[selfIndex][i];
  595. currSeed = pi[2].responseParts[i];
  596. if (i == selfIndex)
  597. {
  598. if (currVote !=
  599. curveG * Scalar(MAX_ALLOWED_VOTE) + curveH * currSeed)
  600. {
  601. std::cerr << "Issue in self vote." << std::endl;
  602. return false;
  603. }
  604. }
  605. else
  606. {
  607. if (currVote !=
  608. curveG * DEFAULT_VOTE + curveH * currSeed)
  609. {
  610. std::cerr << "Issue in vote by verifier for user " << i + 1 << " of " << pi[2].responseParts.size() << "." << std::endl;
  611. return false;
  612. }
  613. }
  614. }
  615. for (size_t i = 0; i < pi[3].responseParts.size(); i++)
  616. {
  617. TwistBipoint currVote = encryptedVoteMatrix[i][selfIndex];
  618. currSeed = pi[3].responseParts[i];
  619. if (i != selfIndex)
  620. {
  621. if (currVote !=
  622. curveG * DEFAULT_VOTE + curveH * currSeed)
  623. {
  624. std::cerr << "Issue in vote for verifier by user " << i + 1 << " of " << pi[3].responseParts.size() << "." << std::endl;
  625. return false;
  626. }
  627. }
  628. }
  629. return true;
  630. }
  631. /*
  632. * EPOCH PROOFS
  633. */
  634. std::vector<Proof> PrsonaBase::generate_valid_permutation_proof(
  635. const std::vector<std::vector<Scalar>>& permutations,
  636. const std::vector<std::vector<Scalar>>& seeds,
  637. const std::vector<std::vector<Twistpoint>>& commits) const
  638. {
  639. std::vector<Proof> retval;
  640. if (!SERVER_IS_MALICIOUS)
  641. {
  642. retval.push_back(Proof("PROOF"));
  643. return retval;
  644. }
  645. Twistpoint g, h;
  646. g = EL_GAMAL_GENERATOR;
  647. h = elGamalBlindGenerator;
  648. std::stringstream oracleInput;
  649. oracleInput << g << h;
  650. retval.push_back(Proof());
  651. std::vector<std::vector<Scalar>> a, s, t;
  652. for (size_t i = 0; i < commits.size(); i++)
  653. {
  654. std::vector<Scalar> currA, currS, currT;
  655. for (size_t j = 0; j < commits[i].size(); j++)
  656. {
  657. oracleInput << commits[i][j];
  658. currA.push_back(Scalar());
  659. currS.push_back(Scalar());
  660. currT.push_back(Scalar());
  661. retval.push_back(Proof());
  662. }
  663. a.push_back(currA);
  664. s.push_back(currS);
  665. t.push_back(currT);
  666. }
  667. // Taken from Fig. 1 in https://eprint.iacr.org/2014/764.pdf
  668. for (size_t i = 0; i < permutations.size(); i++)
  669. {
  670. for (size_t j = 0; j < permutations[i].size(); j++)
  671. {
  672. Twistpoint C, C_a, C_b;
  673. Scalar p, r;
  674. a[i][j].set_random();
  675. s[i][j].set_random();
  676. t[i][j].set_random();
  677. p = permutations[i][j];
  678. r = seeds[i][j];
  679. C = commits[i][j];
  680. C_a = g * a[i][j] + h * s[i][j];
  681. C_b = g * a[i][j] * p + h * t[i][j];
  682. oracleInput << C << C_a << C_b;
  683. }
  684. }
  685. Scalar x = oracle(oracleInput.str());
  686. retval[0].challengeParts.push_back(x);
  687. for (size_t i = 0; i < permutations.size(); i++)
  688. {
  689. for (size_t j = 0; j < permutations[i].size(); j++)
  690. {
  691. size_t piIndex = i * permutations.size() + j + 1;
  692. Scalar f, z_a, z_b, p, r;
  693. p = permutations[i][j];
  694. r = seeds[i][j];
  695. f = p * x + a[i][j];
  696. z_a = r * x + s[i][j];
  697. z_b = r * (x - f) + t[i][j];
  698. retval[piIndex].responseParts.push_back(f);
  699. retval[piIndex].responseParts.push_back(z_a);
  700. retval[piIndex].responseParts.push_back(z_b);
  701. }
  702. }
  703. return retval;
  704. }
  705. bool PrsonaBase::verify_valid_permutation_proof(
  706. const std::vector<Proof>& pi,
  707. const std::vector<std::vector<Twistpoint>>& commits) const
  708. {
  709. // Reject outright if there's no proof to check
  710. if (pi.empty())
  711. {
  712. std::cerr << "Proof was empty, aborting." << std::endl;
  713. return false;
  714. }
  715. if (!SERVER_IS_MALICIOUS)
  716. return pi[0].hbc == "PROOF";
  717. Twistpoint g, h;
  718. g = EL_GAMAL_GENERATOR;
  719. h = elGamalBlindGenerator;
  720. std::stringstream oracleInput;
  721. oracleInput << g << h;
  722. for (size_t i = 0; i < commits.size(); i++)
  723. for (size_t j = 0; j < commits[i].size(); j++)
  724. oracleInput << commits[i][j];
  725. Scalar x = pi[0].challengeParts[0];
  726. for (size_t i = 0; i < commits.size(); i++)
  727. {
  728. for (size_t j = 0; j < commits[i].size(); j++)
  729. {
  730. size_t piIndex = i * commits.size() + j + 1;
  731. Twistpoint C, C_a, C_b;
  732. C = commits[i][j];
  733. Scalar f, z_a, z_b;
  734. f = pi[piIndex].responseParts[0];
  735. z_a = pi[piIndex].responseParts[1];
  736. z_b = pi[piIndex].responseParts[2];
  737. // Taken from Fig. 1 in https://eprint.iacr.org/2014/764.pdf
  738. C_a = g * f + h * z_a - C * x;
  739. C_b = h * z_b - C * (x - f);
  740. oracleInput << C << C_a << C_b;
  741. }
  742. }
  743. if (oracle(oracleInput.str()) != x)
  744. {
  745. std::cerr << "0 or 1 proof failed, aborting." << std::endl;
  746. return false;
  747. }
  748. for (size_t i = 0; i < commits.size(); i++)
  749. {
  750. Twistpoint sum = commits[i][0];
  751. for (size_t j = 1; j < commits[i].size(); j++)
  752. sum = sum + commits[i][j];
  753. if (sum != g)
  754. {
  755. std::cerr << "Commits did not sum to g, aborting." << std::endl;
  756. return false;
  757. }
  758. }
  759. return true;
  760. }
  761. std::vector<Proof> PrsonaBase::generate_proof_of_reordering_plus_power(
  762. const std::vector<std::vector<Scalar>>& permutations,
  763. const Scalar& power,
  764. const std::vector<std::vector<Scalar>>& permutationSeeds,
  765. const std::vector<std::vector<Scalar>>& productSeeds,
  766. const std::vector<Twistpoint>& oldValues,
  767. const std::vector<std::vector<Twistpoint>>& permutationCommits,
  768. const std::vector<std::vector<Twistpoint>>& productCommits,
  769. const std::vector<std::vector<Twistpoint>>& seedCommits) const
  770. {
  771. std::vector<Proof> retval;
  772. if (!SERVER_IS_MALICIOUS)
  773. {
  774. retval.push_back(Proof("PROOF"));
  775. return retval;
  776. }
  777. Proof first;
  778. retval.push_back(first);
  779. Twistpoint g = EL_GAMAL_GENERATOR;
  780. Twistpoint h = elGamalBlindGenerator;
  781. std::stringstream oracleInput;
  782. oracleInput << g << h;
  783. for (size_t i = 0; i < oldValues.size(); i++)
  784. oracleInput << oldValues[i];
  785. for (size_t i = 0; i < permutationCommits.size(); i++)
  786. for (size_t j = 0; j < permutationCommits[i].size(); j++)
  787. oracleInput << permutationCommits[i][j];
  788. for (size_t i = 0; i < productCommits.size(); i++)
  789. for (size_t j = 0; j < productCommits[i].size(); j++)
  790. oracleInput << productCommits[i][j];
  791. for (size_t i = 0; i < seedCommits.size(); i++)
  792. for (size_t j = 0; j < seedCommits[i].size(); j++)
  793. oracleInput << seedCommits[i][j];
  794. Scalar b1;
  795. b1.set_random();
  796. std::vector<std::vector<Scalar>> b2;
  797. std::vector<std::vector<Scalar>> t1;
  798. std::vector<std::vector<Scalar>> t2;
  799. for (size_t i = 0; i < permutationCommits.size(); i++)
  800. {
  801. std::vector<Scalar> currb2Row;
  802. std::vector<Scalar> currt1Row;
  803. std::vector<Scalar> currt2Row;
  804. for (size_t j = 0; j < permutationCommits[i].size(); j++)
  805. {
  806. Proof currProof;
  807. Scalar currb2;
  808. Scalar currt1;
  809. Scalar currt2;
  810. Twistpoint U1, U2, U3, U4;
  811. currb2.set_random();
  812. currt1.set_random();
  813. currt2.set_random();
  814. U1 = g * currb2 + h * currt1;
  815. U2 = oldValues[j] *
  816. (b1 * permutations[j][i] + currb2 * power);
  817. U3 = oldValues[j] * b1 * currb2 + h * currt2;
  818. U4 = g * currt2;
  819. currProof.curvepointUniversals.push_back(U2);
  820. oracleInput << U1 << U2 << U3 << U4;
  821. currb2Row.push_back(currb2);
  822. currt1Row.push_back(currt1);
  823. currt2Row.push_back(currt2);
  824. retval.push_back(currProof);
  825. }
  826. b2.push_back(currb2Row);
  827. t1.push_back(currt1Row);
  828. t2.push_back(currt2Row);
  829. }
  830. Scalar x = oracle(oracleInput.str());
  831. retval[0].challengeParts.push_back(x);
  832. Scalar f1 = power * x + b1;
  833. retval[0].responseParts.push_back(f1);
  834. for (size_t i = 0; i < permutationCommits.size(); i++)
  835. {
  836. for (size_t j = 0; j < permutationCommits[i].size(); j++)
  837. {
  838. size_t piIndex = i * permutationCommits.size() + j + 1;
  839. Scalar f2 = permutations[j][i] * x + b2[i][j];
  840. Scalar z1 = permutationSeeds[j][i] * x + t1[i][j];
  841. Scalar z2 = productSeeds[i][j] * x * x + t2[i][j];
  842. retval[piIndex].responseParts.push_back(f2);
  843. retval[piIndex].responseParts.push_back(z1);
  844. retval[piIndex].responseParts.push_back(z2);
  845. }
  846. }
  847. return retval;
  848. }
  849. bool PrsonaBase::verify_proof_of_reordering_plus_power(
  850. const std::vector<Proof>& pi,
  851. const std::vector<Twistpoint>& oldValues,
  852. const std::vector<std::vector<Twistpoint>>& permutationCommits,
  853. const std::vector<std::vector<Twistpoint>>& productCommits,
  854. const std::vector<std::vector<Twistpoint>>& seedCommits) const
  855. {
  856. if (pi.empty())
  857. return false;
  858. if (!SERVER_IS_MALICIOUS)
  859. return pi[0].hbc == "PROOF";
  860. Twistpoint g = EL_GAMAL_GENERATOR;
  861. Twistpoint h = elGamalBlindGenerator;
  862. std::stringstream oracleInput;
  863. oracleInput << g << h;
  864. for (size_t i = 0; i < oldValues.size(); i++)
  865. oracleInput << oldValues[i];
  866. for (size_t i = 0; i < permutationCommits.size(); i++)
  867. for (size_t j = 0; j < permutationCommits[i].size(); j++)
  868. oracleInput << permutationCommits[i][j];
  869. for (size_t i = 0; i < productCommits.size(); i++)
  870. for (size_t j = 0; j < productCommits[i].size(); j++)
  871. oracleInput << productCommits[i][j];
  872. for (size_t i = 0; i < seedCommits.size(); i++)
  873. for (size_t j = 0; j < seedCommits[i].size(); j++)
  874. oracleInput << seedCommits[i][j];
  875. Scalar x = pi[0].challengeParts[0];
  876. Scalar f1 = pi[0].responseParts[0];
  877. for (size_t i = 0; i < permutationCommits.size(); i++)
  878. {
  879. for (size_t j = 0; j < permutationCommits[i].size(); j++)
  880. {
  881. size_t piIndex = i * permutationCommits.size() + j + 1;
  882. Twistpoint U1, U2, U3, U4;
  883. U2 = pi[piIndex].curvepointUniversals[0];
  884. Scalar f2 = pi[piIndex].responseParts[0];
  885. Scalar z1 = pi[piIndex].responseParts[1];
  886. Scalar z2 = pi[piIndex].responseParts[2];
  887. U1 = g * f2 + h * z1 - permutationCommits[j][i] * x;
  888. U3 = oldValues[j] * f1 * f2 +
  889. h * z2 -
  890. productCommits[i][j] * x * x -
  891. U2 * x;
  892. U4 = g * z2 - seedCommits[i][j] * x * x;
  893. oracleInput << U1 << U2 << U3 << U4;
  894. }
  895. }
  896. if (x != oracle(oracleInput.str()))
  897. {
  898. std::cerr << "Reordered + power things not generated by permutation matrix." << std::endl;
  899. return false;
  900. }
  901. for (size_t i = 0; i < seedCommits.size(); i++)
  902. {
  903. Twistpoint sum = seedCommits[i][0];
  904. for (size_t j = 1; j < seedCommits[i].size(); j++)
  905. sum = sum + seedCommits[i][j];
  906. if (sum != Twistpoint())
  907. {
  908. std::cerr << "seed commits did not sum to 0, aborting." << std::endl;
  909. return false;
  910. }
  911. }
  912. return true;
  913. }
  914. std::vector<Proof> PrsonaBase::generate_user_tally_proofs(
  915. const std::vector<std::vector<Scalar>>& permutations,
  916. const Scalar& power,
  917. const Twistpoint& nextGenerator,
  918. const std::vector<std::vector<Scalar>>& permutationSeeds,
  919. const std::vector<std::vector<Scalar>>& userTallySeeds,
  920. const std::vector<Twistpoint>& currPseudonyms,
  921. const std::vector<Twistpoint>& userTallyMasks,
  922. const std::vector<Twistpoint>& userTallyMessages,
  923. const std::vector<std::vector<Twistpoint>>& permutationCommits,
  924. const std::vector<std::vector<Twistpoint>>& userTallyMaskCommits,
  925. const std::vector<std::vector<Twistpoint>>& userTallyMessageCommits,
  926. const std::vector<std::vector<Twistpoint>>& userTallySeedCommits) const
  927. {
  928. std::vector<Proof> retval;
  929. if (!SERVER_IS_MALICIOUS)
  930. {
  931. retval.push_back(Proof("PROOF"));
  932. return retval;
  933. }
  934. Proof first;
  935. retval.push_back(first);
  936. Twistpoint g = EL_GAMAL_GENERATOR;
  937. Twistpoint h = elGamalBlindGenerator;
  938. std::stringstream oracleInput;
  939. oracleInput << g << h << nextGenerator;
  940. for (size_t i = 0; i < currPseudonyms.size(); i++)
  941. oracleInput << currPseudonyms[i];
  942. for (size_t i = 0; i < userTallyMasks.size(); i++)
  943. oracleInput << userTallyMasks[i];
  944. for (size_t i = 0; i < userTallyMessages.size(); i++)
  945. oracleInput << userTallyMessages[i];
  946. for (size_t i = 0; i < permutationCommits.size(); i++)
  947. for (size_t j = 0; j < permutationCommits[i].size(); j++)
  948. oracleInput << permutationCommits[i][j];
  949. for (size_t i = 0; i < userTallyMaskCommits.size(); i++)
  950. for (size_t j = 0; j < userTallyMaskCommits[i].size(); j++)
  951. oracleInput << userTallyMaskCommits[i][j];
  952. for (size_t i = 0; i < userTallyMessageCommits.size(); i++)
  953. for (size_t j = 0; j < userTallyMessageCommits[i].size(); j++)
  954. oracleInput << userTallyMessageCommits[i][j];
  955. for (size_t i = 0; i < userTallySeedCommits.size(); i++)
  956. for (size_t j = 0; j < userTallySeedCommits[i].size(); j++)
  957. oracleInput << userTallySeedCommits[i][j];
  958. Scalar b1;
  959. b1.set_random();
  960. std::vector<std::vector<Scalar>> b2;
  961. std::vector<std::vector<Scalar>> t1;
  962. std::vector<std::vector<Scalar>> t2;
  963. for (size_t i = 0; i < permutationCommits.size(); i++)
  964. {
  965. std::vector<Scalar> currb2Row;
  966. std::vector<Scalar> currt1Row;
  967. std::vector<Scalar> currt2Row;
  968. for (size_t j = 0; j < permutationCommits[i].size(); j++)
  969. {
  970. Proof currProof;
  971. Scalar currb2;
  972. Scalar currt1;
  973. Scalar currt2;
  974. Twistpoint U1, U2, U3, U4, U5, U6, U7;
  975. currb2.set_random();
  976. currt1.set_random();
  977. currt2.set_random();
  978. U1 = g * currb2 + h * currt1;
  979. U2 = userTallyMasks[j] * (b1 * permutations[j][i] + currb2 * power) +
  980. currPseudonyms[j] * (permutations[j][i] * b1 * userTallySeeds[i][j] + power * currb2 * userTallySeeds[i][j] + permutations[j][i] * power * currt2) +
  981. h * currt2;
  982. U3 = userTallyMasks[j] * (b1 * currb2) +
  983. currPseudonyms[j] * (b1 * currb2 * userTallySeeds[i][j] + permutations[j][i] * b1 * currt2 + power * currb2 * currt2);
  984. U4 = currPseudonyms[j] * (b1 * currb2 * currt2);
  985. U5 = userTallyMessages[j] * currb2 +
  986. nextGenerator * (permutations[j][i] * currt2 + userTallySeeds[i][j] * currb2) +
  987. h * currt2;
  988. U6 = nextGenerator * (currb2 * currt2);
  989. U7 = g * currt2;
  990. currProof.curvepointUniversals.push_back(U2);
  991. currProof.curvepointUniversals.push_back(U3);
  992. currProof.curvepointUniversals.push_back(U5);
  993. oracleInput << U1 << U2 << U3 << U4 << U5 << U6 << U7;
  994. currb2Row.push_back(currb2);
  995. currt1Row.push_back(currt1);
  996. currt2Row.push_back(currt2);
  997. retval.push_back(currProof);
  998. }
  999. b2.push_back(currb2Row);
  1000. t1.push_back(currt1Row);
  1001. t2.push_back(currt2Row);
  1002. }
  1003. Scalar x = oracle(oracleInput.str());
  1004. retval[0].challengeParts.push_back(x);
  1005. Scalar f1 = power * x + b1;
  1006. retval[0].responseParts.push_back(f1);
  1007. for (size_t i = 0; i < permutationCommits.size(); i++)
  1008. {
  1009. for (size_t j = 0; j < permutationCommits[i].size(); j++)
  1010. {
  1011. size_t piIndex = i * permutationCommits.size() + j + 1;
  1012. Scalar f2 = permutations[j][i] * x + b2[i][j];
  1013. Scalar z1 = permutationSeeds[j][i] * x + t1[i][j];
  1014. Scalar z2 = userTallySeeds[i][j] * x + t2[i][j];
  1015. retval[piIndex].responseParts.push_back(f2);
  1016. retval[piIndex].responseParts.push_back(z1);
  1017. retval[piIndex].responseParts.push_back(z2);
  1018. }
  1019. }
  1020. return retval;
  1021. }
  1022. bool PrsonaBase::verify_user_tally_proofs(
  1023. const std::vector<Proof>& pi,
  1024. const Twistpoint& nextGenerator,
  1025. const std::vector<Twistpoint>& currPseudonyms,
  1026. const std::vector<Twistpoint>& userTallyMasks,
  1027. const std::vector<Twistpoint>& userTallyMessages,
  1028. const std::vector<std::vector<Twistpoint>>& permutationCommits,
  1029. const std::vector<std::vector<Twistpoint>>& userTallyMaskCommits,
  1030. const std::vector<std::vector<Twistpoint>>& userTallyMessageCommits,
  1031. const std::vector<std::vector<Twistpoint>>& userTallySeedCommits) const
  1032. {
  1033. if (pi.empty())
  1034. return false;
  1035. if (!SERVER_IS_MALICIOUS)
  1036. return pi[0].hbc == "PROOF";
  1037. Twistpoint g = EL_GAMAL_GENERATOR;
  1038. Twistpoint h = elGamalBlindGenerator;
  1039. std::stringstream oracleInput;
  1040. oracleInput << g << h << nextGenerator;
  1041. for (size_t i = 0; i < currPseudonyms.size(); i++)
  1042. oracleInput << currPseudonyms[i];
  1043. for (size_t i = 0; i < userTallyMasks.size(); i++)
  1044. oracleInput << userTallyMasks[i];
  1045. for (size_t i = 0; i < userTallyMessages.size(); i++)
  1046. oracleInput << userTallyMessages[i];
  1047. for (size_t i = 0; i < permutationCommits.size(); i++)
  1048. for (size_t j = 0; j < permutationCommits[i].size(); j++)
  1049. oracleInput << permutationCommits[i][j];
  1050. for (size_t i = 0; i < userTallyMaskCommits.size(); i++)
  1051. for (size_t j = 0; j < userTallyMaskCommits[i].size(); j++)
  1052. oracleInput << userTallyMaskCommits[i][j];
  1053. for (size_t i = 0; i < userTallyMessageCommits.size(); i++)
  1054. for (size_t j = 0; j < userTallyMessageCommits[i].size(); j++)
  1055. oracleInput << userTallyMessageCommits[i][j];
  1056. for (size_t i = 0; i < userTallySeedCommits.size(); i++)
  1057. for (size_t j = 0; j < userTallySeedCommits[i].size(); j++)
  1058. oracleInput << userTallySeedCommits[i][j];
  1059. Scalar x = pi[0].challengeParts[0];
  1060. Scalar f1 = pi[0].responseParts[0];
  1061. for (size_t i = 0; i < permutationCommits.size(); i++)
  1062. {
  1063. for (size_t j = 0; j < permutationCommits[i].size(); j++)
  1064. {
  1065. size_t piIndex = i * permutationCommits.size() + j + 1;
  1066. Twistpoint U1, U2, U3, U4, U5, U6, U7;
  1067. U2 = pi[piIndex].curvepointUniversals[0];
  1068. U3 = pi[piIndex].curvepointUniversals[1];
  1069. U5 = pi[piIndex].curvepointUniversals[2];
  1070. Scalar f2 = pi[piIndex].responseParts[0];
  1071. Scalar z1 = pi[piIndex].responseParts[1];
  1072. Scalar z2 = pi[piIndex].responseParts[2];
  1073. U1 = g * f2 + h * z1 - permutationCommits[j][i] * x;
  1074. U4 = userTallyMasks[j] * (f1 * f2 * x) +
  1075. currPseudonyms[j] * (f1 * f2 * z2) +
  1076. h * (z2 * x * x) -
  1077. userTallyMaskCommits[i][j] * (x * x * x) -
  1078. U2 * (x * x) -
  1079. U3 * x;
  1080. U6 = userTallyMessages[j] * (f2 * x) +
  1081. nextGenerator * (f2 * z2) +
  1082. h * (z2 * x) -
  1083. userTallyMessageCommits[i][j] * (x * x) -
  1084. U5 * x;
  1085. U7 = g * z2 - userTallySeedCommits[i][j] * x;
  1086. oracleInput << U1 << U2 << U3 << U4 << U5 << U6 << U7;
  1087. }
  1088. }
  1089. if (x != oracle(oracleInput.str()))
  1090. {
  1091. std::cerr << "User tallies not generated by permutation matrix." << std::endl;
  1092. return false;
  1093. }
  1094. for (size_t i = 0; i < userTallySeedCommits.size(); i++)
  1095. {
  1096. Twistpoint sum = userTallySeedCommits[i][0];
  1097. for (size_t j = 1; j < userTallySeedCommits[i].size(); j++)
  1098. sum = sum + userTallySeedCommits[i][j];
  1099. if (sum != Twistpoint())
  1100. {
  1101. std::cerr << "seed commits did not sum to 0, aborting." << std::endl;
  1102. return false;
  1103. }
  1104. }
  1105. return true;
  1106. }
  1107. template <typename T>
  1108. std::vector<Proof> PrsonaBase::generate_proof_of_reordering(
  1109. const std::vector<std::vector<Scalar>>& permutations,
  1110. const std::vector<std::vector<Scalar>>& permutationSeeds,
  1111. const std::vector<std::vector<Scalar>>& productSeeds,
  1112. const std::vector<T>& oldValues,
  1113. const std::vector<std::vector<Twistpoint>>& permutationCommits,
  1114. const std::vector<std::vector<T>>& productCommits,
  1115. const T& otherG,
  1116. const T& otherH) const
  1117. {
  1118. std::vector<Proof> retval;
  1119. if (!SERVER_IS_MALICIOUS)
  1120. {
  1121. retval.push_back(Proof("PROOF"));
  1122. return retval;
  1123. }
  1124. Proof first;
  1125. retval.push_back(first);
  1126. Twistpoint g = EL_GAMAL_GENERATOR;
  1127. Twistpoint h = elGamalBlindGenerator;
  1128. std::stringstream oracleInput;
  1129. oracleInput << g << h << otherG << otherH;
  1130. for (size_t i = 0; i < oldValues.size(); i++)
  1131. oracleInput << oldValues[i];
  1132. for (size_t i = 0; i < permutationCommits.size(); i++)
  1133. for (size_t j = 0; j < permutationCommits[i].size(); j++)
  1134. oracleInput << permutationCommits[i][j];
  1135. for (size_t i = 0; i < productCommits.size(); i++)
  1136. for (size_t j = 0; j < productCommits[i].size(); j++)
  1137. oracleInput << productCommits[i][j];
  1138. std::vector<std::vector<Scalar>> a;
  1139. std::vector<std::vector<Scalar>> t1;
  1140. std::vector<std::vector<Scalar>> t2;
  1141. for (size_t i = 0; i < permutationCommits.size(); i++)
  1142. {
  1143. std::vector<Scalar> curraRow;
  1144. std::vector<Scalar> currt1Row;
  1145. std::vector<Scalar> currt2Row;
  1146. for (size_t j = 0; j < permutationCommits[i].size(); j++)
  1147. {
  1148. Proof currProof;
  1149. Scalar curra;
  1150. Scalar currt1;
  1151. Scalar currt2;
  1152. Twistpoint U1;
  1153. T U2;
  1154. curra.set_random();
  1155. currt1.set_random();
  1156. currt2.set_random();
  1157. U1 = g * curra + h * currt1;
  1158. U2 = oldValues[j] * curra + otherH * currt2;
  1159. oracleInput << U1 << U2;
  1160. std::stringstream out1, out2;
  1161. out1 << U1;
  1162. out2 << U2;
  1163. curraRow.push_back(curra);
  1164. currt1Row.push_back(currt1);
  1165. currt2Row.push_back(currt2);
  1166. retval.push_back(currProof);
  1167. }
  1168. a.push_back(curraRow);
  1169. t1.push_back(currt1Row);
  1170. t2.push_back(currt2Row);
  1171. }
  1172. Scalar x = oracle(oracleInput.str());
  1173. retval[0].challengeParts.push_back(x);
  1174. for (size_t i = 0; i < permutationCommits.size(); i++)
  1175. {
  1176. for (size_t j = 0; j < permutationCommits[i].size(); j++)
  1177. {
  1178. size_t piIndex = i * permutationCommits.size() + j + 1;
  1179. Scalar f = permutations[j][i] * x + a[i][j];
  1180. Scalar z1 = permutationSeeds[j][i] * x + t1[i][j];
  1181. Scalar z2 = productSeeds[i][j] * x + t2[i][j];
  1182. retval[piIndex].responseParts.push_back(f);
  1183. retval[piIndex].responseParts.push_back(z1);
  1184. retval[piIndex].responseParts.push_back(z2);
  1185. }
  1186. }
  1187. return retval;
  1188. }
  1189. template <typename T>
  1190. bool PrsonaBase::verify_proof_of_reordering(
  1191. const std::vector<Proof>& pi,
  1192. const std::vector<T>& oldValues,
  1193. const std::vector<std::vector<Twistpoint>>& permutationCommits,
  1194. const std::vector<std::vector<T>>& productCommits,
  1195. const T& otherG,
  1196. const T& otherH) const
  1197. {
  1198. if (pi.empty())
  1199. return false;
  1200. if (!SERVER_IS_MALICIOUS)
  1201. return pi[0].hbc == "PROOF";
  1202. Twistpoint g = EL_GAMAL_GENERATOR;
  1203. Twistpoint h = elGamalBlindGenerator;
  1204. std::stringstream oracleInput;
  1205. oracleInput << g << h << otherG << otherH;
  1206. for (size_t i = 0; i < oldValues.size(); i++)
  1207. oracleInput << oldValues[i];
  1208. for (size_t i = 0; i < permutationCommits.size(); i++)
  1209. for (size_t j = 0; j < permutationCommits[i].size(); j++)
  1210. oracleInput << permutationCommits[i][j];
  1211. for (size_t i = 0; i < productCommits.size(); i++)
  1212. for (size_t j = 0; j < productCommits[i].size(); j++)
  1213. oracleInput << productCommits[i][j];
  1214. Scalar x = pi[0].challengeParts[0];
  1215. for (size_t i = 0; i < permutationCommits.size(); i++)
  1216. {
  1217. for (size_t j = 0; j < permutationCommits[i].size(); j++)
  1218. {
  1219. size_t piIndex = i * permutationCommits.size() + j + 1;
  1220. Twistpoint U1;
  1221. T U2;
  1222. Scalar f = pi[piIndex].responseParts[0];
  1223. Scalar z1 = pi[piIndex].responseParts[1];
  1224. Scalar z2 = pi[piIndex].responseParts[2];
  1225. U1 = g * f +
  1226. h * z1 -
  1227. permutationCommits[j][i] * x;
  1228. U2 = oldValues[j] * f +
  1229. otherH * z2 -
  1230. productCommits[i][j] * x;
  1231. oracleInput << U1 << U2;
  1232. std::stringstream out1, out2;
  1233. out1 << U1;
  1234. out2 << U2;
  1235. }
  1236. }
  1237. if (x != oracle(oracleInput.str()))
  1238. {
  1239. std::cerr << "Reordered things not generated by permutation matrix." << std::endl;
  1240. return false;
  1241. }
  1242. return true;
  1243. }
  1244. /*
  1245. * SERVER AGREEMENT PROOFS
  1246. */
  1247. Proof PrsonaBase::generate_valid_vote_row_proof(
  1248. const std::vector<TwistBipoint>& commitment) const
  1249. {
  1250. Proof retval;
  1251. if (!SERVER_IS_MALICIOUS)
  1252. {
  1253. retval.hbc = "PROOF";
  1254. return retval;
  1255. }
  1256. std::stringstream oracleInput;
  1257. for (size_t i = 0; i < commitment.size(); i++)
  1258. oracleInput << commitment[i];
  1259. Scalar val = oracle(oracleInput.str());
  1260. retval.responseParts.push_back(val);
  1261. return retval;
  1262. }
  1263. Proof PrsonaBase::generate_valid_vote_matrix_proof(
  1264. const std::vector<std::vector<TwistBipoint>>& commitment) const
  1265. {
  1266. Proof retval;
  1267. if (!SERVER_IS_MALICIOUS)
  1268. {
  1269. retval.hbc = "PROOF";
  1270. return retval;
  1271. }
  1272. std::stringstream oracleInput;
  1273. for (size_t i = 0; i < commitment.size(); i++)
  1274. for (size_t j = 0; j < commitment[i].size(); j++)
  1275. oracleInput << commitment[i][j];
  1276. Scalar val = oracle(oracleInput.str());
  1277. retval.responseParts.push_back(val);
  1278. return retval;
  1279. }
  1280. Proof PrsonaBase::generate_valid_user_tally_proof(
  1281. const EGCiphertext& commitment) const
  1282. {
  1283. Proof retval;
  1284. if (!SERVER_IS_MALICIOUS)
  1285. {
  1286. retval.hbc = "PROOF";
  1287. return retval;
  1288. }
  1289. std::stringstream oracleInput;
  1290. oracleInput << commitment;
  1291. Scalar val = oracle(oracleInput.str());
  1292. retval.responseParts.push_back(val);
  1293. return retval;
  1294. }
  1295. Proof PrsonaBase::generate_valid_server_tally_proof(
  1296. const CurveBipoint& commitment) const
  1297. {
  1298. Proof retval;
  1299. if (!SERVER_IS_MALICIOUS)
  1300. {
  1301. retval.hbc = "PROOF";
  1302. return retval;
  1303. }
  1304. std::stringstream oracleInput;
  1305. oracleInput << commitment;
  1306. Scalar val = oracle(oracleInput.str());
  1307. retval.responseParts.push_back(val);
  1308. return retval;
  1309. }
  1310. Proof PrsonaBase::generate_valid_pseudonyms_proof(
  1311. const std::vector<Twistpoint>& commitment) const
  1312. {
  1313. Proof retval;
  1314. if (!SERVER_IS_MALICIOUS)
  1315. {
  1316. retval.hbc = "PROOF";
  1317. return retval;
  1318. }
  1319. std::stringstream oracleInput;
  1320. for (size_t i = 0; i < commitment.size(); i++)
  1321. oracleInput << commitment[i];
  1322. Scalar val = oracle(oracleInput.str());
  1323. retval.responseParts.push_back(val);
  1324. return retval;
  1325. }
  1326. bool PrsonaBase::verify_valid_vote_row_proof(
  1327. const std::vector<Proof>& pi,
  1328. const std::vector<TwistBipoint>& commitment) const
  1329. {
  1330. if (pi.empty())
  1331. return false;
  1332. if (!SERVER_IS_MALICIOUS)
  1333. return pi[0].hbc == "PROOF";
  1334. Scalar comparison = pi[0].responseParts[0];
  1335. std::stringstream oracleInput;
  1336. for (size_t i = 0; i < commitment.size(); i++)
  1337. oracleInput << commitment[i];
  1338. if (oracle(oracleInput.str()) != comparison)
  1339. {
  1340. std::cerr << "Server's claimed value doesn't match their own commitment." << std::endl;
  1341. return false;
  1342. }
  1343. size_t agreement = 1;
  1344. for (size_t i = 1; i < pi.size(); i++)
  1345. if (comparison == pi[i].responseParts[0])
  1346. agreement++;
  1347. return agreement * 2 > pi.size();
  1348. }
  1349. bool PrsonaBase::verify_valid_vote_matrix_proof(
  1350. const std::vector<Proof>& pi,
  1351. const std::vector<std::vector<TwistBipoint>>& commitment) const
  1352. {
  1353. if (pi.empty())
  1354. return false;
  1355. if (!SERVER_IS_MALICIOUS)
  1356. return pi[0].hbc == "PROOF";
  1357. Scalar comparison = pi[0].responseParts[0];
  1358. std::stringstream oracleInput;
  1359. for (size_t i = 0; i < commitment.size(); i++)
  1360. for (size_t j = 0; j < commitment[i].size(); j++)
  1361. oracleInput << commitment[i][j];
  1362. if (oracle(oracleInput.str()) != comparison)
  1363. {
  1364. std::cerr << "Server's claimed value doesn't match their own commitment." << std::endl;
  1365. return false;
  1366. }
  1367. size_t agreement = 1;
  1368. for (size_t i = 1; i < pi.size(); i++)
  1369. if (comparison == pi[i].responseParts[0])
  1370. agreement++;
  1371. return agreement * 2 > pi.size();
  1372. }
  1373. bool PrsonaBase::verify_valid_user_tally_proof(
  1374. const std::vector<Proof>& pi,
  1375. const EGCiphertext& commitment) const
  1376. {
  1377. if (pi.empty())
  1378. return false;
  1379. if (!SERVER_IS_MALICIOUS)
  1380. return pi[0].hbc == "PROOF";
  1381. Scalar comparison = pi[0].responseParts[0];
  1382. std::stringstream oracleInput;
  1383. oracleInput << commitment;
  1384. if (oracle(oracleInput.str()) != comparison)
  1385. {
  1386. std::cerr << "Server's claimed value doesn't match their own commitment." << std::endl;
  1387. return false;
  1388. }
  1389. size_t agreement = 1;
  1390. for (size_t i = 1; i < pi.size(); i++)
  1391. if (comparison == pi[i].responseParts[0])
  1392. agreement++;
  1393. return agreement * 2 > pi.size();
  1394. }
  1395. bool PrsonaBase::verify_valid_server_tally_proof(
  1396. const std::vector<Proof>& pi,
  1397. const CurveBipoint& commitment) const
  1398. {
  1399. if (pi.empty())
  1400. return false;
  1401. if (!SERVER_IS_MALICIOUS)
  1402. return pi[0].hbc == "PROOF";
  1403. Scalar comparison = pi[0].responseParts[0];
  1404. std::stringstream oracleInput;
  1405. oracleInput << commitment;
  1406. if (oracle(oracleInput.str()) != comparison)
  1407. {
  1408. std::cerr << "Server's claimed value doesn't match their own commitment." << std::endl;
  1409. return false;
  1410. }
  1411. size_t agreement = 1;
  1412. for (size_t i = 1; i < pi.size(); i++)
  1413. if (comparison == pi[i].responseParts[0])
  1414. agreement++;
  1415. return agreement * 2 > pi.size();
  1416. }
  1417. bool PrsonaBase::verify_valid_pseudonyms_proof(
  1418. const std::vector<Proof>& pi,
  1419. const std::vector<Twistpoint>& commitment) const
  1420. {
  1421. if (pi.empty())
  1422. return false;
  1423. if (!SERVER_IS_MALICIOUS)
  1424. return pi[0].hbc == "PROOF";
  1425. Scalar comparison = pi[0].responseParts[0];
  1426. std::stringstream oracleInput;
  1427. for (size_t i = 0; i < commitment.size(); i++)
  1428. oracleInput << commitment[i];
  1429. if (oracle(oracleInput.str()) != comparison)
  1430. {
  1431. std::cerr << "Server's claimed value doesn't match their own commitment." << std::endl;
  1432. return false;
  1433. }
  1434. size_t agreement = 1;
  1435. for (size_t i = 1; i < pi.size(); i++)
  1436. if (comparison == pi[i].responseParts[0])
  1437. agreement++;
  1438. return agreement * 2 > pi.size();
  1439. }
  1440. template std::vector<Proof> PrsonaBase::generate_proof_of_reordering<Twistpoint>(
  1441. const std::vector<std::vector<Scalar>>& permutations,
  1442. const std::vector<std::vector<Scalar>>& permutationSeeds,
  1443. const std::vector<std::vector<Scalar>>& productSeeds,
  1444. const std::vector<Twistpoint>& oldValues,
  1445. const std::vector<std::vector<Twistpoint>>& permutationCommits,
  1446. const std::vector<std::vector<Twistpoint>>& productCommits,
  1447. const Twistpoint& otherG,
  1448. const Twistpoint& otherH) const;
  1449. template std::vector<Proof> PrsonaBase::generate_proof_of_reordering<TwistBipoint>(
  1450. const std::vector<std::vector<Scalar>>& permutations,
  1451. const std::vector<std::vector<Scalar>>& permutationSeeds,
  1452. const std::vector<std::vector<Scalar>>& productSeeds,
  1453. const std::vector<TwistBipoint>& oldValues,
  1454. const std::vector<std::vector<Twistpoint>>& permutationCommits,
  1455. const std::vector<std::vector<TwistBipoint>>& productCommits,
  1456. const TwistBipoint& otherG,
  1457. const TwistBipoint& otherH) const;
  1458. template std::vector<Proof> PrsonaBase::generate_proof_of_reordering<CurveBipoint>(
  1459. const std::vector<std::vector<Scalar>>& permutations,
  1460. const std::vector<std::vector<Scalar>>& permutationSeeds,
  1461. const std::vector<std::vector<Scalar>>& productSeeds,
  1462. const std::vector<CurveBipoint>& oldValues,
  1463. const std::vector<std::vector<Twistpoint>>& permutationCommits,
  1464. const std::vector<std::vector<CurveBipoint>>& productCommits,
  1465. const CurveBipoint& otherG,
  1466. const CurveBipoint& otherH) const;
  1467. template bool PrsonaBase::verify_proof_of_reordering<Twistpoint>(
  1468. const std::vector<Proof>& pi,
  1469. const std::vector<Twistpoint>& oldValues,
  1470. const std::vector<std::vector<Twistpoint>>& permutationCommits,
  1471. const std::vector<std::vector<Twistpoint>>& productCommits,
  1472. const Twistpoint& otherG,
  1473. const Twistpoint& otherH) const;
  1474. template bool PrsonaBase::verify_proof_of_reordering<TwistBipoint>(
  1475. const std::vector<Proof>& pi,
  1476. const std::vector<TwistBipoint>& oldValues,
  1477. const std::vector<std::vector<Twistpoint>>& permutationCommits,
  1478. const std::vector<std::vector<TwistBipoint>>& productCommits,
  1479. const TwistBipoint& otherG,
  1480. const TwistBipoint& otherH) const;
  1481. template bool PrsonaBase::verify_proof_of_reordering<CurveBipoint>(
  1482. const std::vector<Proof>& pi,
  1483. const std::vector<CurveBipoint>& oldValues,
  1484. const std::vector<std::vector<Twistpoint>>& permutationCommits,
  1485. const std::vector<std::vector<CurveBipoint>>& productCommits,
  1486. const CurveBipoint& otherG,
  1487. const CurveBipoint& otherH) const;