base.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971
  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 hi = mid - 1;
  108. }
  109. return lo;
  110. }
  111. /*
  112. * SCHNORR PROOFS
  113. */
  114. Proof PrsonaBase::schnorr_generation(
  115. const Curvepoint& generator,
  116. const Curvepoint& commitment,
  117. const Scalar& log) const
  118. {
  119. Proof retval;
  120. std::stringstream oracleInput;
  121. Scalar r;
  122. r.set_random();
  123. Curvepoint U = generator * r;
  124. oracleInput << generator << commitment << U;
  125. Scalar c = oracle(oracleInput.str());
  126. Scalar z = r.curveAdd(c.curveMult(log));
  127. retval.challengeParts.push_back(c);
  128. retval.responseParts.push_back(z);
  129. return retval;
  130. }
  131. bool PrsonaBase::schnorr_verification(
  132. const Curvepoint& generator,
  133. const Curvepoint& commitment,
  134. const Scalar& c,
  135. const Scalar& z) const
  136. {
  137. Curvepoint U = generator * z - commitment * c;
  138. std::stringstream oracleInput;
  139. oracleInput << generator << commitment << U;
  140. return c == oracle(oracleInput.str());
  141. }
  142. /*
  143. * OWNERSHIP PROOFS
  144. */
  145. // Prove ownership of the short term public key
  146. Proof PrsonaBase::generate_ownership_proof(
  147. const Curvepoint& generator,
  148. const Curvepoint& commitment,
  149. const Scalar& log) const
  150. {
  151. if (!CLIENT_IS_MALICIOUS)
  152. {
  153. Proof retval;
  154. retval.hbc = "PROOF";
  155. return retval;
  156. }
  157. return schnorr_generation(generator, commitment, log);
  158. }
  159. bool PrsonaBase::verify_ownership_proof(
  160. const Proof& pi,
  161. const Curvepoint& generator,
  162. const Curvepoint& commitment) const
  163. {
  164. if (!CLIENT_IS_MALICIOUS)
  165. return pi.hbc == "PROOF";
  166. Scalar c = pi.challengeParts[0];
  167. Scalar z = pi.responseParts[0];
  168. return schnorr_verification(generator, commitment, c, z);
  169. }
  170. /*
  171. * ITERATED SCHNORR PROOFS
  172. */
  173. Proof PrsonaBase::add_to_generator_proof(
  174. const Curvepoint& currGenerator,
  175. const Scalar& seed) const
  176. {
  177. Proof retval;
  178. if (!CLIENT_IS_MALICIOUS)
  179. {
  180. retval.hbc = "PROOF";
  181. return retval;
  182. }
  183. Curvepoint nextGenerator = currGenerator * seed;
  184. retval = schnorr_generation(currGenerator, nextGenerator, seed);
  185. retval.curvepointUniversals.push_back(currGenerator);
  186. return retval;
  187. }
  188. bool PrsonaBase::verify_generator_proof(
  189. const std::vector<Proof>& pi,
  190. const Curvepoint& currGenerator,
  191. size_t numServers) const
  192. {
  193. if (pi.size() != numServers || numServers == 0)
  194. return false;
  195. bool retval = true;
  196. if (!SERVER_IS_MALICIOUS)
  197. {
  198. for (size_t i = 0; i < pi.size(); i++)
  199. retval = retval && pi[i].hbc == "PROOF";
  200. return retval;
  201. }
  202. if (pi[0].curvepointUniversals[0] != EL_GAMAL_GENERATOR)
  203. return false;
  204. for (size_t i = 0; i < pi.size(); i++)
  205. {
  206. Curvepoint generator = pi[i].curvepointUniversals[0];
  207. Curvepoint commitment = (i == pi.size() - 1 ?
  208. currGenerator :
  209. pi[i + 1].curvepointUniversals[0]);
  210. Scalar c = pi[i].challengeParts[0];
  211. Scalar z = pi[i].responseParts[0];
  212. retval = retval &&
  213. schnorr_verification(generator, commitment, c, z);
  214. if (!retval)
  215. std::cerr << "Error in index " << i+1 << " of " << pi.size() << std::endl;
  216. }
  217. return retval;
  218. }
  219. /*
  220. * REPUTATION PROOFS
  221. */
  222. // A pretty straightforward range proof (generation)
  223. std::vector<Proof> PrsonaBase::generate_reputation_proof(
  224. const Proof& ownershipProof,
  225. const EGCiphertext& commitment,
  226. const Scalar& currentScore,
  227. const Scalar& threshold,
  228. const Scalar& inverseKey,
  229. size_t numClients) const
  230. {
  231. std::vector<Proof> retval;
  232. // Base case
  233. if (!CLIENT_IS_MALICIOUS)
  234. {
  235. retval.push_back(Proof("PROOF"));
  236. return retval;
  237. }
  238. // Don't even try if the user asks to make an illegitimate proof
  239. if (threshold.toInt() > (numClients * MAX_ALLOWED_VOTE))
  240. return retval;
  241. // We really have two consecutive proofs in a junction.
  242. // The first is to prove that we are the stpk we claim we are
  243. retval.push_back(ownershipProof);
  244. // The value we're actually using in our proof
  245. mpz_class proofVal = currentScore.curveSub(threshold).toInt();
  246. // Top of the range in our proof determined by what scores are even possible
  247. mpz_class proofBits =
  248. log2(numClients * MAX_ALLOWED_VOTE - threshold.toInt());
  249. // Don't risk a situation that would divulge our private key
  250. if (proofBits <= 1)
  251. proofBits = 2;
  252. // This seems weird, but remember our base is A_t^r, not g^t
  253. std::vector<Scalar> masksPerBit;
  254. masksPerBit.push_back(inverseKey);
  255. for (size_t i = 1; i < proofBits; i++)
  256. {
  257. Scalar currMask;
  258. currMask.set_random();
  259. masksPerBit.push_back(currMask);
  260. masksPerBit[0] =
  261. masksPerBit[0].curveSub(currMask.curveMult(Scalar(1 << i)));
  262. }
  263. // Taken from Fig. 1 in https://eprint.iacr.org/2014/764.pdf
  264. for (size_t i = 0; i < proofBits; i++)
  265. {
  266. Proof currProof;
  267. Curvepoint g, h, c, c_a, c_b;
  268. g = commitment.mask;
  269. h = elGamalBlindGenerator;
  270. mpz_class currBit = bit(proofVal & (1 << i));
  271. Scalar a, s, t, m, r;
  272. a.set_random();
  273. s.set_random();
  274. t.set_random();
  275. m = Scalar(currBit);
  276. r = masksPerBit[i];
  277. c = g * r + h * m;
  278. currProof.curvepointUniversals.push_back(c);
  279. c_a = g * s + h * a;
  280. Scalar am = a.curveMult(m);
  281. c_b = g * t + h * am;
  282. std::stringstream oracleInput;
  283. oracleInput << g << h << c << c_a << c_b;
  284. Scalar x = oracle(oracleInput.str());
  285. currProof.challengeParts.push_back(x);
  286. Scalar f, z_a, z_b;
  287. Scalar mx = m.curveMult(x);
  288. f = mx.curveAdd(a);
  289. Scalar rx = r.curveMult(x);
  290. z_a = rx.curveAdd(s);
  291. Scalar x_f = x.curveSub(f);
  292. Scalar r_x_f = r.curveMult(x_f);
  293. z_b = r_x_f.curveAdd(t);
  294. currProof.responseParts.push_back(f);
  295. currProof.responseParts.push_back(z_a);
  296. currProof.responseParts.push_back(z_b);
  297. retval.push_back(currProof);
  298. }
  299. return retval;
  300. }
  301. // A pretty straightforward range proof (verification)
  302. bool PrsonaBase::verify_reputation_proof(
  303. const std::vector<Proof>& pi,
  304. const Curvepoint& generator,
  305. const Curvepoint& owner,
  306. const EGCiphertext& commitment,
  307. const Scalar& threshold) const
  308. {
  309. // Reject outright if there's no proof to check
  310. if (pi.empty())
  311. {
  312. std::cerr << "Proof was empty, aborting." << std::endl;
  313. return false;
  314. }
  315. // If the range is so big that it wraps around mod n,
  316. // there's a chance the user actually made a proof for a very low reputation
  317. if (pi.size() > 256)
  318. {
  319. std::cerr << "Proof was too big, prover could have cheated." << std::endl;
  320. return false;
  321. }
  322. if (!CLIENT_IS_MALICIOUS)
  323. return pi[0].hbc == "PROOF";
  324. Scalar ownerChallenge, ownerResponse;
  325. ownerChallenge = pi[0].challengeParts[0];
  326. ownerResponse = pi[0].responseParts[0];
  327. // User should be able to prove they are who they say they are
  328. if (!schnorr_verification(generator, owner, ownerChallenge, ownerResponse))
  329. {
  330. std::cerr << "Schnorr proof failed, aborting." << std::endl;
  331. return false;
  332. }
  333. // X is the thing we're going to be checking in on throughout
  334. // to try to get our score commitment back in the end.
  335. Curvepoint X;
  336. for (size_t i = 1; i < pi.size(); i++)
  337. {
  338. Curvepoint c, g, h;
  339. c = pi[i].curvepointUniversals[0];
  340. g = commitment.mask;
  341. h = elGamalBlindGenerator;
  342. X = X + c * Scalar(1 << (i - 1));
  343. Scalar x, f, z_a, z_b;
  344. x = pi[i].challengeParts[0];
  345. f = pi[i].responseParts[0];
  346. z_a = pi[i].responseParts[1];
  347. z_b = pi[i].responseParts[2];
  348. // Taken from Fig. 1 in https://eprint.iacr.org/2014/764.pdf
  349. Curvepoint c_a, c_b;
  350. c_a = g * z_a + h * f - c * x;
  351. Scalar x_f = x.curveSub(f);
  352. c_b = g * z_b - c * x_f;
  353. std::stringstream oracleInput;
  354. oracleInput << g << h << c << c_a << c_b;
  355. if (oracle(oracleInput.str()) != pi[i].challengeParts[0])
  356. {
  357. std::cerr << "0 or 1 proof failed at index " << i << " of " << pi.size() - 1 << ", aborting." << std::endl;
  358. return false;
  359. }
  360. }
  361. Scalar negThreshold;
  362. negThreshold = Scalar(0).curveSub(threshold);
  363. Curvepoint scoreCommitment =
  364. commitment.encryptedMessage +
  365. elGamalBlindGenerator * negThreshold;
  366. return X == scoreCommitment;
  367. }
  368. /*
  369. * VALID VOTE PROOFS
  370. */
  371. std::vector<Proof> PrsonaBase::generate_vote_proof(
  372. const Proof& ownershipProof,
  373. const CurveBipoint& g,
  374. const CurveBipoint& h,
  375. const std::vector<bool>& replaces,
  376. const std::vector<CurveBipoint>& oldEncryptedVotes,
  377. const std::vector<CurveBipoint>& newEncryptedVotes,
  378. const std::vector<Scalar>& seeds,
  379. const std::vector<Scalar>& votes) const
  380. {
  381. std::vector<Proof> retval;
  382. // Base case
  383. if (!CLIENT_IS_MALICIOUS)
  384. {
  385. retval.push_back(Proof("PROOF"));
  386. return retval;
  387. }
  388. // The first need is to prove that we are the stpk we claim we are
  389. retval.push_back(ownershipProof);
  390. // Then, we iterate over all votes for the proofs that they are correct
  391. for (size_t i = 0; i < replaces.size(); i++)
  392. {
  393. std::stringstream oracleInput;
  394. oracleInput << g << h << oldEncryptedVotes[i] << newEncryptedVotes[i];
  395. /* This proof structure is documented in my notes.
  396. * It's inspired by the proof in Fig. 1 at
  397. * https://eprint.iacr.org/2014/764.pdf, but adapted so that you prove
  398. * m(m-1)(m-2) = 0 instead of m(m-1) = 0.
  399. *
  400. * The rerandomization part is just a slight variation on an
  401. * ordinary Schnorr proof, so that part's less scary. */
  402. if (replaces[i]) // CASE: Make new vote
  403. {
  404. Proof currProof;
  405. Scalar c_r, z_r, a, s, t_1, t_2;
  406. c_r.set_random();
  407. z_r.set_random();
  408. a.set_random();
  409. s.set_random();
  410. t_1.set_random();
  411. t_2.set_random();
  412. CurveBipoint U = h * z_r +
  413. oldEncryptedVotes[i] * c_r -
  414. newEncryptedVotes[i] * c_r;
  415. CurveBipoint C_a = g * a + h * s;
  416. Scalar power = (a.curveAdd(a)).curveMult(votes[i].curveMult(votes[i]));
  417. power =
  418. power.curveSub((a.curveAdd(a).curveAdd(a)).curveMult(votes[i]));
  419. CurveBipoint C_b = g * power + h * t_1;
  420. currProof.curveBipointUniversals.push_back(C_b);
  421. CurveBipoint C_c = g * a.curveMult(a.curveMult(votes[i])) +
  422. h * t_2;
  423. oracleInput << U << C_a << C_b << C_c;
  424. Scalar c = oracle(oracleInput.str());
  425. Scalar c_n = c.curveSub(c_r);
  426. currProof.challengeParts.push_back(c_r);
  427. currProof.challengeParts.push_back(c_n);
  428. Scalar f = (votes[i].curveMult(c_n)).curveAdd(a);
  429. Scalar z_na = (seeds[i].curveMult(c_n)).curveAdd(s);
  430. Scalar t_1_c_n_t_2 = (t_1.curveMult(c_n)).curveAdd(t_2);
  431. Scalar f_c_n = f.curveSub(c_n);
  432. Scalar c_n2_f = c_n.curveAdd(c_n).curveSub(f);
  433. Scalar z_nb =
  434. (seeds[i].curveMult(f_c_n).curveMult(c_n2_f)).curveAdd(
  435. t_1_c_n_t_2);
  436. currProof.responseParts.push_back(z_r);
  437. currProof.responseParts.push_back(f);
  438. currProof.responseParts.push_back(z_na);
  439. currProof.responseParts.push_back(z_nb);
  440. retval.push_back(currProof);
  441. }
  442. else // CASE: Rerandomize existing vote
  443. {
  444. Proof currProof;
  445. Scalar u, commitmentLambda_1, commitmentLambda_2,
  446. c_n, z_na, z_nb, f;
  447. u.set_random();
  448. commitmentLambda_1.set_random();
  449. commitmentLambda_2.set_random();
  450. c_n.set_random();
  451. z_na.set_random();
  452. z_nb.set_random();
  453. f.set_random();
  454. CurveBipoint U = h * u;
  455. CurveBipoint C_a = g * f +
  456. h * z_na -
  457. newEncryptedVotes[i] * c_n;
  458. CurveBipoint C_b = g * commitmentLambda_1 + h * commitmentLambda_2;
  459. currProof.curveBipointUniversals.push_back(C_b);
  460. Scalar f_c_n = f.curveSub(c_n);
  461. Scalar c_n2_f = c_n.curveAdd(c_n).curveSub(f);
  462. CurveBipoint C_c =
  463. h * z_nb -
  464. newEncryptedVotes[i] * f_c_n.curveMult(c_n2_f) -
  465. C_b * c_n;
  466. oracleInput << U << C_a << C_b << C_c;
  467. Scalar c = oracle(oracleInput.str());
  468. Scalar c_r = c.curveSub(c_n);
  469. currProof.challengeParts.push_back(c_r);
  470. currProof.challengeParts.push_back(c_n);
  471. Scalar z_r = u.curveAdd(c_r.curveMult(seeds[i]));
  472. currProof.responseParts.push_back(z_r);
  473. currProof.responseParts.push_back(f);
  474. currProof.responseParts.push_back(z_na);
  475. currProof.responseParts.push_back(z_nb);
  476. retval.push_back(currProof);
  477. }
  478. }
  479. return retval;
  480. }
  481. bool PrsonaBase::verify_vote_proof(
  482. const CurveBipoint& g,
  483. const CurveBipoint& h,
  484. const std::vector<Proof>& pi,
  485. const std::vector<CurveBipoint>& oldEncryptedVotes,
  486. const std::vector<CurveBipoint>& newEncryptedVotes,
  487. const Curvepoint& freshGenerator,
  488. const Curvepoint& owner) const
  489. {
  490. // Reject outright if there's no proof to check
  491. if (pi.empty())
  492. {
  493. std::cerr << "Proof was empty, aborting." << std::endl;
  494. return false;
  495. }
  496. // Base case
  497. if (!CLIENT_IS_MALICIOUS)
  498. return pi[0].hbc == "PROOF";
  499. // User should be able to prove they are who they say they are
  500. if (!verify_ownership_proof(pi[0], freshGenerator, owner))
  501. {
  502. std::cerr << "Schnorr proof failed, aborting." << std::endl;
  503. return false;
  504. }
  505. /* This proof structure is documented in my notes.
  506. * It's inspired by the proof in Fig. 1 at
  507. * https://eprint.iacr.org/2014/764.pdf, but adapted so that you prove
  508. * m(m-1)(m-2) = 0 instead of m(m-1) = 0.
  509. *
  510. * The rerandomization part is just a slight variation on an
  511. * ordinary Schnorr proof, so that part's less scary. */
  512. for (size_t i = 1; i < pi.size(); i++)
  513. {
  514. size_t voteIndex = i - 1;
  515. CurveBipoint C_b;
  516. C_b = pi[i].curveBipointUniversals[0];
  517. Scalar c_r, c_n, z_r, f, z_na, z_nb;
  518. c_r = pi[i].challengeParts[0];
  519. c_n = pi[i].challengeParts[1];
  520. z_r = pi[i].responseParts[0];
  521. f = pi[i].responseParts[1];
  522. z_na = pi[i].responseParts[2];
  523. z_nb = pi[i].responseParts[3];
  524. CurveBipoint U, C_a, C_c;
  525. U = h * z_r +
  526. oldEncryptedVotes[voteIndex] * c_r -
  527. newEncryptedVotes[voteIndex] * c_r;
  528. C_a = g * f + h * z_na - newEncryptedVotes[voteIndex] * c_n;
  529. Scalar f_c_n = f.curveSub(c_n);
  530. Scalar c_n2_f = c_n.curveAdd(c_n).curveSub(f);
  531. C_c = h * z_nb -
  532. newEncryptedVotes[voteIndex] * f_c_n.curveMult(c_n2_f) -
  533. C_b * c_n;
  534. std::stringstream oracleInput;
  535. oracleInput << g << h
  536. << oldEncryptedVotes[voteIndex] << newEncryptedVotes[voteIndex]
  537. << U << C_a << C_b << C_c;
  538. if (oracle(oracleInput.str()) != c_r.curveAdd(c_n))
  539. return false;
  540. }
  541. return true;
  542. }
  543. /*
  544. * NEW USER PROOFS
  545. */
  546. std::vector<Proof> PrsonaBase::generate_proof_of_added_user(
  547. const Scalar& twistBipointSeed,
  548. const Scalar& EGCiphertextSeed,
  549. const std::vector<Scalar>& curveBipointSelfSeeds,
  550. const std::vector<Scalar>& curveBipointOtherSeeds) const
  551. {
  552. std::vector<Proof> retval;
  553. if (!SERVER_IS_MALICIOUS)
  554. {
  555. retval.push_back(Proof("PROOF"));
  556. return retval;
  557. }
  558. Proof currProof;
  559. currProof.responseParts.push_back(twistBipointSeed);
  560. retval.push_back(currProof);
  561. currProof.responseParts.clear();
  562. currProof.responseParts.push_back(EGCiphertextSeed);
  563. retval.push_back(currProof);
  564. currProof.responseParts.clear();
  565. for (size_t i = 0; i < curveBipointSelfSeeds.size(); i++)
  566. currProof.responseParts.push_back(curveBipointSelfSeeds[i]);
  567. retval.push_back(currProof);
  568. currProof.responseParts.clear();
  569. for (size_t i = 0; i < curveBipointOtherSeeds.size(); i++)
  570. currProof.responseParts.push_back(curveBipointOtherSeeds[i]);
  571. retval.push_back(currProof);
  572. return retval;
  573. }
  574. bool PrsonaBase::verify_proof_of_added_user(
  575. const std::vector<Proof>& pi,
  576. const Curvepoint& currentFreshGenerator,
  577. const Curvepoint& shortTermPublicKey,
  578. const Curvepoint& elGamalBlindGenerator,
  579. const CurveBipoint& curveG,
  580. const CurveBipoint& curveH,
  581. const TwistBipoint& twistG,
  582. const TwistBipoint& twistH,
  583. size_t selfIndex,
  584. const EGCiphertext& userEncryptedScore,
  585. const TwistBipoint& serverEncryptedScore,
  586. const std::vector<std::vector<CurveBipoint>> encryptedVoteMatrix) const
  587. {
  588. if (pi.empty())
  589. {
  590. std::cerr << "Proof empty." << std::endl;
  591. return false;
  592. }
  593. if (!SERVER_IS_MALICIOUS)
  594. return pi[0].hbc == "PROOF";
  595. Scalar currSeed = pi[0].responseParts[0];
  596. if (serverEncryptedScore !=
  597. twistG * DEFAULT_TALLY + twistH * currSeed)
  598. {
  599. std::cerr << "Issue in server encrypted score." << std::endl;
  600. return false;
  601. }
  602. currSeed = pi[1].responseParts[0];
  603. if (userEncryptedScore.mask != shortTermPublicKey * currSeed)
  604. {
  605. std::cerr << "Issue in user encrypted score: mask." << std::endl;
  606. return false;
  607. }
  608. if (userEncryptedScore.encryptedMessage !=
  609. currentFreshGenerator * currSeed + elGamalBlindGenerator * DEFAULT_TALLY)
  610. {
  611. std::cerr << "Issue in user encrypted score: value." << std::endl;
  612. return false;
  613. }
  614. for (size_t i = 0; i < pi[2].responseParts.size(); i++)
  615. {
  616. CurveBipoint currVote = encryptedVoteMatrix[selfIndex][i];
  617. currSeed = pi[2].responseParts[i];
  618. if (i == selfIndex)
  619. {
  620. if (currVote !=
  621. curveG * Scalar(MAX_ALLOWED_VOTE) + curveH * currSeed)
  622. {
  623. std::cerr << "Issue in self vote." << std::endl;
  624. return false;
  625. }
  626. }
  627. else
  628. {
  629. if (currVote !=
  630. curveG * DEFAULT_VOTE + curveH * currSeed)
  631. {
  632. std::cerr << "Issue in vote by verifier for user " << i + 1
  633. << " of " << pi[2].responseParts.size() << "." << std::endl;
  634. return false;
  635. }
  636. }
  637. }
  638. for (size_t i = 0; i < pi[3].responseParts.size(); i++)
  639. {
  640. CurveBipoint currVote = encryptedVoteMatrix[i][selfIndex];
  641. currSeed = pi[3].responseParts[i];
  642. if (i != selfIndex)
  643. {
  644. if (currVote !=
  645. curveG * DEFAULT_VOTE + curveH * currSeed)
  646. {
  647. std::cerr << "Issue in vote for verifier by user " << i + 1
  648. << " of " << pi[3].responseParts.size() << "." << std::endl;
  649. return false;
  650. }
  651. }
  652. }
  653. return true;
  654. }
  655. /*
  656. * EPOCH PROOFS
  657. */
  658. Proof PrsonaBase::generate_proof_of_correct_tally() const
  659. {
  660. Proof retval;
  661. if (!SERVER_IS_MALICIOUS)
  662. {
  663. retval.hbc = "PROOF";
  664. return retval;
  665. }
  666. retval.hbc = "PROOF";
  667. return retval;
  668. }
  669. Proof PrsonaBase::generate_proof_of_correct_sum() const
  670. {
  671. Proof retval;
  672. if (!SERVER_IS_MALICIOUS)
  673. {
  674. retval.hbc = "PROOF";
  675. return retval;
  676. }
  677. retval.hbc = "PROOF";
  678. return retval;
  679. }
  680. Proof PrsonaBase::generate_proof_of_shuffle() const
  681. {
  682. Proof retval;
  683. if (!SERVER_IS_MALICIOUS)
  684. {
  685. retval.hbc = "PROOF";
  686. return retval;
  687. }
  688. retval.hbc = "PROOF";
  689. return retval;
  690. }
  691. bool PrsonaBase::verify_update_proof(
  692. const Proof& pi) const
  693. {
  694. if (!SERVER_IS_MALICIOUS)
  695. return pi.hbc == "PROOF";
  696. return pi.hbc == "PROOF";
  697. }
  698. /*
  699. * SERVER AGREEMENT PROOFS
  700. */
  701. Proof PrsonaBase::generate_valid_user_tally_proof() const
  702. {
  703. Proof retval;
  704. if (!SERVER_IS_MALICIOUS)
  705. {
  706. retval.hbc = "PROOF";
  707. return retval;
  708. }
  709. retval.hbc = "PROOF";
  710. return retval;
  711. }
  712. Proof PrsonaBase::generate_valid_server_tally_proof() const
  713. {
  714. Proof retval;
  715. if (!SERVER_IS_MALICIOUS)
  716. {
  717. retval.hbc = "PROOF";
  718. return retval;
  719. }
  720. retval.hbc = "PROOF";
  721. return retval;
  722. }
  723. Proof PrsonaBase::generate_valid_vote_row_proof() const
  724. {
  725. Proof retval;
  726. if (!SERVER_IS_MALICIOUS)
  727. {
  728. retval.hbc = "PROOF";
  729. return retval;
  730. }
  731. retval.hbc = "PROOF";
  732. return retval;
  733. }
  734. Proof PrsonaBase::generate_valid_vote_matrix_proof() const
  735. {
  736. Proof retval;
  737. if (!SERVER_IS_MALICIOUS)
  738. {
  739. retval.hbc = "PROOF";
  740. return retval;
  741. }
  742. retval.hbc = "PROOF";
  743. return retval;
  744. }
  745. Proof PrsonaBase::generate_valid_pseudonyms_proof() const
  746. {
  747. Proof retval;
  748. if (!SERVER_IS_MALICIOUS)
  749. {
  750. retval.hbc = "PROOF";
  751. return retval;
  752. }
  753. retval.hbc = "PROOF";
  754. return retval;
  755. }
  756. bool PrsonaBase::verify_valid_user_tally_proof(const Proof& pi) const
  757. {
  758. if (!SERVER_IS_MALICIOUS)
  759. return pi.hbc == "PROOF";
  760. return pi.hbc == "PROOF";
  761. }
  762. bool PrsonaBase::verify_valid_server_tally_proof(const Proof& pi) const
  763. {
  764. if (!SERVER_IS_MALICIOUS)
  765. return pi.hbc == "PROOF";
  766. return pi.hbc == "PROOF";
  767. }
  768. bool PrsonaBase::verify_valid_vote_row_proof(const Proof& pi) const
  769. {
  770. if (!SERVER_IS_MALICIOUS)
  771. return pi.hbc == "PROOF";
  772. return pi.hbc == "PROOF";
  773. }
  774. bool PrsonaBase::verify_valid_vote_matrix_proof(const Proof& pi) const
  775. {
  776. if (!SERVER_IS_MALICIOUS)
  777. return pi.hbc == "PROOF";
  778. return pi.hbc == "PROOF";
  779. }
  780. bool PrsonaBase::verify_valid_pseudonyms_proof(const Proof& pi) const
  781. {
  782. if (!SERVER_IS_MALICIOUS)
  783. return pi.hbc == "PROOF";
  784. return pi.hbc == "PROOF";
  785. }