base.cpp 52 KB

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