123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401 |
- /*
- * 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
- */
- /* jshint node:true */
- 'use strict';
- var elGamal = require('scytl-elgamal');
- var mathematical = require('scytl-mathematical');
- var forge = require('node-forge');
- module.exports = CommonTestData;
- var BigInteger = forge.jsbn.BigInteger;
- /**
- * Provides the common data and functions needed by the zero-knowledge proof of
- * knowledge unit tests.
- */
- function CommonTestData() {
- var mathService = mathematical.newService();
- var mathRandomGenerator_ = mathService.newRandomGenerator();
- var elGamalService_ = elGamal.newService();
- var p_ = new BigInteger(
- '25701322016688441576103032148674110774925156427397637132202577741938936247112125492211659378990027134829873026348759004510642939209382852797923423233606398455768339503774439196473285206499419017249519687083918862292745452369770073017370862703937184066962152692474974647384317528679859283948201449898123774491462507974828236623365121967170401847974506359775053259024902177376974036791676038887180065668218851769610708183278395407393103098286493672450097566567641277262751905925272593655979627326843104589717100845609213331825322091528671293329804211235906640910489075537455976735341285644494144220105240375300711488393');
- var q_ = new BigInteger(
- '81259987775362040571620137377019110900790585487969528507141757273696249070213');
- var g_ = new BigInteger(
- '21303916314604998551484796420422871007468543247831789236879215369694842734099405650535148287249791144057375987697205687518340016316179892851284240278138045703633698036256611527988640313051528625117090689542380890153876064768602704006774164341226969138952495075758675629665109761968589385514561688161321002676900768077022957299407868881468752268501397255241070908793893954188678747644443826465068701078202311876709764302561277744548084228639372458598925393551439452959527949768006498598646518365505226629313181567048632516237514971091380204424481498506499338185144271546651990709723565928420753129878206710329253950578');
- var group_ = mathService.newZpSubgroup(p_, q_, g_);
- var anotherP_ = new BigInteger(
- '22115396014581083143553195792384915983375949993753365299824374182778648887213105675373952839695834312125954513956465041609718392131788741228259266178434294275575978809365653903991346366383637500069010795276889266879661859362340655085050484891149389971190945080643692669920059928787982790808824970597361825060408436004650739931286605415552480363242364319544423959620330010413847743583301091182870021747196927889763205955078275353307312408480155002017730305672359814713050632922694161739281353676187308501682728826507718002850698488786266115311952718697872338756199429262811547458969260835283688979875294699655014592833');
- var anotherQ_ = new BigInteger(
- '79783631514788897688995869254536231266441581267248557197866166084121363399063');
- var anotherG_ = new BigInteger(
- '9484337033848536557358945372517536146444081505783459082983213315915020922388822299017798461933010391712259501201285084235930755858547311934865298396110947362913733900057881561201738951725697128822802249693116611294569213895789823297341865759919045291915705783128173481781221176839434866976235031358969583527093743179257827355453820268832913547364509208164670680381449515691300440305333919098105147193087681183020489724214850151272955879869448467832934822639783688344322183540621808345771717172404141548242866493539424279296365911355186761897533654055060787119955689115570505208857288933136456026541073605147828202749');
- var anotherGroup_ =
- mathService.newZpSubgroup(anotherP_, anotherQ_, anotherG_);
- /**
- * @function getP
- * @returns {forge.jsbn.BigInteger} The modulus of a Zp subgroup.
- */
- this.getP = function() {
- return p_;
- };
- /**
- * @function getQ
- * @returns {forge.jsbn.BigInteger} The order of a Zp subgroup.
- */
- this.getQ = function() {
- return q_;
- };
- /**
- * @function getG
- * @returns {forge.jsbn.BigInteger} The generator of a Zp subgroup.
- */
- this.getG = function() {
- return g_;
- };
- /**
- * @function getGroup
- * @returns {ZpSubgroup} A Zp subgroup.
- */
- this.getGroup = function() {
- return group_;
- };
- /**
- * @function getAnotherP
- * @returns {forge.jsbn.BigInteger} The modulus of another Zp subgroup.
- */
- this.getAnotherP = function() {
- return anotherP_;
- };
- /**
- * @function getAnotherQ
- * @returns {forge.jsbn.BigInteger} The order of another Zp subgroup.
- */
- this.getAnotherQ = function() {
- return anotherQ_;
- };
- /**
- * @function getAnotherG
- * @returns {forge.jsbn.BigInteger} The generator of another Zp subgroup.
- */
- this.getAnotherG = function() {
- return anotherG_;
- };
- /**
- * @function getAnotherGroup
- * @returns {ZpSubgroup} Another Zp subgroup.
- */
- this.getAnotherGroup = function() {
- return anotherGroup_;
- };
- /**
- * Generates a random string.
- *
- * @function generateRandomString
- * @param {number}
- * length The number of characters that are to constitute the
- * string.
- * @returns {string} The random string.
- */
- this.generateRandomString = function(length) {
- var charset = 'abcdefghijklmnopqrstuvwxyz0123456789';
- var string = '';
- for (var i = 0; i < length; i++) {
- string += charset.charAt(Math.floor(Math.random() * charset.length));
- }
- return string;
- };
- /**
- * Generates a random integer whose value is within a specified range.
- *
- * @function generateRandomInteger
- * @param {number}
- * min The minimum value of the integer.
- * @param {number}
- * max The maximum value of the integer.
- * @returns {number} The random integer.
- */
- this.generateRandomInteger = function(min, max) {
- return Math.floor(Math.random() * (max - min + 1)) + min;
- };
- /**
- * Generates an ElGamal key pair.
- *
- * @function generateKeyPair
- * @param {ZpSubgroup}
- * group The Zp subgroup to which the public key elements belong
- * and to which the private key exponents are associated.
- * @param {number}
- * numElements The number of Zp group elements in the public key.
- * @returns {ElGamalKeyPair} The ElGamal key pair.
- */
- this.generateKeyPair = function(group, numElements) {
- var elements = [];
- var exponents = [];
- var exponent;
- var element;
- for (var i = 0; i < numElements; i++) {
- exponent = mathRandomGenerator_.nextExponent(group);
- exponents.push(exponent);
- element = group.generator.exponentiate(exponent);
- elements.push(element);
- }
- var publicKey = elGamalService_.newPublicKey(group, elements);
- var privateKey = elGamalService_.newPrivateKey(group, exponents);
- return elGamalService_.newKeyPair(publicKey, privateKey);
- };
- /**
- * Generates a random array of Zp group elements.
- *
- * @function generateRandomGroupElements
- * @param {ZpSubgroup}
- * group The Zp subgroup to which the Zp group elements belong.
- * @param {number}
- * numElements The number of Zp group elements to generate.
- * @returns {ZpGroupElement[]} The array of Zp group elements.
- */
- this.generateRandomGroupElements = function(group, numElements) {
- var elements = [];
- for (var i = 0; i < numElements; i++) {
- elements.push(mathRandomGenerator_.nextZpGroupElement(group));
- }
- return elements;
- };
- /**
- * Exponentiates an array of Zp group base elements with an exponent.
- *
- * @function exponentiateElements
- * @param {ZpGroupElement[]}
- * baseElements The Zp group base elements to exponentiate.
- * @param {Exponent}
- * exponent The exponent to use for the exponentiation.
- * @return {ZpGroupElement[]} The array of exponentiated Zp group base
- * elements.
- */
- this.exponentiateElements = function(baseElements, exponent) {
- var exponentiatedElements = [];
- for (var i = 0; i < baseElements.length; i++) {
- exponentiatedElements.push(baseElements[i].exponentiate(exponent));
- }
- return exponentiatedElements;
- };
- /**
- *
- * Generates an array of simple plaintext Zp group elements. By definition,
- * all of these elements will have the same value. The number of elements
- * requested must be an even number
- *
- * @function generateSimplePlaintext
- * @param {ZpSubgroup}
- * group The Zp subgroup to which the simple plaintext Zp group
- * elements belong.
- * @param {number}
- * numElements The number of simple plaintext Zp group elements
- * to generate.
- * @returns {ZpGroupElement[]} The array of simple plaintext Zp group
- * elements.
- * @throws {Error}
- * If the number of simple plaintext Zp group elements requested
- * was an odd number.
- */
- this.generateSimplePlaintext = function(group, numElements) {
- var simplePlaintext = [];
- if ((numElements % 2) !== 0) {
- throw new Error(
- 'Simple plaintext must be generated using an even number of elements; Found ' +
- numElements);
- }
- var element = mathRandomGenerator_.nextZpGroupElement(group);
- for (var i = 0; i < numElements; i++) {
- simplePlaintext.push(element);
- }
- return simplePlaintext;
- };
- /**
- * Generates an array of non-simple plaintext Zp group elements. By
- * definition, the array is non-simple because if it contains at least 2
- * elements whose values are different.
- *
- * @function generateNonSimplePlaintext
- * @param {ZpSubgroup}
- * group The Zp subgroup to which all of the generated Zp group
- * elements belong.
- * @param {number}
- * numElements The number of non-simple Zp group elements to
- * generate.
- * @returns {ZpGroupElement[]} The array of non-simple Zp group elements.
- */
- this.generateNonSimplePlaintext = function(group, numElements) {
- var nonSimplePlaintext = [];
- var element = mathRandomGenerator_.nextZpGroupElement(group);
- nonSimplePlaintext.push(element);
- for (var i = 1; i < numElements; i++) {
- do {
- element = mathRandomGenerator_.nextZpGroupElement(group);
- } while (element.value.equals(nonSimplePlaintext[i - 1].value));
- nonSimplePlaintext.push(element);
- }
- return nonSimplePlaintext;
- };
- /**
- * Retrieves an ElGamal public subkey from an existing ElGamal public key.
- *
- * @function getSubPublicKey
- * @param {ZpSubgroup}
- * group The Zp subgroup to which all Zp group elements of the
- * subkey belong.
- * @param {ElGamalPublicKey}
- * publicKey The ElGamal public from which to extract the subkey.
- * @param {number}
- * fromIndex The index (inclusive) of the array of Zp group
- * elements of the existing key that marks the beginning of the
- * subkey.
- * @param {number}
- * toIndex The index (exlusive) of the array of Zp group elements
- * of the existing key that marks the end of the subkey.
- * @returns {ElGamalPublic} The ElGamal public subkey.
- */
- this.getSubPublicKey = function(group, publicKey, fromIndex, toIndex) {
- var subElements = [];
- var elements = publicKey.elements;
- for (var i = fromIndex; i < toIndex; i++) {
- subElements.push(elements[i]);
- }
- return elGamalService_.newPublicKey(group, subElements);
- };
- /**
- * Retrieves an ElGamalEncryptedElements object from an existing
- * ElGamalEncryptedElements object that contains a subset of the phi
- * elements of the existing object.
- *
- * @function getSubEncryptedElements
- * @param {ElGamalEncryptedElements}
- * encryptedElements The ElGamalEncryptedElements object from
- * which to extract the new object.
- * @param {number}
- * fromIndex The index (inclusive) of the phi array of the
- * existing ElGamalEncryptedElements object that marks the
- * beginning of the new phi array.
- * @param {number}
- * toIndex The index (exclusive) of the phi array of the
- * ElGamalEncryptedElements object that marks the end of the
- * new phi array.
- * @returns {ElGamalEncryptedElements} The new ElGamalEncryptedElements
- * object that contains a subset of the phis.
- */
- this.getSubEncryptedElements = function(
- encryptedElements, fromIndex, toIndex) {
- var gamma = encryptedElements.gamma;
- var phis = encryptedElements.phis;
- var subPhis = [];
- for (var i = fromIndex; i < toIndex; i++) {
- subPhis.push(phis[i]);
- }
- return elGamalService_.newEncryptedElements(
- gamma, subPhis, encryptedElements.secret);
- };
- /**
- * Generates the ciphertext needed to generate a plaintext exponent equality
- * zero-knowledge proof of knowledge. The array of base elements provided as
- * input must have an odd number of elements.
- *
- * The procedure is the following:
- * <ol>
- * <li>Generate the plaintext to encrypt by exponentiating a subset of the
- * base elements with the ephermeral key</li>
- * <li>Construct the ElGamal public key from an equal number of remaining
- * base elements</li>
- * <li>Generate the gamma element of the ciphertext by exponentiating the
- * remaining base element with the ephemeral key</li>
- * <li>Generate the phi array of the ciphertext by multiplying each
- * plaintext element with its corresponding public key element, the latter
- * being exponentiated with the message key</li>
- * <li>The resulting ciphertext can be used in a zero knowledge proof of
- * knowledge to show that each plaintext element was generated from the same
- * ephemeral key and that each phi element was generated from the same
- * message key.</li>
- * </ol>
- *
- * @param {ZpGroupElement[]}
- * baseElements The array of base elements.
- * @param {Exponent}
- * ephemeralKey The ephemeral key.
- * @param {Exponent}
- * messageKey The message key.
- * @returns {ElGamalEncryptedElements} The ciphertext.
- * @throws {Error}
- * If the number base elements provided as input is not an odd
- * number.
- */
- this.generatePlaintextExponentEqualityProofCiphertext = function(
- baseElements, ephemeralKey, messageKey) {
- var numBaseElements = baseElements.length;
- if ((numBaseElements % 2) === 0) {
- throw new Error(
- 'Number of base elements must be an odd number for plaintext exponent equality proof generation; Found ' +
- numBaseElements);
- }
- var numPlaintextElements = ((numBaseElements - 1) / 2);
- var plaintext = [];
- for (var i = 0; i < numPlaintextElements; i++) {
- plaintext.push(baseElements[1 + i].exponentiate(ephemeralKey));
- }
- var publicKeyElements = [];
- for (var j = 0; j < numPlaintextElements; j++) {
- publicKeyElements.push(baseElements[1 + numPlaintextElements + j]);
- }
- var gamma = baseElements[0].exponentiate(ephemeralKey);
- var phis = [];
- for (var k = 0; k < numPlaintextElements; k++) {
- phis.push(
- plaintext[k].multiply(publicKeyElements[k].exponentiate(messageKey)));
- }
- return elGamalService_.newEncryptedElements(gamma, phis);
- };
- }
|