/*
* 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);
}