base.cpp 53 KB

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