service.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  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 ZeroKnowledgeProof = require('./proof');
  11. var ZeroKnowledgeProofPreComputation = require('./pre-computation');
  12. var SchnorrProofHandler = require('./handlers/schnorr-proof-handler');
  13. var ExponentiationProofHandler =
  14. require('./handlers/exponentiation-proof-handler');
  15. var PlaintextProofHandler = require('./handlers/plaintext-proof-handler');
  16. var SimplePlaintextEqualityProofHandler =
  17. require('./handlers/simple-plaintext-equality-proof-handler');
  18. var PlaintextEqualityProofHandler =
  19. require('./handlers/plaintext-equality-proof-handler');
  20. var PlaintextExponentEqualityProofHandler =
  21. require('./handlers/plaintext-exponent-equality-proof-handler');
  22. var OrProofHandler = require('./handlers/or-proof-handler');
  23. var cryptoPolicy = require('scytl-cryptopolicy');
  24. var messageDigest = require('scytl-messagedigest');
  25. var mathematical = require('scytl-mathematical');
  26. var validator = require('./input-validator');
  27. var codec = require('scytl-codec');
  28. require('./array');
  29. module.exports = ZeroKnowledgeProofService;
  30. /**
  31. * @class ZeroKnowledgeProofService
  32. * @classdesc The zero-knowledge proof service API. To instantiate this object,
  33. * use the method {@link newService}.
  34. * @hideconstructor
  35. * @param {Object}
  36. * [options] An object containing optional arguments.
  37. * @param {Policy}
  38. * [options.policy=Default policy] The cryptographic policy to use.
  39. * @param {MessageDigestService}
  40. * [options.messageDigestService=Created internally] The message
  41. * digest service to use.
  42. * @param {SecureRandomService}
  43. * [options.secureRandomService=Created internally] The secure random
  44. * service to use.
  45. * @param {MathematicalService}
  46. * [options.mathematicalService=Created internally] The mathematical
  47. * service to use.
  48. */
  49. function ZeroKnowledgeProofService(options) {
  50. options = options || {};
  51. var policy;
  52. if (options.policy) {
  53. policy = options.policy;
  54. } else {
  55. policy = cryptoPolicy.newInstance();
  56. }
  57. var messageDigestService_;
  58. if (options.messageDigestService) {
  59. messageDigestService_ = options.messageDigestService;
  60. } else {
  61. messageDigestService_ = messageDigest.newService({policy: policy});
  62. }
  63. var secureRandomService;
  64. if (options.secureRandomService) {
  65. secureRandomService = options.secureRandomService;
  66. }
  67. var mathService_;
  68. if (options.mathematicalService) {
  69. mathService_ = options.mathematicalService;
  70. } else if (secureRandomService) {
  71. mathService_ =
  72. mathematical.newService({secureRandomService: secureRandomService});
  73. } else {
  74. mathService_ = mathematical.newService();
  75. }
  76. /**
  77. * Creates a new ZeroKnowledgeProof object from a provided zero-knowledge
  78. * proof of knowledge or its components.
  79. *
  80. * @function newProof
  81. * @memberof ZeroKnowledgeProofService
  82. * @param {Exponent}
  83. * hashOrJson The hash of the zero-knowledge proof of knowledge
  84. * <b>OR</b> a JSON string representation of a
  85. * ZeroKnowledgeProof object, compatible with its
  86. * <code>toJson</code> method. For the latter case, any
  87. * additional input arguments will be ignored.
  88. * @param {Exponent[]}
  89. * values The values of the zero-knowledge proof of knowledge.
  90. * @returns {ZeroKnowledgeProof} The new ZeroKnowledgeProof object.
  91. * @throws {Error}
  92. * If the input data validation fails.
  93. */
  94. this.newProof = function(hashOrJson, exponents) {
  95. if (typeof hashOrJson !== 'string') {
  96. validator.checkExponent(
  97. hashOrJson, 'Hash to create new ZeroKnowledgeProof object');
  98. validator.checkExponents(
  99. exponents, 'Exponents to create new ZeroKnowledgeProof object');
  100. return new ZeroKnowledgeProof(hashOrJson, exponents);
  101. } else {
  102. return jsonToProof(hashOrJson);
  103. }
  104. };
  105. /**
  106. * Creates a new ZeroKnowledgeProofPreComputation object from a provided
  107. * zero-knowledge proof of knowledge pre-computation or its components.
  108. *
  109. * @function newPreComputation
  110. * @memberof ZeroKnowledgeProofService
  111. * @param {Exponent[]}
  112. * exponentsOrJson The array of randomly generated exponents that
  113. * comprise the pre-computation <b>OR</b> a JSON string
  114. * representation of a ZeroKnowledgeProofPreComputation object,
  115. * compatible with its <code>toJson</code> method. For the
  116. * latter case, any additional input arguments will be ignored.
  117. * @param {ZpGroupElements[]}
  118. * phiOutputs The array of PHI function output elements that
  119. * comprise the pre-computation.
  120. * @returns {ZeroKnowledgeProofPreComputation} The new
  121. * ZeroKnowledgeProofPreComputation object.
  122. * @throws {Error}
  123. * If the input data validation fails.
  124. */
  125. this.newPreComputation = function(exponentsOrJson, phiOutputs) {
  126. if (typeof exponentsOrJson !== 'string') {
  127. validator.checkExponents(
  128. exponentsOrJson,
  129. 'Exponents to create new ZeroKnowledgeProofPreComputation object');
  130. validator.checkZpGroupElements(
  131. phiOutputs,
  132. 'PHI function output elements to create new ZeroKnowledgeProofPreComputation object');
  133. return new ZeroKnowledgeProofPreComputation(exponentsOrJson, phiOutputs);
  134. } else {
  135. return jsonToPreComputation(exponentsOrJson);
  136. }
  137. };
  138. /**
  139. * Creates new SchnorrProofHandler object, for generating, pre-computing and
  140. * verifying Schnorr zero-knowledge proofs of knowledge.
  141. *
  142. * @function newSchnorrProofHandler
  143. * @memberof ZeroKnowledgeProofService
  144. * @param {ZpSubgroup}
  145. * group The Zp subgroup to which all exponents and Zp group
  146. * elements required for the proof generation are associated or
  147. * belong, respectively.
  148. * @returns {SchnorrProofHandler} The SchnorrProofHandler object.
  149. * @throws {Error}
  150. * If the input data validation fails.
  151. */
  152. this.newSchnorrProofHandler = function(group) {
  153. validator.checkIsObjectWithProperties(
  154. group, 'Zp subgroup for Schnorr proof handler');
  155. return new SchnorrProofHandler(group, messageDigestService_, mathService_);
  156. };
  157. /**
  158. * Creates new ExponentiationProofHandler object, for generating,
  159. * pre-computing and verifying exponentation zero-knowledge proofs of
  160. * knowledge. It must be initialized with base elements before it is used.
  161. *
  162. * @function newExponentiationProofHandler
  163. * @memberof ZeroKnowledgeProofService
  164. * @param {ZpSubgroup}
  165. * group The Zp subgroup to which all exponents and Zp group
  166. * elements required for the proof generation are associated or
  167. * belong, respectively.
  168. * @returns {ExponentiationProofHandler} The ExponentiationProofHandler
  169. * object.
  170. * @throws {Error}
  171. * If the input data validation fails.
  172. */
  173. this.newExponentiationProofHandler = function(group) {
  174. validator.checkIsObjectWithProperties(
  175. group, 'Zp subgroup for exponentiation proof handler');
  176. return new ExponentiationProofHandler(
  177. group, messageDigestService_, mathService_);
  178. };
  179. /**
  180. * Creates new PlaintextProofHandler object, for generating, pre-computing
  181. * and verifying plaintext zero-knowledge proofs of knowledge. It must be
  182. * initialized with an ElGamal public key before it is used.
  183. *
  184. * @function newPlaintextProofHandler
  185. * @memberof ZeroKnowledgeProofService
  186. * @param {ZpSubgroup}
  187. * group The Zp subgroup to which all exponents and Zp group
  188. * elements required for the proof generation are associated or
  189. * belong, respectively.
  190. * @returns {PlaintextProofHandler} The PlaintextProofHandler object.
  191. * @throws {Error}
  192. * If the input data validation fails.
  193. */
  194. this.newPlaintextProofHandler = function(group) {
  195. validator.checkIsObjectWithProperties(
  196. group, 'Zp subgroup for plaintext proof handler');
  197. return new PlaintextProofHandler(
  198. group, messageDigestService_, mathService_);
  199. };
  200. /**
  201. * Creates new SimplePlaintextEqualityProofHandler object, for generating,
  202. * pre-computing and verifying simple plaintext equality zero-knowledge
  203. * proofs of knowledge. It must be initialized with primary and secondary
  204. * ElGamal public keys before it is used.
  205. *
  206. * @function newSimplePlaintextEqualityProofHandler
  207. * @memberof ZeroKnowledgeProofService
  208. * @param {ZpSubgroup}
  209. * group The Zp subgroup to which all exponents and Zp group
  210. * elements required for the proof generation are associated or
  211. * belong, respectively.
  212. * @returns {SimplePlaintextEqualityProofHandler} The
  213. * SimplePlaintextEqualityProofHandler object.
  214. * @throws {Error}
  215. * If the input data validation fails.
  216. */
  217. this.newSimplePlaintextEqualityProofHandler = function(group) {
  218. validator.checkIsObjectWithProperties(
  219. group, 'Zp subgroup for simple plaintext equality proof handler');
  220. return new SimplePlaintextEqualityProofHandler(
  221. group, messageDigestService_, mathService_);
  222. };
  223. /**
  224. * Creates new PlaintextEqualityProofHandler object, for generating,
  225. * pre-computing and verifying plaintext equality zero-knowledge proofs of
  226. * knowledge. It must be initialized with primary and secondary ElGamal
  227. * public keys before it is used.
  228. *
  229. * @function newPlaintextEqualityProofHandler
  230. * @memberof ZeroKnowledgeProofService
  231. * @param {ZpSubgroup}
  232. * group The Zp subgroup to which all exponents and Zp group
  233. * elements required for the proof generation are associated or
  234. * belong, respectively.
  235. * @returns {PlaintextEqualityProofHandler} The
  236. * PlaintextEqualityProofHandler object.
  237. * @throws {Error}
  238. * If the input data validation fails.
  239. */
  240. this.newPlaintextEqualityProofHandler = function(group) {
  241. validator.checkIsObjectWithProperties(
  242. group, 'Zp subgroup for plaintext equality proof handler');
  243. return new PlaintextEqualityProofHandler(
  244. group, messageDigestService_, mathService_);
  245. };
  246. /**
  247. * Creates new PlaintextExponentEqualityProofHandler object, for generating,
  248. * pre-computing and verifying plaintext exponent equality zero-knowledge
  249. * proofs of knowledge. It must be initialized with base elements before it
  250. * is used.
  251. *
  252. * @function newPlaintextExponentEqualityProofHandler
  253. * @memberof ZeroKnowledgeProofService
  254. * @param {ZpSubgroup}
  255. * group The Zp subgroup to which all exponents and Zp group
  256. * elements required for the proof generation are associated or
  257. * belong, respectively.
  258. * @returns {PlaintextExponentEqualityProofHandler} The
  259. * PlaintextExponentEqualityProofHandler object.
  260. * @throws {Error}
  261. * If the input data validation fails.
  262. */
  263. this.newPlaintextExponentEqualityProofHandler = function(group) {
  264. validator.checkIsObjectWithProperties(
  265. group, 'Zp subgroup for plaintext exponent equality proof handler');
  266. return new PlaintextExponentEqualityProofHandler(
  267. group, messageDigestService_, mathService_);
  268. };
  269. /**
  270. * Creates new OrProofHandler object, for generating, pre-computing and
  271. * verifying OR zero-knowledge proofs of knowledge. It must be initialized
  272. * with an ElGamal public key before it is used.
  273. *
  274. * @function newOrProofHandler
  275. * @memberof ZeroKnowledgeProofService
  276. * @param {ZpSubgroup}
  277. * group The Zp subgroup to which all exponents and Zp group
  278. * elements required for the proof generation are associated or
  279. * belong, respectively.
  280. * @returns {OrProofHandler} The OrProofHandler object.
  281. * @throws {Error}
  282. * If the input data validation fails.
  283. */
  284. this.newOrProofHandler = function(group) {
  285. validator.checkIsObjectWithProperties(
  286. group, 'Zp subgroup for OR proof handler');
  287. return new OrProofHandler(group, messageDigestService_, mathService_);
  288. };
  289. function jsonToProof(json) {
  290. validator.checkIsJsonString(
  291. json, 'JSON to deserialize to ZeroKnowledgeProof object');
  292. var parsed = JSON.parse(json).zkProof;
  293. var q = codec.bytesToBigInteger(codec.base64Decode(parsed.q));
  294. var hash = mathService_.newExponent(
  295. q, codec.bytesToBigInteger(codec.base64Decode(parsed.hash)));
  296. var values = [];
  297. var valuesB64 = parsed.values;
  298. for (var i = 0; i < valuesB64.length; i++) {
  299. values.push(mathService_.newExponent(
  300. q, codec.bytesToBigInteger(codec.base64Decode(valuesB64[i]))));
  301. }
  302. return new ZeroKnowledgeProof(hash, values);
  303. }
  304. function jsonToPreComputation(json) {
  305. validator.checkIsJsonString(
  306. json, 'JSON to deserialize to ZeroKnowledgeProofPreComputation object');
  307. var parsed = JSON.parse(json).preComputed;
  308. var p = codec.bytesToBigInteger(codec.base64Decode(parsed.p));
  309. var q = codec.bytesToBigInteger(codec.base64Decode(parsed.q));
  310. var exponentValues = parsed.exponents;
  311. var exponents = [];
  312. for (var i = 0; i < exponentValues.length; i++) {
  313. exponents.push(mathService_.newExponent(
  314. q, codec.bytesToBigInteger(codec.base64Decode(exponentValues[i]))));
  315. }
  316. var phiOutputValues = parsed.phiOutputs;
  317. var phiOutputs = [];
  318. for (var j = 0; j < phiOutputValues.length; j++) {
  319. phiOutputs.push(mathService_.newZpGroupElement(
  320. p, q,
  321. codec.bytesToBigInteger(codec.base64Decode(phiOutputValues[j]))));
  322. }
  323. return new ZeroKnowledgeProofPreComputation(exponents, phiOutputs);
  324. }
  325. }