123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- /*
- * 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 ElGamalPublicKey = require('./public-key');
- var ElGamalEncryptedElements = require('./encrypted-elements');
- var validator = require('./input-validator');
- module.exports = ElGamalPrngDecrypter;
- /**
- * @class ElGamalPrngDecrypter
- * @classdesc The ElGamal PRNG decrypter API. To instantiate this object, use
- * the method {@link ElGamalCryptographyService.newPrngDecrypter}.
- * @hideconstructor
- * @param {MathematicalService}
- * mathService The mathematical service to use.
- */
- function ElGamalPrngDecrypter(mathService) {
- var mathArrayCompressor_ = mathService.newArrayCompressor();
- var mathRandomGenerator_ = mathService.newRandomGenerator();
- var publicKey_;
- var secureRandomGenerator_;
- /**
- * Initializes the ElGamal PRNG decrypter with the provided ElGamal public
- * key and secure random generator.
- *
- * @function init
- * @memberof ElGamalPrngDecrypter
- * @param {ElGamalPublicKey}
- * publicKey The ElGamal public key with which to initialize the
- * ElGamal PRNG decrypter.
- * @param {SecureRandomGenerator}
- * secureRandomGenerator The secure random generator which which
- * to initialize the ElGamal PRNG decrypter.
- * @returns {ElGamalPrngDecrypter} A reference to this object, to facilitate
- * method chaining.
- * @throws {Error}
- * If the input data validation fails.
- */
- this.init = function(publicKey, secureRandomGenerator) {
- checkElGamalPublicKey(
- publicKey,
- 'ElGamal public key with which to initialize ElGamal PRNG decrypter');
- validator.checkIsObjectWithProperties(
- secureRandomGenerator,
- 'Secure random generator with which to initialize ElGamal PRNG decrypter');
- publicKey_ = publicKey;
- secureRandomGenerator_ = secureRandomGenerator;
- return this;
- };
- /**
- * ElGamal decrypts some ElGamal encrypted Zp group elements. Before using
- * this method, the decrypter must have been initialized with an ElGamal
- * public key and a secure random generator, via the method
- * {@link ElGamalPrngDecrypter.init}.
- * <p>
- * The number of phi elements that comprise the encryption must be less than
- * or equal to the number of elements in the ElGamal public key that was
- * used to initialize the ElGamal PRNG decrypter.
- *
- * @function decrypt
- * @memberof ElGamalPrngDecrypter
- * @param {ElGamalEncryptedElements}
- * encryptedElements The ElGamal encrypted Zp group elements.
- * @param {Object}
- * [options] An object containing optional arguments.
- * @param {boolean}
- * [options.confirmMembership=false] If <true>true</false>, then
- * each of the encryption elements will be checked for membership
- * in the Zp subgroup associated with the public key.
- * <b>WARNING:</b> This operation is computationally costly and increases
- * linearly with the number of encrypted elements.
- * @param {boolean}
- * [options.useShortExponent=false] If <code>true</code>, a
- * <code>short</code> secret exponent was used for the
- * encryption and must be regenerated for the decryption.
- * @returns {ZpGroupElement[]} The decrypted Zp group elements.
- * @throws {Error}
- * If the input data validation fails.
- */
- this.decrypt = function(encryptedElements, options) {
- if (typeof publicKey_ === 'undefined') {
- throw new Error(
- 'Could not ElGamal decrypt; PRNG decrypter has not been initialized with any ElGamal public key');
- }
- options = options || {};
- checkDecryptionData(publicKey_, encryptedElements, options);
- var phis = encryptedElements.phis;
- var group = publicKey_.group;
- var checkMembership = options.checkMembership || false;
- if (checkMembership) {
- for (var i = 0; i < phis.length; i++) {
- if (!(group.isGroupMember(phis[i]))) {
- throw new Error(
- 'Found phi element with value: ' + phis[i].value +
- ' that is not member of Zp subgroup associated with public key.');
- }
- }
- }
- var compressedPublicKey = compressPublicKey(publicKey_, phis.length);
- var publicKeyElements = compressedPublicKey.elements;
- var useShortExponent = options.useShortExponent || false;
- var secret = mathRandomGenerator_.nextExponent(group, {
- secureRandomGenerator: secureRandomGenerator_,
- useShortExponent: useShortExponent
- });
- var negatedSecret = secret.negate();
- var decryptedElements = [];
- for (var j = 0; j < encryptedElements.phis.length; j++) {
- decryptedElements.push(
- publicKeyElements[j].exponentiate(negatedSecret).multiply(phis[j]));
- }
- return decryptedElements;
- };
- function checkElGamalPublicKey(publicKey, label) {
- validator.checkElGamalPublicKey(publicKey, label);
- validator.checkIsInstanceOf(
- publicKey, ElGamalPublicKey, 'ElGamalPublicKey', label);
- }
- function checkElGamalEncryptedElements(elements, label) {
- validator.checkElGamalEncryptedElements(elements, label);
- validator.checkIsInstanceOf(
- elements, ElGamalEncryptedElements, 'ElGamalEncryptedElements', label);
- }
- function checkDecryptionData(publicKey, encryptedElements, options) {
- checkElGamalEncryptedElements(
- encryptedElements, 'ElGamal encrypted elements to decrypt, using PRNG');
- var numPublicKeyElements = publicKey.elements.length;
- var numPhis = encryptedElements.phis.length;
- if (numPublicKeyElements < numPhis) {
- throw new Error(
- 'Expected number of phi elements to decrypt, using PRNG, to be less than or equal to number of public key elements: ' +
- numPublicKeyElements + ' ; Found: ' + numPhis);
- }
- var confirmMembership = options.confirmMembership;
- if (typeof confirmMembership !== 'undefined') {
- validator.checkIsType(
- confirmMembership, 'boolean',
- '\"Confirm group membership\" flag for decryption, using PRNG');
- }
- var useShortExponent = options.useShortExponent;
- if (typeof useShortExponent !== 'undefined') {
- validator.checkIsType(
- useShortExponent, 'boolean',
- '\"Use shoft exponent\" flag for decryption, using PRNG');
- }
- }
- function compressPublicKey(publicKey, numPhis) {
- var elements = publicKey.elements;
- var group = publicKey.group;
- if (elements.length === numPhis) {
- return publicKey;
- } else {
- var compressedElements =
- mathArrayCompressor_.compressTrailingZpGroupElements(
- elements, numPhis);
- return new ElGamalPublicKey(group, compressedElements);
- }
- }
- }
|