123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- /*
- * 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 ElGamalKeyPair = require('./key-pair');
- var ElGamalPublicKey = require('./public-key');
- var ElGamalPrivateKey = require('./private-key');
- var ElGamalEncrypter = require('./encrypter');
- var ElGamalDecrypter = require('./decrypter');
- var ElGamalPrngDecrypter = require('./prng-decrypter');
- var ElGamalEncryptedElements = require('./encrypted-elements');
- var mathematical = require('scytl-mathematical');
- var validator = require('./input-validator');
- var codec = require('scytl-codec');
- module.exports = ElGamalCryptographyService;
- /**
- * @class ElGamalCryptographyService
- * @classdesc The ElGamal cryptography service API. To instantiate this object,
- * use the method {@link newService}.
- * @hideconstructor
- * @param {Object}
- * [options] An object containing optional arguments.
- * @param {SecureRandomService}
- * [options.secureRandomService=Created internally] The secure random
- * service to use.
- * @param {MathematicalService}
- * [options.mathematicalService=Created internally] The mathematical
- * service to use.
- */
- function ElGamalCryptographyService(options) {
- options = options || {};
- var secureRandomService;
- if (options.secureRandomService) {
- secureRandomService = options.secureRandomService;
- }
- var mathService_;
- if (options.mathematicalService) {
- mathService_ = options.mathematicalService;
- } else if (secureRandomService) {
- mathService_ =
- mathematical.newService({secureRandomService: secureRandomService});
- } else {
- mathService_ = mathematical.newService();
- }
- /**
- * Creates a new ElGamalPublicKey object, which encapsulates an ElGamal
- * public key.
- *
- * @function newPublicKey
- * @memberof ElGamalCryptographyService
- * @param {ZpSubgroup|string}
- * groupOrJson The Zp subgroup to which the elements of the
- * public key belong <b>OR</b> a JSON string representation of
- * an ElGamalPublicKey object, compatible with its
- * <code>toJson</code> method. For the latter case, any
- * additional input arguments will be ignored.
- * @param {ZpGroupElement[]}
- * elements The Zp group elements that comprise the public key.
- * @returns {ElGamalPublicKey} The ElGamalPublicKey object.
- * @throws {Error}
- * If the input data validation fails.
- */
- this.newPublicKey = function(groupOrJson, elements) {
- if (typeof groupOrJson !== 'string') {
- validator.checkIsObjectWithProperties(
- groupOrJson, 'Zp subgroup for new ElGamalPublicKey object');
- validator.checkZpGroupElements(
- elements, 'Zp group elements for new ElGamalPublicKey object',
- groupOrJson);
- return new ElGamalPublicKey(groupOrJson, elements);
- } else {
- return jsonToPublicKey(groupOrJson);
- }
- };
- /**
- * Creates a new ElGamalPrivateKey object, which encapsulates an ElGamal
- * private key.
- *
- * @function newPrivateKey
- * @memberof ElGamalCryptographyService
- * @param {ZpSubgroup|string}
- * groupOrJson The Zp subgroup to which the exponents of the
- * private key are associated <b>OR</b> a JSON string
- * representation of an ElGamalPrivateKey object, compatible with
- * its <code>toJson</code> method. For the latter case, any
- * additional input arguments will be ignored.
- * @param {Exponent[]}
- * exponents The exponents that comprise the private key.
- * @returns {ElGamalPrivateKey} The new ElGamalPrivateKey object.
- * @throws {Error}
- * If the input data validation fails.
- */
- this.newPrivateKey = function(groupOrJson, exponents) {
- if (typeof groupOrJson !== 'string') {
- validator.checkIsObjectWithProperties(
- groupOrJson, 'Zp subgroup for new ElGamalPrivateKey object');
- validator.checkExponents(
- exponents, 'Exponents for new ElGamalPrivateKey object',
- groupOrJson.q);
- return new ElGamalPrivateKey(groupOrJson, exponents);
- } else {
- return jsonToPrivateKey(groupOrJson);
- }
- };
- /**
- * Creates a new ElGamalKeyPair object, which encapsulates an ElGamal key
- * pair.
- *
- * @function newKeyPair
- * @memberof ElGamalCryptographyService
- * @param {ElGamalPublicKey}
- * publicKey The ElGamal public key comprising the key pair.
- * @param {ElGamalPrivateKey}
- * privateKey The ElGamal private key comprising the key pair.
- * @returns {ElGamalKeyPair} The new ElGamalKeyPair object.
- * @throws {Error}
- * If the input data validation fails.
- */
- this.newKeyPair = function(publicKey, privateKey) {
- checkElGamalPublicKey(
- publicKey, 'ElGamal public key for new ElGamalKeyPair object');
- checkElGamalPrivateKey(
- privateKey, 'ElGamal private key for new ElGamalKeyPair object');
- return new ElGamalKeyPair(publicKey, privateKey);
- };
- /**
- * Creates a new ElGamalEncryptedElements object, which encapsulates the
- * encryption or encryption pre-computation of some Zp group elements.
- *
- * @function newEncryptedElements
- * @memberof ElGamalCryptographyService
- * @param {ZpGroupElement|string}
- * gammaOrJson The gamma Zp group element comprising the
- * encryption or pre-computation <b>OR</b> a JSON string
- * representation of an ElGamalEncryptedElements object,
- * compatible with its <code>toJson</code> method. For the
- * latter case, any additional input arguments will be ignored.
- * @param {ZpGroupElement[]}
- * phis The phi Zp group elements comprising the encryption or
- * pre-computation.
- * @param {Exponent}
- * [secret] The secret exponent comprising the encryption or
- * pre-computation. <b>CAUTION:</b> Provide only when the secret
- * is really needed later (e.g. for zero-knowledge proof
- * generation).
- * @returns {ElGamalEncryptedElements} The new ElGamalEncryptedElements
- * object.
- * @throws {Error}
- * If the input data validation fails.
- */
- this.newEncryptedElements = function(gammaOrJson, phis, secret) {
- if (typeof gammaOrJson !== 'string') {
- validator.checkZpGroupElement(
- gammaOrJson,
- 'Gamma Zp group element for new ElGamalEncryptedElements object');
- validator.checkZpGroupElements(
- phis,
- 'Phi Zp group elements for new ElGamalEncryptedElements object');
- if (typeof secret !== 'undefined') {
- validator.checkExponent(secret, 'ElGamal encryption secret exponent');
- }
- return new ElGamalEncryptedElements(gammaOrJson, phis, secret);
- } else {
- return jsonToEncryptedElements(gammaOrJson);
- }
- };
- /**
- * Creates a new ElGamalEncrypter object for ElGamal encrypting data. It
- * must be initialized with an ElGamal public key.
- *
- * @function newEncrypter
- * @memberof ElGamalCryptographyService
- * @returns {ElGamalEncrypter} The new ElGamalEncrypter object.
- */
- this.newEncrypter = function() {
- return new ElGamalEncrypter(mathService_);
- };
- /**
- * Creates a new ElGamalDecrypter object for ElGamal decrypting data. It
- * must be initialized with an ElGamal private key.
- *
- * @function newDecrypter
- * @memberof ElGamalCryptographyService
- * @returns {ElGamalDecrypter} The new ElGamalDecrypter object.
- */
- this.newDecrypter = function() {
- return new ElGamalDecrypter(mathService_);
- };
- /**
- * Creates a new ElGamalPrngDecrypter object for ElGamal decrypting data,
- * via the PRNG seed used for encrypting the data. It must be initialized
- * with an ElGamal public key and a secure random generator, the latter
- * having been initialized with the seed.
- *
- * @function newPrngDecrypter
- * @memberof ElGamalCryptographyService
- * @returns {ElGamalPrngDecrypter} The new ElGamalPrngDecrypter object.
- */
- this.newPrngDecrypter = function() {
- return new ElGamalPrngDecrypter(mathService_);
- };
- function checkElGamalPublicKey(publicKey, label) {
- validator.checkElGamalPublicKey(publicKey, label);
- validator.checkIsInstanceOf(
- publicKey, ElGamalPublicKey, 'ElGamalPublicKey', label);
- }
- function checkElGamalPrivateKey(privateKey, label) {
- validator.checkElGamalPrivateKey(privateKey, label);
- validator.checkIsInstanceOf(
- privateKey, ElGamalPrivateKey, 'ElGamalPrivateKey', label);
- }
- function jsonToPublicKey(json) {
- validator.checkIsJsonString(
- json, 'JSON string to deserialize to ElGamalPublicKey object');
- var parsed = JSON.parse(json).publicKey;
- var p = codec.bytesToBigInteger(
- codec.base64Decode(parsed.zpSubgroup.p.toString()));
- var q = codec.bytesToBigInteger(
- codec.base64Decode(parsed.zpSubgroup.q.toString()));
- var g = codec.bytesToBigInteger(
- codec.base64Decode(parsed.zpSubgroup.g.toString()));
- var group = mathService_.newZpSubgroup(p, q, g);
- var elements = [];
- for (var i = 0; i < parsed.elements.length; i++) {
- var value =
- codec.bytesToBigInteger(codec.base64Decode(parsed.elements[i]));
- var element = mathService_.newZpGroupElement(p, q, value);
- elements.push(element);
- }
- return new ElGamalPublicKey(group, elements);
- }
- function jsonToPrivateKey(json) {
- validator.checkIsJsonString(
- json, 'JSON string representation of ElGamalPrivateKey object');
- var parsed = JSON.parse(json).privateKey;
- var g = codec.bytesToBigInteger(
- codec.base64Decode(parsed.zpSubgroup.g.toString()));
- var p = codec.bytesToBigInteger(
- codec.base64Decode(parsed.zpSubgroup.p.toString()));
- var q = codec.bytesToBigInteger(
- codec.base64Decode(parsed.zpSubgroup.q.toString()));
- var group = mathService_.newZpSubgroup(p, q, g);
- var exponents = [];
- for (var i = 0; i < parsed.exponents.length; i++) {
- var value =
- codec.bytesToBigInteger(codec.base64Decode(parsed.exponents[i]));
- var exponent = mathService_.newExponent(q, value);
- exponents.push(exponent);
- }
- return new ElGamalPrivateKey(group, exponents);
- }
- function jsonToEncryptedElements(json) {
- validator.checkIsJsonString(
- json, 'JSON string representation of ElGamalEncryptedElements object');
- var parsed = JSON.parse(json).ciphertext;
- var p = codec.bytesToBigInteger(codec.base64Decode(parsed.p));
- var q = codec.bytesToBigInteger(codec.base64Decode(parsed.q));
- var gammaFromJson = mathService_.newZpGroupElement(
- p, q, codec.bytesToBigInteger(codec.base64Decode(parsed.gamma)));
- var phisFromJson = [];
- for (var i = 0; i < parsed.phis.length; i++) {
- phisFromJson.push(mathService_.newZpGroupElement(
- p, q, codec.bytesToBigInteger(codec.base64Decode(parsed.phis[i]))));
- }
- return new ElGamalEncryptedElements(gammaFromJson, phisFromJson);
- }
- }
|