base.cpp 54 KB

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