2
0

proofs.js 75 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620
  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. cryptolib.modules = cryptolib.modules || {};
  9. cryptolib.modules.proofs = cryptolib.modules.proofs || {};
  10. /**
  11. * Defines Zero-Knowledge Proofs (ZKPs).
  12. */
  13. cryptolib.modules.proofs.implementation = function(box) {
  14. 'use strict';
  15. box.proofs = box.proofs || {};
  16. var exceptions, mathematical, utils, converters, secureRandomFactory,
  17. messageDigestFactory;
  18. var f = function(box) {
  19. exceptions = box.commons.exceptions;
  20. mathematical = box.commons.mathematical;
  21. utils = box.commons.utils;
  22. converters = new box.commons.utils.Converters();
  23. secureRandomFactory =
  24. new box.primitives.securerandom.factory.SecureRandomFactory();
  25. messageDigestFactory =
  26. new box.primitives.messagedigest.factory.MessageDigestFactory();
  27. };
  28. f.policies = {
  29. primitives: {
  30. messagedigest: {
  31. algorithm: box.policies.proofs.messagedigest.algorithm,
  32. provider: box.policies.proofs.messagedigest.provider
  33. },
  34. secureRandom: {provider: box.policies.proofs.secureRandom.provider}
  35. }
  36. };
  37. cryptolib(
  38. 'commons.exceptions', 'commons.mathematical', 'primitives.messagedigest',
  39. 'commons.utils', 'primitives.securerandom', f);
  40. /**
  41. * Schnorr proof generator.
  42. */
  43. box.proofs.SchnorrProofGenerator = function(voterID, electionID, group) {
  44. checkNotEmpty('voter ID', voterID);
  45. checkNotEmpty('election ID', electionID);
  46. checkDefined('group', group);
  47. var computationRules = [[[1, 1]]];
  48. var _voterID = voterID;
  49. var _electionID = electionID;
  50. var _progressMeter;
  51. var _numOutputs = 1;
  52. var buildListOfBaseElements = function() {
  53. var baseElements = [];
  54. baseElements.push(group.getGenerator());
  55. return baseElements;
  56. };
  57. var phiFunctionSchnorr = new box.proofs.PhiFunction(
  58. group, 1, _numOutputs, buildListOfBaseElements(), computationRules);
  59. var _prover = new box.proofs.Prover(group, phiFunctionSchnorr);
  60. this._buildListPublicValues = function(exponentiatedElement) {
  61. var publicList = [];
  62. publicList.push(exponentiatedElement);
  63. return publicList;
  64. };
  65. this._getProver = function() {
  66. return _prover;
  67. };
  68. this._buildListExponents = function(witness) {
  69. var exponentList = [];
  70. exponentList.push(witness);
  71. return exponentList;
  72. };
  73. this._buildDataString = function() {
  74. return 'SchnorrProof:VoterID=' + _voterID +
  75. 'ElectionEventID=' + _electionID;
  76. };
  77. this._getProgressMeter = function() {
  78. return _progressMeter;
  79. };
  80. this.initProgressMeter = function(
  81. progressCallback, progressPercentMinCheckInterval) {
  82. _progressMeter = createProgressMeter(
  83. _numOutputs, progressCallback, progressPercentMinCheckInterval);
  84. return this;
  85. };
  86. };
  87. box.proofs.SchnorrProofGenerator.prototype = {
  88. preCompute: function() {
  89. return this._getProver().preCompute(1, this._getProgressMeter());
  90. },
  91. generate: function(exponentiatedElement, witness, preComputedValues) {
  92. checkDefined('exponentiated element', exponentiatedElement);
  93. checkDefined('witness', witness);
  94. if (!preComputedValues) {
  95. preComputedValues = this.preCompute();
  96. }
  97. return this._getProver().prove(
  98. this._buildListPublicValues(exponentiatedElement),
  99. this._buildListExponents(witness), this._buildDataString(),
  100. preComputedValues);
  101. }
  102. };
  103. /**
  104. * Exponentiation proof generator.
  105. */
  106. box.proofs.ExponentiationProofGenerator = function(baseElements, group) {
  107. checkDefined('base elements', baseElements);
  108. checkDefined('group', group);
  109. var buildComputationRules = function(k) {
  110. var rules = [];
  111. for (var i = 0; i < k; i++) {
  112. rules[i] = [];
  113. rules[i][0] = [];
  114. rules[i][0].push(i + 1);
  115. rules[i][0].push(1);
  116. }
  117. return rules;
  118. };
  119. var _numOutputs = baseElements.length;
  120. var phiFunctionExponentiation = new box.proofs.PhiFunction(
  121. group, 1, _numOutputs, baseElements,
  122. buildComputationRules(_numOutputs));
  123. var _prover = new box.proofs.Prover(group, phiFunctionExponentiation);
  124. var _progressMeter;
  125. this._getProgressMeter = function() {
  126. return _progressMeter;
  127. };
  128. this.initProgressMeter = function(
  129. progressCallback, progressPercentMinCheckInterval) {
  130. _progressMeter = createProgressMeter(
  131. _numOutputs, progressCallback, progressPercentMinCheckInterval);
  132. return this;
  133. };
  134. this.check = function(exponentiatedElements) {
  135. if (exponentiatedElements.length !== _numOutputs) {
  136. throw new exceptions.CryptoLibException(
  137. 'The number of exponentiated elements must be equal to the number of base elements');
  138. }
  139. };
  140. this._getProver = function() {
  141. return _prover;
  142. };
  143. };
  144. box.proofs.ExponentiationProofGenerator.prototype = {
  145. preCompute: function() {
  146. var EXPONENT_QUANTITY = 1;
  147. return this._getProver().preCompute(
  148. EXPONENT_QUANTITY, this._getProgressMeter());
  149. },
  150. generate: function(exponentiatedElements, exponent, preComputedValues) {
  151. checkDefined('exponentiatedElements', exponentiatedElements);
  152. checkDefined('exponent', exponent);
  153. this.check(exponentiatedElements);
  154. var exponents = [];
  155. exponents.push(exponent);
  156. if (!preComputedValues) {
  157. preComputedValues = this.preCompute();
  158. }
  159. return this._getProver().prove(
  160. exponentiatedElements, exponents,
  161. box.EXPONENTIATION_PROOF_AUXILIARY_DATA, preComputedValues);
  162. }
  163. };
  164. /**
  165. * Plaintext proof generator.
  166. */
  167. box.proofs.PlaintextProofGenerator = function(publicKey, group) {
  168. checkDefined('public key', publicKey);
  169. checkDefined('group', group);
  170. var buildListOfBaseElements = function() {
  171. var list = [];
  172. list.push(group.getGenerator());
  173. list.addAll(publicKey.getGroupElementsArray());
  174. return list;
  175. };
  176. var buildComputationRules = function(k) {
  177. var rules = [];
  178. for (var i = 0; i < (k + 1); i++) {
  179. rules[i] = [];
  180. rules[i][0] = [];
  181. rules[i][0].push(i + 1);
  182. rules[i][0].push(1);
  183. }
  184. return rules;
  185. };
  186. var _publicKeyLength = publicKey.getGroupElementsArray().length;
  187. var numOutputs = _publicKeyLength + 1;
  188. var phiFunctionPlaintext = new box.proofs.PhiFunction(
  189. group, 1, numOutputs, buildListOfBaseElements(),
  190. buildComputationRules(_publicKeyLength));
  191. var _prover = new box.proofs.Prover(group, phiFunctionPlaintext);
  192. var _progressMeter;
  193. this._buildListPublicValues = function(ciphertext, plaintext) {
  194. var dividedCiphertext =
  195. mathematical.groupUtils.divide(ciphertext.getPhis(), plaintext);
  196. var publicValues = [];
  197. publicValues.push(ciphertext.getGamma());
  198. publicValues.addAll(dividedCiphertext);
  199. return publicValues;
  200. };
  201. this._getPublicKeyLength = function() {
  202. return _publicKeyLength;
  203. };
  204. this._getProver = function() {
  205. return _prover;
  206. };
  207. this._getProgressMeter = function() {
  208. return _progressMeter;
  209. };
  210. this.initProgressMeter = function(
  211. progressCallback, progressPercentMinCheckInterval) {
  212. _progressMeter = createProgressMeter(
  213. _publicKeyLength + 1, progressCallback,
  214. progressPercentMinCheckInterval);
  215. return this;
  216. };
  217. };
  218. box.proofs.PlaintextProofGenerator.prototype = {
  219. preCompute: function() {
  220. return this._getProver().preCompute(1, this._getProgressMeter());
  221. },
  222. generate: function(ciphertext, plaintext, witness, preComputedValues) {
  223. checkDefined('ciphertext', ciphertext);
  224. checkDefined('plaintext', plaintext);
  225. checkDefined('witness', witness);
  226. var publicKeyLength = this._getPublicKeyLength();
  227. var numPhis = ciphertext.getPhis().length;
  228. if (publicKeyLength !== numPhis) {
  229. throw new exceptions.CryptoLibException(
  230. 'The length of the ciphertext must be equal to the length of the public key + 1.');
  231. }
  232. if (publicKeyLength !== plaintext.length) {
  233. throw new exceptions.CryptoLibException(
  234. 'The public key and the plaintext must have the same number of elements');
  235. }
  236. if (!preComputedValues) {
  237. preComputedValues = this.preCompute();
  238. }
  239. var exponents = [];
  240. exponents.push(witness);
  241. return this._getProver().prove(
  242. this._buildListPublicValues(ciphertext, plaintext), exponents,
  243. box.PLAINTEXT_PROOF_AUXILIARY_DATA, preComputedValues);
  244. }
  245. };
  246. /**
  247. * Simple plaintext equality proof generator.
  248. */
  249. box.proofs.SimplePlaintextEqualityProofGenerator = function(
  250. primaryPublicKey, secondaryPublicKey, group) {
  251. checkDefined('primary public key', primaryPublicKey);
  252. checkDefined('secondary public key', secondaryPublicKey);
  253. checkDefined('group', group);
  254. var _primaryPublicKey = primaryPublicKey;
  255. var _secondaryPublicKey = secondaryPublicKey;
  256. var _group = group;
  257. var buildComputationRules = function(k) {
  258. var rules = [];
  259. var firstDimensionLength = k + 1;
  260. rules[0] = [];
  261. rules[0][0] = [];
  262. rules[0][0].push(1);
  263. rules[0][0].push(1);
  264. for (var i = 1; i < firstDimensionLength; i++) {
  265. rules[i] = [];
  266. rules[i][0] = [];
  267. rules[i][1] = [];
  268. rules[i][0].push(i + 1);
  269. rules[i][0].push(1);
  270. rules[i][1].push(i + 1 + k);
  271. rules[i][1].push(1);
  272. }
  273. return rules;
  274. };
  275. var buildSecondaryInvertedPublicKey = function() {
  276. var listInvertedElements = [];
  277. var keys = _secondaryPublicKey.getGroupElementsArray();
  278. for (var i = 0; i < keys.length; i++) {
  279. listInvertedElements.push(keys[i].invert());
  280. }
  281. return listInvertedElements;
  282. };
  283. var buildListOfBaseElements = function() {
  284. var invertedSecondaryKeyValues = buildSecondaryInvertedPublicKey();
  285. var baseElements = [];
  286. baseElements.push(group.getGenerator());
  287. baseElements.addAll(_primaryPublicKey.getGroupElementsArray());
  288. baseElements.addAll(invertedSecondaryKeyValues);
  289. return baseElements;
  290. };
  291. var primaryPublicKeyLength =
  292. primaryPublicKey.getGroupElementsArray().length;
  293. var secondaryPublicKeyLength =
  294. secondaryPublicKey.getGroupElementsArray().length;
  295. if (primaryPublicKeyLength !== secondaryPublicKeyLength) {
  296. throw new exceptions.CryptoLibException(
  297. 'The number of elements in the primary and secondary public keys must be equal');
  298. }
  299. var _progressMeter;
  300. var _numKeyElements = primaryPublicKey.getGroupElementsArray().length;
  301. var numOutputs = _numKeyElements + 1;
  302. var rules = buildComputationRules(_numKeyElements);
  303. var phiFunctionSimplePlaintextEquality = new box.proofs.PhiFunction(
  304. group, 1, numOutputs, buildListOfBaseElements(), rules);
  305. var _prover =
  306. new box.proofs.Prover(_group, phiFunctionSimplePlaintextEquality);
  307. this._buildListExponents = function(witness) {
  308. var exponentList = [];
  309. exponentList.push(witness);
  310. return exponentList;
  311. };
  312. this._buildInputList = function(primaryCiphertext, secondaryCiphertext) {
  313. var dividedSubCiphertext = mathematical.groupUtils.divide(
  314. primaryCiphertext.getPhis(), secondaryCiphertext.getPhis());
  315. var generatedList = [];
  316. generatedList.push(secondaryCiphertext.getGamma());
  317. generatedList.addAll(dividedSubCiphertext);
  318. return generatedList;
  319. };
  320. this._getProgressMeter = function() {
  321. return _progressMeter;
  322. };
  323. this.initProgressMeter = function(
  324. progressCallback, progressPercentMinCheckInterval) {
  325. _progressMeter = createProgressMeter(
  326. _numKeyElements * 2 + 1, progressCallback,
  327. progressPercentMinCheckInterval);
  328. return this;
  329. };
  330. this._getProver = function() {
  331. return _prover;
  332. };
  333. this._check = function(primaryCiphertextLength) {
  334. if (primaryCiphertextLength !== (primaryPublicKeyLength + 1)) {
  335. throw new exceptions.CryptoLibException(
  336. 'The number of elements in the ciphertext must be equal to the number in the public key + 1');
  337. }
  338. };
  339. };
  340. box.proofs.SimplePlaintextEqualityProofGenerator.prototype = {
  341. preCompute: function() {
  342. return this._getProver().preCompute(1, this._getProgressMeter());
  343. },
  344. generate: function(
  345. primaryCiphertext, secondaryCiphertext, witness, preComputedValues) {
  346. checkDefined('primary ciphertext', primaryCiphertext);
  347. checkDefined('secondary ciphertext', secondaryCiphertext);
  348. checkDefined('witness', witness);
  349. var primaryCiphertextLength = primaryCiphertext.getPhis().length + 1;
  350. var secondaryCiphertextLength = secondaryCiphertext.getPhis().length + 1;
  351. if (primaryCiphertextLength !== secondaryCiphertextLength) {
  352. throw new exceptions.CryptoLibException(
  353. 'The number of elements in the primary and secondary ciphertext must be equal');
  354. }
  355. this._check(primaryCiphertextLength);
  356. if (!preComputedValues) {
  357. preComputedValues = this.preCompute();
  358. }
  359. return this._getProver().prove(
  360. this._buildInputList(primaryCiphertext, secondaryCiphertext),
  361. this._buildListExponents(witness),
  362. box.SIMPLE_PLAINTEXT_EQUALITY_PROOF_AUXILIARY_DATA,
  363. preComputedValues);
  364. }
  365. };
  366. /**
  367. * Plaintext equality proof generator.
  368. */
  369. box.proofs.PlaintextEqualityProofGenerator = function(
  370. primaryPublicKey, secondaryPublicKey, group) {
  371. checkDefined('primary public key', primaryPublicKey);
  372. checkDefined('secondary public key', secondaryPublicKey);
  373. checkDefined('group', group);
  374. var numPrimaryPublicKeyElements =
  375. primaryPublicKey.getGroupElementsArray().length;
  376. var numSecondaryPublicKeyElements =
  377. secondaryPublicKey.getGroupElementsArray().length;
  378. if (numPrimaryPublicKeyElements !== numSecondaryPublicKeyElements) {
  379. throw new exceptions.CryptoLibException(
  380. 'The primary and secondary public keys contain different numbers of elements: ' +
  381. numPrimaryPublicKeyElements + ', ' + numSecondaryPublicKeyElements);
  382. }
  383. var _primaryPublicKey = primaryPublicKey;
  384. var _secondaryPublicKey = secondaryPublicKey;
  385. var _group = group;
  386. var _progressMeter;
  387. this._buildListExponents = function(primaryWitness, secondaryWitness) {
  388. var exponentList = [];
  389. exponentList.push(primaryWitness);
  390. exponentList.push(secondaryWitness);
  391. return exponentList;
  392. };
  393. this._buildInputList = function(primaryCiphertext, secondaryCiphertext) {
  394. var dividedSubCiphertext = mathematical.groupUtils.divide(
  395. primaryCiphertext.getPhis(), secondaryCiphertext.getPhis());
  396. var generatedList = [];
  397. generatedList.push(primaryCiphertext.getGamma());
  398. generatedList.push(secondaryCiphertext.getGamma());
  399. generatedList.addAll(dividedSubCiphertext);
  400. return generatedList;
  401. };
  402. function buildComputationRules(k) {
  403. var firstDimensionLength = k + 2;
  404. var rules = [];
  405. rules[0] = [];
  406. rules[0][0] = [];
  407. rules[0][0].push(1);
  408. rules[0][0].push(1);
  409. rules[1] = [];
  410. rules[1][0] = [];
  411. rules[1][0].push(1);
  412. rules[1][0].push(2);
  413. for (var i = 2; i < firstDimensionLength; i++) {
  414. rules[i] = [];
  415. rules[i][0] = [];
  416. rules[i][0].push(i);
  417. rules[i][0].push(1);
  418. rules[i][1] = [];
  419. rules[i][1].push(i + k);
  420. rules[i][1].push(2);
  421. }
  422. return rules;
  423. }
  424. function buildListOfBaseElements() {
  425. var invertedSecondaryKeyValues = buildSecondaryInvertedPublicKey();
  426. var baseElements = [];
  427. baseElements.push(group.getGenerator());
  428. baseElements.addAll(_primaryPublicKey.getGroupElementsArray());
  429. baseElements.addAll(invertedSecondaryKeyValues);
  430. return baseElements;
  431. }
  432. function buildSecondaryInvertedPublicKey() {
  433. var listInvertedElements = [];
  434. var keys = _secondaryPublicKey.getGroupElementsArray();
  435. for (var i = 0; i < keys.length; i++) {
  436. listInvertedElements.push(keys[i].invert());
  437. }
  438. return listInvertedElements;
  439. }
  440. var numKeyElements = primaryPublicKey.getGroupElementsArray().length;
  441. var _numOutputs = numKeyElements + 2;
  442. var rules = buildComputationRules(numKeyElements);
  443. var phiFunctionPlaintextEquality = new box.proofs.PhiFunction(
  444. group, 2, _numOutputs, buildListOfBaseElements(), rules);
  445. var _prover = new box.proofs.Prover(group, phiFunctionPlaintextEquality);
  446. this.getPrimaryPublicKey = function() {
  447. return _primaryPublicKey;
  448. };
  449. this.getSecondaryPublicKey = function() {
  450. return _secondaryPublicKey;
  451. };
  452. this.getGroup = function() {
  453. return _group;
  454. };
  455. this._getProgressMeter = function() {
  456. return _progressMeter;
  457. };
  458. this.initProgressMeter = function(
  459. progressCallback, progressPercentMinCheckInterval) {
  460. _progressMeter = createProgressMeter(
  461. numKeyElements * 2 + 2, progressCallback,
  462. progressPercentMinCheckInterval);
  463. return this;
  464. };
  465. this._getProver = function() {
  466. return _prover;
  467. };
  468. this.check = function(numPrimaryCiphertextElements) {
  469. if (numPrimaryCiphertextElements !== (numPrimaryPublicKeyElements + 1)) {
  470. throw new exceptions.CryptoLibException(
  471. 'The number of ciphertext elements is not equal to the number public key elements plus one.');
  472. }
  473. };
  474. };
  475. box.proofs.PlaintextEqualityProofGenerator.prototype = {
  476. preCompute: function() {
  477. return this._getProver().preCompute(2, this._getProgressMeter());
  478. },
  479. generate: function(
  480. primaryCiphertext, primaryWitness, secondaryCiphertext,
  481. secondaryWitness, preComputedValues) {
  482. checkDefined('primary ciphertext', primaryCiphertext);
  483. checkDefined('primary witness', primaryWitness);
  484. checkDefined('secondary ciphertext', secondaryCiphertext);
  485. checkDefined('secondary witness', secondaryWitness);
  486. var numPrimaryCiphertextElements = primaryCiphertext.getPhis().length + 1;
  487. var numSecondaryCiphertextElements =
  488. secondaryCiphertext.getPhis().length + 1;
  489. if (numPrimaryCiphertextElements !== numSecondaryCiphertextElements) {
  490. throw new exceptions.CryptoLibException(
  491. 'The primary and secondary ciphertexts contain different numbers of elements: ' +
  492. numPrimaryCiphertextElements + ', ' +
  493. numSecondaryCiphertextElements);
  494. }
  495. this.check(numPrimaryCiphertextElements);
  496. if (!preComputedValues) {
  497. preComputedValues = this.preCompute();
  498. }
  499. return this._getProver().prove(
  500. this._buildInputList(primaryCiphertext, secondaryCiphertext),
  501. this._buildListExponents(primaryWitness, secondaryWitness),
  502. box.PLAINTEXT_EQUALITY_PROOF_AUXILIARY_DATA, preComputedValues);
  503. }
  504. };
  505. /**
  506. * Plaintext exponent equality proof generator.
  507. */
  508. box.proofs.PlaintextExponentEqualityProofGenerator = function(
  509. baseElements, group) {
  510. var buildComputationRules = function(k) {
  511. var rules = [];
  512. var firstDimensionLength = k + 1;
  513. rules[0] = [];
  514. rules[0][0] = [];
  515. rules[0][0].push(1);
  516. rules[0][0].push(1);
  517. for (var i = 1; i < firstDimensionLength; i++) {
  518. rules[i] = [];
  519. rules[i][0] = [];
  520. rules[i][1] = [];
  521. rules[i][0].push(i + 1);
  522. rules[i][0].push(1);
  523. rules[i][1].push(i + 1 + k);
  524. rules[i][1].push(2);
  525. }
  526. return rules;
  527. };
  528. checkDefined('base elements', baseElements);
  529. checkDefined('group', group);
  530. var _numBaseElements = baseElements.length;
  531. var _progressMeter;
  532. var k = (_numBaseElements - 1) / 2;
  533. var numOutputs = k + 1;
  534. var phiFunctionPlaintextExponentEquality = new box.proofs.PhiFunction(
  535. group, 2, numOutputs, baseElements, buildComputationRules(k));
  536. var _prover =
  537. new box.proofs.Prover(group, phiFunctionPlaintextExponentEquality);
  538. this._buildListExponents = function(witness1, witness2) {
  539. var exponentList = [];
  540. exponentList.push(witness1);
  541. exponentList.push(witness2);
  542. return exponentList;
  543. };
  544. this._buildListPublicValues = function(ciphertext) {
  545. var list = [];
  546. list.push(ciphertext.getGamma());
  547. list.addAll(ciphertext.getPhis());
  548. return list;
  549. };
  550. this._getProver = function() {
  551. return _prover;
  552. };
  553. this._getProgressMeter = function() {
  554. return _progressMeter;
  555. };
  556. this.initProgressMeter = function(
  557. progressCallback, progressPercentMinCheckInterval) {
  558. _progressMeter = createProgressMeter(
  559. _numBaseElements, progressCallback, progressPercentMinCheckInterval);
  560. return this;
  561. };
  562. this._checkLengthOf = function(ciphertext) {
  563. var k = ciphertext.getPhis().length;
  564. var expectedNumBaseElements = (2 * k) + 1;
  565. if (_numBaseElements !== expectedNumBaseElements) {
  566. throw new exceptions.CryptoLibException(
  567. 'The lengths of the ciphertext and the base elements do not have the expected relationship.');
  568. }
  569. };
  570. };
  571. box.proofs.PlaintextExponentEqualityProofGenerator.prototype = {
  572. preCompute: function() {
  573. return this._getProver().preCompute(2, this._getProgressMeter());
  574. },
  575. generate: function(ciphertext, witness1, witness2, preComputedValues) {
  576. checkDefined('ciphertext', ciphertext);
  577. checkDefined('witness1', witness1);
  578. checkDefined('witness2', witness2);
  579. this._checkLengthOf(ciphertext);
  580. if (!preComputedValues) {
  581. preComputedValues = this.preCompute();
  582. }
  583. return this._getProver().prove(
  584. this._buildListPublicValues(ciphertext),
  585. this._buildListExponents(witness1, witness2),
  586. box.PLAINTEXT_EXPONENT_EQUALITY_PROOF_AUXILIARY_DATA,
  587. preComputedValues);
  588. }
  589. };
  590. /**
  591. * OR-proof generator.
  592. */
  593. box.proofs.ORProofGenerator = function(publicKey, numElements, group) {
  594. checkPublicKey(publicKey);
  595. checkNumElements(numElements);
  596. checkGroup(group);
  597. var _publicKey = publicKey;
  598. var _numElements = numElements;
  599. var _group = group;
  600. var _numOutputs = _numElements * 2;
  601. var _progressMeter;
  602. function checkPublicKey(publicKey) {
  603. checkDefined('public key', publicKey);
  604. checkNotNull('public key', publicKey);
  605. var publicKeyLength = publicKey.getGroupElementsArray().length;
  606. if (publicKeyLength !== 1) {
  607. throw new exceptions.CryptoLibException(
  608. 'Expected public key length: 1 ; Found: ' + publicKeyLength);
  609. }
  610. }
  611. function checkNumElements(numElements) {
  612. checkDefined('numElements', numElements);
  613. checkNotNull('numElements', numElements);
  614. if (numElements < 2) {
  615. throw new exceptions.CryptoLibException(
  616. 'Expected number of elements to be greater than 1 ; Found: ' +
  617. numElements);
  618. }
  619. }
  620. function checkGroup(group) {
  621. checkDefined('group', group);
  622. checkNotNull('group', group);
  623. }
  624. function buildBaseElements() {
  625. var baseElements = [];
  626. baseElements.push(_group.getGenerator());
  627. baseElements.push(_publicKey.getGroupElementsArray()[0]);
  628. return baseElements;
  629. }
  630. function buildComputationRules(numOutputs) {
  631. var rules = [];
  632. var index1;
  633. var index2 = 0;
  634. for (var i = 0; i < numOutputs; i++) {
  635. index1 = 1 + (i % 2);
  636. if (i % 2 === 0) {
  637. index2++;
  638. }
  639. rules[i] = [];
  640. rules[i][0] = [];
  641. rules[i][0].push(index1);
  642. rules[i][0].push(index2);
  643. }
  644. return rules;
  645. }
  646. var phiFunctionOR = new box.proofs.PhiFunction(
  647. group, _numElements, _numOutputs, buildBaseElements(),
  648. buildComputationRules(_numOutputs));
  649. var _prover = new box.proofs.Prover(_group, phiFunctionOR);
  650. this.getNumElements = function() {
  651. return _numElements;
  652. };
  653. this.getProver = function() {
  654. return _prover;
  655. };
  656. this.buildPublicValues = function(ciphertext) {
  657. var publicValues = [];
  658. publicValues.push(ciphertext.getGamma());
  659. publicValues.push(ciphertext.getPhis()[0]);
  660. return publicValues;
  661. };
  662. this.getProgressMeter = function() {
  663. return _progressMeter;
  664. };
  665. this.initProgressMeter = function(
  666. progressCallback, progressPercentMinCheckInterval) {
  667. _progressMeter = createProgressMeter(
  668. _numOutputs, progressCallback, progressPercentMinCheckInterval);
  669. return this;
  670. };
  671. };
  672. box.proofs.ORProofGenerator.prototype = {
  673. preCompute: function() {
  674. return this.getProver().preCompute(
  675. this.getNumElements(), this.getProgressMeter());
  676. },
  677. generate: function(
  678. ciphertext, witness, elements, index, data, preComputedValues) {
  679. checkCiphertext(ciphertext);
  680. checkWitness(witness);
  681. checkElements(elements, this.getNumElements());
  682. checkIndex(index, this.getNumElements());
  683. checkDefined('data', data);
  684. function checkCiphertext(ciphertext) {
  685. checkDefined('ciphertext', ciphertext);
  686. checkNotNull('ciphertext', ciphertext);
  687. var ciphertextLength = ciphertext.getPhis().length + 1;
  688. if (ciphertextLength !== 2) {
  689. throw new exceptions.CryptoLibException(
  690. 'Expected ciphertext length: 2 ; Found: ' + ciphertextLength);
  691. }
  692. }
  693. function checkWitness(witness) {
  694. checkDefined('witness', witness);
  695. checkNotNull('witness', witness);
  696. }
  697. function checkElements(elements, numElementsExpected) {
  698. checkDefined('elements', elements);
  699. checkNotNull('elements', elements);
  700. var numElementsFound = elements.length;
  701. if (numElementsFound !== numElementsExpected) {
  702. throw new exceptions.CryptoLibException(
  703. 'Expected number of elements: ' + numElementsExpected +
  704. ' ; Found: ' + numElementsFound);
  705. }
  706. }
  707. function checkIndex(index, numElements) {
  708. checkDefined('index', index);
  709. checkNotNull('index', index);
  710. if (index < 0) {
  711. throw new exceptions.CryptoLibException(
  712. 'Expected index of encrypted element to be positive ; Found: ' +
  713. index);
  714. }
  715. if (index >= numElements) {
  716. throw new exceptions.CryptoLibException(
  717. 'Expected index of encrypted element to be less than number of elements: ' +
  718. numElements + ' ; Found: ' + index);
  719. }
  720. }
  721. var publicValues = this.buildPublicValues(ciphertext);
  722. var privateValues = [];
  723. privateValues.push(witness);
  724. if (data === null) {
  725. data = '';
  726. }
  727. if (!preComputedValues) {
  728. preComputedValues = this.preCompute();
  729. }
  730. return this.getProver().prove(
  731. publicValues, privateValues, data, preComputedValues, elements,
  732. index);
  733. }
  734. };
  735. /**
  736. * Schnorr proof verifier.
  737. */
  738. box.proofs.SchnorrProofVerifier = function(
  739. exponentiatedElement, voterID, electionID, proof, group) {
  740. checkDefined('exponentiated element', exponentiatedElement);
  741. checkNotEmpty('voter ID', voterID);
  742. checkNotEmpty('election ID', electionID);
  743. checkDefined('proof', proof);
  744. checkDefined('group', group);
  745. var _exponentiatedElement = exponentiatedElement;
  746. var _voterID = voterID;
  747. var _electionID = electionID;
  748. var _proof = proof;
  749. var _group = group;
  750. var _progressMeter;
  751. this._buildListOfBaseElements = function() {
  752. var baseElements = [];
  753. baseElements.push(_group.getGenerator());
  754. return baseElements;
  755. };
  756. this._buildExponentiatedElementsList = function() {
  757. var exponentiatedElements = [];
  758. exponentiatedElements.push(_exponentiatedElement);
  759. return exponentiatedElements;
  760. };
  761. this._buildDataString = function() {
  762. return 'SchnorrProof:VoterID=' + _voterID +
  763. 'ElectionEventID=' + _electionID;
  764. };
  765. var computationRules = [[[1, 1]]];
  766. var _numOutputs = 1;
  767. var phiFunction = new box.proofs.PhiFunction(
  768. _group, 1, _numOutputs, this._buildListOfBaseElements(),
  769. computationRules);
  770. var _verifier = new box.proofs.Verifier(_group, phiFunction);
  771. this._getProof = function() {
  772. return _proof;
  773. };
  774. this._getVerifier = function() {
  775. return _verifier;
  776. };
  777. this._getProgressMeter = function() {
  778. return _progressMeter;
  779. };
  780. this.initProgressMeter = function(
  781. progressCallback, progressPercentMinCheckInterval) {
  782. _progressMeter = createProgressMeter(
  783. _numOutputs, progressCallback, progressPercentMinCheckInterval);
  784. return this;
  785. };
  786. };
  787. box.proofs.SchnorrProofVerifier.prototype = {
  788. verify: function() {
  789. return this._getVerifier().verify(
  790. this._buildExponentiatedElementsList(), this._getProof(),
  791. this._buildDataString(), this._getProgressMeter());
  792. }
  793. };
  794. /**
  795. * Exponentiation proof verifier.
  796. */
  797. box.proofs.ExponentiationProofVerifier = function(
  798. exponentiatedElements, baseElements, proof, group) {
  799. checkDefined('exponentiated elements', exponentiatedElements);
  800. checkDefined('base elements', baseElements);
  801. checkDefined('proof', proof);
  802. checkDefined('group', group);
  803. var _exponentiatedElements = exponentiatedElements;
  804. var _proof = proof;
  805. var _progressMeter;
  806. this._buildComputationRules = function(k) {
  807. var rules = [];
  808. for (var i = 0; i < k; i++) {
  809. rules[i] = [];
  810. rules[i][0] = [];
  811. rules[i][0].push(i + 1);
  812. rules[i][0].push(1);
  813. }
  814. return rules;
  815. };
  816. var _numOutputs = exponentiatedElements.length;
  817. var phiFunctionExponentiation = new box.proofs.PhiFunction(
  818. group, 1, _numOutputs, baseElements,
  819. this._buildComputationRules(_numOutputs));
  820. var _verifier = new box.proofs.Verifier(group, phiFunctionExponentiation);
  821. this._getProof = function() {
  822. return _proof;
  823. };
  824. this.getExponentiatedElements = function() {
  825. return _exponentiatedElements;
  826. };
  827. this._getVerifier = function() {
  828. return _verifier;
  829. };
  830. this._getProgressMeter = function() {
  831. return _progressMeter;
  832. };
  833. this.initProgressMeter = function(
  834. progressCallback, progressPercentMinCheckInterval) {
  835. _progressMeter = createProgressMeter(
  836. _numOutputs, progressCallback, progressPercentMinCheckInterval);
  837. return this;
  838. };
  839. };
  840. box.proofs.ExponentiationProofVerifier.prototype = {
  841. verify: function() {
  842. return this._getVerifier().verify(
  843. this.getExponentiatedElements(), this._getProof(),
  844. box.EXPONENTIATION_PROOF_AUXILIARY_DATA, this._getProgressMeter());
  845. }
  846. };
  847. /**
  848. * Plaintext proof verifier.
  849. */
  850. box.proofs.PlaintextProofVerifier = function(publicKey, group) {
  851. checkDefined('public key', publicKey);
  852. checkDefined('group', group);
  853. var _publicKey = publicKey;
  854. var _group = group;
  855. var _progressMeter;
  856. this._buildListOfBaseElements = function() {
  857. var list = [];
  858. list.push(_group.getGenerator());
  859. list.addAll(_publicKey.getGroupElementsArray());
  860. return list;
  861. };
  862. this._buildListPublicValues = function(ciphertext, plaintext) {
  863. var dividedCiphertext =
  864. mathematical.groupUtils.divide(ciphertext.getPhis(), plaintext);
  865. var publicValues = [];
  866. publicValues.push(ciphertext.getGamma());
  867. publicValues.addAll(dividedCiphertext);
  868. return publicValues;
  869. };
  870. this._buildComputationRules = function(k) {
  871. var rules = [];
  872. for (var i = 0; i < (k + 1); i++) {
  873. rules[i] = [];
  874. rules[i][0] = [];
  875. rules[i][0].push(i + 1);
  876. rules[i][0].push(1);
  877. }
  878. return rules;
  879. };
  880. var _publicKeyLength = _publicKey.getGroupElementsArray().length;
  881. var numOutputs = _publicKeyLength + 1;
  882. var phiFunctionPlaintext = new box.proofs.PhiFunction(
  883. _group, 1, numOutputs, this._buildListOfBaseElements(),
  884. this._buildComputationRules(_publicKeyLength));
  885. var _verifier = new box.proofs.Verifier(_group, phiFunctionPlaintext);
  886. this.getPublicKey = function() {
  887. return _publicKey;
  888. };
  889. this.getGroup = function() {
  890. return _group;
  891. };
  892. this._getVerifier = function() {
  893. return _verifier;
  894. };
  895. this._getProgressMeter = function() {
  896. return _progressMeter;
  897. };
  898. this.initProgressMeter = function(
  899. progressCallback, progressPercentMinCheckInterval) {
  900. _progressMeter = createProgressMeter(
  901. _publicKeyLength + 1, progressCallback,
  902. progressPercentMinCheckInterval);
  903. return this;
  904. };
  905. };
  906. box.proofs.PlaintextProofVerifier.prototype = {
  907. verify: function(ciphertext, plaintext, proof) {
  908. checkDefined('ciphertext', ciphertext);
  909. checkDefined('plaintext', plaintext);
  910. checkDefined('proof', proof);
  911. return this._getVerifier().verify(
  912. this._buildListPublicValues(ciphertext, plaintext), proof,
  913. box.PLAINTEXT_PROOF_AUXILIARY_DATA, this._getProgressMeter());
  914. }
  915. };
  916. /**
  917. * Simple plaintext equality proof verifier.
  918. */
  919. box.proofs.SimplePlaintextEqualityProofVerifier = function(
  920. primaryCiphertext, primaryPublicKey, secondaryCiphertext,
  921. secondaryPublicKey, proof, group) {
  922. checkDefined('primary ciphertext', primaryCiphertext);
  923. checkDefined('primary public key', primaryPublicKey);
  924. checkDefined('secondary ciphertext', secondaryCiphertext);
  925. checkDefined('secondary public key', secondaryPublicKey);
  926. checkDefined('proof', proof);
  927. checkDefined('group', group);
  928. var numPrimaryCiphertextElements = primaryCiphertext.getPhis().length + 1;
  929. var numPrimaryPublicKeyElements =
  930. primaryPublicKey.getGroupElementsArray().length;
  931. var numSecondaryCiphertextElements =
  932. secondaryCiphertext.getPhis().length + 1;
  933. var numSecondaryPublicKeyElements =
  934. secondaryPublicKey.getGroupElementsArray().length;
  935. if (numPrimaryCiphertextElements !== numSecondaryCiphertextElements) {
  936. throw new exceptions.CryptoLibException(
  937. 'The primary and secondary ciphertexts contain different numbers of elements: ' +
  938. numPrimaryCiphertextElements + ', ' + numSecondaryCiphertextElements);
  939. }
  940. if (numPrimaryPublicKeyElements !== numSecondaryPublicKeyElements) {
  941. throw new exceptions.CryptoLibException(
  942. 'The primary and secondary public keys contain different numbers of elements: ' +
  943. numPrimaryPublicKeyElements + ', ' + numSecondaryPublicKeyElements);
  944. }
  945. if (numPrimaryCiphertextElements !== (numPrimaryPublicKeyElements + 1)) {
  946. throw new exceptions.CryptoLibException(
  947. 'The number of ciphertext elements is not equal to the number public key elements plus one.');
  948. }
  949. var _primaryCiphertext = primaryCiphertext;
  950. var _primaryPublicKey = primaryPublicKey;
  951. var _secondaryCiphertext = secondaryCiphertext;
  952. var _secondaryPublicKey = secondaryPublicKey;
  953. var _proof = proof;
  954. var _progressMeter;
  955. function buildComputationRules(k) {
  956. var rules = [];
  957. var firstDimensionLength = k + 1;
  958. rules[0] = [];
  959. rules[0][0] = [];
  960. rules[0][0].push(1);
  961. rules[0][0].push(1);
  962. for (var i = 1; i < firstDimensionLength; i++) {
  963. rules[i] = [];
  964. rules[i][0] = [];
  965. rules[i][1] = [];
  966. rules[i][0].push(i + 1);
  967. rules[i][0].push(1);
  968. rules[i][1].push(i + 1 + k);
  969. rules[i][1].push(1);
  970. }
  971. return rules;
  972. }
  973. function buildListOfBaseElements() {
  974. var invertedSecondaryKeyValues = buildSecondaryInvertedPublicKey();
  975. var baseElements = [];
  976. baseElements.push(group.getGenerator());
  977. baseElements.addAll(_primaryPublicKey.getGroupElementsArray());
  978. baseElements.addAll(invertedSecondaryKeyValues);
  979. return baseElements;
  980. }
  981. function buildSecondaryInvertedPublicKey() {
  982. var listInvertedElements = [];
  983. var keys = _secondaryPublicKey.getGroupElementsArray();
  984. for (var i = 0; i < keys.length; i++) {
  985. listInvertedElements.push(keys[i].invert());
  986. }
  987. return listInvertedElements;
  988. }
  989. var _primarySubCiphertext = _primaryCiphertext.getPhis();
  990. var _secondarySubCiphertext = _secondaryCiphertext.getPhis();
  991. var _numKeyElements = _primaryPublicKey.getGroupElementsArray().length;
  992. var numOutputs = _numKeyElements + 1;
  993. var phiFunctionSimplePlaintextEquality = new box.proofs.PhiFunction(
  994. group, 1, numOutputs, buildListOfBaseElements(),
  995. buildComputationRules(_numKeyElements));
  996. var _verifier =
  997. new box.proofs.Verifier(group, phiFunctionSimplePlaintextEquality);
  998. this._buildInputList = function() {
  999. var dividedSubCiphertext = mathematical.groupUtils.divide(
  1000. _primarySubCiphertext, _secondarySubCiphertext);
  1001. var generatedList = [];
  1002. generatedList.push(_primaryCiphertext.getGamma());
  1003. generatedList.addAll(dividedSubCiphertext);
  1004. return generatedList;
  1005. };
  1006. this._getProof = function() {
  1007. return _proof;
  1008. };
  1009. this._getProgressMeter = function() {
  1010. return _progressMeter;
  1011. };
  1012. this.initProgressMeter = function(
  1013. progressCallback, progressPercentMinCheckInterval) {
  1014. _progressMeter = createProgressMeter(
  1015. _numKeyElements * 2 + 1, progressCallback,
  1016. progressPercentMinCheckInterval);
  1017. return this;
  1018. };
  1019. this._getVerifier = function() {
  1020. return _verifier;
  1021. };
  1022. };
  1023. box.proofs.SimplePlaintextEqualityProofVerifier.prototype = {
  1024. verify: function() {
  1025. return this._getVerifier().verify(
  1026. this._buildInputList(), this._getProof(),
  1027. box.SIMPLE_PLAINTEXT_EQUALITY_PROOF_AUXILIARY_DATA,
  1028. this._getProgressMeter());
  1029. }
  1030. };
  1031. /**
  1032. * Plaintext equality proof verifier.
  1033. */
  1034. box.proofs.PlaintextEqualityProofVerifier = function(
  1035. primaryCiphertext, primaryPublicKey, secondaryCiphertext,
  1036. secondaryPublicKey, proof, group) {
  1037. checkDefined('primary ciphertext', primaryCiphertext);
  1038. checkDefined('primary public key', primaryPublicKey);
  1039. checkDefined('secondary ciphertext', secondaryCiphertext);
  1040. checkDefined('secondary public key', secondaryPublicKey);
  1041. checkDefined('proof', proof);
  1042. checkDefined('group', group);
  1043. var _primaryCiphertext = primaryCiphertext;
  1044. var _primaryPublicKey = primaryPublicKey;
  1045. var _secondaryCiphertext = secondaryCiphertext;
  1046. var _secondaryPublicKey = secondaryPublicKey;
  1047. var _proof = proof;
  1048. var buildComputationRules = function(k) {
  1049. var firstDimensionLength = k + 2;
  1050. var rules = [];
  1051. rules[0] = [];
  1052. rules[0][0] = [];
  1053. rules[0][0].push(1);
  1054. rules[0][0].push(1);
  1055. rules[1] = [];
  1056. rules[1][0] = [];
  1057. rules[1][0].push(1);
  1058. rules[1][0].push(2);
  1059. for (var i = 2; i < firstDimensionLength; i++) {
  1060. rules[i] = [];
  1061. rules[i][0] = [];
  1062. rules[i][1] = [];
  1063. rules[i][0].push(i);
  1064. rules[i][0].push(1);
  1065. rules[i][1].push(i + k);
  1066. rules[i][1].push(2);
  1067. }
  1068. return rules;
  1069. };
  1070. function buildListOfBaseElements() {
  1071. var invertedSecondaryKeyValues = buildSecondaryInvertedPublicKey();
  1072. var baseElements = [];
  1073. baseElements.push(group.getGenerator());
  1074. baseElements.addAll(_primaryPublicKey.getGroupElementsArray());
  1075. baseElements.addAll(invertedSecondaryKeyValues);
  1076. return baseElements;
  1077. }
  1078. function buildSecondaryInvertedPublicKey() {
  1079. var listInvertedElements = [];
  1080. var keys = _secondaryPublicKey.getGroupElementsArray();
  1081. for (var i = 0; i < keys.length; i++) {
  1082. listInvertedElements.push(keys[i].invert());
  1083. }
  1084. return listInvertedElements;
  1085. }
  1086. var _progressMeter;
  1087. var _primarySubCiphertext = _primaryCiphertext.getPhis();
  1088. var _secondarySubCiphertext = _secondaryCiphertext.getPhis();
  1089. var _numKeyElements = primaryPublicKey.getGroupElementsArray().length;
  1090. var numOutputs = _numKeyElements + 2;
  1091. var phiFunctionPlaintextEquality = new box.proofs.PhiFunction(
  1092. group, 2, numOutputs, buildListOfBaseElements(),
  1093. buildComputationRules(_numKeyElements));
  1094. var _verifier =
  1095. new box.proofs.Verifier(group, phiFunctionPlaintextEquality);
  1096. this._buildInputList = function() {
  1097. var dividedSubCiphertext = mathematical.groupUtils.divide(
  1098. _primarySubCiphertext, _secondarySubCiphertext);
  1099. var generatedList = [];
  1100. generatedList.push(_primaryCiphertext.getGamma());
  1101. generatedList.push(_secondaryCiphertext.getGamma());
  1102. generatedList.addAll(dividedSubCiphertext);
  1103. return generatedList;
  1104. };
  1105. this._getProof = function() {
  1106. return _proof;
  1107. };
  1108. this._getProgressMeter = function() {
  1109. return _progressMeter;
  1110. };
  1111. this.initProgressMeter = function(
  1112. progressCallback, progressPercentMinCheckInterval) {
  1113. _progressMeter = createProgressMeter(
  1114. _numKeyElements * 2 + 2, progressCallback,
  1115. progressPercentMinCheckInterval);
  1116. return this;
  1117. };
  1118. this._getVerifier = function() {
  1119. return _verifier;
  1120. };
  1121. };
  1122. box.proofs.PlaintextEqualityProofVerifier.prototype = {
  1123. verify: function() {
  1124. return this._getVerifier().verify(
  1125. this._buildInputList(), this._getProof(),
  1126. box.PLAINTEXT_EQUALITY_PROOF_AUXILIARY_DATA,
  1127. this._getProgressMeter());
  1128. }
  1129. };
  1130. /**
  1131. * Plaintext exponent equality proof verifier.
  1132. */
  1133. box.proofs.PlaintextExponentEqualityProofVerifier = function(
  1134. ciphertext, baseElements, proof, group) {
  1135. checkDefined('ciphertext', ciphertext);
  1136. checkDefined('base elements', baseElements);
  1137. checkDefined('proof', proof);
  1138. checkDefined('group', group);
  1139. var _ciphertext = ciphertext;
  1140. var _baseElements = baseElements;
  1141. var _proof = proof;
  1142. var _group = group;
  1143. var _progressMeter;
  1144. this._buildComputationRules = function(k) {
  1145. var rules = [];
  1146. var firstDimensionLength = k + 1;
  1147. rules[0] = [];
  1148. rules[0][0] = [];
  1149. rules[0][0].push(1);
  1150. rules[0][0].push(1);
  1151. for (var i = 1; i < firstDimensionLength; i++) {
  1152. rules[i] = [];
  1153. rules[i][0] = [];
  1154. rules[i][1] = [];
  1155. rules[i][0].push(i + 1);
  1156. rules[i][0].push(1);
  1157. rules[i][1].push(i + 1 + k);
  1158. rules[i][1].push(2);
  1159. }
  1160. return rules;
  1161. };
  1162. this._buildListPublicValues = function() {
  1163. var list = [];
  1164. list.push(_ciphertext.getGamma());
  1165. list.addAll(_ciphertext.getPhis());
  1166. return list;
  1167. };
  1168. var _k = _ciphertext.getPhis().length;
  1169. var numOutputs = _k + 1;
  1170. var phiFunctionPlaintextExponentEquality = new box.proofs.PhiFunction(
  1171. _group, 2, numOutputs, _baseElements, this._buildComputationRules(_k));
  1172. var _verifier =
  1173. new box.proofs.Verifier(_group, phiFunctionPlaintextExponentEquality);
  1174. this._getProof = function() {
  1175. return _proof;
  1176. };
  1177. this._getVerifier = function() {
  1178. return _verifier;
  1179. };
  1180. this._getProgressMeter = function() {
  1181. return _progressMeter;
  1182. };
  1183. this.initProgressMeter = function(
  1184. progressCallback, progressPercentMinCheckInterval) {
  1185. _progressMeter = createProgressMeter(
  1186. _k * 2 + 1, progressCallback, progressPercentMinCheckInterval);
  1187. return this;
  1188. };
  1189. };
  1190. box.proofs.PlaintextExponentEqualityProofVerifier.prototype = {
  1191. verify: function() {
  1192. return this._getVerifier().verify(
  1193. this._buildListPublicValues(), this._getProof(),
  1194. box.PLAINTEXT_EXPONENT_EQUALITY_PROOF_AUXILIARY_DATA,
  1195. this._getProgressMeter());
  1196. }
  1197. };
  1198. /**
  1199. * OR-proof verifier.
  1200. */
  1201. box.proofs.ORProofVerifier = function(publicKey, numElements, group) {
  1202. checkPublicKey(publicKey);
  1203. checkNumElements(numElements);
  1204. checkGroup(group);
  1205. var _publicKey = publicKey;
  1206. var _numElements = numElements;
  1207. var _group = group;
  1208. var _numOutputs = _numElements * 2;
  1209. var _progressMeter;
  1210. function checkPublicKey(publicKey) {
  1211. checkDefined('public key', publicKey);
  1212. checkNotNull('public key', publicKey);
  1213. var publicKeyLength = publicKey.getGroupElementsArray().length;
  1214. if (publicKeyLength !== 1) {
  1215. throw new exceptions.CryptoLibException(
  1216. 'Expected public key length: 1 ; Found: ' + publicKeyLength);
  1217. }
  1218. }
  1219. function checkNumElements(numElements) {
  1220. checkDefined('numElements', numElements);
  1221. checkNotNull('numElements', numElements);
  1222. if (numElements < 2) {
  1223. throw new exceptions.CryptoLibException(
  1224. 'Expected number of elements to be greater than 1 ; Found: ' +
  1225. numElements);
  1226. }
  1227. }
  1228. function checkGroup(group) {
  1229. checkDefined('group', group);
  1230. checkNotNull('group', group);
  1231. }
  1232. function buildBaseElements() {
  1233. var baseElements = [];
  1234. baseElements.push(_group.getGenerator());
  1235. baseElements.push(_publicKey.getGroupElementsArray()[0]);
  1236. return baseElements;
  1237. }
  1238. function buildComputationRules(numOutputs) {
  1239. var rules = [];
  1240. var index1;
  1241. var index2 = 0;
  1242. for (var i = 0; i < numOutputs; i++) {
  1243. index1 = 1 + (i % 2);
  1244. if (i % 2 === 0) {
  1245. index2++;
  1246. }
  1247. rules[i] = [];
  1248. rules[i][0] = [];
  1249. rules[i][0].push(index1);
  1250. rules[i][0].push(index2);
  1251. }
  1252. return rules;
  1253. }
  1254. var phiFunctionOR = new box.proofs.PhiFunction(
  1255. _group, _numElements, _numOutputs, buildBaseElements(),
  1256. buildComputationRules(_numOutputs));
  1257. var _verifier = new box.proofs.Verifier(_group, phiFunctionOR);
  1258. this.buildPublicValues = function(ciphertext) {
  1259. var publicValues = [];
  1260. publicValues.push(ciphertext.getGamma());
  1261. publicValues.push(ciphertext.getPhis()[0]);
  1262. return publicValues;
  1263. };
  1264. this.getNumElements = function() {
  1265. return _numElements;
  1266. };
  1267. this.getVerifier = function() {
  1268. return _verifier;
  1269. };
  1270. this.getProgressMeter = function() {
  1271. return _progressMeter;
  1272. };
  1273. this.initProgressMeter = function(
  1274. progressCallback, progressPercentMinCheckInterval) {
  1275. _progressMeter = createProgressMeter(
  1276. _numOutputs, progressCallback, progressPercentMinCheckInterval);
  1277. return this;
  1278. };
  1279. };
  1280. box.proofs.ORProofVerifier.prototype = {
  1281. verify: function(ciphertext, elements, data, proof) {
  1282. checkCiphertext(ciphertext);
  1283. checkElements(elements, this.getNumElements());
  1284. checkDefined('data', data);
  1285. checkProof(proof);
  1286. function checkCiphertext(ciphertext) {
  1287. checkDefined('ciphertext', ciphertext);
  1288. checkNotNull('ciphertext', ciphertext);
  1289. var ciphertextLength = ciphertext.getPhis().length + 1;
  1290. if (ciphertextLength !== 2) {
  1291. throw new exceptions.CryptoLibException(
  1292. 'Expected ciphertext length: 2 ; Found: ' + ciphertextLength);
  1293. }
  1294. }
  1295. function checkElements(elements, numElementsExpected) {
  1296. checkDefined('elements', elements);
  1297. checkNotNull('elements', elements);
  1298. var numElementsFound = elements.length;
  1299. if (numElementsFound !== numElementsExpected) {
  1300. throw new exceptions.CryptoLibException(
  1301. 'Expected number of elements: ' + numElementsExpected +
  1302. ' ; Found: ' + numElementsFound);
  1303. }
  1304. }
  1305. function checkProof(proof) {
  1306. checkDefined('proof', proof);
  1307. checkNotNull('proof', proof);
  1308. }
  1309. if (data === null) {
  1310. data = '';
  1311. }
  1312. return this.getVerifier().verify(
  1313. this.buildPublicValues(ciphertext), proof, data, elements,
  1314. this.getProgressMeter());
  1315. }
  1316. };
  1317. /**
  1318. * Proofs factory, can be used for creating proof generators and verifiers.
  1319. */
  1320. box.proofs.ProofsFactory = function() {
  1321. };
  1322. box.proofs.ProofsFactory.prototype = {
  1323. createSchnorrProofGenerator: function(voterID, electionID, group) {
  1324. return new box.proofs.SchnorrProofGenerator(voterID, electionID, group);
  1325. },
  1326. createExponentiationProofGenerator: function(baseElements, group) {
  1327. return new box.proofs.ExponentiationProofGenerator(baseElements, group);
  1328. },
  1329. createPlaintextProofGenerator: function(publicKey, group) {
  1330. return new box.proofs.PlaintextProofGenerator(publicKey, group);
  1331. },
  1332. createSimplePlaintextEqualityProofGenerator: function(
  1333. primaryPublicKey, secondaryPublicKey, group) {
  1334. return new box.proofs.SimplePlaintextEqualityProofGenerator(
  1335. primaryPublicKey, secondaryPublicKey, group);
  1336. },
  1337. createPlaintextEqualityProofGenerator: function(
  1338. primaryPublicKey, secondaryPublicKey, group) {
  1339. return new box.proofs.PlaintextEqualityProofGenerator(
  1340. primaryPublicKey, secondaryPublicKey, group);
  1341. },
  1342. createPlaintextExponentEqualityProofGenerator: function(
  1343. baseElements, group) {
  1344. return new box.proofs.PlaintextExponentEqualityProofGenerator(
  1345. baseElements, group);
  1346. },
  1347. createORProofGenerator: function(publicKey, numElements, group) {
  1348. return new box.proofs.ORProofGenerator(publicKey, numElements, group);
  1349. },
  1350. createSchnorrProofVerifier: function(
  1351. element, voterID, electionEventID, proof, group) {
  1352. return new box.proofs.SchnorrProofVerifier(
  1353. element, voterID, electionEventID, proof, group);
  1354. },
  1355. createExponentiationProofVerifier: function(
  1356. exponentiatedElements, baseElements, proof, group) {
  1357. return new box.proofs.ExponentiationProofVerifier(
  1358. exponentiatedElements, baseElements, proof, group);
  1359. },
  1360. createPlaintextProofVerifier: function(
  1361. publicKey, ciphertext, plaintext, proof, group) {
  1362. return new box.proofs.PlaintextProofVerifier(
  1363. publicKey, ciphertext, plaintext, proof, group);
  1364. },
  1365. createSimplePlaintextEqualityProofVerifier: function(
  1366. primaryCiphertext, primaryPublicKey, secondaryCiphertext,
  1367. secondaryPublicKey, proof, group) {
  1368. return new box.proofs.SimplePlaintextEqualityProofVerifier(
  1369. primaryCiphertext, primaryPublicKey, secondaryCiphertext,
  1370. secondaryPublicKey, proof, group);
  1371. },
  1372. createPlaintextEqualityProofVerifier: function(
  1373. primaryCiphertext, primaryPublicKey, secondaryCiphertext,
  1374. secondaryPublicKey, proof, group) {
  1375. return new box.proofs.PlaintextEqualityProofVerifier(
  1376. primaryCiphertext, primaryPublicKey, secondaryCiphertext,
  1377. secondaryPublicKey, proof, group);
  1378. },
  1379. createPlaintextExponentEqualityProofVerifier: function(
  1380. ciphertext, baseElements, proof, group) {
  1381. return new box.proofs.PlaintextExponentEqualityProofVerifier(
  1382. ciphertext, baseElements, proof, group);
  1383. },
  1384. createORProofVerifier: function(publicKey, numElements, group) {
  1385. return new box.proofs.ORProofVerifier(publicKey, numElements, group);
  1386. }
  1387. };
  1388. /**
  1389. * Represents the PHI function of Maurer's Unified Zero-Knowledge Proof of
  1390. * Knowledge (ZK-PoK) scheme.
  1391. */
  1392. box.proofs.PhiFunction = function(
  1393. group, numInputs, numOutputs, baseElements, computationRules) {
  1394. var validateComputationRules = function(
  1395. numInputs, numOutputs, baseElements, computationRules) {
  1396. // Validate that both of the values in each of the
  1397. // pairs of rules have values in the correct ranges
  1398. var numBaseElements = baseElements.length;
  1399. for (var i = 0; i < numOutputs; i++) {
  1400. for (var j = 0; j < computationRules[i].length; j++) {
  1401. // Validate the first value of the pair
  1402. var pairValue1 = computationRules[i][j][0];
  1403. if ((pairValue1 < 1) || (pairValue1 > numBaseElements)) {
  1404. throw new exceptions.CryptoLibException(
  1405. 'Invalid first value in index pair - should be in the range 1 to ' +
  1406. numBaseElements + ', but it was ' + pairValue1);
  1407. }
  1408. // Validate the second value of the pair
  1409. var pairValue2 = computationRules[i][j][1];
  1410. if ((pairValue2 < 1) || (pairValue2 > numInputs)) {
  1411. throw new exceptions.CryptoLibException(
  1412. 'Invalid second value in index pair - should be in the range 1 to ' +
  1413. numInputs + ', but it was ' + pairValue2);
  1414. }
  1415. }
  1416. }
  1417. };
  1418. checkDefined('group', group);
  1419. checkIsPositive('number of inputs', numInputs);
  1420. checkIsPositive('number of outputs', numOutputs);
  1421. checkInitializedArray('base elements', baseElements);
  1422. checkDefined('computation rules', computationRules);
  1423. validateComputationRules(
  1424. numInputs, numOutputs, baseElements, computationRules);
  1425. var _numInputs = numInputs;
  1426. var _numOutputs = numOutputs;
  1427. var _baseElements = baseElements;
  1428. var _computationRules = computationRules;
  1429. /**
  1430. * @return The number of inputs
  1431. */
  1432. this.getNumInputs = function() {
  1433. return _numInputs;
  1434. };
  1435. /**
  1436. * @return The number of outputs
  1437. */
  1438. this.getNumOutputs = function() {
  1439. return _numOutputs;
  1440. };
  1441. /**
  1442. * @return The list of base elements
  1443. */
  1444. this.getBaseElements = function() {
  1445. return _baseElements;
  1446. };
  1447. /**
  1448. * @return The computation rules.
  1449. */
  1450. this.getComputationRules = function() {
  1451. return _computationRules;
  1452. };
  1453. };
  1454. box.proofs.PhiFunction.prototype = {
  1455. calculatePhi: function(inputs, progressMeter) {
  1456. checkDefined('inputs', inputs);
  1457. if (progressMeter === undefined) {
  1458. progressMeter = new utils.ProgressMeter();
  1459. }
  1460. checkDefined('progressMeter', progressMeter);
  1461. var computationsRules = this.getComputationRules();
  1462. var baseElements = this.getBaseElements();
  1463. var partialResult;
  1464. var resultForThisListOfPairs;
  1465. var result = [];
  1466. var progress = 0;
  1467. for (var i = 0; i < computationsRules.length; i++) {
  1468. var numPairsInList = computationsRules[i].length;
  1469. resultForThisListOfPairs =
  1470. baseElements[computationsRules[i][0][0] - 1].exponentiate(
  1471. inputs[computationsRules[i][0][1] - 1]);
  1472. progressMeter.update(++progress);
  1473. for (var j = 1; j < numPairsInList; j++) {
  1474. var index1 = computationsRules[i][j][0];
  1475. index1 = index1 - 1;
  1476. var index2 = computationsRules[i][j][1];
  1477. index2 = index2 - 1;
  1478. partialResult = baseElements[index1].exponentiate(inputs[index2]);
  1479. resultForThisListOfPairs =
  1480. resultForThisListOfPairs.multiply(partialResult);
  1481. progressMeter.update(++progress);
  1482. }
  1483. result.push(resultForThisListOfPairs);
  1484. }
  1485. return result;
  1486. }
  1487. };
  1488. /**
  1489. * Acts as a prover in a Zero-Knowledge Proof of Knowledge (ZK-PoK) exchange
  1490. * using Maurer's unified PHI function.
  1491. */
  1492. box.proofs.Prover = function(group, phiFunction) {
  1493. checkDefined('group', group);
  1494. checkDefined('phiFunction', phiFunction);
  1495. var _group = group;
  1496. var _phiFunction = phiFunction;
  1497. var _cryptoRandomInteger = secureRandomFactory.getCryptoRandomInteger();
  1498. /**
  1499. * @return Get the group.
  1500. */
  1501. this.getGroup = function() {
  1502. return _group;
  1503. };
  1504. /**
  1505. * @return Get the phi function.
  1506. */
  1507. this.getPhiFunction = function() {
  1508. return _phiFunction;
  1509. };
  1510. this._calculateRandomExponents = function(numExponentsNeeded) {
  1511. var exponentsArray = [];
  1512. for (var i = 0; i < numExponentsNeeded; i++) {
  1513. var randomExponent = mathematical.groupUtils.generateRandomExponent(
  1514. _group, _cryptoRandomInteger);
  1515. exponentsArray.push(randomExponent);
  1516. }
  1517. return exponentsArray;
  1518. };
  1519. this._generateHash = function(publicValues, phiOutputs, data) {
  1520. var hashBuilder = new box.proofs.HashBuilder();
  1521. var hashB64 =
  1522. hashBuilder.buildHashForProof(publicValues, phiOutputs, data);
  1523. var hash = converters.base64Decode(hashB64);
  1524. var hashBytes = converters.bytesFromString(hash);
  1525. hashBytes.unshift(0);
  1526. var value = new box.forge.jsbn.BigInteger(hashBytes);
  1527. return new mathematical.Exponent(_group.getQ(), value);
  1528. };
  1529. this._generateValuesList = function(
  1530. privateValues, hash, randomExponents, index) {
  1531. var proofValues = [];
  1532. var proofValue;
  1533. if (typeof index === 'undefined') {
  1534. for (var i = 0; i < privateValues.length; i++) {
  1535. proofValue = randomExponents[i].getValue().add(
  1536. privateValues[i].getValue().multiply(hash.getValue()));
  1537. proofValues.push(
  1538. new mathematical.Exponent(_group.getQ(), proofValue));
  1539. }
  1540. } else {
  1541. var numElements = randomExponents.length / 2;
  1542. var updatedHash = hash;
  1543. for (var j = 0; j < numElements; j++) {
  1544. if (j === index) {
  1545. for (var k = 0; k < numElements; k++) {
  1546. if (k !== index) {
  1547. updatedHash = updatedHash.subtract(randomExponents[k]);
  1548. }
  1549. }
  1550. proofValues.push(updatedHash);
  1551. } else {
  1552. proofValues.push(randomExponents[j]);
  1553. }
  1554. }
  1555. for (var m = numElements; m < (numElements * 2); m++) {
  1556. if (m === (numElements + index)) {
  1557. proofValue = randomExponents[m].getValue().add(
  1558. privateValues[0].getValue().multiply(updatedHash.getValue()));
  1559. proofValues.push(
  1560. new mathematical.Exponent(_group.getQ(), proofValue));
  1561. } else {
  1562. proofValues.push(randomExponents[m]);
  1563. }
  1564. }
  1565. }
  1566. return proofValues;
  1567. };
  1568. this._updatePreComputedValues = function(
  1569. preComputedValues, publicValues, elements, index) {
  1570. var gamma = publicValues[0];
  1571. var phi = publicValues[1];
  1572. var numElements = elements.length;
  1573. var challenges = this._calculateRandomExponents(numElements);
  1574. var updatedExponents = [];
  1575. updatedExponents.addAll(challenges);
  1576. updatedExponents.addAll(preComputedValues.getExponents());
  1577. var updatedPhiOutputs = [];
  1578. var phiOutputs = preComputedValues.getPhiOutputs();
  1579. for (var j = 0; j < numElements; j++) {
  1580. var offset = 2 * j;
  1581. if (j === index) {
  1582. updatedPhiOutputs.push(phiOutputs[offset]);
  1583. updatedPhiOutputs.push(phiOutputs[offset + 1]);
  1584. } else {
  1585. var gammaFactor = gamma.invert().exponentiate(challenges[j]);
  1586. var phiFactor =
  1587. (phi.invert().multiply(elements[j])).exponentiate(challenges[j]);
  1588. updatedPhiOutputs.push(phiOutputs[offset].multiply(gammaFactor));
  1589. updatedPhiOutputs.push(phiOutputs[offset + 1].multiply(phiFactor));
  1590. }
  1591. }
  1592. return new box.proofs.ProofPreComputedValues(
  1593. updatedExponents, updatedPhiOutputs);
  1594. };
  1595. };
  1596. box.proofs.Prover.prototype = {
  1597. /**
  1598. * Pre-compute time-consuming values, so they can be used later for
  1599. * method prove().
  1600. */
  1601. preCompute: function(privateValuesLength, progressMeter) {
  1602. var randomExponents = this._calculateRandomExponents(privateValuesLength);
  1603. var phiOutputs =
  1604. this.getPhiFunction().calculatePhi(randomExponents, progressMeter);
  1605. return new box.proofs.ProofPreComputedValues(randomExponents, phiOutputs);
  1606. },
  1607. /**
  1608. * Performs prover steps in a ZK-PoK exchange using Maurer's unified PHI
  1609. * function. This involves generating a proof, using the received inputs
  1610. * and this Prover's internal fields.
  1611. */
  1612. prove: function(
  1613. publicValues, privateValues, data, preComputedValues, elements, index) {
  1614. checkDefined('public values', publicValues);
  1615. checkDefined('private values', privateValues);
  1616. checkDefined('data', data);
  1617. if (!preComputedValues ||
  1618. typeof preComputedValues.getPhiOutputs() === 'undefined' ||
  1619. typeof preComputedValues.getExponents() === 'undefined') {
  1620. throw new exceptions.CryptoLibException(
  1621. 'The precomputed values must be initialized');
  1622. }
  1623. if (typeof elements !== 'undefined') {
  1624. preComputedValues = this._updatePreComputedValues(
  1625. preComputedValues, publicValues, elements, index);
  1626. }
  1627. var hash = this._generateHash(
  1628. publicValues, preComputedValues.getPhiOutputs(), data);
  1629. var proofValues = this._generateValuesList(
  1630. privateValues, hash, preComputedValues.getExponents(), index);
  1631. return new box.proofs.Proof(hash, proofValues);
  1632. }
  1633. };
  1634. /**
  1635. * Acts as a verifier in a Zero-Knowledge Proof of Knowledge (ZK-PoK)
  1636. * exchange using Maurer's unified PHI function.
  1637. */
  1638. box.proofs.Verifier = function(group, phiFunction) {
  1639. checkDefined('group', group);
  1640. checkDefined('phiFunction', phiFunction);
  1641. var _group = group;
  1642. var _phiFunction = phiFunction;
  1643. /**
  1644. * @return Get the group.
  1645. */
  1646. this.getGroup = function() {
  1647. return _group;
  1648. };
  1649. /**
  1650. * @return Get the phi function.
  1651. */
  1652. this.getPhiFunction = function() {
  1653. return _phiFunction;
  1654. };
  1655. this._calculateComputedValues = function(
  1656. publicValues, phiOutputs, proofHashValueOrElements, challenges) {
  1657. var proofHashValue;
  1658. var elements;
  1659. if (!isArray(proofHashValueOrElements)) {
  1660. proofHashValue = proofHashValueOrElements;
  1661. } else {
  1662. elements = proofHashValueOrElements;
  1663. }
  1664. var computedValues = [];
  1665. if (typeof proofHashValue !== 'undefined') {
  1666. for (var i = 0; i < phiOutputs.length; i++) {
  1667. computedValues.push(phiOutputs[i].multiply(
  1668. publicValues[i].exponentiate(proofHashValue.negate())));
  1669. }
  1670. } else {
  1671. var gamma = publicValues[0];
  1672. var phi = publicValues[1];
  1673. for (var j = 0; j < challenges.length; j++) {
  1674. var offset = 2 * j;
  1675. var gammaFactor = gamma.invert().exponentiate(challenges[j]);
  1676. var phiFactor =
  1677. (phi.invert().multiply(elements[j])).exponentiate(challenges[j]);
  1678. computedValues.push(phiOutputs[offset].multiply(gammaFactor));
  1679. computedValues.push(phiOutputs[offset + 1].multiply(phiFactor));
  1680. }
  1681. }
  1682. return computedValues;
  1683. };
  1684. this._calculateHash = function(publicValues, computedValues, data) {
  1685. var hashBuilder = new box.proofs.HashBuilder();
  1686. var hashB64 =
  1687. hashBuilder.buildHashForProof(publicValues, computedValues, data);
  1688. var hash = converters.base64Decode(hashB64);
  1689. var hashBytes = converters.bytesFromString(hash);
  1690. hashBytes.unshift(0);
  1691. var value = new box.forge.jsbn.BigInteger(hashBytes);
  1692. return new mathematical.Exponent(_group.getQ(), value);
  1693. };
  1694. };
  1695. box.proofs.Verifier.prototype = {
  1696. /**
  1697. * Verifies the received input as being true or false.
  1698. */
  1699. verify: function(
  1700. publicValues, proof, data, elementsOrProgressMeter, progressMeter) {
  1701. checkDefined('public values', publicValues);
  1702. checkDefined('proof', proof);
  1703. checkDefined('data', data);
  1704. var elements;
  1705. if (!isArray(elementsOrProgressMeter)) {
  1706. progressMeter = elementsOrProgressMeter;
  1707. } else {
  1708. elements = elementsOrProgressMeter;
  1709. }
  1710. var proofHashValue = proof.getHash();
  1711. var phiOutputs;
  1712. var computedValues;
  1713. if (typeof elements === 'undefined') {
  1714. phiOutputs = this.getPhiFunction().calculatePhi(
  1715. proof.getValues(), progressMeter);
  1716. computedValues = this._calculateComputedValues(
  1717. publicValues, phiOutputs, proofHashValue);
  1718. } else {
  1719. var numElements = elements.length;
  1720. var proofValues = proof.getValues();
  1721. var challenges = proofValues.slice(0, numElements);
  1722. var phiInputs = proofValues.slice(numElements, numElements * 2);
  1723. phiOutputs =
  1724. this.getPhiFunction().calculatePhi(phiInputs, progressMeter);
  1725. computedValues = this._calculateComputedValues(
  1726. publicValues, phiOutputs, elements, challenges);
  1727. }
  1728. var calculatedHash =
  1729. this._calculateHash(publicValues, computedValues, data);
  1730. return proofHashValue.equals(calculatedHash);
  1731. }
  1732. };
  1733. /**
  1734. * @class ProofPreComputedValues stores randomly created exponents and
  1735. * outputs of box.proofs.PhiFunction.calculatePhi().
  1736. */
  1737. box.proofs.ProofPreComputedValues = function(exponents, phiOutputs) {
  1738. this.className = 'ProofPreComputedValues';
  1739. var _exponents = exponents;
  1740. var _phiOutputs = phiOutputs;
  1741. /**
  1742. * @return the exponents.
  1743. */
  1744. this.getExponents = function() {
  1745. return _exponents;
  1746. };
  1747. /**
  1748. * @return the phi function output.
  1749. */
  1750. this.getPhiOutputs = function() {
  1751. return _phiOutputs;
  1752. };
  1753. };
  1754. box.proofs.ProofPreComputedValues.prototype = {
  1755. stringify: function() {
  1756. var exponentValues = Array();
  1757. var phiOutputValues = Array();
  1758. for (var i = 0; i < this.getExponents().length; i++) {
  1759. exponentValues[i] =
  1760. converters.base64FromBigInteger(this.getExponents()[i].getValue());
  1761. }
  1762. for (var j = 0; j < this.getPhiOutputs().length; j++) {
  1763. phiOutputValues[j] = converters.base64FromBigInteger(
  1764. this.getPhiOutputs()[j].getElementValue());
  1765. }
  1766. return JSON.stringify({
  1767. preComputed: {
  1768. p: converters.base64FromBigInteger(this.getPhiOutputs()[0].getP()),
  1769. q: converters.base64FromBigInteger(this.getPhiOutputs()[0].getQ()),
  1770. exponents: exponentValues,
  1771. phiOutputs: phiOutputValues
  1772. }
  1773. });
  1774. }
  1775. };
  1776. /**
  1777. * Represents a proof in a ZKP exchange.
  1778. */
  1779. box.proofs.Proof = function(hashValue, values) {
  1780. checkDefined('hash value', hashValue);
  1781. checkDefined('values', values);
  1782. var _hashValue = hashValue;
  1783. var _values = values;
  1784. /**
  1785. * @return Get the hash value of this proof.
  1786. */
  1787. this.getHash = function() {
  1788. return _hashValue;
  1789. };
  1790. /**
  1791. * @return Get the list of values of this proof.
  1792. */
  1793. this.getValues = function() {
  1794. return _values;
  1795. };
  1796. };
  1797. box.proofs.Proof.prototype = {
  1798. /**
  1799. * @return true if the given proof has the same hash and values.
  1800. */
  1801. equals: function(proof) {
  1802. return proof.getHash().equals(this.getHash()) &&
  1803. proof.getValues().equals(this.getValues());
  1804. },
  1805. /**
  1806. * Displays a string representation of this proof JSON.
  1807. * <p>
  1808. * Note: in order to permit interoperability between libraries, this
  1809. * representation should match the equivalent representation in Java.
  1810. *
  1811. * @function
  1812. * @returns a string representation of this proof JSON.
  1813. */
  1814. stringify: function() {
  1815. var values = Array();
  1816. for (var i = 0; i < this.getValues().length; i++) {
  1817. values[i] =
  1818. converters.base64FromBigInteger(this.getValues()[i].getValue());
  1819. }
  1820. return JSON.stringify({
  1821. zkProof: {
  1822. q: converters.base64FromBigInteger(this.getHash().getQ()),
  1823. hash: converters.base64FromBigInteger(this.getHash().getValue()),
  1824. values: values
  1825. }
  1826. });
  1827. }
  1828. };
  1829. /**
  1830. * A class which provides utility methods for generating a hash from a set
  1831. * of inputs.
  1832. */
  1833. box.proofs.HashBuilder = function() {
  1834. /**
  1835. * Convert an integer to a byte array
  1836. */
  1837. this._getInt64Bytes = function(x) {
  1838. var bytes = [];
  1839. var i = 8;
  1840. do {
  1841. bytes[--i] = x & (255);
  1842. x = x >> 8;
  1843. } while (i);
  1844. return bytes;
  1845. };
  1846. /**
  1847. * Converts an array to a String.
  1848. */
  1849. this._arrayElementValuesToString = function(groupElements) {
  1850. var str = '';
  1851. for (var i = 0; i < groupElements.length; i++) {
  1852. if (groupElements[i].getElementValue() !== undefined) {
  1853. str += groupElements[i].getElementValue();
  1854. } else {
  1855. throw new exceptions.CryptoLibException(
  1856. 'Group Element must implement getElementValue() method.');
  1857. }
  1858. }
  1859. return str;
  1860. };
  1861. };
  1862. box.proofs.HashBuilder.prototype = {
  1863. /**
  1864. * Generates a hash value based on the element values of publicValues
  1865. * and generatedValues and the data.
  1866. *
  1867. * @function
  1868. * @param publicValues
  1869. * {array} group elements representing public values.
  1870. * @param generatedValues
  1871. * {array} group elements representing generated values.
  1872. * @param data
  1873. * {string} some data encoded as a String.
  1874. * @returns a generated hash code.
  1875. * @throws CryptoLibException
  1876. * if any of the received objects has unsupported type.
  1877. */
  1878. buildHashForProof: function(publicValues, generatedValues, data) {
  1879. checkInitializedArray('public values', publicValues);
  1880. checkInitializedArray('generated values', generatedValues);
  1881. var messageDigester = messageDigestFactory.getCryptoMessageDigest();
  1882. messageDigester.start();
  1883. messageDigester = update(
  1884. messageDigester, this._arrayElementValuesToString(publicValues));
  1885. messageDigester = update(
  1886. messageDigester, this._arrayElementValuesToString(generatedValues));
  1887. messageDigester = update(messageDigester, data);
  1888. return messageDigester.digest();
  1889. }
  1890. };
  1891. /**
  1892. * Utility method that updates messageDigester with the provided string.
  1893. */
  1894. function update(messageDigester, str) {
  1895. var stringRepresentationB64 = converters.base64Encode(str);
  1896. var arrayToHash = [];
  1897. arrayToHash.push(stringRepresentationB64);
  1898. messageDigester.update(arrayToHash);
  1899. return messageDigester;
  1900. }
  1901. /**
  1902. * Utility method that checks that value is defined and not null and throws
  1903. * related exception otherwise.
  1904. */
  1905. function checkDefined(key, value) {
  1906. if (typeof value === 'undefined') {
  1907. throw new exceptions.CryptoLibException(
  1908. 'The ' + key + ' must be defined');
  1909. }
  1910. }
  1911. /**
  1912. * Utility method that checks that value is initialized array and throws
  1913. * related exception otherwise.
  1914. */
  1915. function checkInitializedArray(key, value) {
  1916. checkDefined(key, value);
  1917. if (!isArray(value)) {
  1918. throw new exceptions.CryptoLibException(
  1919. 'The ' + key + ' must be an initialized array');
  1920. }
  1921. }
  1922. /**
  1923. * Utility method that checks that value is not null and throws related
  1924. * exception otherwise.
  1925. */
  1926. function checkNotNull(key, value) {
  1927. checkDefined(key, value);
  1928. if (value === null) {
  1929. throw new exceptions.CryptoLibException(
  1930. 'The ' + key + ' must not be null');
  1931. }
  1932. }
  1933. /**
  1934. * Utility method that checks that value is not empty and throws related
  1935. * exception otherwise.
  1936. */
  1937. function checkNotEmpty(key, value) {
  1938. checkDefined(key, value);
  1939. if (value.length === 0) {
  1940. throw new exceptions.CryptoLibException(
  1941. 'The ' + key + ' must not be empty');
  1942. }
  1943. }
  1944. /**
  1945. * Utility method that checks that value is positive and throws related
  1946. * exception otherwise.
  1947. */
  1948. function checkIsPositive(key, value) {
  1949. checkDefined(key, value);
  1950. if (isNaN(value)) {
  1951. throw new exceptions.CryptoLibException(
  1952. 'The ' + key + ' must be a number; Found ' + value);
  1953. }
  1954. if (value <= 0) {
  1955. throw new exceptions.CryptoLibException(
  1956. 'The ' + key + ' must be positive; Found ' + value);
  1957. }
  1958. }
  1959. /**
  1960. * Utility method that checks that values are defined and throws related
  1961. * exception otherwise.
  1962. */
  1963. var checkDefinedProgressParams = function(
  1964. progressCallback, progressPercentMinCheckInterval) {
  1965. if (typeof progressCallback !== 'undefined' &&
  1966. typeof progressCallback !== 'function') {
  1967. throw new exceptions.CryptoLibException(
  1968. 'The progress callback function provided as input is not a function');
  1969. }
  1970. if (typeof progressPercentMinCheckInterval !== 'undefined' &&
  1971. isNaN(progressPercentMinCheckInterval)) {
  1972. throw new exceptions.CryptoLibException(
  1973. 'The progress percentage check interval provided as input is not a number');
  1974. }
  1975. };
  1976. function isArray(a) {
  1977. return (!!a) && (a.constructor === Array);
  1978. }
  1979. /**
  1980. * Utility method that creates a new instance of ProgressMeter.
  1981. */
  1982. function createProgressMeter(
  1983. progressMax, progressCallback, progressPercentMinCheckInterval) {
  1984. checkDefinedProgressParams(
  1985. progressCallback, progressPercentMinCheckInterval);
  1986. return new utils.ProgressMeter(
  1987. progressMax, progressCallback, progressPercentMinCheckInterval);
  1988. }
  1989. /**
  1990. * Provides utility functionality for working with proofs.
  1991. *
  1992. * @class utils
  1993. * @memberof proofs
  1994. */
  1995. box.proofs.utils = (function() {
  1996. /**
  1997. * Deserializes a Proof JSON string representation to a Proof object.
  1998. *
  1999. * @function
  2000. * @memberof proofs.utils
  2001. * @param jsonAsString
  2002. * {JSON} a JSON representation of a proof.
  2003. * @returns a new Proof, created from the received string.
  2004. */
  2005. function deserializeProof(jsonAsString) {
  2006. var proofJson = JSON.parse(jsonAsString).zkProof;
  2007. var q = converters.base64ToBigInteger(proofJson.q);
  2008. var hash = new box.commons.mathematical.Exponent(
  2009. q, converters.base64ToBigInteger(proofJson.hash));
  2010. var values = [];
  2011. for (var i = 0; i < proofJson.values.length; i++) {
  2012. values.push(new box.commons.mathematical.Exponent(
  2013. q, converters.base64ToBigInteger(proofJson.values[i])));
  2014. }
  2015. return new box.proofs.Proof(hash, values);
  2016. }
  2017. /**
  2018. * Deserializes a ProofPreComputedValues JSON string representation to a
  2019. * ProofPreComputedValues object.
  2020. *
  2021. * @function
  2022. * @memberof proofs.utils
  2023. * @param jsonAsString
  2024. * {JSON} a JSON representation of a pre-computed value.
  2025. * @returns a new ProofPreComputedValues, created from the received
  2026. * string.
  2027. */
  2028. function deserializeProofPreComputedValues(jsonAsString) {
  2029. var proofPreComputedValuesJson = JSON.parse(jsonAsString).preComputed;
  2030. var p = converters.base64ToBigInteger(proofPreComputedValuesJson.p);
  2031. var q = converters.base64ToBigInteger(proofPreComputedValuesJson.q);
  2032. var exponentValues = proofPreComputedValuesJson.exponents;
  2033. var exponents = [];
  2034. var value;
  2035. for (var i = 0; i < exponentValues.length; i++) {
  2036. value = converters.base64ToBigInteger(exponentValues[i]);
  2037. exponents.push(new box.commons.mathematical.Exponent(q, value));
  2038. }
  2039. var phiOutputValues = proofPreComputedValuesJson.phiOutputs;
  2040. var phiOutputs = [];
  2041. for (var j = 0; j < phiOutputValues.length; j++) {
  2042. value = converters.base64ToBigInteger(phiOutputValues[j]);
  2043. phiOutputs.push(
  2044. new box.commons.mathematical.ZpGroupElement(value, p, q));
  2045. }
  2046. return new box.proofs.ProofPreComputedValues(exponents, phiOutputs);
  2047. }
  2048. return {
  2049. deserializeProof: deserializeProof,
  2050. deserializeProofPreComputedValues: deserializeProofPreComputedValues
  2051. };
  2052. })();
  2053. };