/* * 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 HashGenerator = require('./hash-generator'); var codec = require('scytl-codec'); module.exports = ZeroKnowledgeProofVerifier; /** * @class ZeroKnowledgeProofVerifier * @classdesc Encapsulates a zero-knowledge proof of knowledge verifier that * uses the PHI function defined in Maurer's unified framework. * @private * @param {MessageDigestService} * messageDigestService The message digest service. * @param {MathematicalService} * mathService The mathematical service. */ function ZeroKnowledgeProofVerifier(messageDigestService, mathService) { /** * Verifies a zero-knowledge proof of knowledge. * * @function verify * @memberof ZeroKnowledgeProofVerifier * @param {ZpSubgroup} * group The Zp subgroup to which all exponents and Zp group * elements required for the proof verification are associated or * belong, respectively. * @param {ZeroKnowledgeProof} * proof The zero-knowledge proof of knowledge to verify. * @param {PhiFunction} * phiFunction The PHI function used for the verification. * @param {ZpGroupElement[]} * publicValues The public values used to verify the proof. * @param {Uint8Array|string} * data Auxiliary data. * @param {ZpGroupElement[]|ProgressMeter} * [elementsOrProgressMeter=Not used] The possible Zp group * elements used to generate the ciphertext of an OR * zero-knowledge proof OR a progress meter. * @param {number} * [progressMeter=Not used] A parameter that can be used as a * progress meter, for the case in which the previous parameter * was of type ZpGroupElements[]. * @returns {boolean} true if the zero-knowledge proof of * knowledge was verified, false otherwise. */ this.verify = function( group, proof, phiFunction, publicValues, data, elementsOrProgressMeter, progressMeter) { var elements; if (!isArray(elementsOrProgressMeter)) { progressMeter = elementsOrProgressMeter; } else { elements = elementsOrProgressMeter; } var proofHash = proof.hash; var phiOutputs; var generatedValues; if (typeof elements === 'undefined') { phiOutputs = phiFunction.calculate(proof.values, progressMeter); generatedValues = generateValues(publicValues, phiOutputs, proofHash); } else { var numElements = elements.length; var proofValues = proof.values; var challenges = proofValues.slice(0, numElements); var phiInputs = proofValues.slice(numElements, numElements * 2); phiOutputs = phiFunction.calculate(phiInputs, progressMeter); generatedValues = generateValues(publicValues, phiOutputs, elements, challenges); } var calculatedHash = generateHash(group, publicValues, generatedValues, data); return proofHash.equals(calculatedHash); }; function generateValues( publicValues, phiOutputs, proofHashOrElements, challenges) { var proofHash; var elements; if (!isArray(proofHashOrElements)) { proofHash = proofHashOrElements; } else { elements = proofHashOrElements; } var generatedValues = []; if (typeof proofHash !== 'undefined') { for (var i = 0; i < phiOutputs.length; i++) { generatedValues.push(phiOutputs[i].multiply( publicValues[i].exponentiate(proofHash.negate()))); } } else { var gamma = publicValues[0]; var phi = publicValues[1]; for (var j = 0; j < challenges.length; j++) { var offset = 2 * j; var gammaFactor = gamma.invert().exponentiate(challenges[j]); var phiFactor = (phi.invert().multiply(elements[j])).exponentiate(challenges[j]); generatedValues.push(phiOutputs[offset].multiply(gammaFactor)); generatedValues.push(phiOutputs[offset + 1].multiply(phiFactor)); } } return generatedValues; } function generateHash(group, publicValues, generatedValues, data) { var hashGenerator = new HashGenerator(messageDigestService); var hashBytes = hashGenerator.generate(publicValues, generatedValues, data); var hashByteArray = Array.apply([], hashBytes); hashByteArray.unshift(0); var value = codec.bytesToBigInteger(hashBytes); return mathService.newExponent(group.q, value); } function isArray(a) { return (!!a) && (a.constructor === Array); } }