homomorphic.service.spec.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  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. describe('Homomorphic service...', function() {
  9. 'use strict';
  10. var MAX_EXPONENT_BYTES = 2;
  11. var NUM_GROUP_ELEMENTS = 2;
  12. var NUM_SINGLE_GROUP_ELEMENTS = 5;
  13. var G_STR = '2';
  14. var P_STR = '23';
  15. var Q_STR = '11';
  16. var ELEMENT_1_STR = '2';
  17. var ELEMENT_2_STR = '4';
  18. var EXPONENT_1_STR = '1';
  19. var EXPONENT_2_STR = '2';
  20. var P_LARGE_STR =
  21. '22588801568735561413035633152679913053449200833478689904902877673687016391844561133376032309307885537704777240609087377993341380751697605235541131273868440070920362148431866829787784445019147999379498503693247429579480289226602748397335327890884464685051682703709742724121783217827040722415360103179289160056581759372475845985438977307323570530753362027145384124771826114651710264766437273044759690955051982839684910462609395741692689616014805965573558015387956017183286848440036954926101719205598449898400180082053755864070690174202432196678045052744337832802051787273056312757384654145455745603262082348042780103679';
  22. var Q_LARGE_STR =
  23. '11294400784367780706517816576339956526724600416739344952451438836843508195922280566688016154653942768852388620304543688996670690375848802617770565636934220035460181074215933414893892222509573999689749251846623714789740144613301374198667663945442232342525841351854871362060891608913520361207680051589644580028290879686237922992719488653661785265376681013572692062385913057325855132383218636522379845477525991419842455231304697870846344808007402982786779007693978008591643424220018477463050859602799224949200090041026877932035345087101216098339022526372168916401025893636528156378692327072727872801631041174021390051839';
  24. var ELEMENT_1_LARGE_STR =
  25. '8008650650117182055231947796743510595354735701773678127718063162818861428894482760351040442014062206238677757186380515026469824595870224783896120627455841205517047520359887236518609328142965980653129280864098892996273964740090483597375107437139254412471355470548193136206727124381287524666926794272344682267309880188101372142121235759763117992716726731820970068223350454790098901032607754554402031099573358614926437378953856998041036773132081351057601842441454945388068039731483320814325657715553744820319265534754357498649904400594493834709761403358903505501640705996603619499187129497007221246019054462834616450362';
  26. var ELEMENT_2_LARGE_STR =
  27. '11633656285653208443919333339470607846301429932894308783457570029107286147936455427826899303856584843544699293627942560893304455970515082299498680026759665698080990494885992738624255552297867735585728427220214607212173788862760053487198296321130486607904876481443447070538549541504734530736112052175501932133880661864111558469545768002897528612084034669926036569715266022136440126595140089621370735885927146016552642348282420224106653601826235849885956583427798077317966671703306684815012981357245529568157986211578924579799810305712551845266909314082456551659795959581952216679219662533353585637849875985836675331118';
  28. var EXPONENT_1_LARGE_STR =
  29. '2310427452287266604038074581830299484831755686607108413899820257798165596547227594518989253178264380941033095268581246346863002280809127490132335557543545847332023813499454886051935043363376517658050024793517465349562106228739828060169613880190064891580719513382177220752409776280150551117185655930834371803832590064152233876708731218969195345490200219499344738664373593917843352485459832349992908261365788172930979823955846952949156058247067965643074532679047274706566088888021355575983368719069681293419346162608049979977471053590745499346591475991673763640645139343249862033377744682868210594034732021779460567412';
  30. var EXPONENT_2_LARGE_STR =
  31. '7533608948657130117198364792462971241599837777629317286887202126604432685322243335715285630236984093165224740099563982076007648728594011814311120331313200895892632245003875959905589367483155794698953057915454892457379023058909518440394905695255170407948701433659375513788930419544151891518689331636455316691827048845766063478445484089208223819510250476623436782404385896353292653750744111841510466992101967325081746747885221256692886521245630131046183525331085171958919416648097910028887247120874015121272894655357197879292253781160838729753609784455892951965051119314203469298666741439497193677501351952497150273389';
  32. var _initialized = false;
  33. var _elGamalPublicKey;
  34. var _elGamalPrivateKey;
  35. var _elGamalEncrypter;
  36. var _elGamalDecrypter;
  37. var _elGamalKeyPair;
  38. var _zpSubgroup;
  39. var _zpGroupElements;
  40. var _elGamalPublicKeyLarge;
  41. var _elGamalPrivateKeyLarge;
  42. var _elGamalEncrypterLarge;
  43. var _elGamalDecrypterLarge;
  44. var _zpGroupElementsLarge;
  45. var _zpGroupElementsLargeNonQR;
  46. var _singleZpGroupElements;
  47. var _elGamalEncrypterUsingSeed;
  48. var _elGamalRandomDecrypter;
  49. beforeEach(function() {
  50. if (!_initialized) {
  51. cryptolib(
  52. 'commons.utils', 'commons.mathematical', 'homomorphic.service',
  53. function(box) {
  54. var converters = new box.commons.utils.Converters();
  55. var gB64 = converters.base64FromBigInteger(
  56. new forge.jsbn.BigInteger(G_STR));
  57. var pB64 = converters.base64FromBigInteger(
  58. new forge.jsbn.BigInteger(P_STR));
  59. var qB64 = converters.base64FromBigInteger(
  60. new forge.jsbn.BigInteger(Q_STR));
  61. var element1B64 = converters.base64FromBigInteger(
  62. new forge.jsbn.BigInteger(ELEMENT_1_STR));
  63. var element2B64 = converters.base64FromBigInteger(
  64. new forge.jsbn.BigInteger(ELEMENT_2_STR));
  65. var exponent1B64 = converters.base64FromBigInteger(
  66. new forge.jsbn.BigInteger(EXPONENT_1_STR));
  67. var exponent2B64 = converters.base64FromBigInteger(
  68. new forge.jsbn.BigInteger(EXPONENT_2_STR));
  69. var elGamalPublicKeyJson = '{"publicKey":{"zpSubgroup":{"g":"' +
  70. gB64 + '","p":"' + pB64 + '","q":"' + qB64 +
  71. '"},"elements":["' + element1B64 + '","' + element2B64 + '"]}}';
  72. var elGamalPrivateKeyJson = '{"privateKey":{"zpSubgroup":{"g":"' +
  73. gB64 + '","p":"' + pB64 + '","q":"' + qB64 +
  74. '"},"exponents":["' + exponent1B64 + '","' + exponent2B64 +
  75. '"]}}';
  76. var elGamalPublicKeyJsonB64 =
  77. converters.base64Encode(elGamalPublicKeyJson);
  78. var elGamalPrivateKeyJsonB64 =
  79. converters.base64Encode(elGamalPrivateKeyJson);
  80. _elGamalPublicKey = box.homomorphic.service.createElGamalPublicKey(
  81. elGamalPublicKeyJsonB64);
  82. _elGamalPrivateKey =
  83. box.homomorphic.service.createElGamalPrivateKey(
  84. elGamalPrivateKeyJsonB64);
  85. _elGamalKeyPair = new box.homomorphic.service.createElGamalKeyPair(
  86. _elGamalPublicKey, _elGamalPrivateKey);
  87. _elGamalEncrypter =
  88. box.homomorphic.service.createEncrypter(_elGamalPublicKey);
  89. _elGamalDecrypter =
  90. box.homomorphic.service.createDecrypter(_elGamalPrivateKey);
  91. var g = new box.forge.jsbn.BigInteger(G_STR);
  92. var p = new box.forge.jsbn.BigInteger(P_STR);
  93. var q = new box.forge.jsbn.BigInteger(Q_STR);
  94. _zpSubgroup = new box.commons.mathematical.ZpSubgroup(g, p, q);
  95. _zpGroupElements =
  96. generateGroupElements(_zpSubgroup, NUM_GROUP_ELEMENTS);
  97. gB64 = converters.base64FromBigInteger(
  98. new forge.jsbn.BigInteger(G_STR));
  99. pB64 = converters.base64FromBigInteger(
  100. new forge.jsbn.BigInteger(P_LARGE_STR));
  101. qB64 = converters.base64FromBigInteger(
  102. new forge.jsbn.BigInteger(Q_LARGE_STR));
  103. element1B64 = converters.base64FromBigInteger(
  104. new forge.jsbn.BigInteger(ELEMENT_1_LARGE_STR));
  105. element2B64 = converters.base64FromBigInteger(
  106. new forge.jsbn.BigInteger(ELEMENT_2_LARGE_STR));
  107. exponent1B64 = converters.base64FromBigInteger(
  108. new forge.jsbn.BigInteger(EXPONENT_1_LARGE_STR));
  109. exponent2B64 = converters.base64FromBigInteger(
  110. new forge.jsbn.BigInteger(EXPONENT_2_LARGE_STR));
  111. var elGamalPublicKeyLargeJson =
  112. '{"publicKey":{"zpSubgroup":{"g":"' + gB64 + '","p":"' + pB64 +
  113. '","q":"' + qB64 + '"},"elements":["' + element1B64 + '","' +
  114. element2B64 + '"]}}';
  115. var elGamalPrivateKeyLargeJson =
  116. '{"privateKey":{"zpSubgroup":{"g":"' + gB64 + '","p":"' + pB64 +
  117. '","q":"' + qB64 + '"},"exponents":["' + exponent1B64 + '","' +
  118. exponent2B64 + '"]}}';
  119. var elGamalPublicKeyLargeJsonB64 =
  120. converters.base64Encode(elGamalPublicKeyLargeJson);
  121. var elGamalPrivateKeyLargeJsonB64 =
  122. converters.base64Encode(elGamalPrivateKeyLargeJson);
  123. _elGamalPublicKeyLarge =
  124. box.homomorphic.service.createElGamalPublicKey(
  125. elGamalPublicKeyLargeJsonB64);
  126. _elGamalPrivateKeyLarge =
  127. box.homomorphic.service.createElGamalPrivateKey(
  128. elGamalPrivateKeyLargeJsonB64);
  129. _elGamalEncrypterLarge =
  130. box.homomorphic.service.createEncrypter(_elGamalPublicKeyLarge);
  131. _elGamalDecrypterLarge = box.homomorphic.service.createDecrypter(
  132. _elGamalPrivateKeyLarge);
  133. g = new box.forge.jsbn.BigInteger(G_STR);
  134. p = new box.forge.jsbn.BigInteger(P_LARGE_STR);
  135. q = new box.forge.jsbn.BigInteger(Q_LARGE_STR);
  136. var zpSubgroup = new box.commons.mathematical.ZpSubgroup(g, p, q);
  137. _zpGroupElementsLarge =
  138. generateGroupElements(zpSubgroup, NUM_GROUP_ELEMENTS);
  139. g = new box.forge.jsbn.BigInteger(G_STR);
  140. p = new box.forge.jsbn.BigInteger(P_LARGE_STR);
  141. q = new box.forge.jsbn.BigInteger(Q_LARGE_STR)
  142. .subtract(box.forge.jsbn.BigInteger.ONE);
  143. zpSubgroup = new box.commons.mathematical.ZpSubgroup(g, p, q);
  144. _zpGroupElementsLargeNonQR =
  145. generateGroupElements(zpSubgroup, NUM_GROUP_ELEMENTS);
  146. g = new box.forge.jsbn.BigInteger(G_STR);
  147. p = new box.forge.jsbn.BigInteger(P_LARGE_STR);
  148. q = new box.forge.jsbn.BigInteger(Q_LARGE_STR);
  149. zpSubgroup = new box.commons.mathematical.ZpSubgroup(g, p, q);
  150. _singleZpGroupElements =
  151. generateGroupElements(zpSubgroup, NUM_SINGLE_GROUP_ELEMENTS);
  152. });
  153. _initialized = true;
  154. }
  155. cryptolib('primitives.service', 'homomorphic.service', function(box) {
  156. // Generate seed and define callback function to initialize random
  157. // integer generator with seed.
  158. var seedHex = cryptoPRNG.generateRandomSeedInHex();
  159. var cryptoRandomInteger;
  160. var initRandomGenerator = function(box) {
  161. cryptoRandomInteger = box.primitives.service.getCryptoRandomInteger();
  162. };
  163. // Create new encrypter that uses random integer generator initialized
  164. // with seed.
  165. initRandomGenerator.prng = cryptoPRNG.createPRNGFromSeed(seedHex);
  166. cryptolib('primitives.service', initRandomGenerator);
  167. _elGamalEncrypterUsingSeed = box.homomorphic.service.createEncrypter(
  168. _elGamalPublicKeyLarge, cryptoRandomInteger);
  169. // Create new decrypter that uses random integer generator initialized
  170. // with seed.
  171. initRandomGenerator.prng = cryptoPRNG.createPRNGFromSeed(seedHex);
  172. cryptolib('primitives.service', initRandomGenerator);
  173. _elGamalRandomDecrypter = box.homomorphic.service.createRandomDecrypter(
  174. _elGamalPublicKeyLarge, cryptoRandomInteger);
  175. });
  176. });
  177. describe('should be able to ..', function() {
  178. it('create an ElGamal key pair', function() {
  179. validateElGamalPublicKey(_elGamalKeyPair.getPublicKey());
  180. validateElGamalPrivateKey(_elGamalKeyPair.getPrivateKey());
  181. });
  182. it('and create an ElGamal encrypter', function() {
  183. validateElGamalPublicKey(_elGamalEncrypter.getElGamalPublicKey());
  184. });
  185. it('and create an ElGamal decrypter', function() {
  186. validateElGamalPrivateKey(_elGamalDecrypter.getElGamalPrivateKey());
  187. });
  188. it('and deserialize an ElGamal public key', function() {
  189. expect(_elGamalPublicKey.getGroup()
  190. .getGenerator()
  191. .getElementValue()
  192. .toString())
  193. .toEqual(G_STR);
  194. expect(_elGamalPublicKey.getGroup().getP().toString()).toEqual(P_STR);
  195. expect(_elGamalPublicKey.getGroup().getQ().toString()).toEqual(Q_STR);
  196. expect(_elGamalPublicKey.getGroupElementsArray().length).toEqual(2);
  197. expect(_elGamalPublicKey.getGroupElementsArray()[0]
  198. .getElementValue()
  199. .toString())
  200. .toEqual(ELEMENT_1_STR);
  201. expect(_elGamalPublicKey.getGroupElementsArray()[1]
  202. .getElementValue()
  203. .toString())
  204. .toEqual(ELEMENT_2_STR);
  205. });
  206. it('and deserialize an ElGamal private key', function() {
  207. expect(_elGamalPrivateKey.getGroup()
  208. .getGenerator()
  209. .getElementValue()
  210. .toString())
  211. .toEqual(G_STR);
  212. expect(_elGamalPrivateKey.getGroup().getP().toString()).toEqual(P_STR);
  213. expect(_elGamalPrivateKey.getGroup().getQ().toString()).toEqual(Q_STR);
  214. expect(_elGamalPrivateKey.getExponentsArray().length).toEqual(2);
  215. expect(_elGamalPrivateKey.getExponentsArray()[0].getValue().toString())
  216. .toEqual(EXPONENT_1_STR);
  217. expect(_elGamalPrivateKey.getExponentsArray()[1].getValue().toString())
  218. .toEqual(EXPONENT_2_STR);
  219. });
  220. it('and ElGamal encrypt and decrypt some group elements', function() {
  221. var encryptedGroupElements =
  222. _elGamalEncrypter.encryptGroupElements(_zpGroupElements);
  223. var decryptedGroupElements =
  224. _elGamalDecrypter.decrypt(encryptedGroupElements, true);
  225. expect(decryptedGroupElements.length).toBe(_zpGroupElements.length);
  226. for (var i = 0; i < decryptedGroupElements.length; i++) {
  227. expect(decryptedGroupElements[i].equals(_zpGroupElements[i]))
  228. .toBeTruthy();
  229. }
  230. });
  231. it('and ElGamal encrypt and decrypt some group elements, using pre-computed encryption values',
  232. function() {
  233. var preComputedValues = _elGamalEncrypter.preCompute();
  234. var encryptedGroupElements = _elGamalEncrypter.encryptGroupElements(
  235. _zpGroupElements, preComputedValues);
  236. var decryptedGroupElements =
  237. _elGamalDecrypter.decrypt(encryptedGroupElements, true);
  238. expect(decryptedGroupElements.length).toBe(_zpGroupElements.length);
  239. for (var i = 0; i < decryptedGroupElements.length; i++) {
  240. expect(decryptedGroupElements[i].equals(_zpGroupElements[i]))
  241. .toBeTruthy();
  242. }
  243. });
  244. it('and ElGamal encrypt and decrypt some group elements, using encryption values generated with a short exponent',
  245. function() {
  246. cryptolib(function(box) {
  247. var encryptedGroupElements =
  248. _elGamalEncrypterLarge.encryptGroupElements(
  249. _zpGroupElementsLarge, true);
  250. expect(encryptedGroupElements.getR().getValue().bitLength())
  251. .not.toBeGreaterThan(box.SHORT_EXPONENT_BIT_LENGTH);
  252. var decryptedGroupElements =
  253. _elGamalDecrypterLarge.decrypt(encryptedGroupElements, true);
  254. expect(decryptedGroupElements.length)
  255. .toBe(_zpGroupElementsLarge.length);
  256. for (var i = 0; i < decryptedGroupElements.length; i++) {
  257. expect(decryptedGroupElements[i].equals(_zpGroupElementsLarge[i]))
  258. .toBeTruthy();
  259. }
  260. });
  261. });
  262. it('and ElGamal encrypt and decrypt some group elements, using pre-computed encryption values generated with a short exponent',
  263. function() {
  264. cryptolib(function(box) {
  265. var preComputedValues = _elGamalEncrypterLarge.preCompute(true);
  266. var encryptedGroupElements =
  267. _elGamalEncrypterLarge.encryptGroupElements(
  268. _zpGroupElementsLarge, preComputedValues);
  269. expect(encryptedGroupElements.getR().getValue().bitLength())
  270. .not.toBeGreaterThan(box.SHORT_EXPONENT_BIT_LENGTH);
  271. var decryptedGroupElements =
  272. _elGamalDecrypterLarge.decrypt(encryptedGroupElements, true);
  273. expect(decryptedGroupElements.length)
  274. .toBe(_zpGroupElementsLarge.length);
  275. for (var i = 0; i < decryptedGroupElements.length; i++) {
  276. expect(decryptedGroupElements[i].equals(_zpGroupElementsLarge[i]))
  277. .toBeTruthy();
  278. }
  279. });
  280. });
  281. it('and ElGamal encrypt and decrypt some group elements, using a random seed',
  282. function() {
  283. var encryptedGroupElements =
  284. _elGamalEncrypterUsingSeed.encryptGroupElements(
  285. _zpGroupElementsLarge);
  286. var decryptedGroupElements =
  287. _elGamalRandomDecrypter.decrypt(encryptedGroupElements, true);
  288. expect(decryptedGroupElements.length)
  289. .toBe(_zpGroupElementsLarge.length);
  290. for (var i = 0; i < decryptedGroupElements.length; i++) {
  291. expect(decryptedGroupElements[i].equals(_zpGroupElementsLarge[i]))
  292. .toBeTruthy();
  293. }
  294. });
  295. it('and ElGamal encrypt and decrypt some group elements, using a random seed and pre-computed encryption values',
  296. function() {
  297. var preComputedValues = _elGamalEncrypterUsingSeed.preCompute();
  298. var encryptedGroupElements = _elGamalEncrypter.encryptGroupElements(
  299. _zpGroupElementsLarge, preComputedValues);
  300. var decryptedGroupElements =
  301. _elGamalRandomDecrypter.decrypt(encryptedGroupElements, true);
  302. expect(decryptedGroupElements.length)
  303. .toBe(_zpGroupElementsLarge.length);
  304. for (var i = 0; i < decryptedGroupElements.length; i++) {
  305. expect(decryptedGroupElements[i].equals(_zpGroupElementsLarge[i]))
  306. .toBeTruthy();
  307. }
  308. });
  309. it('and ElGamal encrypt and decrypt some group elements, using a random seed and encryption values generated with a short exponent',
  310. function() {
  311. cryptolib(function(box) {
  312. var encryptedGroupElements =
  313. _elGamalEncrypterUsingSeed.encryptGroupElements(
  314. _zpGroupElementsLarge, true);
  315. expect(encryptedGroupElements.getR().getValue().bitLength())
  316. .not.toBeGreaterThan(box.SHORT_EXPONENT_BIT_LENGTH);
  317. var decryptedGroupElements = _elGamalRandomDecrypter.decrypt(
  318. encryptedGroupElements, true, true);
  319. expect(decryptedGroupElements.length)
  320. .toBe(_zpGroupElementsLarge.length);
  321. for (var i = 0; i < decryptedGroupElements.length; i++) {
  322. expect(decryptedGroupElements[i].equals(_zpGroupElementsLarge[i]))
  323. .toBeTruthy();
  324. }
  325. });
  326. });
  327. it('and ElGamal encrypt and decrypt some group elements, using a random seed and pre-computed encryption values generated with a short exponent',
  328. function() {
  329. cryptolib(function(box) {
  330. var preComputedValues = _elGamalEncrypterUsingSeed.preCompute(true);
  331. var encryptedGroupElements =
  332. _elGamalEncrypterUsingSeed.encryptGroupElements(
  333. _zpGroupElementsLarge, preComputedValues);
  334. expect(encryptedGroupElements.getR().getValue().bitLength())
  335. .not.toBeGreaterThan(box.SHORT_EXPONENT_BIT_LENGTH);
  336. var decryptedGroupElements = _elGamalRandomDecrypter.decrypt(
  337. encryptedGroupElements, true, true);
  338. expect(decryptedGroupElements.length)
  339. .toBe(_zpGroupElementsLarge.length);
  340. for (var i = 0; i < decryptedGroupElements.length; i++) {
  341. expect(decryptedGroupElements[i].equals(_zpGroupElementsLarge[i]))
  342. .toBeTruthy();
  343. }
  344. });
  345. });
  346. it('and ElGamal encrypt and decrypt some single group elements, using a random seed',
  347. function() {
  348. var encryptedGroupElementArray = [];
  349. for (var i = 0; i < _singleZpGroupElements.length; i++) {
  350. var encryptedGroupElement =
  351. _elGamalEncrypterUsingSeed.encryptGroupElements(
  352. [_singleZpGroupElements[i]]);
  353. encryptedGroupElementArray.push(encryptedGroupElement);
  354. }
  355. var decryptedGroupElementArray = [];
  356. for (var j = 0; j < encryptedGroupElementArray.length; j++) {
  357. var decryptedGroupElement = _elGamalRandomDecrypter.decrypt(
  358. encryptedGroupElementArray[j], true)[0];
  359. decryptedGroupElementArray.push(decryptedGroupElement);
  360. }
  361. expect(decryptedGroupElementArray.length)
  362. .toBe(_singleZpGroupElements.length);
  363. for (var k = 0; k < decryptedGroupElementArray.length; k++) {
  364. expect(
  365. decryptedGroupElementArray[k].equals(_singleZpGroupElements[k]))
  366. .toBeTruthy();
  367. }
  368. });
  369. it('and ElGamal encrypt and decrypt some single group elements, using a random seed and pre-computed encryption values',
  370. function() {
  371. var preComputedValuesArray = [];
  372. for (var i = 0; i < _singleZpGroupElements.length; i++) {
  373. var preComputedValues = _elGamalEncrypterUsingSeed.preCompute();
  374. preComputedValuesArray.push(preComputedValues);
  375. }
  376. var encryptedGroupElementArray = [];
  377. for (var j = 0; j < _singleZpGroupElements.length; j++) {
  378. var encryptedGroupElement =
  379. _elGamalEncrypterUsingSeed.encryptGroupElements(
  380. [_singleZpGroupElements[j]], preComputedValuesArray[j]);
  381. encryptedGroupElementArray.push(encryptedGroupElement);
  382. }
  383. var decryptedGroupElementArray = [];
  384. for (var k = 0; k < encryptedGroupElementArray.length; k++) {
  385. var decryptedGroupElement = _elGamalRandomDecrypter.decrypt(
  386. encryptedGroupElementArray[k], true)[0];
  387. decryptedGroupElementArray.push(decryptedGroupElement);
  388. }
  389. expect(decryptedGroupElementArray.length)
  390. .toBe(_singleZpGroupElements.length);
  391. for (var l = 0; l < decryptedGroupElementArray.length; l++) {
  392. expect(
  393. decryptedGroupElementArray[l].equals(_singleZpGroupElements[l]))
  394. .toBeTruthy();
  395. }
  396. });
  397. it('and ElGamal encrypt and decrypt some single group elements, using a random seed and encryption values generated with a short exponent',
  398. function() {
  399. cryptolib(function(box) {
  400. var encryptedGroupElementArray = [];
  401. for (var i = 0; i < _singleZpGroupElements.length; i++) {
  402. var encryptedGroupElement =
  403. _elGamalEncrypterUsingSeed.encryptGroupElements(
  404. [_singleZpGroupElements[i]], true);
  405. expect(encryptedGroupElement.getR().getValue().bitLength())
  406. .not.toBeGreaterThan(box.SHORT_EXPONENT_BIT_LENGTH);
  407. encryptedGroupElementArray.push(encryptedGroupElement);
  408. }
  409. var decryptedGroupElementArray = [];
  410. for (var j = 0; j < encryptedGroupElementArray.length; j++) {
  411. var decryptedGroupElement = _elGamalRandomDecrypter.decrypt(
  412. encryptedGroupElementArray[j], true, true)[0];
  413. decryptedGroupElementArray.push(decryptedGroupElement);
  414. }
  415. expect(decryptedGroupElementArray.length)
  416. .toBe(_singleZpGroupElements.length);
  417. for (var k = 0; k < decryptedGroupElementArray.length; k++) {
  418. expect(decryptedGroupElementArray[k].equals(
  419. _singleZpGroupElements[k]))
  420. .toBeTruthy();
  421. }
  422. });
  423. });
  424. it('and ElGamal encrypt and decrypt some single group elements, using a random seed and pre-computed encryption values generated with a short exponent',
  425. function() {
  426. cryptolib(function(box) {
  427. var preComputedValuesArray = [];
  428. for (var i = 0; i < _singleZpGroupElements.length; i++) {
  429. var preComputedValues =
  430. _elGamalEncrypterUsingSeed.preCompute(true);
  431. preComputedValuesArray.push(preComputedValues);
  432. }
  433. var encryptedGroupElementArray = [];
  434. for (var j = 0; j < _singleZpGroupElements.length; j++) {
  435. var encryptedGroupElement =
  436. _elGamalEncrypterUsingSeed.encryptGroupElements(
  437. [_singleZpGroupElements[j]], preComputedValuesArray[j]);
  438. expect(encryptedGroupElement.getR().getValue().bitLength())
  439. .not.toBeGreaterThan(box.SHORT_EXPONENT_BIT_LENGTH);
  440. encryptedGroupElementArray.push(encryptedGroupElement);
  441. }
  442. var decryptedGroupElementArray = [];
  443. for (var k = 0; k < encryptedGroupElementArray.length; k++) {
  444. var decryptedGroupElement = _elGamalRandomDecrypter.decrypt(
  445. encryptedGroupElementArray[k], true, true)[0];
  446. decryptedGroupElementArray.push(decryptedGroupElement);
  447. }
  448. expect(decryptedGroupElementArray.length)
  449. .toBe(_singleZpGroupElements.length);
  450. for (var l = 0; l < decryptedGroupElementArray.length; l++) {
  451. expect(decryptedGroupElementArray[l].equals(
  452. _singleZpGroupElements[l]))
  453. .toBeTruthy();
  454. }
  455. });
  456. });
  457. it('and ElGamal encrypt and decrypt some group elements, using serialized encryption values',
  458. function() {
  459. cryptolib('homomorphic.cipher', function(box) {
  460. var encryptedGroupElements =
  461. _elGamalEncrypter.encryptGroupElements(_zpGroupElements);
  462. var encryptedGroupElementsJson =
  463. encryptedGroupElements.getElGamalComputationValues().stringify();
  464. var encryptedGroupElementsFromJson =
  465. box.homomorphic.cipher.deserializeElGamalComputationValues(
  466. encryptedGroupElementsJson);
  467. var decryptedGroupElements =
  468. _elGamalDecrypter.decrypt(encryptedGroupElementsFromJson, true);
  469. expect(decryptedGroupElements.length).toBe(_zpGroupElements.length);
  470. for (var i = 0; i < decryptedGroupElements.length; i++) {
  471. expect(decryptedGroupElements[i].equals(_zpGroupElements[i]))
  472. .toBeTruthy();
  473. }
  474. });
  475. });
  476. it('and ElGamal encrypt and decrypt some group elements, using serialized pre-computed encryption values',
  477. function() {
  478. cryptolib('homomorphic.cipher', function(box) {
  479. var preComputedValues = _elGamalEncrypter.preCompute();
  480. var preComputedValuesJson =
  481. preComputedValues.getElGamalComputationValues().stringify();
  482. var preComputedValuesFromJson =
  483. box.homomorphic.cipher.deserializeElGamalComputationValues(
  484. preComputedValuesJson);
  485. var gamma = preComputedValuesFromJson.getGamma();
  486. var phis = preComputedValuesFromJson.getPhis();
  487. preComputedValuesFromJson =
  488. new box.homomorphic.cipher.ElGamalEncrypterValues(
  489. null, gamma, phis);
  490. var encryptedGroupElements = _elGamalEncrypter.encryptGroupElements(
  491. _zpGroupElements, preComputedValuesFromJson);
  492. var decryptedGroupElements =
  493. _elGamalDecrypter.decrypt(encryptedGroupElements, true);
  494. expect(decryptedGroupElements.length).toBe(_zpGroupElements.length);
  495. for (var i = 0; i < decryptedGroupElements.length; i++) {
  496. expect(decryptedGroupElements[i].equals(_zpGroupElements[i]))
  497. .toBeTruthy();
  498. }
  499. });
  500. });
  501. it('and throw an exception when attempting to ElGamal encrypt, using a short exponent, for a group that is not of type quadratic residue',
  502. function() {
  503. expect(function() {
  504. _elGamalEncrypterLarge.encryptGroupElements(
  505. _zpGroupElementsLargeNonQR, true);
  506. }).toThrow();
  507. });
  508. it('and throw an exception when attempting to ElGamal encrypt, using a short exponent, for a group whose order is smaller than this exponent',
  509. function() {
  510. expect(function() {
  511. _elGamalEncrypter.encryptGroupElements(_zpGroupElements, true);
  512. }).toThrow();
  513. });
  514. it('and fail to decrypt some encrypted elements when using a random seed but not reinitializing the random generator with the seed',
  515. function() {
  516. var encryptedGroupElements =
  517. _elGamalEncrypterUsingSeed.encryptGroupElements(
  518. _zpGroupElementsLarge);
  519. // Decryption should be successful the first time.
  520. var decryptedGroupElements =
  521. _elGamalRandomDecrypter.decrypt(encryptedGroupElements, true);
  522. expect(decryptedGroupElements.length)
  523. .toBe(_zpGroupElementsLarge.length);
  524. for (var i = 0; i < decryptedGroupElements.length; i++) {
  525. expect(decryptedGroupElements[i].equals(_zpGroupElementsLarge[i]))
  526. .toBeTruthy();
  527. }
  528. // Decryption should fail the second time since the random generator
  529. // was not re-initialized with the seed first.
  530. decryptedGroupElements =
  531. _elGamalRandomDecrypter.decrypt(encryptedGroupElements, true);
  532. expect(decryptedGroupElements.length)
  533. .toBe(_zpGroupElementsLarge.length);
  534. for (var j = 0; j < decryptedGroupElements.length; j++) {
  535. expect(decryptedGroupElements[j].equals(_zpGroupElementsLarge[j]))
  536. .toBeFalsy();
  537. }
  538. });
  539. });
  540. function generateRandomExponent(zpSubgroup) {
  541. var exponent;
  542. cryptolib('commons.mathematical', function(box) {
  543. do {
  544. var randomInt = new box.forge.jsbn.BigInteger(
  545. box.forge.random.getBytes(MAX_EXPONENT_BYTES));
  546. exponent =
  547. new box.commons.mathematical.Exponent(zpSubgroup.getQ(), randomInt);
  548. } while (exponent.getValue().equals(box.forge.jsbn.BigInteger.ZERO));
  549. });
  550. return exponent;
  551. }
  552. function generateGroupElements(zpSubgroup, numElements) {
  553. var element;
  554. var groupElements = [];
  555. for (var i = 0; i < numElements; i++) {
  556. element = zpSubgroup.getGenerator().exponentiate(
  557. generateRandomExponent(zpSubgroup));
  558. groupElements.push(element);
  559. }
  560. return groupElements;
  561. }
  562. function validateElGamalPublicKey(elGamalPublicKey) {
  563. expect(elGamalPublicKey.getGroup().equals(_zpSubgroup)).toBeTruthy();
  564. var keyElements = elGamalPublicKey.getGroupElementsArray();
  565. expect(keyElements.length).toBe(NUM_GROUP_ELEMENTS);
  566. expect(keyElements[0].getElementValue().toString()).toEqual(ELEMENT_1_STR);
  567. expect(keyElements[1].getElementValue().toString()).toEqual(ELEMENT_2_STR);
  568. }
  569. function validateElGamalPrivateKey(elGamalPrivateKey) {
  570. expect(elGamalPrivateKey.getGroup().equals(_zpSubgroup)).toBeTruthy();
  571. var keyExponents = elGamalPrivateKey.getExponentsArray();
  572. expect(keyExponents.length).toBe(NUM_GROUP_ELEMENTS);
  573. expect(keyExponents[0].getValue().toString()).toEqual(EXPONENT_1_STR);
  574. expect(keyExponents[1].getValue().toString()).toEqual(EXPONENT_2_STR);
  575. }
  576. });