proofs.service.spec.lib.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. /*
  2. * Copyright 2018 Scytl Secure Electronic Voting SA
  3. *
  4. * All rights reserved
  5. *
  6. * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
  7. */
  8. // The global namespace pollution and other glaring violations of anything
  9. // resembling best practices is due to the intended short-livedness of this
  10. // implementation.
  11. var MAX_EXPONENT_BYTES = 2;
  12. var PROGRESS_PERCENT_MIN_CHECK_INTERVAL = 10;
  13. var GENERATOR =
  14. '21303916314604998551484796420422871007468543247831789236879215369694842734099405650535148287249791144057375987697205687518340016316179892851284240278138045703633698036256611527988640313051528625117090689542380890153876064768602704006774164341226969138952495075758675629665109761968589385514561688161321002676900768077022957299407868881468752268501397255241070908793893954188678747644443826465068701078202311876709764302561277744548084228639372458598925393551439452959527949768006498598646518365505226629313181567048632516237514971091380204424481498506499338185144271546651990709723565928420753129878206710329253950578';
  15. var P =
  16. '25701322016688441576103032148674110774925156427397637132202577741938936247112125492211659378990027134829873026348759004510642939209382852797923423233606398455768339503774439196473285206499419017249519687083918862292745452369770073017370862703937184066962152692474974647384317528679859283948201449898123774491462507974828236623365121967170401847974506359775053259024902177376974036791676038887180065668218851769610708183278395407393103098286493672450097566567641277262751905925272593655979627326843104589717100845609213331825322091528671293329804211235906640910489075537455976735341285644494144220105240375300711488393';
  17. var Q =
  18. '81259987775362040571620137377019110900790585487969528507141757273696249070213';
  19. var ANOTHER_GENERATOR =
  20. '9484337033848536557358945372517536146444081505783459082983213315915020922388822299017798461933010391712259501201285084235930755858547311934865298396110947362913733900057881561201738951725697128822802249693116611294569213895789823297341865759919045291915705783128173481781221176839434866976235031358969583527093743179257827355453820268832913547364509208164670680381449515691300440305333919098105147193087681183020489724214850151272955879869448467832934822639783688344322183540621808345771717172404141548242866493539424279296365911355186761897533654055060787119955689115570505208857288933136456026541073605147828202749';
  21. var ANOTHER_P =
  22. '22115396014581083143553195792384915983375949993753365299824374182778648887213105675373952839695834312125954513956465041609718392131788741228259266178434294275575978809365653903991346366383637500069010795276889266879661859362340655085050484891149389971190945080643692669920059928787982790808824970597361825060408436004650739931286605415552480363242364319544423959620330010413847743583301091182870021747196927889763205955078275353307312408480155002017730305672359814713050632922694161739281353676187308501682728826507718002850698488786266115311952718697872338756199429262811547458969260835283688979875294699655014592833';
  23. var ANOTHER_Q =
  24. '79783631514788897688995869254536231266441581267248557197866166084121363399063';
  25. var _converters;
  26. var _keyFactory;
  27. var _elGamalCipherFactory;
  28. var _g;
  29. var _p;
  30. var _q;
  31. var _zpSubgroup;
  32. var _anotherZpSubgroup;
  33. var _progressPercentSum;
  34. var _progressPercentLatest;
  35. var isInitialized = false;
  36. function initializeTestVars() {
  37. if (!isInitialized) {
  38. cryptolib(
  39. 'commons.mathematical', 'commons.utils', 'homomorphic.keypair',
  40. 'homomorphic.cipher', function(box) {
  41. _converters = new box.commons.utils.Converters();
  42. _keyFactory = new box.homomorphic.keypair.factory.KeyFactory();
  43. _elGamalCipherFactory =
  44. new box.homomorphic.cipher.factory.ElGamalCipherFactory();
  45. _g = new box.forge.jsbn.BigInteger(GENERATOR);
  46. _p = new box.forge.jsbn.BigInteger(P);
  47. _q = new box.forge.jsbn.BigInteger(Q);
  48. _zpSubgroup = new box.commons.mathematical.ZpSubgroup(_g, _p, _q);
  49. var g = new box.forge.jsbn.BigInteger(ANOTHER_GENERATOR);
  50. var p = new box.forge.jsbn.BigInteger(ANOTHER_P);
  51. var q = new box.forge.jsbn.BigInteger(ANOTHER_Q);
  52. _anotherZpSubgroup = new box.commons.mathematical.ZpSubgroup(g, p, q);
  53. initializeProgressMeter();
  54. });
  55. isInitialized = true;
  56. }
  57. }
  58. function generateRandomInteger(min, max) {
  59. return Math.floor(Math.random() * (max - min + 1)) + min;
  60. }
  61. function generateRandomString(length) {
  62. var charset = 'abcdefghijklmnopqrstuvwxyz0123456789';
  63. var string = '';
  64. for (var i = 0; i < length; i++)
  65. string += charset.charAt(Math.floor(Math.random() * charset.length));
  66. return string;
  67. }
  68. function generateRandomExponent(zpSubgroup) {
  69. var exponent;
  70. cryptolib('commons.mathematical', function(box) {
  71. do {
  72. var randomInt = new box.forge.jsbn.BigInteger(
  73. box.forge.random.getBytes(MAX_EXPONENT_BYTES));
  74. exponent =
  75. new box.commons.mathematical.Exponent(zpSubgroup.getQ(), randomInt);
  76. } while (exponent.getValue().equals(box.forge.jsbn.BigInteger.ZERO));
  77. });
  78. return exponent;
  79. }
  80. function generateRandomGroupElement(zpSubgroup) {
  81. var element = zpSubgroup.getGenerator().exponentiate(
  82. generateRandomExponent(zpSubgroup));
  83. cryptolib('commons.exceptions', function(box) {
  84. if (!zpSubgroup.isGroupMember(element)) {
  85. throw new box.commons.exceptions.CryptoLibException(
  86. 'Randomly generated element is not a member of the required mathematical group');
  87. }
  88. });
  89. return element;
  90. }
  91. function generateExponentiatedElements(baseElements, exponent) {
  92. var exponentiatedElements = [];
  93. for (var i = 0; i < baseElements.length; i++) {
  94. var element = baseElements[i].exponentiate(exponent);
  95. exponentiatedElements.push(element);
  96. }
  97. return exponentiatedElements;
  98. }
  99. function generatePlaintext(numElements) {
  100. var plaintext = [];
  101. var element = generateRandomGroupElement(_zpSubgroup);
  102. plaintext.push(element);
  103. for (var i = 1; i < numElements; i++) {
  104. element = generateRandomGroupElement(_zpSubgroup);
  105. plaintext.push(element);
  106. }
  107. return plaintext;
  108. }
  109. function generateSimplePlaintext(numElements) {
  110. var plaintext = [];
  111. cryptolib('commons.exceptions', function(box) {
  112. if ((numElements % 2) !== 0) {
  113. throw new box.commons.exceptions.CryptoLibException(
  114. 'Plaintext must have even number of elements for simple plaintext equality proof generation.');
  115. }
  116. // Note that all elements of a simple plaintext must have the same value.
  117. var element = generateRandomGroupElement(_zpSubgroup);
  118. for (var i = 0; i < numElements; i++) {
  119. plaintext.push(element);
  120. }
  121. });
  122. return plaintext;
  123. }
  124. function generateNonSimplePlaintext(numElements) {
  125. var plaintext = [];
  126. var element = generateRandomGroupElement(_zpSubgroup);
  127. plaintext.push(element);
  128. for (var i = 1; i < numElements; i++) {
  129. do {
  130. element = generateRandomGroupElement(_zpSubgroup);
  131. } while (
  132. element.getElementValue().equals(plaintext[i - 1].getElementValue()));
  133. plaintext.push(element);
  134. }
  135. return plaintext;
  136. }
  137. function generateElGamalKeyPair(numElements) {
  138. var elements = [];
  139. var exponents = [];
  140. var exponent = generateRandomExponent(_zpSubgroup);
  141. var element = _zpSubgroup.getGenerator().exponentiate(exponent);
  142. exponents.push(exponent);
  143. elements.push(element);
  144. for (var i = 1; i < numElements; i++) {
  145. exponent = generateRandomExponent(_zpSubgroup);
  146. element = _zpSubgroup.getGenerator().exponentiate(exponent);
  147. exponents.push(exponent);
  148. elements.push(element);
  149. }
  150. var elGamalPublicKey = _keyFactory.createPublicKey(elements, _zpSubgroup);
  151. var elGamalPrivateKey = _keyFactory.createPrivateKey(exponents, _zpSubgroup);
  152. return _keyFactory.createKeyPair(elGamalPublicKey, elGamalPrivateKey);
  153. }
  154. function generateCiphertext(publicKey, plaintext) {
  155. var encrypter = _elGamalCipherFactory.createEncrypter(publicKey);
  156. return encrypter.encryptGroupElements(plaintext);
  157. }
  158. function generateExponentCiphertext(
  159. plaintext, primaryWitness, secondaryWitness) {
  160. var ciphertext;
  161. cryptolib('commons.exceptions', 'homomorphic.cipher', function(box) {
  162. var plaintextLength = plaintext.length;
  163. if ((plaintextLength % 2) === 0) {
  164. throw new box.commons.exceptions.CryptoLibException(
  165. 'Plaintext must have odd number of elements for plaintext exponent equality proof generation.');
  166. }
  167. var numCiphertextElements = ((plaintextLength - 1) / 2) + 1;
  168. var exponents = [];
  169. exponents.push(primaryWitness);
  170. exponents.push(secondaryWitness);
  171. var gamma = plaintext[0].exponentiate(exponents[0]);
  172. var phis = [];
  173. for (var i = 0; i < (numCiphertextElements - 1); i++) {
  174. var phi = plaintext[i + 1].exponentiate(exponents[0]);
  175. phi = phi.multiply(
  176. plaintext[i + numCiphertextElements].exponentiate(exponents[1]));
  177. phis.push(phi);
  178. }
  179. ciphertext =
  180. new box.homomorphic.cipher.ElGamalEncrypterValues(null, gamma, phis);
  181. });
  182. return ciphertext;
  183. }
  184. function getSubElGamalPublicKey(publicKey, fromIndex, toIndex) {
  185. var elements = publicKey.getGroupElementsArray();
  186. var subElements = [];
  187. for (var i = fromIndex; i < toIndex; i++) {
  188. subElements.push(elements[i]);
  189. }
  190. return _keyFactory.createPublicKey(subElements, _zpSubgroup);
  191. }
  192. function getSubCiphertext(encrypterValues, fromIndex, toIndex) {
  193. var subCiphertext;
  194. cryptolib('homomorphic.cipher', function(box) {
  195. var exponent = encrypterValues.getR();
  196. var gamma = encrypterValues.getGamma();
  197. var phis = encrypterValues.getPhis();
  198. var subPhis = [];
  199. for (var i = fromIndex; i < toIndex; i++) {
  200. subPhis.push(phis[i]);
  201. }
  202. subCiphertext = new box.homomorphic.cipher.ElGamalEncrypterValues(
  203. exponent, gamma, subPhis);
  204. });
  205. return subCiphertext;
  206. }
  207. function initializeProgressMeter() {
  208. _progressPercentSum = 0;
  209. _progressPercentLatest = 0;
  210. }
  211. function progressCallback(progressPercent) {
  212. _progressPercentSum += progressPercent;
  213. _progressPercentLatest = progressPercent;
  214. };
  215. function getProgressPercentSum(numChecks, minCheckInterval) {
  216. var percent = 0;
  217. var lastPercent = 0;
  218. var percentChange = 0;
  219. var incrementPercentSum = false;
  220. var percentSum = 0;
  221. for (var i = 0; i < numChecks; i++) {
  222. percent = Math.floor(((i + 1) / numChecks) * 100);
  223. percent = Math.min(percent, 100);
  224. percentChange = percent - lastPercent;
  225. if (percentChange > 0) {
  226. incrementPercentSum =
  227. (percentChange >= minCheckInterval) || (percent === 100);
  228. if (incrementPercentSum) {
  229. lastPercent = percent;
  230. percentSum += percent;
  231. }
  232. }
  233. }
  234. return percentSum;
  235. }