plaintext-exponent-equality-proof-handler.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  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 ZeroKnowledgeProofProver = require('../prover');
  11. var ZeroKnowledgeProofVerifier = require('../verifier');
  12. var ZeroKnowledgeProof = require('../proof');
  13. var ZeroKnowledgeProofPreComputation = require('../pre-computation');
  14. var PhiFunction = require('../phi-function');
  15. var ProgressMeter = require('../progress-meter');
  16. var validator = require('../input-validator');
  17. module.exports = PlaintextExponentEqualityProofHandler;
  18. /**
  19. * @class PlaintextExponentEqualityProofHandler
  20. * @classdesc Encapsulates a handler for the plaintext exponent equality
  21. * zero-knowledge proof of knowledge generation, pre-computation and
  22. * verification processes. To instantiate this object, use the method
  23. * {@link
  24. * ZeroKnowledgeProofService.newPlaintextExponentEqualityProofHandler}.
  25. * @param {ZpSubgroup}
  26. * group The Zp subgroup to which all exponents and Zp group elements
  27. * required for the proof generation are associated or belong,
  28. * respectively.
  29. * @param {MessageDigestService}
  30. * messageDigestService The message digest service.
  31. * @param {MathematicalService}
  32. * mathematicalService The mathematical service.
  33. */
  34. function PlaintextExponentEqualityProofHandler(
  35. group, messageDigestService, mathematicalService) {
  36. var NUM_PHI_INPUTS = 2;
  37. var DEFAULT_AUXILIARY_DATA = 'PlaintextExponentEqualityProof';
  38. var prover_ =
  39. new ZeroKnowledgeProofProver(messageDigestService, mathematicalService);
  40. var verifier_ =
  41. new ZeroKnowledgeProofVerifier(messageDigestService, mathematicalService);
  42. var progressCallback_;
  43. var progressPercentMinCheckInterval_;
  44. var measureProgress_ = false;
  45. var baseElements_;
  46. /**
  47. * Initializes the handler with the provided base elements.
  48. *
  49. * @function init
  50. * @memberof PlaintextExponentEqualityProofHandler
  51. * @param {ZpGroupElement[]}
  52. * baseElements The base elements.
  53. * @returns {PlaintextExponentEqualityProofHandler} A reference to this
  54. * object, to facilitate method chaining.
  55. * @throws {Error}
  56. * If the input data validation fails.
  57. */
  58. this.init = function(baseElements) {
  59. validator.checkZpGroupElements(
  60. baseElements,
  61. 'Base elements for plaintext exponent eqaulity proof handler initialization',
  62. group);
  63. baseElements_ = baseElements;
  64. return this;
  65. };
  66. /**
  67. * Generates a plaintext exponent equality zero-knowledge proof of
  68. * knowledge. Before using this method, the handler must have been
  69. * initialized with base elements, via the method
  70. * {@link PlaintextExponentEqualityProofHandler.init}.
  71. *
  72. * @function generate
  73. * @memberof PlaintextExponentEqualityProofHandler
  74. * @param {Exponent}
  75. * firstSecret The "ephemeral key" used to generate the gamma
  76. * element of the ciphertext, the knowledge of which must be
  77. * proven.
  78. * @param {Exponent}
  79. * secondSecret The "message key" used to generate the phi
  80. * elements of the ciphertext, the knowledge of which must be
  81. * proven.
  82. * @param {ElGamalEncryptedElements}
  83. * ciphertext The ciphertext.
  84. * @param {Object}
  85. * [options] An object containing optional arguments.
  86. * @param {Uint8Array|string}
  87. * [options.data='PlaintextExponentEqualityProof'] Auxiliary
  88. * data.
  89. * @param {ZeroKnowledgeProofPreComputation}
  90. * [options.preComputation=Generated internally] A
  91. * pre-computation of the plaintext exponent equality
  92. * zero-knowledge proof of knowledge.
  93. * @returns {ZeroKnowledgeProof} The plaintext exponent equality
  94. * zero-knowledge proof of knowledge.
  95. * @throws {Error}
  96. * If the input data validation fails.
  97. */
  98. this.generate = function(firstSecret, secondSecret, ciphertext, options) {
  99. if (typeof baseElements_ === 'undefined') {
  100. throw new Error(
  101. 'Cannot generate plaintext exponent equality proof; Associated handler has not been initialized with any base elements');
  102. }
  103. options = options || {};
  104. checkGenerationData(firstSecret, secondSecret, ciphertext, options);
  105. var data = options.data;
  106. if (typeof data === 'undefined') {
  107. data = DEFAULT_AUXILIARY_DATA;
  108. }
  109. var preComputation = options.preComputation;
  110. var privateValues = [firstSecret, secondSecret];
  111. var publicValues = generatePublicValues(ciphertext);
  112. if (typeof preComputation === 'undefined') {
  113. preComputation = this.preCompute();
  114. }
  115. return prover_.prove(
  116. group, privateValues, publicValues, data, preComputation);
  117. };
  118. /**
  119. * Pre-computes a plaintext exponent equality zero-knowledge proof of
  120. * knowledge. IMPORTANT: The same pre-computed values must not be used
  121. * twice. Before using this method, the handler must have been initialized
  122. * with base elements, via the method {@link
  123. * PlaintextExponentEqualityProofHandler.init}.
  124. *
  125. * @function preCompute
  126. * @memberof PlaintextExponentEqualityProofHandler
  127. * @returns {ZeroKnowledgeProofPreComputation} The plaintext exponent
  128. * equality zero-knowledge proof of knowledge pre-computation.
  129. */
  130. this.preCompute = function() {
  131. if (typeof baseElements_ === 'undefined') {
  132. throw new Error(
  133. 'Cannot pre-compute plaintext exponent equality proof; Associated handler has not been initialized with any base elements');
  134. }
  135. var phiFunction = newPhiFunction(group, baseElements_);
  136. if (!measureProgress_) {
  137. return prover_.preCompute(group, phiFunction);
  138. } else {
  139. var preComputation = prover_.preCompute(
  140. group, phiFunction, newProgressMeter(baseElements_));
  141. measureProgress_ = false;
  142. return preComputation;
  143. }
  144. };
  145. /**
  146. * Verifies a plaintext exponent equality zero-knowledge proof of knowledge.
  147. * Before using this method, the handler must have been initialized with
  148. * base elements, via the method {@link
  149. * PlaintextExponentEqualityProofHandler.init}.
  150. *
  151. * @function verify
  152. * @memberof PlaintextExponentEqualityProofHandler
  153. * @param {Proof}
  154. * proof The plaintext exponent equality zero-knowledge proof of
  155. * knowledge to verify.
  156. * @param {ElGamalEncryptedElements}
  157. * ciphertext The ciphertext.
  158. * @param {Object}
  159. * [options] An object containing optional arguments.
  160. * @param {Uint8Array|string}
  161. * [options.data='PlaintextExponentEqualityProof'] Auxiliary
  162. * data. It must be the same as that used to generate the proof.
  163. * @returns {boolean} <code>true</code> if the plaintext exponent equality
  164. * zero-knowledge proof of knowledge was verified,
  165. * <code>false</code> otherwise.
  166. * @throws {Error}
  167. * If the input data validation fails.
  168. */
  169. this.verify = function(proof, ciphertext, options) {
  170. if (typeof baseElements_ === 'undefined') {
  171. throw new Error(
  172. 'Cannot verify plaintext exponent equality proof; Associated handler has not been initialized with any base elements');
  173. }
  174. options = options || {};
  175. checkVerificationData(proof, ciphertext, options);
  176. var data = options.data;
  177. if (typeof data === 'undefined') {
  178. data = DEFAULT_AUXILIARY_DATA;
  179. }
  180. var phiFunction = newPhiFunction(group, baseElements_);
  181. var publicValues = generatePublicValues(ciphertext);
  182. if (!measureProgress_) {
  183. return verifier_.verify(group, proof, phiFunction, publicValues, data);
  184. } else {
  185. var verified = verifier_.verify(
  186. group, proof, phiFunction, publicValues, data,
  187. newProgressMeter(baseElements_));
  188. measureProgress_ = false;
  189. return verified;
  190. }
  191. };
  192. /**
  193. * Indicates that a progress meter is to be used for the next plaintext
  194. * exponent equality zero-knowledge proof of knowledge operation to be
  195. * performed.
  196. *
  197. * @function measureProgress
  198. * @memberof PlaintextExponentEqualityProofHandler
  199. * @param {function}
  200. * callback The callback function for the progress meter.
  201. * @param {Object}
  202. * [options] An object containing optional arguments.
  203. * @param {number}
  204. * [minCheckInterval=10] The minimum interval used to check
  205. * progress, as a percentage of the expected final progress
  206. * value.
  207. * @returns {PlaintextExponentEqualityProofHandler} A reference to this
  208. * object, to facilitate method chaining.
  209. * @throws {Error}
  210. * If the input data validation fails.
  211. */
  212. this.measureProgress = function(callback, minCheckInterval) {
  213. validator.checkProgressMeterData(
  214. callback, minCheckInterval,
  215. 'Plaintext exponent equality zero-knowledge proof');
  216. progressCallback_ = callback;
  217. progressPercentMinCheckInterval_ = minCheckInterval;
  218. measureProgress_ = true;
  219. return this;
  220. };
  221. function generatePublicValues(ciphertext) {
  222. return [ciphertext.gamma].concat(ciphertext.phis);
  223. }
  224. function newPhiFunction(group, baseElements) {
  225. var numOutputs = ((baseElements.length - 1) / 2) + 1;
  226. var computationRules = generateComputationRules(numOutputs);
  227. return new PhiFunction(
  228. NUM_PHI_INPUTS, numOutputs, computationRules, baseElements);
  229. }
  230. function generateComputationRules(numOutputs) {
  231. var rules = [];
  232. rules[0] = [];
  233. rules[0][0] = [];
  234. rules[0][0].push(1);
  235. rules[0][0].push(1);
  236. for (var i = 1; i < numOutputs; i++) {
  237. rules[i] = [];
  238. rules[i][0] = [];
  239. rules[i][1] = [];
  240. rules[i][0].push(i + 1);
  241. rules[i][0].push(1);
  242. rules[i][1].push(i + numOutputs);
  243. rules[i][1].push(2);
  244. }
  245. return rules;
  246. }
  247. function newProgressMeter(baseElements) {
  248. var progressMax = baseElements.length;
  249. return new ProgressMeter(
  250. progressMax, progressCallback_, progressPercentMinCheckInterval_);
  251. }
  252. function checkGenerationData(firstSecret, secondSecret, ciphertext, options) {
  253. validator.checkExponent(
  254. firstSecret,
  255. 'First secret exponent for plaintext exponent equality proof generation',
  256. group.q);
  257. validator.checkExponent(
  258. secondSecret,
  259. 'Second secret exponent for plaintext exponent equality proof generation',
  260. group.q);
  261. validator.checkElGamalEncryptedElements(
  262. ciphertext,
  263. 'Ciphertext ElGamal encrypted elements for plaintext exponent equality proof generation',
  264. group);
  265. checkCiphertextLength(ciphertext, baseElements_);
  266. if (typeof options.data !== 'undefined' &&
  267. typeof options.data !== 'string') {
  268. validator.checkIsInstanceOf(
  269. options.data, Uint8Array, 'Uint8Array',
  270. 'Non-string auxiliary data for plaintext exponent equality proof generation');
  271. }
  272. if (typeof options.preComputation !== 'undefined') {
  273. validator.checkIsInstanceOf(
  274. options.preComputation, ZeroKnowledgeProofPreComputation,
  275. 'ZeroKnowledgeProofPreComputation',
  276. 'Pre-computation for plaintext exponent equality proof generation');
  277. }
  278. }
  279. function checkVerificationData(proof, ciphertext, options) {
  280. validator.checkIsInstanceOf(
  281. proof, ZeroKnowledgeProof, 'ZeroKnowledgeProof',
  282. 'Plaintext exponent equality zero-knowledge proof');
  283. validator.checkElGamalEncryptedElements(
  284. ciphertext,
  285. 'Ciphertext ElGamal encrypted elements for plaintext exponent equality proof verification',
  286. group);
  287. checkCiphertextLength(ciphertext, baseElements_);
  288. if (typeof options.data !== 'undefined' &&
  289. typeof options.data !== 'string') {
  290. validator.checkIsInstanceOf(
  291. options.data, Uint8Array, 'Uint8Array',
  292. 'Non-string auxiliary data for plaintext exponent equality proof verification');
  293. }
  294. }
  295. function checkCiphertextLength(ciphertext, baseElements) {
  296. var numPhisFound = ciphertext.phis.length;
  297. var numPhisExpected = (baseElements.length - 1) / 2;
  298. if (numPhisFound !== numPhisExpected) {
  299. throw new Error(
  300. 'Expected number of ElGamal phi elements in ciphertext used for plaintext exponent equality proof opertion to be: ' +
  301. numPhisExpected + ' ; Found: ' + numPhisFound);
  302. }
  303. }
  304. }