base.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116
  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 r;
  124. r.set_random();
  125. Curvepoint U = generator * r;
  126. oracleInput << generator << commitment << U;
  127. Scalar c = oracle(oracleInput.str());
  128. Scalar z = r.curveAdd(c.curveMult(log));
  129. retval.challengeParts.push_back(c);
  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& c,
  137. const Scalar& z) const
  138. {
  139. Curvepoint U = generator * z - commitment * c;
  140. std::stringstream oracleInput;
  141. oracleInput << generator << commitment << U;
  142. return c == 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.curveSub(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].curveSub(currMask.curveMult(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. Scalar am = a.curveMult(m);
  283. c_b = g * t + h * am;
  284. std::stringstream oracleInput;
  285. oracleInput << g << h << c << c_a << c_b;
  286. Scalar x = oracle(oracleInput.str());
  287. currProof.challengeParts.push_back(x);
  288. Scalar f, z_a, z_b;
  289. Scalar mx = m.curveMult(x);
  290. f = mx.curveAdd(a);
  291. Scalar rx = r.curveMult(x);
  292. z_a = rx.curveAdd(s);
  293. Scalar x_f = x.curveSub(f);
  294. Scalar r_x_f = r.curveMult(x_f);
  295. z_b = r_x_f.curveAdd(t);
  296. currProof.responseParts.push_back(f);
  297. currProof.responseParts.push_back(z_a);
  298. currProof.responseParts.push_back(z_b);
  299. retval.push_back(currProof);
  300. }
  301. return retval;
  302. }
  303. // A pretty straightforward range proof (verification)
  304. bool PrsonaBase::verify_reputation_proof(
  305. const std::vector<Proof>& pi,
  306. const Curvepoint& generator,
  307. const Curvepoint& owner,
  308. const EGCiphertext& commitment,
  309. const Scalar& threshold) const
  310. {
  311. // Reject outright if there's no proof to check
  312. if (pi.empty())
  313. {
  314. std::cerr << "Proof was empty, aborting." << std::endl;
  315. return false;
  316. }
  317. // If the range is so big that it wraps around mod n,
  318. // there's a chance the user actually made a proof for a very low reputation
  319. if (pi.size() > 256)
  320. {
  321. std::cerr << "Proof was too big, prover could have cheated." << std::endl;
  322. return false;
  323. }
  324. if (!CLIENT_IS_MALICIOUS)
  325. return pi[0].hbc == "PROOF";
  326. Scalar ownerChallenge, ownerResponse;
  327. ownerChallenge = pi[0].challengeParts[0];
  328. ownerResponse = pi[0].responseParts[0];
  329. // User should be able to prove they are who they say they are
  330. if (!schnorr_verification(generator, owner, ownerChallenge, ownerResponse))
  331. {
  332. std::cerr << "Schnorr proof failed, aborting." << std::endl;
  333. return false;
  334. }
  335. // X is the thing we're going to be checking in on throughout
  336. // to try to get our score commitment back in the end.
  337. Curvepoint X;
  338. for (size_t i = 1; i < pi.size(); i++)
  339. {
  340. Curvepoint c, g, h;
  341. c = pi[i].curvepointUniversals[0];
  342. g = commitment.mask;
  343. h = elGamalBlindGenerator;
  344. X = X + c * Scalar(1 << (i - 1));
  345. Scalar x, f, z_a, z_b;
  346. x = pi[i].challengeParts[0];
  347. f = pi[i].responseParts[0];
  348. z_a = pi[i].responseParts[1];
  349. z_b = pi[i].responseParts[2];
  350. // Taken from Fig. 1 in https://eprint.iacr.org/2014/764.pdf
  351. Curvepoint c_a, c_b;
  352. c_a = g * z_a + h * f - c * x;
  353. Scalar x_f = x.curveSub(f);
  354. c_b = g * z_b - c * x_f;
  355. std::stringstream oracleInput;
  356. oracleInput << g << h << c << c_a << c_b;
  357. if (oracle(oracleInput.str()) != pi[i].challengeParts[0])
  358. {
  359. std::cerr << "0 or 1 proof failed at index " << i << " of " << pi.size() - 1 << ", aborting." << std::endl;
  360. return false;
  361. }
  362. }
  363. Scalar negThreshold;
  364. negThreshold = Scalar(0).curveSub(threshold);
  365. Curvepoint scoreCommitment =
  366. commitment.encryptedMessage +
  367. elGamalBlindGenerator * negThreshold;
  368. return X == scoreCommitment;
  369. }
  370. /*
  371. * VALID VOTE PROOFS
  372. */
  373. std::vector<Proof> PrsonaBase::generate_vote_proof(
  374. const Proof& ownershipProof,
  375. const CurveBipoint& g,
  376. const CurveBipoint& h,
  377. const std::vector<bool>& replaces,
  378. const std::vector<CurveBipoint>& oldEncryptedVotes,
  379. const std::vector<CurveBipoint>& newEncryptedVotes,
  380. const std::vector<Scalar>& seeds,
  381. const std::vector<Scalar>& votes) const
  382. {
  383. std::vector<Proof> retval;
  384. // Base case
  385. if (!CLIENT_IS_MALICIOUS)
  386. {
  387. retval.push_back(Proof("PROOF"));
  388. return retval;
  389. }
  390. // The first need is to prove that we are the stpk we claim we are
  391. retval.push_back(ownershipProof);
  392. // Then, we iterate over all votes for the proofs that they are correct
  393. for (size_t i = 0; i < replaces.size(); i++)
  394. {
  395. std::stringstream oracleInput;
  396. oracleInput << g << h << oldEncryptedVotes[i] << newEncryptedVotes[i];
  397. /* This proof structure is documented in my notes.
  398. * It's inspired by the proof in Fig. 1 at
  399. * https://eprint.iacr.org/2014/764.pdf, but adapted so that you prove
  400. * m(m-1)(m-2) = 0 instead of m(m-1) = 0.
  401. *
  402. * The rerandomization part is just a slight variation on an
  403. * ordinary Schnorr proof, so that part's less scary. */
  404. if (replaces[i]) // CASE: Make new vote
  405. {
  406. Proof currProof;
  407. Scalar c_r, z_r, a, s, t_1, t_2;
  408. c_r.set_random();
  409. z_r.set_random();
  410. a.set_random();
  411. s.set_random();
  412. t_1.set_random();
  413. t_2.set_random();
  414. CurveBipoint U = h * z_r +
  415. oldEncryptedVotes[i] * c_r -
  416. newEncryptedVotes[i] * c_r;
  417. CurveBipoint C_a = g * a + h * s;
  418. Scalar power = (a.curveAdd(a)).curveMult(votes[i].curveMult(votes[i]));
  419. power =
  420. power.curveSub((a.curveAdd(a).curveAdd(a)).curveMult(votes[i]));
  421. CurveBipoint C_b = g * power + h * t_1;
  422. currProof.curveBipointUniversals.push_back(C_b);
  423. CurveBipoint C_c = g * a.curveMult(a.curveMult(votes[i])) +
  424. h * t_2;
  425. oracleInput << U << C_a << C_b << C_c;
  426. Scalar c = oracle(oracleInput.str());
  427. Scalar c_n = c.curveSub(c_r);
  428. currProof.challengeParts.push_back(c_r);
  429. currProof.challengeParts.push_back(c_n);
  430. Scalar f = (votes[i].curveMult(c_n)).curveAdd(a);
  431. Scalar z_na = (seeds[i].curveMult(c_n)).curveAdd(s);
  432. Scalar t_1_c_n_t_2 = (t_1.curveMult(c_n)).curveAdd(t_2);
  433. Scalar f_c_n = f.curveSub(c_n);
  434. Scalar c_n2_f = c_n.curveAdd(c_n).curveSub(f);
  435. Scalar z_nb =
  436. (seeds[i].curveMult(f_c_n).curveMult(c_n2_f)).curveAdd(
  437. t_1_c_n_t_2);
  438. currProof.responseParts.push_back(z_r);
  439. currProof.responseParts.push_back(f);
  440. currProof.responseParts.push_back(z_na);
  441. currProof.responseParts.push_back(z_nb);
  442. retval.push_back(currProof);
  443. }
  444. else // CASE: Rerandomize existing vote
  445. {
  446. Proof currProof;
  447. Scalar u, commitmentLambda_1, commitmentLambda_2,
  448. c_n, z_na, z_nb, f;
  449. u.set_random();
  450. commitmentLambda_1.set_random();
  451. commitmentLambda_2.set_random();
  452. c_n.set_random();
  453. z_na.set_random();
  454. z_nb.set_random();
  455. f.set_random();
  456. CurveBipoint U = h * u;
  457. CurveBipoint C_a = g * f +
  458. h * z_na -
  459. newEncryptedVotes[i] * c_n;
  460. CurveBipoint C_b = g * commitmentLambda_1 + h * commitmentLambda_2;
  461. currProof.curveBipointUniversals.push_back(C_b);
  462. Scalar f_c_n = f.curveSub(c_n);
  463. Scalar c_n2_f = c_n.curveAdd(c_n).curveSub(f);
  464. CurveBipoint C_c =
  465. h * z_nb -
  466. newEncryptedVotes[i] * f_c_n.curveMult(c_n2_f) -
  467. C_b * c_n;
  468. oracleInput << U << C_a << C_b << C_c;
  469. Scalar c = oracle(oracleInput.str());
  470. Scalar c_r = c.curveSub(c_n);
  471. currProof.challengeParts.push_back(c_r);
  472. currProof.challengeParts.push_back(c_n);
  473. Scalar z_r = u.curveAdd(c_r.curveMult(seeds[i]));
  474. currProof.responseParts.push_back(z_r);
  475. currProof.responseParts.push_back(f);
  476. currProof.responseParts.push_back(z_na);
  477. currProof.responseParts.push_back(z_nb);
  478. retval.push_back(currProof);
  479. }
  480. }
  481. return retval;
  482. }
  483. bool PrsonaBase::verify_vote_proof(
  484. const CurveBipoint& g,
  485. const CurveBipoint& h,
  486. const std::vector<Proof>& pi,
  487. const std::vector<CurveBipoint>& oldEncryptedVotes,
  488. const std::vector<CurveBipoint>& newEncryptedVotes,
  489. const Curvepoint& freshGenerator,
  490. const Curvepoint& owner) const
  491. {
  492. // Reject outright if there's no proof to check
  493. if (pi.empty())
  494. {
  495. std::cerr << "Proof was empty, aborting." << std::endl;
  496. return false;
  497. }
  498. // Base case
  499. if (!CLIENT_IS_MALICIOUS)
  500. return pi[0].hbc == "PROOF";
  501. // User should be able to prove they are who they say they are
  502. if (!verify_ownership_proof(pi[0], freshGenerator, owner))
  503. {
  504. std::cerr << "Schnorr proof failed, aborting." << std::endl;
  505. return false;
  506. }
  507. /* This proof structure is documented in my notes.
  508. * It's inspired by the proof in Fig. 1 at
  509. * https://eprint.iacr.org/2014/764.pdf, but adapted so that you prove
  510. * m(m-1)(m-2) = 0 instead of m(m-1) = 0.
  511. *
  512. * The rerandomization part is just a slight variation on an
  513. * ordinary Schnorr proof, so that part's less scary. */
  514. for (size_t i = 1; i < pi.size(); i++)
  515. {
  516. size_t voteIndex = i - 1;
  517. CurveBipoint C_b;
  518. C_b = pi[i].curveBipointUniversals[0];
  519. Scalar c_r, c_n, z_r, f, z_na, z_nb;
  520. c_r = pi[i].challengeParts[0];
  521. c_n = pi[i].challengeParts[1];
  522. z_r = pi[i].responseParts[0];
  523. f = pi[i].responseParts[1];
  524. z_na = pi[i].responseParts[2];
  525. z_nb = pi[i].responseParts[3];
  526. CurveBipoint U, C_a, C_c;
  527. U = h * z_r +
  528. oldEncryptedVotes[voteIndex] * c_r -
  529. newEncryptedVotes[voteIndex] * c_r;
  530. C_a = g * f + h * z_na - newEncryptedVotes[voteIndex] * c_n;
  531. Scalar f_c_n = f.curveSub(c_n);
  532. Scalar c_n2_f = c_n.curveAdd(c_n).curveSub(f);
  533. C_c = h * z_nb -
  534. newEncryptedVotes[voteIndex] * f_c_n.curveMult(c_n2_f) -
  535. C_b * c_n;
  536. std::stringstream oracleInput;
  537. oracleInput << g << h
  538. << oldEncryptedVotes[voteIndex] << newEncryptedVotes[voteIndex]
  539. << U << C_a << C_b << C_c;
  540. if (oracle(oracleInput.str()) != c_r.curveAdd(c_n))
  541. return false;
  542. }
  543. return true;
  544. }
  545. /*
  546. * NEW USER PROOFS
  547. */
  548. std::vector<Proof> PrsonaBase::generate_proof_of_added_user(
  549. const Scalar& twistBipointSeed,
  550. const Scalar& EGCiphertextSeed,
  551. const std::vector<Scalar>& curveBipointSelfSeeds,
  552. const std::vector<Scalar>& curveBipointOtherSeeds) const
  553. {
  554. std::vector<Proof> retval;
  555. if (!SERVER_IS_MALICIOUS)
  556. {
  557. retval.push_back(Proof("PROOF"));
  558. return retval;
  559. }
  560. Proof currProof;
  561. currProof.responseParts.push_back(twistBipointSeed);
  562. retval.push_back(currProof);
  563. currProof.responseParts.clear();
  564. currProof.responseParts.push_back(EGCiphertextSeed);
  565. retval.push_back(currProof);
  566. currProof.responseParts.clear();
  567. for (size_t i = 0; i < curveBipointSelfSeeds.size(); i++)
  568. currProof.responseParts.push_back(curveBipointSelfSeeds[i]);
  569. retval.push_back(currProof);
  570. currProof.responseParts.clear();
  571. for (size_t i = 0; i < curveBipointOtherSeeds.size(); i++)
  572. currProof.responseParts.push_back(curveBipointOtherSeeds[i]);
  573. retval.push_back(currProof);
  574. return retval;
  575. }
  576. bool PrsonaBase::verify_proof_of_added_user(
  577. const std::vector<Proof>& pi,
  578. const Curvepoint& currentFreshGenerator,
  579. const Curvepoint& shortTermPublicKey,
  580. const Curvepoint& elGamalBlindGenerator,
  581. const CurveBipoint& curveG,
  582. const CurveBipoint& curveH,
  583. const TwistBipoint& twistG,
  584. const TwistBipoint& twistH,
  585. size_t selfIndex,
  586. const EGCiphertext& userEncryptedScore,
  587. const TwistBipoint& serverEncryptedScore,
  588. const std::vector<std::vector<CurveBipoint>> encryptedVoteMatrix) const
  589. {
  590. if (pi.empty())
  591. {
  592. std::cerr << "Proof empty." << std::endl;
  593. return false;
  594. }
  595. if (!SERVER_IS_MALICIOUS)
  596. return pi[0].hbc == "PROOF";
  597. Scalar currSeed = pi[0].responseParts[0];
  598. if (serverEncryptedScore !=
  599. twistG * DEFAULT_TALLY + twistH * currSeed)
  600. {
  601. std::cerr << "Issue in server encrypted score." << std::endl;
  602. return false;
  603. }
  604. currSeed = pi[1].responseParts[0];
  605. if (userEncryptedScore.mask != shortTermPublicKey * currSeed)
  606. {
  607. std::cerr << "Issue in user encrypted score: mask." << std::endl;
  608. return false;
  609. }
  610. if (userEncryptedScore.encryptedMessage !=
  611. currentFreshGenerator * currSeed + elGamalBlindGenerator * DEFAULT_TALLY)
  612. {
  613. std::cerr << "Issue in user encrypted score: value." << std::endl;
  614. return false;
  615. }
  616. for (size_t i = 0; i < pi[2].responseParts.size(); i++)
  617. {
  618. CurveBipoint currVote = encryptedVoteMatrix[selfIndex][i];
  619. currSeed = pi[2].responseParts[i];
  620. if (i == selfIndex)
  621. {
  622. if (currVote !=
  623. curveG * Scalar(MAX_ALLOWED_VOTE) + curveH * currSeed)
  624. {
  625. std::cerr << "Issue in self vote." << std::endl;
  626. return false;
  627. }
  628. }
  629. else
  630. {
  631. if (currVote !=
  632. curveG * DEFAULT_VOTE + curveH * currSeed)
  633. {
  634. std::cerr << "Issue in vote by verifier for user " << i + 1
  635. << " of " << pi[2].responseParts.size() << "." << std::endl;
  636. return false;
  637. }
  638. }
  639. }
  640. for (size_t i = 0; i < pi[3].responseParts.size(); i++)
  641. {
  642. CurveBipoint currVote = encryptedVoteMatrix[i][selfIndex];
  643. currSeed = pi[3].responseParts[i];
  644. if (i != selfIndex)
  645. {
  646. if (currVote !=
  647. curveG * DEFAULT_VOTE + curveH * currSeed)
  648. {
  649. std::cerr << "Issue in vote for verifier by user " << i + 1
  650. << " of " << pi[3].responseParts.size() << "." << std::endl;
  651. return false;
  652. }
  653. }
  654. }
  655. return true;
  656. }
  657. /*
  658. * EPOCH PROOFS
  659. */
  660. Proof PrsonaBase::generate_proof_of_correct_tally() const
  661. {
  662. Proof retval;
  663. if (!SERVER_IS_MALICIOUS)
  664. {
  665. retval.hbc = "PROOF";
  666. return retval;
  667. }
  668. retval.hbc = "PROOF";
  669. return retval;
  670. }
  671. Proof PrsonaBase::generate_proof_of_correct_sum() const
  672. {
  673. Proof retval;
  674. if (!SERVER_IS_MALICIOUS)
  675. {
  676. retval.hbc = "PROOF";
  677. return retval;
  678. }
  679. retval.hbc = "PROOF";
  680. return retval;
  681. }
  682. Proof PrsonaBase::generate_proof_of_shuffle() const
  683. {
  684. Proof retval;
  685. if (!SERVER_IS_MALICIOUS)
  686. {
  687. retval.hbc = "PROOF";
  688. return retval;
  689. }
  690. retval.hbc = "PROOF";
  691. return retval;
  692. }
  693. bool PrsonaBase::verify_update_proof(
  694. const Proof& pi) const
  695. {
  696. if (!SERVER_IS_MALICIOUS)
  697. return pi.hbc == "PROOF";
  698. return pi.hbc == "PROOF";
  699. }
  700. /*
  701. * SERVER AGREEMENT PROOFS
  702. */
  703. Proof PrsonaBase::generate_valid_vote_row_proof(
  704. const 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. oracleInput << commitment[i];
  715. Scalar val = oracle(oracleInput.str());
  716. retval.responseParts.push_back(val);
  717. return retval;
  718. }
  719. Proof PrsonaBase::generate_valid_vote_matrix_proof(
  720. const std::vector<std::vector<CurveBipoint>>& commitment) const
  721. {
  722. Proof retval;
  723. if (!SERVER_IS_MALICIOUS)
  724. {
  725. retval.hbc = "PROOF";
  726. return retval;
  727. }
  728. std::stringstream oracleInput;
  729. for (size_t i = 0; i < commitment.size(); i++)
  730. for (size_t j = 0; j < commitment[i].size(); j++)
  731. oracleInput << commitment[i][j];
  732. Scalar val = oracle(oracleInput.str());
  733. retval.responseParts.push_back(val);
  734. return retval;
  735. }
  736. Proof PrsonaBase::generate_valid_user_tally_proof(
  737. const EGCiphertext& commitment) const
  738. {
  739. Proof retval;
  740. if (!SERVER_IS_MALICIOUS)
  741. {
  742. retval.hbc = "PROOF";
  743. return retval;
  744. }
  745. std::stringstream oracleInput;
  746. oracleInput << commitment;
  747. Scalar val = oracle(oracleInput.str());
  748. retval.responseParts.push_back(val);
  749. return retval;
  750. }
  751. Proof PrsonaBase::generate_valid_server_tally_proof(
  752. const TwistBipoint& commitment) const
  753. {
  754. Proof retval;
  755. if (!SERVER_IS_MALICIOUS)
  756. {
  757. retval.hbc = "PROOF";
  758. return retval;
  759. }
  760. std::stringstream oracleInput;
  761. oracleInput << commitment;
  762. Scalar val = oracle(oracleInput.str());
  763. retval.responseParts.push_back(val);
  764. return retval;
  765. }
  766. Proof PrsonaBase::generate_valid_pseudonyms_proof(
  767. const std::vector<Curvepoint>& commitment) const
  768. {
  769. Proof retval;
  770. if (!SERVER_IS_MALICIOUS)
  771. {
  772. retval.hbc = "PROOF";
  773. return retval;
  774. }
  775. std::stringstream oracleInput;
  776. for (size_t i = 0; i < commitment.size(); i++)
  777. oracleInput << commitment[i];
  778. Scalar val = oracle(oracleInput.str());
  779. retval.responseParts.push_back(val);
  780. return retval;
  781. }
  782. bool PrsonaBase::verify_valid_vote_row_proof(
  783. const std::vector<Proof>& pi,
  784. const std::vector<CurveBipoint>& commitment) const
  785. {
  786. if (pi.empty())
  787. return false;
  788. if (!SERVER_IS_MALICIOUS)
  789. return pi[0].hbc == "PROOF";
  790. Scalar comparison = pi[0].responseParts[0];
  791. std::stringstream oracleInput;
  792. for (size_t i = 0; i < commitment.size(); i++)
  793. oracleInput << commitment[i];
  794. if (oracle(oracleInput.str()) != comparison)
  795. {
  796. std::cerr << "Server's claimed value doesn't match their own commitment." << std::endl;
  797. return false;
  798. }
  799. size_t agreement = 1;
  800. for (size_t i = 1; i < pi.size(); i++)
  801. if (comparison == pi[i].responseParts[0])
  802. agreement++;
  803. return agreement * 2 > pi.size();
  804. }
  805. bool PrsonaBase::verify_valid_vote_matrix_proof(
  806. const std::vector<Proof>& pi,
  807. const std::vector<std::vector<CurveBipoint>>& commitment) const
  808. {
  809. if (pi.empty())
  810. return false;
  811. if (!SERVER_IS_MALICIOUS)
  812. return pi[0].hbc == "PROOF";
  813. Scalar comparison = pi[0].responseParts[0];
  814. std::stringstream oracleInput;
  815. for (size_t i = 0; i < commitment.size(); i++)
  816. for (size_t j = 0; j < commitment[i].size(); j++)
  817. oracleInput << commitment[i][j];
  818. if (oracle(oracleInput.str()) != comparison)
  819. {
  820. std::cerr << "Server's claimed value doesn't match their own commitment." << std::endl;
  821. return false;
  822. }
  823. size_t agreement = 1;
  824. for (size_t i = 1; i < pi.size(); i++)
  825. if (comparison == pi[i].responseParts[0])
  826. agreement++;
  827. return agreement * 2 > pi.size();
  828. }
  829. bool PrsonaBase::verify_valid_user_tally_proof(
  830. const std::vector<Proof>& pi,
  831. const EGCiphertext& commitment) const
  832. {
  833. if (pi.empty())
  834. return false;
  835. if (!SERVER_IS_MALICIOUS)
  836. return pi[0].hbc == "PROOF";
  837. Scalar comparison = pi[0].responseParts[0];
  838. std::stringstream oracleInput;
  839. oracleInput << commitment;
  840. if (oracle(oracleInput.str()) != comparison)
  841. {
  842. std::cerr << "Server's claimed value doesn't match their own commitment." << std::endl;
  843. return false;
  844. }
  845. size_t agreement = 1;
  846. for (size_t i = 1; i < pi.size(); i++)
  847. if (comparison == pi[i].responseParts[0])
  848. agreement++;
  849. return agreement * 2 > pi.size();
  850. }
  851. bool PrsonaBase::verify_valid_server_tally_proof(
  852. const std::vector<Proof>& pi,
  853. const TwistBipoint& commitment) const
  854. {
  855. if (pi.empty())
  856. return false;
  857. if (!SERVER_IS_MALICIOUS)
  858. return pi[0].hbc == "PROOF";
  859. Scalar comparison = pi[0].responseParts[0];
  860. std::stringstream oracleInput;
  861. oracleInput << commitment;
  862. if (oracle(oracleInput.str()) != comparison)
  863. {
  864. std::cerr << "Server's claimed value doesn't match their own commitment." << std::endl;
  865. return false;
  866. }
  867. size_t agreement = 1;
  868. for (size_t i = 1; i < pi.size(); i++)
  869. if (comparison == pi[i].responseParts[0])
  870. agreement++;
  871. return agreement * 2 > pi.size();
  872. }
  873. bool PrsonaBase::verify_valid_pseudonyms_proof(
  874. const std::vector<Proof>& pi,
  875. const std::vector<Curvepoint>& commitment) const
  876. {
  877. if (pi.empty())
  878. return false;
  879. if (!SERVER_IS_MALICIOUS)
  880. return pi[0].hbc == "PROOF";
  881. Scalar comparison = pi[0].responseParts[0];
  882. std::stringstream oracleInput;
  883. for (size_t i = 0; i < commitment.size(); i++)
  884. oracleInput << commitment[i];
  885. if (oracle(oracleInput.str()) != comparison)
  886. {
  887. std::cerr << "Server's claimed value doesn't match their own commitment." << std::endl;
  888. return false;
  889. }
  890. size_t agreement = 1;
  891. for (size_t i = 1; i < pi.size(); i++)
  892. if (comparison == pi[i].responseParts[0])
  893. agreement++;
  894. return agreement * 2 > pi.size();
  895. }