123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- /*
- * 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 ZeroKnowledgeProof = require('./proof.js');
- var ZeroKnowledgeProofPreComputation = require('./pre-computation.js');
- var HashGenerator = require('./hash-generator');
- var codec = require('scytl-codec');
- module.exports = ZeroKnowledgeProofProver;
- /**
- * @class ZeroKnowledgeProofProver
- * @classdesc Encapsulates a zero-knowledge proof of knowledge prover that uses
- * the PHI function defined in Maurer's unified framework.
- * @private
- * @param {MessageDigestService}
- * messageDigestService The message digest service to use.
- * @param {MathematicalService}
- * mathService The mathematical service to use.
- */
- function ZeroKnowledgeProofProver(messageDigestService, mathService) {
- var mathRandomGenerator_ = mathService.newRandomGenerator();
- /**
- * Generates a zero-knowledge proof of knowledge.
- *
- * @function prove
- * @memberof ZeroKnowledgeProofProver
- * @param {ZpSubgroup}
- * group The Zp subgroup to which all exponents and Zp group
- * elements required for the proof generation are associated or
- * belong, respectively.
- * @param {Exponent[]}
- * privateValues The private values used to generate the proof.
- * @param {ZpGroupElement[]}
- * publicValues The public values used to generate the proof.
- * @param {Uint8Array|string}
- * data Auxiliary data.
- * @param {ZeroKnowledgeProofPreComputation}
- * preComputation The zero-knowledge proof of knowledge
- * pre-computation.
- * @param {ZpGroupElement[]}
- * [elements] A parameter to be used only for the generation of
- * OR zero-knowledge proofs of knowledge. It consists of the
- * possible Zp group elements used to generate the ciphertext.
- * @param {number}
- * [index] A parameter that is only to be used if the previous
- * parameter was used. It is the secret index of the Zp group
- * element that was used to generate the ciphertext of an OR
- * zero-knowledge proof of knowledge.
- * @returns {ZeroKnowledgeProof} The generated zero-knowledge proof of
- * knowledge.
- */
- this.prove = function(
- group, privateValues, publicValues, data, preComputation, elements,
- index) {
- if (typeof elements !== 'undefined') {
- preComputation = updatePreComputation(
- group, preComputation, publicValues, elements, index);
- }
- var hash =
- generateHash(group, publicValues, preComputation.phiOutputs, data);
- var proofValues = generateProofValues(
- group, privateValues, hash, preComputation.exponents, index);
- return new ZeroKnowledgeProof(hash, proofValues);
- };
- /**
- * Pre-computes a Schnorr zero-knowledge proof of knowledge. IMPORTANT: The
- * same pre-computed values must not be used twice.
- *
- * @function preComputeSchnorrProof
- * @memberof ZeroKnowledgeProofProver
- * @param {ZpSubgroup}
- * group The Zp subgroup to which all exponents and Zp group
- * elements required for the pre-computation are associated or
- * belong, respectively.
- * @param {PhiFunction}
- * phiFunction The PHI function used for the pre-computation.
- * @param {ProgressMeter}
- * [progressMeter=Not used] A progress meter.
- * @returns {ZeroKnowledgeProofPreComputation} The Schnorr zero-knowledge
- * proof of knowledge pre-computation.
- */
- this.preCompute = function(group, phiFunction, progressMeter) {
- var exponents = generateExponents(group, phiFunction.numInputs);
- var phiOutputs = phiFunction.calculate(exponents, progressMeter);
- return new ZeroKnowledgeProofPreComputation(exponents, phiOutputs);
- };
- function generateHash(group, publicValues, phiOutputs, data) {
- var hashGenerator = new HashGenerator(messageDigestService);
- var hashBytes = hashGenerator.generate(publicValues, phiOutputs, data);
- var hashByteArray = Array.apply([], hashBytes);
- hashByteArray.unshift(0);
- var value = codec.bytesToBigInteger(hashBytes);
- return mathService.newExponent(group.q, value);
- }
- function generateProofValues(group, privateValues, hash, exponents, index) {
- var proofValues = [];
- var proofValue;
- if (typeof index === 'undefined') {
- for (var i = 0; i < privateValues.length; i++) {
- proofValue =
- exponents[i].value.add(privateValues[i].value.multiply(hash.value));
- proofValues.push(mathService.newExponent(group.q, proofValue));
- }
- } else {
- var numElements = exponents.length / 2;
- var updatedHash = hash;
- for (var j = 0; j < numElements; j++) {
- if (j === index) {
- for (var k = 0; k < numElements; k++) {
- if (k !== index) {
- updatedHash = updatedHash.subtract(exponents[k]);
- }
- }
- proofValues.push(updatedHash);
- } else {
- proofValues.push(exponents[j]);
- }
- }
- for (var m = numElements; m < (numElements * 2); m++) {
- if (m === (numElements + index)) {
- proofValue = exponents[m].value.add(
- privateValues[0].value.multiply(updatedHash.value));
- proofValues.push(mathService.newExponent(group.q, proofValue));
- } else {
- proofValues.push(exponents[m]);
- }
- }
- }
- return proofValues;
- }
- function updatePreComputation(
- group, preComputation, publicValues, elements, index) {
- var gamma = publicValues[0];
- var phi = publicValues[1];
- var numElements = elements.length;
- var challenges = generateExponents(group, numElements);
- var updatedExponents = challenges.concat(preComputation.exponents);
- var updatedPhiOutputs = [];
- var phiOutputs = preComputation.phiOutputs;
- for (var j = 0; j < numElements; j++) {
- var offset = 2 * j;
- if (j === index) {
- updatedPhiOutputs.push(phiOutputs[offset]);
- updatedPhiOutputs.push(phiOutputs[offset + 1]);
- } else {
- var gammaFactor = gamma.invert().exponentiate(challenges[j]);
- var phiFactor =
- (phi.invert().multiply(elements[j])).exponentiate(challenges[j]);
- updatedPhiOutputs.push(phiOutputs[offset].multiply(gammaFactor));
- updatedPhiOutputs.push(phiOutputs[offset + 1].multiply(phiFactor));
- }
- }
- return new ZeroKnowledgeProofPreComputation(
- updatedExponents, updatedPhiOutputs);
- }
- function generateExponents(group, numExponents) {
- var exponents = [];
- for (var i = 0; i < numExponents; i++) {
- exponents.push(mathRandomGenerator_.nextExponent(group));
- }
- return exponents;
- }
- }
|