base.cpp 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096
  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 (!CLIENT_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 Curvepoint& elGamalBlindGenerator,
  565. const CurveBipoint& curveG,
  566. const CurveBipoint& curveH,
  567. const TwistBipoint& twistG,
  568. const TwistBipoint& twistH,
  569. size_t selfIndex,
  570. const EGCiphertext& userEncryptedScore,
  571. const TwistBipoint& serverEncryptedScore,
  572. const std::vector<std::vector<CurveBipoint>> 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. CurveBipoint 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. CurveBipoint 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. Proof PrsonaBase::generate_proof_of_correct_tally() const
  645. {
  646. Proof retval;
  647. if (!SERVER_IS_MALICIOUS)
  648. {
  649. retval.hbc = "PROOF";
  650. return retval;
  651. }
  652. retval.hbc = "PROOF";
  653. return retval;
  654. }
  655. Proof PrsonaBase::generate_proof_of_correct_sum() const
  656. {
  657. Proof retval;
  658. if (!SERVER_IS_MALICIOUS)
  659. {
  660. retval.hbc = "PROOF";
  661. return retval;
  662. }
  663. retval.hbc = "PROOF";
  664. return retval;
  665. }
  666. Proof PrsonaBase::generate_proof_of_shuffle() const
  667. {
  668. Proof retval;
  669. if (!SERVER_IS_MALICIOUS)
  670. {
  671. retval.hbc = "PROOF";
  672. return retval;
  673. }
  674. retval.hbc = "PROOF";
  675. return retval;
  676. }
  677. bool PrsonaBase::verify_update_proof(
  678. const Proof& pi) const
  679. {
  680. if (!SERVER_IS_MALICIOUS)
  681. return pi.hbc == "PROOF";
  682. return pi.hbc == "PROOF";
  683. }
  684. /*
  685. * SERVER AGREEMENT PROOFS
  686. */
  687. Proof PrsonaBase::generate_valid_vote_row_proof(
  688. const std::vector<CurveBipoint>& commitment) const
  689. {
  690. Proof retval;
  691. if (!SERVER_IS_MALICIOUS)
  692. {
  693. retval.hbc = "PROOF";
  694. return retval;
  695. }
  696. std::stringstream oracleInput;
  697. for (size_t i = 0; i < commitment.size(); i++)
  698. oracleInput << commitment[i];
  699. Scalar val = oracle(oracleInput.str());
  700. retval.responseParts.push_back(val);
  701. return retval;
  702. }
  703. Proof PrsonaBase::generate_valid_vote_matrix_proof(
  704. const std::vector<std::vector<CurveBipoint>>& commitment) const
  705. {
  706. Proof retval;
  707. if (!SERVER_IS_MALICIOUS)
  708. {
  709. retval.hbc = "PROOF";
  710. return retval;
  711. }
  712. std::stringstream oracleInput;
  713. for (size_t i = 0; i < commitment.size(); i++)
  714. for (size_t j = 0; j < commitment[i].size(); j++)
  715. oracleInput << commitment[i][j];
  716. Scalar val = oracle(oracleInput.str());
  717. retval.responseParts.push_back(val);
  718. return retval;
  719. }
  720. Proof PrsonaBase::generate_valid_user_tally_proof(
  721. const EGCiphertext& commitment) const
  722. {
  723. Proof retval;
  724. if (!SERVER_IS_MALICIOUS)
  725. {
  726. retval.hbc = "PROOF";
  727. return retval;
  728. }
  729. std::stringstream oracleInput;
  730. oracleInput << commitment;
  731. Scalar val = oracle(oracleInput.str());
  732. retval.responseParts.push_back(val);
  733. return retval;
  734. }
  735. Proof PrsonaBase::generate_valid_server_tally_proof(
  736. const TwistBipoint& commitment) const
  737. {
  738. Proof retval;
  739. if (!SERVER_IS_MALICIOUS)
  740. {
  741. retval.hbc = "PROOF";
  742. return retval;
  743. }
  744. std::stringstream oracleInput;
  745. oracleInput << commitment;
  746. Scalar val = oracle(oracleInput.str());
  747. retval.responseParts.push_back(val);
  748. return retval;
  749. }
  750. Proof PrsonaBase::generate_valid_pseudonyms_proof(
  751. const std::vector<Curvepoint>& commitment) const
  752. {
  753. Proof retval;
  754. if (!SERVER_IS_MALICIOUS)
  755. {
  756. retval.hbc = "PROOF";
  757. return retval;
  758. }
  759. std::stringstream oracleInput;
  760. for (size_t i = 0; i < commitment.size(); i++)
  761. oracleInput << commitment[i];
  762. Scalar val = oracle(oracleInput.str());
  763. retval.responseParts.push_back(val);
  764. return retval;
  765. }
  766. bool PrsonaBase::verify_valid_vote_row_proof(
  767. const std::vector<Proof>& pi,
  768. const std::vector<CurveBipoint>& commitment) const
  769. {
  770. if (pi.empty())
  771. return false;
  772. if (!SERVER_IS_MALICIOUS)
  773. return pi[0].hbc == "PROOF";
  774. Scalar comparison = pi[0].responseParts[0];
  775. std::stringstream oracleInput;
  776. for (size_t i = 0; i < commitment.size(); i++)
  777. oracleInput << commitment[i];
  778. if (oracle(oracleInput.str()) != comparison)
  779. {
  780. std::cerr << "Server's claimed value doesn't match their own commitment." << std::endl;
  781. return false;
  782. }
  783. size_t agreement = 1;
  784. for (size_t i = 1; i < pi.size(); i++)
  785. if (comparison == pi[i].responseParts[0])
  786. agreement++;
  787. return agreement * 2 > pi.size();
  788. }
  789. bool PrsonaBase::verify_valid_vote_matrix_proof(
  790. const std::vector<Proof>& pi,
  791. const std::vector<std::vector<CurveBipoint>>& commitment) const
  792. {
  793. if (pi.empty())
  794. return false;
  795. if (!SERVER_IS_MALICIOUS)
  796. return pi[0].hbc == "PROOF";
  797. Scalar comparison = pi[0].responseParts[0];
  798. std::stringstream oracleInput;
  799. for (size_t i = 0; i < commitment.size(); i++)
  800. for (size_t j = 0; j < commitment[i].size(); j++)
  801. oracleInput << commitment[i][j];
  802. if (oracle(oracleInput.str()) != comparison)
  803. {
  804. std::cerr << "Server's claimed value doesn't match their own commitment." << std::endl;
  805. return false;
  806. }
  807. size_t agreement = 1;
  808. for (size_t i = 1; i < pi.size(); i++)
  809. if (comparison == pi[i].responseParts[0])
  810. agreement++;
  811. return agreement * 2 > pi.size();
  812. }
  813. bool PrsonaBase::verify_valid_user_tally_proof(
  814. const std::vector<Proof>& pi,
  815. const EGCiphertext& commitment) const
  816. {
  817. if (pi.empty())
  818. return false;
  819. if (!SERVER_IS_MALICIOUS)
  820. return pi[0].hbc == "PROOF";
  821. Scalar comparison = pi[0].responseParts[0];
  822. std::stringstream oracleInput;
  823. oracleInput << commitment;
  824. if (oracle(oracleInput.str()) != comparison)
  825. {
  826. std::cerr << "Server's claimed value doesn't match their own commitment." << std::endl;
  827. return false;
  828. }
  829. size_t agreement = 1;
  830. for (size_t i = 1; i < pi.size(); i++)
  831. if (comparison == pi[i].responseParts[0])
  832. agreement++;
  833. return agreement * 2 > pi.size();
  834. }
  835. bool PrsonaBase::verify_valid_server_tally_proof(
  836. const std::vector<Proof>& pi,
  837. const TwistBipoint& commitment) const
  838. {
  839. if (pi.empty())
  840. return false;
  841. if (!SERVER_IS_MALICIOUS)
  842. return pi[0].hbc == "PROOF";
  843. Scalar comparison = pi[0].responseParts[0];
  844. std::stringstream oracleInput;
  845. oracleInput << commitment;
  846. if (oracle(oracleInput.str()) != comparison)
  847. {
  848. std::cerr << "Server's claimed value doesn't match their own commitment." << std::endl;
  849. return false;
  850. }
  851. size_t agreement = 1;
  852. for (size_t i = 1; i < pi.size(); i++)
  853. if (comparison == pi[i].responseParts[0])
  854. agreement++;
  855. return agreement * 2 > pi.size();
  856. }
  857. bool PrsonaBase::verify_valid_pseudonyms_proof(
  858. const std::vector<Proof>& pi,
  859. const std::vector<Curvepoint>& commitment) const
  860. {
  861. if (pi.empty())
  862. return false;
  863. if (!SERVER_IS_MALICIOUS)
  864. return pi[0].hbc == "PROOF";
  865. Scalar comparison = pi[0].responseParts[0];
  866. std::stringstream oracleInput;
  867. for (size_t i = 0; i < commitment.size(); i++)
  868. oracleInput << commitment[i];
  869. if (oracle(oracleInput.str()) != comparison)
  870. {
  871. std::cerr << "Server's claimed value doesn't match their own commitment." << std::endl;
  872. return false;
  873. }
  874. size_t agreement = 1;
  875. for (size_t i = 1; i < pi.size(); i++)
  876. if (comparison == pi[i].responseParts[0])
  877. agreement++;
  878. return agreement * 2 > pi.size();
  879. }