/* * Copyright 2018 Scytl Secure Electronic Voting SA * * All rights reserved * * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package */ describe('Homomorphic service...', function() { 'use strict'; var MAX_EXPONENT_BYTES = 2; var NUM_GROUP_ELEMENTS = 2; var NUM_SINGLE_GROUP_ELEMENTS = 5; var G_STR = '2'; var P_STR = '23'; var Q_STR = '11'; var ELEMENT_1_STR = '2'; var ELEMENT_2_STR = '4'; var EXPONENT_1_STR = '1'; var EXPONENT_2_STR = '2'; var P_LARGE_STR = '22588801568735561413035633152679913053449200833478689904902877673687016391844561133376032309307885537704777240609087377993341380751697605235541131273868440070920362148431866829787784445019147999379498503693247429579480289226602748397335327890884464685051682703709742724121783217827040722415360103179289160056581759372475845985438977307323570530753362027145384124771826114651710264766437273044759690955051982839684910462609395741692689616014805965573558015387956017183286848440036954926101719205598449898400180082053755864070690174202432196678045052744337832802051787273056312757384654145455745603262082348042780103679'; var Q_LARGE_STR = '11294400784367780706517816576339956526724600416739344952451438836843508195922280566688016154653942768852388620304543688996670690375848802617770565636934220035460181074215933414893892222509573999689749251846623714789740144613301374198667663945442232342525841351854871362060891608913520361207680051589644580028290879686237922992719488653661785265376681013572692062385913057325855132383218636522379845477525991419842455231304697870846344808007402982786779007693978008591643424220018477463050859602799224949200090041026877932035345087101216098339022526372168916401025893636528156378692327072727872801631041174021390051839'; var ELEMENT_1_LARGE_STR = '8008650650117182055231947796743510595354735701773678127718063162818861428894482760351040442014062206238677757186380515026469824595870224783896120627455841205517047520359887236518609328142965980653129280864098892996273964740090483597375107437139254412471355470548193136206727124381287524666926794272344682267309880188101372142121235759763117992716726731820970068223350454790098901032607754554402031099573358614926437378953856998041036773132081351057601842441454945388068039731483320814325657715553744820319265534754357498649904400594493834709761403358903505501640705996603619499187129497007221246019054462834616450362'; var ELEMENT_2_LARGE_STR = '11633656285653208443919333339470607846301429932894308783457570029107286147936455427826899303856584843544699293627942560893304455970515082299498680026759665698080990494885992738624255552297867735585728427220214607212173788862760053487198296321130486607904876481443447070538549541504734530736112052175501932133880661864111558469545768002897528612084034669926036569715266022136440126595140089621370735885927146016552642348282420224106653601826235849885956583427798077317966671703306684815012981357245529568157986211578924579799810305712551845266909314082456551659795959581952216679219662533353585637849875985836675331118'; var EXPONENT_1_LARGE_STR = '2310427452287266604038074581830299484831755686607108413899820257798165596547227594518989253178264380941033095268581246346863002280809127490132335557543545847332023813499454886051935043363376517658050024793517465349562106228739828060169613880190064891580719513382177220752409776280150551117185655930834371803832590064152233876708731218969195345490200219499344738664373593917843352485459832349992908261365788172930979823955846952949156058247067965643074532679047274706566088888021355575983368719069681293419346162608049979977471053590745499346591475991673763640645139343249862033377744682868210594034732021779460567412'; var EXPONENT_2_LARGE_STR = '7533608948657130117198364792462971241599837777629317286887202126604432685322243335715285630236984093165224740099563982076007648728594011814311120331313200895892632245003875959905589367483155794698953057915454892457379023058909518440394905695255170407948701433659375513788930419544151891518689331636455316691827048845766063478445484089208223819510250476623436782404385896353292653750744111841510466992101967325081746747885221256692886521245630131046183525331085171958919416648097910028887247120874015121272894655357197879292253781160838729753609784455892951965051119314203469298666741439497193677501351952497150273389'; var _initialized = false; var _elGamalPublicKey; var _elGamalPrivateKey; var _elGamalEncrypter; var _elGamalDecrypter; var _elGamalKeyPair; var _zpSubgroup; var _zpGroupElements; var _elGamalPublicKeyLarge; var _elGamalPrivateKeyLarge; var _elGamalEncrypterLarge; var _elGamalDecrypterLarge; var _zpGroupElementsLarge; var _zpGroupElementsLargeNonQR; var _singleZpGroupElements; var _elGamalEncrypterUsingSeed; var _elGamalRandomDecrypter; beforeEach(function() { if (!_initialized) { cryptolib( 'commons.utils', 'commons.mathematical', 'homomorphic.service', function(box) { var converters = new box.commons.utils.Converters(); var gB64 = converters.base64FromBigInteger( new forge.jsbn.BigInteger(G_STR)); var pB64 = converters.base64FromBigInteger( new forge.jsbn.BigInteger(P_STR)); var qB64 = converters.base64FromBigInteger( new forge.jsbn.BigInteger(Q_STR)); var element1B64 = converters.base64FromBigInteger( new forge.jsbn.BigInteger(ELEMENT_1_STR)); var element2B64 = converters.base64FromBigInteger( new forge.jsbn.BigInteger(ELEMENT_2_STR)); var exponent1B64 = converters.base64FromBigInteger( new forge.jsbn.BigInteger(EXPONENT_1_STR)); var exponent2B64 = converters.base64FromBigInteger( new forge.jsbn.BigInteger(EXPONENT_2_STR)); var elGamalPublicKeyJson = '{"publicKey":{"zpSubgroup":{"g":"' + gB64 + '","p":"' + pB64 + '","q":"' + qB64 + '"},"elements":["' + element1B64 + '","' + element2B64 + '"]}}'; var elGamalPrivateKeyJson = '{"privateKey":{"zpSubgroup":{"g":"' + gB64 + '","p":"' + pB64 + '","q":"' + qB64 + '"},"exponents":["' + exponent1B64 + '","' + exponent2B64 + '"]}}'; var elGamalPublicKeyJsonB64 = converters.base64Encode(elGamalPublicKeyJson); var elGamalPrivateKeyJsonB64 = converters.base64Encode(elGamalPrivateKeyJson); _elGamalPublicKey = box.homomorphic.service.createElGamalPublicKey( elGamalPublicKeyJsonB64); _elGamalPrivateKey = box.homomorphic.service.createElGamalPrivateKey( elGamalPrivateKeyJsonB64); _elGamalKeyPair = new box.homomorphic.service.createElGamalKeyPair( _elGamalPublicKey, _elGamalPrivateKey); _elGamalEncrypter = box.homomorphic.service.createEncrypter(_elGamalPublicKey); _elGamalDecrypter = box.homomorphic.service.createDecrypter(_elGamalPrivateKey); var g = new box.forge.jsbn.BigInteger(G_STR); var p = new box.forge.jsbn.BigInteger(P_STR); var q = new box.forge.jsbn.BigInteger(Q_STR); _zpSubgroup = new box.commons.mathematical.ZpSubgroup(g, p, q); _zpGroupElements = generateGroupElements(_zpSubgroup, NUM_GROUP_ELEMENTS); gB64 = converters.base64FromBigInteger( new forge.jsbn.BigInteger(G_STR)); pB64 = converters.base64FromBigInteger( new forge.jsbn.BigInteger(P_LARGE_STR)); qB64 = converters.base64FromBigInteger( new forge.jsbn.BigInteger(Q_LARGE_STR)); element1B64 = converters.base64FromBigInteger( new forge.jsbn.BigInteger(ELEMENT_1_LARGE_STR)); element2B64 = converters.base64FromBigInteger( new forge.jsbn.BigInteger(ELEMENT_2_LARGE_STR)); exponent1B64 = converters.base64FromBigInteger( new forge.jsbn.BigInteger(EXPONENT_1_LARGE_STR)); exponent2B64 = converters.base64FromBigInteger( new forge.jsbn.BigInteger(EXPONENT_2_LARGE_STR)); var elGamalPublicKeyLargeJson = '{"publicKey":{"zpSubgroup":{"g":"' + gB64 + '","p":"' + pB64 + '","q":"' + qB64 + '"},"elements":["' + element1B64 + '","' + element2B64 + '"]}}'; var elGamalPrivateKeyLargeJson = '{"privateKey":{"zpSubgroup":{"g":"' + gB64 + '","p":"' + pB64 + '","q":"' + qB64 + '"},"exponents":["' + exponent1B64 + '","' + exponent2B64 + '"]}}'; var elGamalPublicKeyLargeJsonB64 = converters.base64Encode(elGamalPublicKeyLargeJson); var elGamalPrivateKeyLargeJsonB64 = converters.base64Encode(elGamalPrivateKeyLargeJson); _elGamalPublicKeyLarge = box.homomorphic.service.createElGamalPublicKey( elGamalPublicKeyLargeJsonB64); _elGamalPrivateKeyLarge = box.homomorphic.service.createElGamalPrivateKey( elGamalPrivateKeyLargeJsonB64); _elGamalEncrypterLarge = box.homomorphic.service.createEncrypter(_elGamalPublicKeyLarge); _elGamalDecrypterLarge = box.homomorphic.service.createDecrypter( _elGamalPrivateKeyLarge); g = new box.forge.jsbn.BigInteger(G_STR); p = new box.forge.jsbn.BigInteger(P_LARGE_STR); q = new box.forge.jsbn.BigInteger(Q_LARGE_STR); var zpSubgroup = new box.commons.mathematical.ZpSubgroup(g, p, q); _zpGroupElementsLarge = generateGroupElements(zpSubgroup, NUM_GROUP_ELEMENTS); g = new box.forge.jsbn.BigInteger(G_STR); p = new box.forge.jsbn.BigInteger(P_LARGE_STR); q = new box.forge.jsbn.BigInteger(Q_LARGE_STR) .subtract(box.forge.jsbn.BigInteger.ONE); zpSubgroup = new box.commons.mathematical.ZpSubgroup(g, p, q); _zpGroupElementsLargeNonQR = generateGroupElements(zpSubgroup, NUM_GROUP_ELEMENTS); g = new box.forge.jsbn.BigInteger(G_STR); p = new box.forge.jsbn.BigInteger(P_LARGE_STR); q = new box.forge.jsbn.BigInteger(Q_LARGE_STR); zpSubgroup = new box.commons.mathematical.ZpSubgroup(g, p, q); _singleZpGroupElements = generateGroupElements(zpSubgroup, NUM_SINGLE_GROUP_ELEMENTS); }); _initialized = true; } cryptolib('primitives.service', 'homomorphic.service', function(box) { // Generate seed and define callback function to initialize random // integer generator with seed. var seedHex = cryptoPRNG.generateRandomSeedInHex(); var cryptoRandomInteger; var initRandomGenerator = function(box) { cryptoRandomInteger = box.primitives.service.getCryptoRandomInteger(); }; // Create new encrypter that uses random integer generator initialized // with seed. initRandomGenerator.prng = cryptoPRNG.createPRNGFromSeed(seedHex); cryptolib('primitives.service', initRandomGenerator); _elGamalEncrypterUsingSeed = box.homomorphic.service.createEncrypter( _elGamalPublicKeyLarge, cryptoRandomInteger); // Create new decrypter that uses random integer generator initialized // with seed. initRandomGenerator.prng = cryptoPRNG.createPRNGFromSeed(seedHex); cryptolib('primitives.service', initRandomGenerator); _elGamalRandomDecrypter = box.homomorphic.service.createRandomDecrypter( _elGamalPublicKeyLarge, cryptoRandomInteger); }); }); describe('should be able to ..', function() { it('create an ElGamal key pair', function() { validateElGamalPublicKey(_elGamalKeyPair.getPublicKey()); validateElGamalPrivateKey(_elGamalKeyPair.getPrivateKey()); }); it('and create an ElGamal encrypter', function() { validateElGamalPublicKey(_elGamalEncrypter.getElGamalPublicKey()); }); it('and create an ElGamal decrypter', function() { validateElGamalPrivateKey(_elGamalDecrypter.getElGamalPrivateKey()); }); it('and deserialize an ElGamal public key', function() { expect(_elGamalPublicKey.getGroup() .getGenerator() .getElementValue() .toString()) .toEqual(G_STR); expect(_elGamalPublicKey.getGroup().getP().toString()).toEqual(P_STR); expect(_elGamalPublicKey.getGroup().getQ().toString()).toEqual(Q_STR); expect(_elGamalPublicKey.getGroupElementsArray().length).toEqual(2); expect(_elGamalPublicKey.getGroupElementsArray()[0] .getElementValue() .toString()) .toEqual(ELEMENT_1_STR); expect(_elGamalPublicKey.getGroupElementsArray()[1] .getElementValue() .toString()) .toEqual(ELEMENT_2_STR); }); it('and deserialize an ElGamal private key', function() { expect(_elGamalPrivateKey.getGroup() .getGenerator() .getElementValue() .toString()) .toEqual(G_STR); expect(_elGamalPrivateKey.getGroup().getP().toString()).toEqual(P_STR); expect(_elGamalPrivateKey.getGroup().getQ().toString()).toEqual(Q_STR); expect(_elGamalPrivateKey.getExponentsArray().length).toEqual(2); expect(_elGamalPrivateKey.getExponentsArray()[0].getValue().toString()) .toEqual(EXPONENT_1_STR); expect(_elGamalPrivateKey.getExponentsArray()[1].getValue().toString()) .toEqual(EXPONENT_2_STR); }); it('and ElGamal encrypt and decrypt some group elements', function() { var encryptedGroupElements = _elGamalEncrypter.encryptGroupElements(_zpGroupElements); var decryptedGroupElements = _elGamalDecrypter.decrypt(encryptedGroupElements, true); expect(decryptedGroupElements.length).toBe(_zpGroupElements.length); for (var i = 0; i < decryptedGroupElements.length; i++) { expect(decryptedGroupElements[i].equals(_zpGroupElements[i])) .toBeTruthy(); } }); it('and ElGamal encrypt and decrypt some group elements, using pre-computed encryption values', function() { var preComputedValues = _elGamalEncrypter.preCompute(); var encryptedGroupElements = _elGamalEncrypter.encryptGroupElements( _zpGroupElements, preComputedValues); var decryptedGroupElements = _elGamalDecrypter.decrypt(encryptedGroupElements, true); expect(decryptedGroupElements.length).toBe(_zpGroupElements.length); for (var i = 0; i < decryptedGroupElements.length; i++) { expect(decryptedGroupElements[i].equals(_zpGroupElements[i])) .toBeTruthy(); } }); it('and ElGamal encrypt and decrypt some group elements, using encryption values generated with a short exponent', function() { cryptolib(function(box) { var encryptedGroupElements = _elGamalEncrypterLarge.encryptGroupElements( _zpGroupElementsLarge, true); expect(encryptedGroupElements.getR().getValue().bitLength()) .not.toBeGreaterThan(box.SHORT_EXPONENT_BIT_LENGTH); var decryptedGroupElements = _elGamalDecrypterLarge.decrypt(encryptedGroupElements, true); expect(decryptedGroupElements.length) .toBe(_zpGroupElementsLarge.length); for (var i = 0; i < decryptedGroupElements.length; i++) { expect(decryptedGroupElements[i].equals(_zpGroupElementsLarge[i])) .toBeTruthy(); } }); }); it('and ElGamal encrypt and decrypt some group elements, using pre-computed encryption values generated with a short exponent', function() { cryptolib(function(box) { var preComputedValues = _elGamalEncrypterLarge.preCompute(true); var encryptedGroupElements = _elGamalEncrypterLarge.encryptGroupElements( _zpGroupElementsLarge, preComputedValues); expect(encryptedGroupElements.getR().getValue().bitLength()) .not.toBeGreaterThan(box.SHORT_EXPONENT_BIT_LENGTH); var decryptedGroupElements = _elGamalDecrypterLarge.decrypt(encryptedGroupElements, true); expect(decryptedGroupElements.length) .toBe(_zpGroupElementsLarge.length); for (var i = 0; i < decryptedGroupElements.length; i++) { expect(decryptedGroupElements[i].equals(_zpGroupElementsLarge[i])) .toBeTruthy(); } }); }); it('and ElGamal encrypt and decrypt some group elements, using a random seed', function() { var encryptedGroupElements = _elGamalEncrypterUsingSeed.encryptGroupElements( _zpGroupElementsLarge); var decryptedGroupElements = _elGamalRandomDecrypter.decrypt(encryptedGroupElements, true); expect(decryptedGroupElements.length) .toBe(_zpGroupElementsLarge.length); for (var i = 0; i < decryptedGroupElements.length; i++) { expect(decryptedGroupElements[i].equals(_zpGroupElementsLarge[i])) .toBeTruthy(); } }); it('and ElGamal encrypt and decrypt some group elements, using a random seed and pre-computed encryption values', function() { var preComputedValues = _elGamalEncrypterUsingSeed.preCompute(); var encryptedGroupElements = _elGamalEncrypter.encryptGroupElements( _zpGroupElementsLarge, preComputedValues); var decryptedGroupElements = _elGamalRandomDecrypter.decrypt(encryptedGroupElements, true); expect(decryptedGroupElements.length) .toBe(_zpGroupElementsLarge.length); for (var i = 0; i < decryptedGroupElements.length; i++) { expect(decryptedGroupElements[i].equals(_zpGroupElementsLarge[i])) .toBeTruthy(); } }); it('and ElGamal encrypt and decrypt some group elements, using a random seed and encryption values generated with a short exponent', function() { cryptolib(function(box) { var encryptedGroupElements = _elGamalEncrypterUsingSeed.encryptGroupElements( _zpGroupElementsLarge, true); expect(encryptedGroupElements.getR().getValue().bitLength()) .not.toBeGreaterThan(box.SHORT_EXPONENT_BIT_LENGTH); var decryptedGroupElements = _elGamalRandomDecrypter.decrypt( encryptedGroupElements, true, true); expect(decryptedGroupElements.length) .toBe(_zpGroupElementsLarge.length); for (var i = 0; i < decryptedGroupElements.length; i++) { expect(decryptedGroupElements[i].equals(_zpGroupElementsLarge[i])) .toBeTruthy(); } }); }); it('and ElGamal encrypt and decrypt some group elements, using a random seed and pre-computed encryption values generated with a short exponent', function() { cryptolib(function(box) { var preComputedValues = _elGamalEncrypterUsingSeed.preCompute(true); var encryptedGroupElements = _elGamalEncrypterUsingSeed.encryptGroupElements( _zpGroupElementsLarge, preComputedValues); expect(encryptedGroupElements.getR().getValue().bitLength()) .not.toBeGreaterThan(box.SHORT_EXPONENT_BIT_LENGTH); var decryptedGroupElements = _elGamalRandomDecrypter.decrypt( encryptedGroupElements, true, true); expect(decryptedGroupElements.length) .toBe(_zpGroupElementsLarge.length); for (var i = 0; i < decryptedGroupElements.length; i++) { expect(decryptedGroupElements[i].equals(_zpGroupElementsLarge[i])) .toBeTruthy(); } }); }); it('and ElGamal encrypt and decrypt some single group elements, using a random seed', function() { var encryptedGroupElementArray = []; for (var i = 0; i < _singleZpGroupElements.length; i++) { var encryptedGroupElement = _elGamalEncrypterUsingSeed.encryptGroupElements( [_singleZpGroupElements[i]]); encryptedGroupElementArray.push(encryptedGroupElement); } var decryptedGroupElementArray = []; for (var j = 0; j < encryptedGroupElementArray.length; j++) { var decryptedGroupElement = _elGamalRandomDecrypter.decrypt( encryptedGroupElementArray[j], true)[0]; decryptedGroupElementArray.push(decryptedGroupElement); } expect(decryptedGroupElementArray.length) .toBe(_singleZpGroupElements.length); for (var k = 0; k < decryptedGroupElementArray.length; k++) { expect( decryptedGroupElementArray[k].equals(_singleZpGroupElements[k])) .toBeTruthy(); } }); it('and ElGamal encrypt and decrypt some single group elements, using a random seed and pre-computed encryption values', function() { var preComputedValuesArray = []; for (var i = 0; i < _singleZpGroupElements.length; i++) { var preComputedValues = _elGamalEncrypterUsingSeed.preCompute(); preComputedValuesArray.push(preComputedValues); } var encryptedGroupElementArray = []; for (var j = 0; j < _singleZpGroupElements.length; j++) { var encryptedGroupElement = _elGamalEncrypterUsingSeed.encryptGroupElements( [_singleZpGroupElements[j]], preComputedValuesArray[j]); encryptedGroupElementArray.push(encryptedGroupElement); } var decryptedGroupElementArray = []; for (var k = 0; k < encryptedGroupElementArray.length; k++) { var decryptedGroupElement = _elGamalRandomDecrypter.decrypt( encryptedGroupElementArray[k], true)[0]; decryptedGroupElementArray.push(decryptedGroupElement); } expect(decryptedGroupElementArray.length) .toBe(_singleZpGroupElements.length); for (var l = 0; l < decryptedGroupElementArray.length; l++) { expect( decryptedGroupElementArray[l].equals(_singleZpGroupElements[l])) .toBeTruthy(); } }); it('and ElGamal encrypt and decrypt some single group elements, using a random seed and encryption values generated with a short exponent', function() { cryptolib(function(box) { var encryptedGroupElementArray = []; for (var i = 0; i < _singleZpGroupElements.length; i++) { var encryptedGroupElement = _elGamalEncrypterUsingSeed.encryptGroupElements( [_singleZpGroupElements[i]], true); expect(encryptedGroupElement.getR().getValue().bitLength()) .not.toBeGreaterThan(box.SHORT_EXPONENT_BIT_LENGTH); encryptedGroupElementArray.push(encryptedGroupElement); } var decryptedGroupElementArray = []; for (var j = 0; j < encryptedGroupElementArray.length; j++) { var decryptedGroupElement = _elGamalRandomDecrypter.decrypt( encryptedGroupElementArray[j], true, true)[0]; decryptedGroupElementArray.push(decryptedGroupElement); } expect(decryptedGroupElementArray.length) .toBe(_singleZpGroupElements.length); for (var k = 0; k < decryptedGroupElementArray.length; k++) { expect(decryptedGroupElementArray[k].equals( _singleZpGroupElements[k])) .toBeTruthy(); } }); }); it('and ElGamal encrypt and decrypt some single group elements, using a random seed and pre-computed encryption values generated with a short exponent', function() { cryptolib(function(box) { var preComputedValuesArray = []; for (var i = 0; i < _singleZpGroupElements.length; i++) { var preComputedValues = _elGamalEncrypterUsingSeed.preCompute(true); preComputedValuesArray.push(preComputedValues); } var encryptedGroupElementArray = []; for (var j = 0; j < _singleZpGroupElements.length; j++) { var encryptedGroupElement = _elGamalEncrypterUsingSeed.encryptGroupElements( [_singleZpGroupElements[j]], preComputedValuesArray[j]); expect(encryptedGroupElement.getR().getValue().bitLength()) .not.toBeGreaterThan(box.SHORT_EXPONENT_BIT_LENGTH); encryptedGroupElementArray.push(encryptedGroupElement); } var decryptedGroupElementArray = []; for (var k = 0; k < encryptedGroupElementArray.length; k++) { var decryptedGroupElement = _elGamalRandomDecrypter.decrypt( encryptedGroupElementArray[k], true, true)[0]; decryptedGroupElementArray.push(decryptedGroupElement); } expect(decryptedGroupElementArray.length) .toBe(_singleZpGroupElements.length); for (var l = 0; l < decryptedGroupElementArray.length; l++) { expect(decryptedGroupElementArray[l].equals( _singleZpGroupElements[l])) .toBeTruthy(); } }); }); it('and ElGamal encrypt and decrypt some group elements, using serialized encryption values', function() { cryptolib('homomorphic.cipher', function(box) { var encryptedGroupElements = _elGamalEncrypter.encryptGroupElements(_zpGroupElements); var encryptedGroupElementsJson = encryptedGroupElements.getElGamalComputationValues().stringify(); var encryptedGroupElementsFromJson = box.homomorphic.cipher.deserializeElGamalComputationValues( encryptedGroupElementsJson); var decryptedGroupElements = _elGamalDecrypter.decrypt(encryptedGroupElementsFromJson, true); expect(decryptedGroupElements.length).toBe(_zpGroupElements.length); for (var i = 0; i < decryptedGroupElements.length; i++) { expect(decryptedGroupElements[i].equals(_zpGroupElements[i])) .toBeTruthy(); } }); }); it('and ElGamal encrypt and decrypt some group elements, using serialized pre-computed encryption values', function() { cryptolib('homomorphic.cipher', function(box) { var preComputedValues = _elGamalEncrypter.preCompute(); var preComputedValuesJson = preComputedValues.getElGamalComputationValues().stringify(); var preComputedValuesFromJson = box.homomorphic.cipher.deserializeElGamalComputationValues( preComputedValuesJson); var gamma = preComputedValuesFromJson.getGamma(); var phis = preComputedValuesFromJson.getPhis(); preComputedValuesFromJson = new box.homomorphic.cipher.ElGamalEncrypterValues( null, gamma, phis); var encryptedGroupElements = _elGamalEncrypter.encryptGroupElements( _zpGroupElements, preComputedValuesFromJson); var decryptedGroupElements = _elGamalDecrypter.decrypt(encryptedGroupElements, true); expect(decryptedGroupElements.length).toBe(_zpGroupElements.length); for (var i = 0; i < decryptedGroupElements.length; i++) { expect(decryptedGroupElements[i].equals(_zpGroupElements[i])) .toBeTruthy(); } }); }); it('and throw an exception when attempting to ElGamal encrypt, using a short exponent, for a group that is not of type quadratic residue', function() { expect(function() { _elGamalEncrypterLarge.encryptGroupElements( _zpGroupElementsLargeNonQR, true); }).toThrow(); }); it('and throw an exception when attempting to ElGamal encrypt, using a short exponent, for a group whose order is smaller than this exponent', function() { expect(function() { _elGamalEncrypter.encryptGroupElements(_zpGroupElements, true); }).toThrow(); }); it('and fail to decrypt some encrypted elements when using a random seed but not reinitializing the random generator with the seed', function() { var encryptedGroupElements = _elGamalEncrypterUsingSeed.encryptGroupElements( _zpGroupElementsLarge); // Decryption should be successful the first time. var decryptedGroupElements = _elGamalRandomDecrypter.decrypt(encryptedGroupElements, true); expect(decryptedGroupElements.length) .toBe(_zpGroupElementsLarge.length); for (var i = 0; i < decryptedGroupElements.length; i++) { expect(decryptedGroupElements[i].equals(_zpGroupElementsLarge[i])) .toBeTruthy(); } // Decryption should fail the second time since the random generator // was not re-initialized with the seed first. decryptedGroupElements = _elGamalRandomDecrypter.decrypt(encryptedGroupElements, true); expect(decryptedGroupElements.length) .toBe(_zpGroupElementsLarge.length); for (var j = 0; j < decryptedGroupElements.length; j++) { expect(decryptedGroupElements[j].equals(_zpGroupElementsLarge[j])) .toBeFalsy(); } }); }); function generateRandomExponent(zpSubgroup) { var exponent; cryptolib('commons.mathematical', function(box) { do { var randomInt = new box.forge.jsbn.BigInteger( box.forge.random.getBytes(MAX_EXPONENT_BYTES)); exponent = new box.commons.mathematical.Exponent(zpSubgroup.getQ(), randomInt); } while (exponent.getValue().equals(box.forge.jsbn.BigInteger.ZERO)); }); return exponent; } function generateGroupElements(zpSubgroup, numElements) { var element; var groupElements = []; for (var i = 0; i < numElements; i++) { element = zpSubgroup.getGenerator().exponentiate( generateRandomExponent(zpSubgroup)); groupElements.push(element); } return groupElements; } function validateElGamalPublicKey(elGamalPublicKey) { expect(elGamalPublicKey.getGroup().equals(_zpSubgroup)).toBeTruthy(); var keyElements = elGamalPublicKey.getGroupElementsArray(); expect(keyElements.length).toBe(NUM_GROUP_ELEMENTS); expect(keyElements[0].getElementValue().toString()).toEqual(ELEMENT_1_STR); expect(keyElements[1].getElementValue().toString()).toEqual(ELEMENT_2_STR); } function validateElGamalPrivateKey(elGamalPrivateKey) { expect(elGamalPrivateKey.getGroup().equals(_zpSubgroup)).toBeTruthy(); var keyExponents = elGamalPrivateKey.getExponentsArray(); expect(keyExponents.length).toBe(NUM_GROUP_ELEMENTS); expect(keyExponents[0].getValue().toString()).toEqual(EXPONENT_1_STR); expect(keyExponents[1].getValue().toString()).toEqual(EXPONENT_2_STR); } });