/* * 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 ZpSubgroup = require('./zp-subgroup'); var ZpGroupElement = require('./zp-group-element'); var Exponent = require('./exponent'); var MathematicalArrayCompressor = require('./array-compressor'); var MathematicalRandomGenerator = require('./random-generator'); var MathematicalGroupHandler = require('./group-handler'); var secureRandom = require('scytl-securerandom'); var validator = require('./input-validator'); var codec = require('scytl-codec'); var forge = require('node-forge'); var BigInteger = forge.jsbn.BigInteger; module.exports = MathematicalService; /** * @class MathematicalService * @classdesc The mathematical 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. */ function MathematicalService(options) { options = options || {}; var secureRandomService; if (options.secureRandomService) { secureRandomService = options.secureRandomService; } else { secureRandomService = secureRandom.newService(); } /** * Creates a new MathematicalRandomGenerator object for generating random * mathematical objects. * * @function newRandomGenerator * @memberof MathematicalService * @returns {MathematicalRandomGenerator} The new * MathematicalRandomGenerator object. */ this.newRandomGenerator = function() { return new MathematicalRandomGenerator(secureRandomService); }; } MathematicalService.prototype = { /** * Creates a new ZpSubgroup object, which encapsulates a Zp subgroup. * * @function newZpSubgroup * @memberof MathematicalService * @param {forge.jsbn.BigInteger|string} * pOrJson The modulus of the Zp subgroup OR a JSON * string representation of a ZpSubgroup object, compatible with * its toJson method. For the latter case, any * additional input arguments will be ignored. * @param {forge.jsbn.BigInteger} * q The order of the Zp subgroup. It must be within the range * [1, p-1]. * @param {forge.jsbn.BigInteger} * g The generator of the Zp subgroup. It must be within the * range [2, p-1]. * @returns {ZpSubgroup} The new ZpSubgroup object. * @throws {Error} * If the input data validation fails. */ newZpSubgroup: function(pOrJson, q, g) { if (typeof pOrJson !== 'string') { validator.checkZpSubgroupModulus( pOrJson, 'Modulus p to create new ZpSubgroup object'); validator.checkZpSubgroupOrder( q, 'Order q to create new ZpSubgroup object', pOrJson); validator.checkZpSubgroupGenerator( g, 'Generator to create new ZpSubgroup object', pOrJson); return new ZpSubgroup(pOrJson, q, g); } else { return jsonToZpSubgroup(pOrJson); } }, /** * Creates a new ZpGroupElement object, which encapsulates a Zp group * element. * * @function newZpGroupElement * @memberof MathematicalService * @param {forge.jsbn.BigInteger|string} * pOrJson The modulus of the Zp subgroup to which the Zp group * element belongs OR a JSON string representation of a * ZpGroupElement object, compatible with its toJson * method. For the latter case, any additional input arguments * will be ignored. * @param {forge.jsbn.BigInteger} * q The order of the Zp subgroup to which the Zp group element * belongs. It must be within the range [1, p-1]. * @param {forge.jsbn.BigInteger} * value The value of the Zp group element. It must be within the * range [1, p-1]. * @returns {ZpGroupElement} The new ZpGroupElement object. * @throws {Error} * If the input data validation fails. */ newZpGroupElement: function(pOrJson, q, value) { if (typeof pOrJson !== 'string') { validator.checkZpSubgroupModulus( pOrJson, 'Modulus p to create new ZpGroupElement object'); validator.checkZpSubgroupOrder( q, 'Order q to create new ZpGroupElement object', pOrJson); validator.checkZpGroupElementValue( value, 'Value to create new ZpGroupElement object', pOrJson); return new ZpGroupElement(pOrJson, q, value); } else { return jsonToZpGroupElement(pOrJson); } }, /** * Creates a new Exponent object, which encapsulates an exponent. * * @function newExponent * @memberof MathematicalService * @param {forge.jsbn.BigInteger|string} * qOrJson The order of the Zp subgroup to which the exponent is * associated OR a JSON string representation of an * Exponent object, compatible with its toJson * method. For the latter case, any additional input arguments * will be ignored. * @param {forge.jsbn.BigInteger} * value The value of the exponent. If this value is greater than * or equal to q it will be adjusted to be less * then q, via the mod(q) * operation. * @returns {Exponent} The new Exponent object. * @throws {Error} * If the input data validation fails. */ newExponent: function(qOrJson, value) { if (typeof qOrJson !== 'string') { validator.checkZpSubgroupOrder( qOrJson, 'Order q to create new Exponent object'); validator.checkExponentValue( value, 'Value to create new Exponent object'); return new Exponent(qOrJson, value); } else { return jsonToExponent(qOrJson); } }, /** * Creates a new quadratic residue Zp subgroup from the modulus * p and generator provided as input. *

* NOTE: This method creates a particular type of Zp subgroup, with * the following property: *

* p = 2q + 1 * * @function newQuadraticResidueGroup * @memberof MathematicalService * @param {forge.jsbn.BigInteger} * p The modulus of the quadratic residue group. * @param {forge.jsbn.BigInteger} * g The generator of the quadratic residue group. * @returns {ZpSubgroup} The quadratic residue group. * @throws {Error} * If the input validation fails. */ newQuadraticResidueGroup: function(p, g) { validator.checkZpSubgroupModulus( p, 'Modulus p for quadratic residue group generation'); validator.checkZpSubgroupGenerator( g, 'Generator for quadratic residue group generation', p); var q = p.subtract(BigInteger.ONE).divide(new BigInteger('2')); return new ZpSubgroup(p, q, g); }, /** * Creates a new MathematicalArrayCompressor object for reducing the size of * arrays containing mathematical objects. * * @function newArrayCompressor * @memberof MathematicalService * @returns {MathematicalArrayCompressor} The new * MathematicalArrayCompressor object. */ newArrayCompressor: function() { return new MathematicalArrayCompressor(); }, /** * Creates a new MathematicalGroupHandler object for performing operations * involving mathematical groups. * * @function newGroupHandler * @memberof MathematicalService * @returns {MathematicalGroupHandler} The new MathematicalGroupHandler * object. */ newGroupHandler: function() { return new MathematicalGroupHandler(); } }; function jsonToZpSubgroup(json) { validator.checkIsJsonString( json, 'JSON string representation of ZpSubgroup object'); var parsed = JSON.parse(json); var p = codec.bytesToBigInteger(codec.base64Decode(parsed.zpSubgroup.p)); var q = codec.bytesToBigInteger(codec.base64Decode(parsed.zpSubgroup.q)); var g = codec.bytesToBigInteger(codec.base64Decode(parsed.zpSubgroup.g)); return new ZpSubgroup(p, q, g); } function jsonToZpGroupElement(json) { validator.checkIsJsonString( json, 'JSON string representation of ZpGroupElement object'); var parsed = JSON.parse(json); var p = codec.bytesToBigInteger(codec.base64Decode(parsed.zpGroupElement.p)); var q = codec.bytesToBigInteger(codec.base64Decode(parsed.zpGroupElement.q)); var value = codec.bytesToBigInteger(codec.base64Decode(parsed.zpGroupElement.value)); return new ZpGroupElement(p, q, value); } function jsonToExponent(json) { validator.checkIsJsonString( json, 'JSON string representation of Exponent object'); var parsed = JSON.parse(json); var q = codec.bytesToBigInteger(codec.base64Decode(parsed.exponent.q)); var value = codec.bytesToBigInteger(codec.base64Decode(parsed.exponent.value)); return new Exponent(q, value); }