/*
* 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';
module.exports = PhiFunction;
/**
* @class PhiFunction
* @classdesc Encapsulates the PHI function defined by Maurer's unified
* framework for zero-knowledge proofs of knowledge. This object is
* instantiated internally by the prove
method of any
* zero-knowledge proof of knowledge prover object or the
* verify
method of any zero-knowledge proof of
* knowledge verifier object.
* @private
* @param {number}
* numInputs The number of inputs of the PHI function.
* @param {number}
* numOutputs The number of outputs of the PHI function.
* @param {number[][][]}
* computationRules The computation rules of the PHI function.
* @param {ZpGroupElement[]}
* baseElements The base elements of the PHI function.
*/
function PhiFunction(numInputs, numOutputs, computationRules, baseElements) {
validateComputationRules(
numInputs, numOutputs, computationRules, baseElements);
this.numInputs = numInputs;
this.numOutputs = numOutputs;
Object.freeze(this.computationRules = computationRules);
Object.freeze(this.baseElements = baseElements);
function validateComputationRules(
numSecrets, numOutputs, computationRules, baseElements) {
// Validate that both of the values in each of the
// pairs of rules have values in the correct ranges.
var numBaseElements = baseElements.length;
for (var i = 0; i < numOutputs; i++) {
for (var j = 0; j < computationRules[i].length; j++) {
// Validate the first value of the pair
var pairValue1 = computationRules[i][j][0];
if ((pairValue1 < 1) || (pairValue1 > numBaseElements)) {
throw new Error(
'First value in index pair is invalid; It should be within the range [1, ' +
numBaseElements + '], but it was ' + pairValue1);
}
// Validate the second value of the pair.
var pairValue2 = computationRules[i][j][1];
if ((pairValue2 < 1) || (pairValue2 > numSecrets)) {
throw new Error(
'Second value in index pair is valid; It should be within the range [1, ' +
numSecrets + '], but it was ' + pairValue2);
}
}
}
}
}
PhiFunction.prototype = {
/**
* Performs the PHI function calculation.
*
* @function calculate
* @memberof PhiFunction
* @param {Exponent[]}
* exponents The exponents with which to exponentiate the base
* elements.
* @param {function}
* [progressCallback] An optional callback function if a progress
* meter is being used.
* @returns {ZpGroupElement[]} The array of Zp group elements that comprise
* the output of the PHI function calculation.
*/
calculate: function(exponents, progressMeter) {
var measureProgress = false;
if (typeof progressMeter !== 'undefined') {
progressMeter.reset();
measureProgress = true;
}
var partialResult;
var resultForThisListOfPairs;
var result = [];
var progress = 0;
for (var i = 0; i < this.computationRules.length; i++) {
var numPairsInList = this.computationRules[i].length;
resultForThisListOfPairs =
this.baseElements[this.computationRules[i][0][0] - 1].exponentiate(
exponents[this.computationRules[i][0][1] - 1]);
if (measureProgress) {
progressMeter.update(++progress);
}
for (var j = 1; j < numPairsInList; j++) {
var index1 = this.computationRules[i][j][0];
index1 = index1 - 1;
var index2 = this.computationRules[i][j][1];
index2 = index2 - 1;
partialResult =
this.baseElements[index1].exponentiate(exponents[index2]);
resultForThisListOfPairs =
resultForThisListOfPairs.multiply(partialResult);
if (measureProgress) {
progressMeter.update(++progress);
}
}
result.push(resultForThisListOfPairs);
}
return result;
}
};