verifier.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. /*
  2. * Copyright 2018 Scytl Secure Electronic Voting SA
  3. *
  4. * All rights reserved
  5. *
  6. * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
  7. */
  8. /* jshint node:true */
  9. 'use strict';
  10. var HashGenerator = require('./hash-generator');
  11. var codec = require('scytl-codec');
  12. module.exports = ZeroKnowledgeProofVerifier;
  13. /**
  14. * @class ZeroKnowledgeProofVerifier
  15. * @classdesc Encapsulates a zero-knowledge proof of knowledge verifier that
  16. * uses the PHI function defined in Maurer's unified framework.
  17. * @private
  18. * @param {MessageDigestService}
  19. * messageDigestService The message digest service.
  20. * @param {MathematicalService}
  21. * mathService The mathematical service.
  22. */
  23. function ZeroKnowledgeProofVerifier(messageDigestService, mathService) {
  24. /**
  25. * Verifies a zero-knowledge proof of knowledge.
  26. *
  27. * @function verify
  28. * @memberof ZeroKnowledgeProofVerifier
  29. * @param {ZpSubgroup}
  30. * group The Zp subgroup to which all exponents and Zp group
  31. * elements required for the proof verification are associated or
  32. * belong, respectively.
  33. * @param {ZeroKnowledgeProof}
  34. * proof The zero-knowledge proof of knowledge to verify.
  35. * @param {PhiFunction}
  36. * phiFunction The PHI function used for the verification.
  37. * @param {ZpGroupElement[]}
  38. * publicValues The public values used to verify the proof.
  39. * @param {Uint8Array|string}
  40. * data Auxiliary data.
  41. * @param {ZpGroupElement[]|ProgressMeter}
  42. * [elementsOrProgressMeter=Not used] The possible Zp group
  43. * elements used to generate the ciphertext of an OR
  44. * zero-knowledge proof <b>OR</b> a progress meter.
  45. * @param {number}
  46. * [progressMeter=Not used] A parameter that can be used as a
  47. * progress meter, for the case in which the previous parameter
  48. * was of type <code>ZpGroupElements[]</code>.
  49. * @returns {boolean} <code>true</code> if the zero-knowledge proof of
  50. * knowledge was verified, <code>false</code> otherwise.
  51. */
  52. this.verify = function(
  53. group, proof, phiFunction, publicValues, data, elementsOrProgressMeter,
  54. progressMeter) {
  55. var elements;
  56. if (!isArray(elementsOrProgressMeter)) {
  57. progressMeter = elementsOrProgressMeter;
  58. } else {
  59. elements = elementsOrProgressMeter;
  60. }
  61. var proofHash = proof.hash;
  62. var phiOutputs;
  63. var generatedValues;
  64. if (typeof elements === 'undefined') {
  65. phiOutputs = phiFunction.calculate(proof.values, progressMeter);
  66. generatedValues = generateValues(publicValues, phiOutputs, proofHash);
  67. } else {
  68. var numElements = elements.length;
  69. var proofValues = proof.values;
  70. var challenges = proofValues.slice(0, numElements);
  71. var phiInputs = proofValues.slice(numElements, numElements * 2);
  72. phiOutputs = phiFunction.calculate(phiInputs, progressMeter);
  73. generatedValues =
  74. generateValues(publicValues, phiOutputs, elements, challenges);
  75. }
  76. var calculatedHash =
  77. generateHash(group, publicValues, generatedValues, data);
  78. return proofHash.equals(calculatedHash);
  79. };
  80. function generateValues(
  81. publicValues, phiOutputs, proofHashOrElements, challenges) {
  82. var proofHash;
  83. var elements;
  84. if (!isArray(proofHashOrElements)) {
  85. proofHash = proofHashOrElements;
  86. } else {
  87. elements = proofHashOrElements;
  88. }
  89. var generatedValues = [];
  90. if (typeof proofHash !== 'undefined') {
  91. for (var i = 0; i < phiOutputs.length; i++) {
  92. generatedValues.push(phiOutputs[i].multiply(
  93. publicValues[i].exponentiate(proofHash.negate())));
  94. }
  95. } else {
  96. var gamma = publicValues[0];
  97. var phi = publicValues[1];
  98. for (var j = 0; j < challenges.length; j++) {
  99. var offset = 2 * j;
  100. var gammaFactor = gamma.invert().exponentiate(challenges[j]);
  101. var phiFactor =
  102. (phi.invert().multiply(elements[j])).exponentiate(challenges[j]);
  103. generatedValues.push(phiOutputs[offset].multiply(gammaFactor));
  104. generatedValues.push(phiOutputs[offset + 1].multiply(phiFactor));
  105. }
  106. }
  107. return generatedValues;
  108. }
  109. function generateHash(group, publicValues, generatedValues, data) {
  110. var hashGenerator = new HashGenerator(messageDigestService);
  111. var hashBytes = hashGenerator.generate(publicValues, generatedValues, data);
  112. var hashByteArray = Array.apply([], hashBytes);
  113. hashByteArray.unshift(0);
  114. var value = codec.bytesToBigInteger(hashBytes);
  115. return mathService.newExponent(group.q, value);
  116. }
  117. function isArray(a) {
  118. return (!!a) && (a.constructor === Array);
  119. }
  120. }