@zkpassport/sdk 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/esm/index.js CHANGED
@@ -1,18 +1,18 @@
1
- import { randomBytes } from 'crypto';
2
- import { getAlpha3Code, registerLocale } from 'i18n-iso-countries';
3
- import { getProofData, getCommitmentFromDSCProof, getCommitmentInFromIDDataProof, getCommitmentOutFromIDDataProof, getNullifierFromDisclosureProof, getCommitmentInFromIntegrityProof, getCommitmentOutFromIntegrityProof, getCommitmentInFromDisclosureProof, getMerkleRootFromDSCProof, getCurrentDateFromIntegrityProof, getMaxAgeFromProof, getMinAgeFromProof, getCurrentDateFromAgeProof, getMinDateFromProof, getMaxDateFromProof, getCountryListFromExclusionProof, getCountryListFromInclusionProof, DisclosedData, formatName, getHostedPackagedCircuitByName, } from '@zkpassport/utils';
4
- import { bytesToHex } from '@noble/ciphers/utils';
5
- import { getWebSocketClient } from './websocket';
6
- import { createEncryptedJsonRpcRequest } from './json-rpc';
7
- import { decrypt, generateECDHKeyPair, getSharedSecret } from './encryption';
8
- import logger from './logger';
9
- import { ungzip } from 'node-gzip';
1
+ import { randomBytes } from "crypto";
2
+ import { getAlpha3Code, registerLocale } from "i18n-iso-countries";
3
+ import { getProofData, getCommitmentFromDSCProof, getCommitmentInFromIDDataProof, getCommitmentOutFromIDDataProof, getNullifierFromDisclosureProof, getCommitmentInFromIntegrityProof, getCommitmentOutFromIntegrityProof, getCommitmentInFromDisclosureProof, getMerkleRootFromDSCProof, getCurrentDateFromIntegrityProof, getMaxAgeFromProof, getMinAgeFromProof, getCurrentDateFromAgeProof, getMinDateFromProof, getMaxDateFromProof, getCountryListFromExclusionProof, getCountryListFromInclusionProof, DisclosedData, formatName, getHostedPackagedCircuitByName, } from "@zkpassport/utils";
4
+ import { bytesToHex } from "@noble/ciphers/utils";
5
+ import { getWebSocketClient } from "./websocket";
6
+ import { createEncryptedJsonRpcRequest } from "./json-rpc";
7
+ import { decrypt, generateECDHKeyPair, getSharedSecret } from "./encryption";
8
+ import { noLogger as logger } from "./logger";
9
+ import { ungzip } from "node-gzip";
10
10
  //import initNoirC from '@noir-lang/noirc_abi'
11
11
  //import initACVM from '@noir-lang/acvm_js'
12
- registerLocale(require('i18n-iso-countries/langs/en.json'));
12
+ registerLocale(require("i18n-iso-countries/langs/en.json"));
13
13
  function normalizeCountry(country) {
14
14
  let normalizedCountry;
15
- const alpha3 = getAlpha3Code(country, 'en');
15
+ const alpha3 = getAlpha3Code(country, "en");
16
16
  normalizedCountry = alpha3 || country;
17
17
  return normalizedCountry;
18
18
  }
@@ -34,7 +34,7 @@ function generalCompare(fnName, key, value, requestId, requestIdToConfig) {
34
34
  [fnName]: value,
35
35
  };
36
36
  }
37
- export { SANCTIONED_COUNTRIES, EU_COUNTRIES, EEA_COUNTRIES, SCHENGEN_COUNTRIES, ASEAN_COUNTRIES, MERCOSUR_COUNTRIES, } from '@zkpassport/utils';
37
+ export { SANCTIONED_COUNTRIES, EU_COUNTRIES, EEA_COUNTRIES, SCHENGEN_COUNTRIES, ASEAN_COUNTRIES, MERCOSUR_COUNTRIES, } from "@zkpassport/utils";
38
38
  export class ZKPassport {
39
39
  //private wasmVerifierInit: boolean = false
40
40
  constructor(_domain) {
@@ -52,8 +52,8 @@ export class ZKPassport {
52
52
  this.onResultCallbacks = {};
53
53
  this.onRejectCallbacks = {};
54
54
  this.onErrorCallbacks = {};
55
- if (!_domain && typeof window === 'undefined') {
56
- throw new Error('Domain argument is required in Node.js environment');
55
+ if (!_domain && typeof window === "undefined") {
56
+ throw new Error("Domain argument is required in Node.js environment");
57
57
  }
58
58
  this.domain = _domain || window.location.hostname;
59
59
  }
@@ -69,19 +69,19 @@ export class ZKPassport {
69
69
  * @param outerRequest The outer request.
70
70
  */
71
71
  async handleEncryptedMessage(topic, request, outerRequest) {
72
- logger.debug('Received encrypted message:', request);
73
- if (request.method === 'accept') {
72
+ logger.debug("Received encrypted message:", request);
73
+ if (request.method === "accept") {
74
74
  logger.debug(`User accepted the request and is generating a proof`);
75
75
  await Promise.all(this.onGeneratingProofCallbacks[topic].map((callback) => callback(topic)));
76
76
  }
77
- else if (request.method === 'reject') {
77
+ else if (request.method === "reject") {
78
78
  logger.debug(`User rejected the request`);
79
79
  await Promise.all(this.onRejectCallbacks[topic].map((callback) => callback()));
80
80
  }
81
- else if (request.method === 'proof') {
81
+ else if (request.method === "proof") {
82
82
  logger.debug(`User generated proof`);
83
83
  // Uncompress the proof and convert it to a hex string
84
- const bytesProof = Buffer.from(request.params.proof, 'base64');
84
+ const bytesProof = Buffer.from(request.params.proof, "base64");
85
85
  const uncompressedProof = await ungzip(bytesProof);
86
86
  // The gzip lib in the app compress the proof as ASCII
87
87
  // and since the app passes the proof as a hex string, we can
@@ -96,7 +96,7 @@ export class ZKPassport {
96
96
  this.topicToProofs[topic].push(processedProof);
97
97
  await Promise.all(this.onProofGeneratedCallbacks[topic].map((callback) => callback(processedProof)));
98
98
  }
99
- else if (request.method === 'done') {
99
+ else if (request.method === "done") {
100
100
  logger.debug(`User sent the query result`);
101
101
  // Verify the proofs and extract the unique identifier (aka nullifier) and the verification result
102
102
  const { uniqueIdentifier, verified } = await this.verify(topic, this.topicToProofs[topic], request.params);
@@ -106,21 +106,21 @@ export class ZKPassport {
106
106
  result: request.params,
107
107
  })));
108
108
  }
109
- else if (request.method === 'error') {
109
+ else if (request.method === "error") {
110
110
  await Promise.all(this.onErrorCallbacks[topic].map((callback) => callback(request.params.error)));
111
111
  }
112
112
  }
113
113
  getZkPassportRequest(topic) {
114
114
  return {
115
115
  eq: (key, value) => {
116
- if (key === 'issuing_country' || key === 'nationality') {
116
+ if (key === "issuing_country" || key === "nationality") {
117
117
  value = normalizeCountry(value);
118
118
  }
119
- generalCompare('eq', key, value, topic, this.topicToConfig);
119
+ generalCompare("eq", key, value, topic, this.topicToConfig);
120
120
  return this.getZkPassportRequest(topic);
121
121
  },
122
122
  gte: (key, value) => {
123
- numericalCompare('gte', key, value, topic, this.topicToConfig);
123
+ numericalCompare("gte", key, value, topic, this.topicToConfig);
124
124
  return this.getZkPassportRequest(topic);
125
125
  },
126
126
  /*gt: <T extends NumericalIDCredential>(key: T, value: IDCredentialValue<T>) => {
@@ -128,11 +128,11 @@ export class ZKPassport {
128
128
  return this.getZkPassportRequest(topic)
129
129
  },*/
130
130
  lte: (key, value) => {
131
- numericalCompare('lte', key, value, topic, this.topicToConfig);
131
+ numericalCompare("lte", key, value, topic, this.topicToConfig);
132
132
  return this.getZkPassportRequest(topic);
133
133
  },
134
134
  lt: (key, value) => {
135
- numericalCompare('lt', key, value, topic, this.topicToConfig);
135
+ numericalCompare("lt", key, value, topic, this.topicToConfig);
136
136
  return this.getZkPassportRequest(topic);
137
137
  },
138
138
  range: (key, start, end) => {
@@ -141,12 +141,12 @@ export class ZKPassport {
141
141
  },
142
142
  in: (key, value) => {
143
143
  value = value.map((v) => normalizeCountry(v));
144
- generalCompare('in', key, value, topic, this.topicToConfig);
144
+ generalCompare("in", key, value, topic, this.topicToConfig);
145
145
  return this.getZkPassportRequest(topic);
146
146
  },
147
147
  out: (key, value) => {
148
148
  value = value.map((v) => normalizeCountry(v));
149
- generalCompare('out', key, value, topic, this.topicToConfig);
149
+ generalCompare("out", key, value, topic, this.topicToConfig);
150
150
  return this.getZkPassportRequest(topic);
151
151
  },
152
152
  disclose: (key) => {
@@ -160,8 +160,8 @@ export class ZKPassport {
160
160
  return this.getZkPassportRequest(topic)
161
161
  },*/
162
162
  done: () => {
163
- const base64Config = Buffer.from(JSON.stringify(this.topicToConfig[topic])).toString('base64');
164
- const base64Service = Buffer.from(JSON.stringify(this.topicToService[topic])).toString('base64');
163
+ const base64Config = Buffer.from(JSON.stringify(this.topicToConfig[topic])).toString("base64");
164
+ const base64Service = Buffer.from(JSON.stringify(this.topicToService[topic])).toString("base64");
165
165
  const pubkey = bytesToHex(this.topicToKeyPair[topic].publicKey);
166
166
  return {
167
167
  url: `https://zkpassport.id/r?d=${this.domain}&t=${topic}&c=${base64Config}&s=${base64Service}&p=${pubkey}`,
@@ -184,7 +184,7 @@ export class ZKPassport {
184
184
  * @returns The query builder object.
185
185
  */
186
186
  async request({ name, logo, purpose, scope, topicOverride, keyPairOverride, }) {
187
- const topic = topicOverride || randomBytes(16).toString('hex');
187
+ const topic = topicOverride || randomBytes(16).toString("hex");
188
188
  const keyPair = keyPairOverride || (await generateECDHKeyPair());
189
189
  this.topicToKeyPair[topic] = {
190
190
  privateKey: keyPair.privateKey,
@@ -203,30 +203,30 @@ export class ZKPassport {
203
203
  const wsClient = getWebSocketClient(`wss://bridge.zkpassport.id?topic=${topic}`, this.domain);
204
204
  this.topicToWebSocketClient[topic] = wsClient;
205
205
  wsClient.onopen = async () => {
206
- logger.info('[frontend] WebSocket connection established');
206
+ logger.info("[frontend] WebSocket connection established");
207
207
  await Promise.all(this.onBridgeConnectCallbacks[topic].map((callback) => callback()));
208
208
  };
209
- wsClient.addEventListener('message', async (event) => {
210
- logger.debug('[frontend] Received message:', event.data);
209
+ wsClient.addEventListener("message", async (event) => {
210
+ logger.debug("[frontend] Received message:", event.data);
211
211
  try {
212
212
  const data = JSON.parse(event.data);
213
213
  // Handshake happens when the mobile app scans the QR code and connects to the bridge
214
- if (data.method === 'handshake') {
215
- logger.debug('[frontend] Received handshake:', event.data);
214
+ if (data.method === "handshake") {
215
+ logger.debug("[frontend] Received handshake:", event.data);
216
216
  this.topicToRequestReceived[topic] = true;
217
217
  this.topicToSharedSecret[topic] = await getSharedSecret(bytesToHex(keyPair.privateKey), data.params.pubkey);
218
- logger.debug('[frontend] Shared secret:', Buffer.from(this.topicToSharedSecret[topic]).toString('hex'));
219
- const encryptedMessage = await createEncryptedJsonRpcRequest('hello', null, this.topicToSharedSecret[topic], topic);
220
- logger.debug('[frontend] Sending encrypted message:', encryptedMessage);
218
+ logger.debug("[frontend] Shared secret:", Buffer.from(this.topicToSharedSecret[topic]).toString("hex"));
219
+ const encryptedMessage = await createEncryptedJsonRpcRequest("hello", null, this.topicToSharedSecret[topic], topic);
220
+ logger.debug("[frontend] Sending encrypted message:", encryptedMessage);
221
221
  wsClient.send(JSON.stringify(encryptedMessage));
222
222
  await Promise.all(this.onRequestReceivedCallbacks[topic].map((callback) => callback()));
223
223
  return;
224
224
  }
225
225
  // Handle encrypted messages
226
- if (data.method === 'encryptedMessage') {
226
+ if (data.method === "encryptedMessage") {
227
227
  // Decode the payload from base64 to Uint8Array
228
228
  const payload = new Uint8Array(atob(data.params.payload)
229
- .split('')
229
+ .split("")
230
230
  .map((c) => c.charCodeAt(0)));
231
231
  try {
232
232
  // Decrypt the payload using the shared secret
@@ -235,17 +235,17 @@ export class ZKPassport {
235
235
  this.handleEncryptedMessage(topic, decryptedJson, data);
236
236
  }
237
237
  catch (error) {
238
- logger.error('[frontend] Error decrypting message:', error);
238
+ logger.error("[frontend] Error decrypting message:", error);
239
239
  }
240
240
  return;
241
241
  }
242
242
  }
243
243
  catch (error) {
244
- logger.error('[frontend] Error:', error);
244
+ logger.error("[frontend] Error:", error);
245
245
  }
246
246
  });
247
247
  wsClient.onerror = (error) => {
248
- logger.error('[frontend] WebSocket error:', error);
248
+ logger.error("[frontend] WebSocket error:", error);
249
249
  };
250
250
  return this.getZkPassportRequest(topic);
251
251
  }
@@ -254,7 +254,7 @@ export class ZKPassport {
254
254
  let commitmentOut;
255
255
  let isCorrect = true;
256
256
  let uniqueIdentifier;
257
- const expectedMerkleRoot = BigInt('21301853597069384763054217328384418971999152625381818922211526730996340553696');
257
+ const expectedMerkleRoot = BigInt("21301853597069384763054217328384418971999152625381818922211526730996340553696");
258
258
  const defaultDateValue = new Date(1111, 10, 11);
259
259
  const currentTime = new Date();
260
260
  const today = new Date(currentTime.getFullYear(), currentTime.getMonth(), currentTime.getDate(), 0, 0, 0, 0);
@@ -262,46 +262,46 @@ export class ZKPassport {
262
262
  // by their expected order: root signature check -> ID signature check -> integrity check -> disclosure
263
263
  const sortedProofs = proofs.sort((a, b) => {
264
264
  const proofOrder = [
265
- 'sig_check_dsc',
266
- 'sig_check_id_data',
267
- 'data_check_integrity',
268
- 'disclose_bytes',
269
- 'compare_age',
270
- 'compare_birthdate',
271
- 'compare_expiry',
272
- 'exclusion_check_country',
273
- 'inclusion_check_country',
265
+ "sig_check_dsc",
266
+ "sig_check_id_data",
267
+ "data_check_integrity",
268
+ "disclose_bytes",
269
+ "compare_age",
270
+ "compare_birthdate",
271
+ "compare_expiry",
272
+ "exclusion_check_country",
273
+ "inclusion_check_country",
274
274
  ];
275
275
  const getIndex = (proof) => {
276
- const name = proof.name || '';
276
+ const name = proof.name || "";
277
277
  return proofOrder.findIndex((p) => name.startsWith(p));
278
278
  };
279
279
  return getIndex(a) - getIndex(b);
280
280
  });
281
281
  for (const proof of sortedProofs) {
282
282
  const proofData = getProofData(proof.proof, true);
283
- if (proof.name?.startsWith('sig_check_dsc')) {
283
+ if (proof.name?.startsWith("sig_check_dsc")) {
284
284
  commitmentOut = getCommitmentFromDSCProof(proofData);
285
285
  const merkleRoot = getMerkleRootFromDSCProof(proofData);
286
286
  if (merkleRoot !== expectedMerkleRoot) {
287
- console.warn('The ID was signed by an unrecognized root certificate');
287
+ console.warn("The ID was signed by an unrecognized root certificate");
288
288
  isCorrect = false;
289
289
  break;
290
290
  }
291
291
  }
292
- else if (proof.name?.startsWith('sig_check_id_data')) {
292
+ else if (proof.name?.startsWith("sig_check_id_data")) {
293
293
  commitmentIn = getCommitmentInFromIDDataProof(proofData);
294
294
  if (commitmentIn !== commitmentOut) {
295
- console.warn('Failed to check the link between the certificate signature and ID signature');
295
+ console.warn("Failed to check the link between the certificate signature and ID signature");
296
296
  isCorrect = false;
297
297
  break;
298
298
  }
299
299
  commitmentOut = getCommitmentOutFromIDDataProof(proofData);
300
300
  }
301
- else if (proof.name?.startsWith('data_check_integrity')) {
301
+ else if (proof.name?.startsWith("data_check_integrity")) {
302
302
  commitmentIn = getCommitmentInFromIntegrityProof(proofData);
303
303
  if (commitmentIn !== commitmentOut) {
304
- console.warn('Failed to check the link between the ID signature and the data signed');
304
+ console.warn("Failed to check the link between the ID signature and the data signed");
305
305
  isCorrect = false;
306
306
  break;
307
307
  }
@@ -311,33 +311,33 @@ export class ZKPassport {
311
311
  // (if the proof request was requested just before midnight and is finalized after)
312
312
  if (currentDate.getTime() !== today.getTime() &&
313
313
  currentDate.getTime() !== today.getTime() - 86400000) {
314
- console.warn('Current date used to check the validity of the ID is too old');
314
+ console.warn("Current date used to check the validity of the ID is too old");
315
315
  isCorrect = false;
316
316
  break;
317
317
  }
318
318
  }
319
- else if (proof.name === 'disclose_bytes') {
319
+ else if (proof.name === "disclose_bytes") {
320
320
  commitmentIn = getCommitmentInFromDisclosureProof(proofData);
321
321
  if (commitmentIn !== commitmentOut) {
322
- console.warn('Failed to check the link between the validity of the ID and the data to disclose');
322
+ console.warn("Failed to check the link between the validity of the ID and the data to disclose");
323
323
  isCorrect = false;
324
324
  break;
325
325
  }
326
326
  // We can't be certain that the disclosed data is for a passport or an ID card
327
327
  // so we need to check both (unless the document type is revealed)
328
- const disclosedDataPassport = DisclosedData.fromBytesProof(proofData, 'passport');
329
- const disclosedDataIDCard = DisclosedData.fromBytesProof(proofData, 'id_card');
328
+ const disclosedDataPassport = DisclosedData.fromBytesProof(proofData, "passport");
329
+ const disclosedDataIDCard = DisclosedData.fromBytesProof(proofData, "id_card");
330
330
  if (queryResult.document_type) {
331
331
  // Document type is always at the same index in the disclosed data
332
332
  if (queryResult.document_type.eq &&
333
333
  queryResult.document_type.eq.result &&
334
334
  queryResult.document_type.eq.expected !== disclosedDataPassport.documentType) {
335
- console.warn('Document type does not match the expected document type');
335
+ console.warn("Document type does not match the expected document type");
336
336
  isCorrect = false;
337
337
  break;
338
338
  }
339
339
  if (queryResult.document_type.disclose?.result !== disclosedDataIDCard.documentType) {
340
- console.warn('Document type does not match the disclosed document type in query result');
340
+ console.warn("Document type does not match the disclosed document type in query result");
341
341
  isCorrect = false;
342
342
  break;
343
343
  }
@@ -349,14 +349,14 @@ export class ZKPassport {
349
349
  queryResult.birthdate.eq.result &&
350
350
  queryResult.birthdate.eq.expected.getTime() !== birthdatePassport.getTime() &&
351
351
  queryResult.birthdate.eq.expected.getTime() !== birthdateIDCard.getTime()) {
352
- console.warn('Birthdate does not match the expected birthdate');
352
+ console.warn("Birthdate does not match the expected birthdate");
353
353
  isCorrect = false;
354
354
  break;
355
355
  }
356
356
  if (queryResult.birthdate.disclose &&
357
357
  queryResult.birthdate.disclose.result.getTime() !== birthdatePassport.getTime() &&
358
358
  queryResult.birthdate.disclose.result.getTime() !== birthdateIDCard.getTime()) {
359
- console.warn('Birthdate does not match the disclosed birthdate in query result');
359
+ console.warn("Birthdate does not match the disclosed birthdate in query result");
360
360
  isCorrect = false;
361
361
  break;
362
362
  }
@@ -368,14 +368,14 @@ export class ZKPassport {
368
368
  queryResult.expiry_date.eq.result &&
369
369
  queryResult.expiry_date.eq.expected.getTime() !== expiryDatePassport.getTime() &&
370
370
  queryResult.expiry_date.eq.expected.getTime() !== expiryDateIDCard.getTime()) {
371
- console.warn('Expiry date does not match the expected expiry date');
371
+ console.warn("Expiry date does not match the expected expiry date");
372
372
  isCorrect = false;
373
373
  break;
374
374
  }
375
375
  if (queryResult.expiry_date.disclose &&
376
376
  queryResult.expiry_date.disclose.result.getTime() !== expiryDatePassport.getTime() &&
377
377
  queryResult.expiry_date.disclose.result.getTime() !== expiryDateIDCard.getTime()) {
378
- console.warn('Expiry date does not match the disclosed expiry date in query result');
378
+ console.warn("Expiry date does not match the disclosed expiry date in query result");
379
379
  isCorrect = false;
380
380
  break;
381
381
  }
@@ -387,14 +387,14 @@ export class ZKPassport {
387
387
  queryResult.nationality.eq.result &&
388
388
  queryResult.nationality.eq.expected !== nationalityPassport &&
389
389
  queryResult.nationality.eq.expected !== nationalityIDCard) {
390
- console.warn('Nationality does not match the expected nationality');
390
+ console.warn("Nationality does not match the expected nationality");
391
391
  isCorrect = false;
392
392
  break;
393
393
  }
394
394
  if (queryResult.nationality.disclose &&
395
395
  queryResult.nationality.disclose.result !== nationalityPassport &&
396
396
  queryResult.nationality.disclose.result !== nationalityIDCard) {
397
- console.warn('Nationality does not match the disclosed nationality in query result');
397
+ console.warn("Nationality does not match the disclosed nationality in query result");
398
398
  isCorrect = false;
399
399
  break;
400
400
  }
@@ -406,14 +406,14 @@ export class ZKPassport {
406
406
  queryResult.document_number.eq.result &&
407
407
  queryResult.document_number.eq.expected !== documentNumberPassport &&
408
408
  queryResult.document_number.eq.expected !== documentNumberIDCard) {
409
- console.warn('Document number does not match the expected document number');
409
+ console.warn("Document number does not match the expected document number");
410
410
  isCorrect = false;
411
411
  break;
412
412
  }
413
413
  if (queryResult.document_number.disclose &&
414
414
  queryResult.document_number.disclose.result !== documentNumberPassport &&
415
415
  queryResult.document_number.disclose.result !== documentNumberIDCard) {
416
- console.warn('Document number does not match the disclosed document number in query result');
416
+ console.warn("Document number does not match the disclosed document number in query result");
417
417
  isCorrect = false;
418
418
  break;
419
419
  }
@@ -425,14 +425,14 @@ export class ZKPassport {
425
425
  queryResult.gender.eq.result &&
426
426
  queryResult.gender.eq.expected !== genderPassport &&
427
427
  queryResult.gender.eq.expected !== genderIDCard) {
428
- console.warn('Gender does not match the expected gender');
428
+ console.warn("Gender does not match the expected gender");
429
429
  isCorrect = false;
430
430
  break;
431
431
  }
432
432
  if (queryResult.gender.disclose &&
433
433
  queryResult.gender.disclose.result !== genderPassport &&
434
434
  queryResult.gender.disclose.result !== genderIDCard) {
435
- console.warn('Gender does not match the disclosed gender in query result');
435
+ console.warn("Gender does not match the disclosed gender in query result");
436
436
  isCorrect = false;
437
437
  break;
438
438
  }
@@ -444,14 +444,14 @@ export class ZKPassport {
444
444
  queryResult.issuing_country.eq.result &&
445
445
  queryResult.issuing_country.eq.expected !== issuingCountryPassport &&
446
446
  queryResult.issuing_country.eq.expected !== issuingCountryIDCard) {
447
- console.warn('Issuing country does not match the expected issuing country');
447
+ console.warn("Issuing country does not match the expected issuing country");
448
448
  isCorrect = false;
449
449
  break;
450
450
  }
451
451
  if (queryResult.issuing_country.disclose &&
452
452
  queryResult.issuing_country.disclose.result !== issuingCountryPassport &&
453
453
  queryResult.issuing_country.disclose.result !== issuingCountryIDCard) {
454
- console.warn('Issuing country does not match the disclosed issuing country in query result');
454
+ console.warn("Issuing country does not match the disclosed issuing country in query result");
455
455
  isCorrect = false;
456
456
  break;
457
457
  }
@@ -465,7 +465,7 @@ export class ZKPassport {
465
465
  fullnamePassport.toLowerCase() &&
466
466
  formatName(queryResult.fullname.eq.expected).toLowerCase() !==
467
467
  fullnameIDCard.toLowerCase()) {
468
- console.warn('Fullname does not match the expected fullname');
468
+ console.warn("Fullname does not match the expected fullname");
469
469
  isCorrect = false;
470
470
  break;
471
471
  }
@@ -474,7 +474,7 @@ export class ZKPassport {
474
474
  fullnamePassport.toLowerCase() &&
475
475
  formatName(queryResult.fullname.disclose.result).toLowerCase() !==
476
476
  fullnameIDCard.toLowerCase()) {
477
- console.warn('Fullname does not match the disclosed fullname in query result');
477
+ console.warn("Fullname does not match the disclosed fullname in query result");
478
478
  isCorrect = false;
479
479
  break;
480
480
  }
@@ -493,7 +493,7 @@ export class ZKPassport {
493
493
  firstnamePassport.toLowerCase() &&
494
494
  formatName(queryResult.firstname.eq.expected).toLowerCase() !==
495
495
  firstnameIDCard.toLowerCase()) {
496
- console.warn('Firstname does not match the expected firstname');
496
+ console.warn("Firstname does not match the expected firstname");
497
497
  isCorrect = false;
498
498
  break;
499
499
  }
@@ -502,7 +502,7 @@ export class ZKPassport {
502
502
  firstnamePassport.toLowerCase() &&
503
503
  formatName(queryResult.firstname.disclose.result).toLowerCase() !==
504
504
  firstnameIDCard.toLowerCase()) {
505
- console.warn('Firstname does not match the disclosed firstname in query result');
505
+ console.warn("Firstname does not match the disclosed firstname in query result");
506
506
  isCorrect = false;
507
507
  break;
508
508
  }
@@ -521,7 +521,7 @@ export class ZKPassport {
521
521
  lastnamePassport.toLowerCase() &&
522
522
  formatName(queryResult.lastname.eq.expected).toLowerCase() !==
523
523
  lastnameIDCard.toLowerCase()) {
524
- console.warn('Lastname does not match the expected lastname');
524
+ console.warn("Lastname does not match the expected lastname");
525
525
  isCorrect = false;
526
526
  break;
527
527
  }
@@ -530,17 +530,17 @@ export class ZKPassport {
530
530
  lastnamePassport.toLowerCase() &&
531
531
  formatName(queryResult.lastname.disclose.result).toLowerCase() !==
532
532
  lastnameIDCard.toLowerCase()) {
533
- console.warn('Lastname does not match the disclosed lastname in query result');
533
+ console.warn("Lastname does not match the disclosed lastname in query result");
534
534
  isCorrect = false;
535
535
  break;
536
536
  }
537
537
  }
538
538
  uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10);
539
539
  }
540
- else if (proof.name === 'compare_age') {
540
+ else if (proof.name === "compare_age") {
541
541
  commitmentIn = getCommitmentInFromDisclosureProof(proofData);
542
542
  if (commitmentIn !== commitmentOut) {
543
- console.warn('Failed to check the link between the validity of the ID and the age derived from it');
543
+ console.warn("Failed to check the link between the validity of the ID and the age derived from it");
544
544
  isCorrect = false;
545
545
  break;
546
546
  }
@@ -550,14 +550,14 @@ export class ZKPassport {
550
550
  if (queryResult.age.gte &&
551
551
  queryResult.age.gte.result &&
552
552
  minAge < queryResult.age.gte.expected) {
553
- console.warn('Age is not greater than or equal to the expected age');
553
+ console.warn("Age is not greater than or equal to the expected age");
554
554
  isCorrect = false;
555
555
  break;
556
556
  }
557
557
  if (queryResult.age.lt &&
558
558
  queryResult.age.lt.result &&
559
559
  maxAge >= queryResult.age.lt.expected) {
560
- console.warn('Age is not less than the expected age');
560
+ console.warn("Age is not less than the expected age");
561
561
  isCorrect = false;
562
562
  break;
563
563
  }
@@ -565,47 +565,47 @@ export class ZKPassport {
565
565
  if (queryResult.age.range.result &&
566
566
  (minAge < queryResult.age.range.expected[0] ||
567
567
  maxAge >= queryResult.age.range.expected[1])) {
568
- console.warn('Age is not in the expected range');
568
+ console.warn("Age is not in the expected range");
569
569
  isCorrect = false;
570
570
  break;
571
571
  }
572
572
  }
573
573
  if (!queryResult.age.lt && !queryResult.age.range && maxAge != 0) {
574
- console.warn('Maximum age should be equal to 0');
574
+ console.warn("Maximum age should be equal to 0");
575
575
  isCorrect = false;
576
576
  break;
577
577
  }
578
578
  if (!queryResult.age.gte && !queryResult.age.range && minAge != 0) {
579
- console.warn('Minimum age should be equal to 0');
579
+ console.warn("Minimum age should be equal to 0");
580
580
  isCorrect = false;
581
581
  break;
582
582
  }
583
583
  if (queryResult.age.disclose &&
584
584
  (queryResult.age.disclose.result !== minAge ||
585
585
  queryResult.age.disclose.result !== maxAge)) {
586
- console.warn('Age does not match the disclosed age in query result');
586
+ console.warn("Age does not match the disclosed age in query result");
587
587
  isCorrect = false;
588
588
  break;
589
589
  }
590
590
  }
591
591
  else {
592
- console.warn('Age is not set in the query result');
592
+ console.warn("Age is not set in the query result");
593
593
  isCorrect = false;
594
594
  break;
595
595
  }
596
596
  const currentDate = getCurrentDateFromAgeProof(proofData);
597
597
  if (currentDate.getTime() !== today.getTime() &&
598
598
  currentDate.getTime() !== today.getTime() - 86400000) {
599
- console.warn('Current date in the proof is too old');
599
+ console.warn("Current date in the proof is too old");
600
600
  isCorrect = false;
601
601
  break;
602
602
  }
603
603
  uniqueIdentifier = getCommitmentInFromDisclosureProof(proofData).toString(10);
604
604
  }
605
- else if (proof.name === 'compare_birthdate') {
605
+ else if (proof.name === "compare_birthdate") {
606
606
  commitmentIn = getCommitmentInFromDisclosureProof(proofData);
607
607
  if (commitmentIn !== commitmentOut) {
608
- console.warn('Failed to check the link between the validity of the ID and the birthdate derived from it');
608
+ console.warn("Failed to check the link between the validity of the ID and the birthdate derived from it");
609
609
  isCorrect = false;
610
610
  break;
611
611
  }
@@ -615,14 +615,14 @@ export class ZKPassport {
615
615
  if (queryResult.birthdate.gte &&
616
616
  queryResult.birthdate.gte.result &&
617
617
  minDate < queryResult.birthdate.gte.expected) {
618
- console.warn('Birthdate is not greater than or equal to the expected birthdate');
618
+ console.warn("Birthdate is not greater than or equal to the expected birthdate");
619
619
  isCorrect = false;
620
620
  break;
621
621
  }
622
622
  if (queryResult.birthdate.lte &&
623
623
  queryResult.birthdate.lte.result &&
624
624
  maxDate > queryResult.birthdate.lte.expected) {
625
- console.warn('Birthdate is not less than the expected birthdate');
625
+ console.warn("Birthdate is not less than the expected birthdate");
626
626
  isCorrect = false;
627
627
  break;
628
628
  }
@@ -630,7 +630,7 @@ export class ZKPassport {
630
630
  if (queryResult.birthdate.range.result &&
631
631
  (minDate < queryResult.birthdate.range.expected[0] ||
632
632
  maxDate > queryResult.birthdate.range.expected[1])) {
633
- console.warn('Birthdate is not in the expected range');
633
+ console.warn("Birthdate is not in the expected range");
634
634
  isCorrect = false;
635
635
  break;
636
636
  }
@@ -638,29 +638,29 @@ export class ZKPassport {
638
638
  if (!queryResult.birthdate.lte &&
639
639
  !queryResult.birthdate.range &&
640
640
  maxDate.getTime() != defaultDateValue.getTime()) {
641
- console.warn('Maximum birthdate should be equal to default date value');
641
+ console.warn("Maximum birthdate should be equal to default date value");
642
642
  isCorrect = false;
643
643
  break;
644
644
  }
645
645
  if (!queryResult.birthdate.gte &&
646
646
  !queryResult.birthdate.range &&
647
647
  minDate.getTime() != defaultDateValue.getTime()) {
648
- console.warn('Minimum birthdate should be equal to default date value');
648
+ console.warn("Minimum birthdate should be equal to default date value");
649
649
  isCorrect = false;
650
650
  break;
651
651
  }
652
652
  }
653
653
  else {
654
- console.warn('Birthdate is not set in the query result');
654
+ console.warn("Birthdate is not set in the query result");
655
655
  isCorrect = false;
656
656
  break;
657
657
  }
658
658
  uniqueIdentifier = getCommitmentInFromDisclosureProof(proofData).toString(10);
659
659
  }
660
- else if (proof.name === 'compare_expiry') {
660
+ else if (proof.name === "compare_expiry") {
661
661
  commitmentIn = getCommitmentInFromDisclosureProof(proofData);
662
662
  if (commitmentIn !== commitmentOut) {
663
- console.warn('Failed to check the link between the validity of the ID and its expiry date');
663
+ console.warn("Failed to check the link between the validity of the ID and its expiry date");
664
664
  isCorrect = false;
665
665
  break;
666
666
  }
@@ -670,14 +670,14 @@ export class ZKPassport {
670
670
  if (queryResult.expiry_date.gte &&
671
671
  queryResult.expiry_date.gte.result &&
672
672
  minDate < queryResult.expiry_date.gte.expected) {
673
- console.warn('Expiry date is not greater than or equal to the expected expiry date');
673
+ console.warn("Expiry date is not greater than or equal to the expected expiry date");
674
674
  isCorrect = false;
675
675
  break;
676
676
  }
677
677
  if (queryResult.expiry_date.lte &&
678
678
  queryResult.expiry_date.lte.result &&
679
679
  maxDate > queryResult.expiry_date.lte.expected) {
680
- console.warn('Expiry date is not less than the expected expiry date');
680
+ console.warn("Expiry date is not less than the expected expiry date");
681
681
  isCorrect = false;
682
682
  break;
683
683
  }
@@ -685,7 +685,7 @@ export class ZKPassport {
685
685
  if (queryResult.expiry_date.range.result &&
686
686
  (minDate < queryResult.expiry_date.range.expected[0] ||
687
687
  maxDate > queryResult.expiry_date.range.expected[1])) {
688
- console.warn('Expiry date is not in the expected range');
688
+ console.warn("Expiry date is not in the expected range");
689
689
  isCorrect = false;
690
690
  break;
691
691
  }
@@ -693,29 +693,29 @@ export class ZKPassport {
693
693
  if (!queryResult.expiry_date.lte &&
694
694
  !queryResult.expiry_date.range &&
695
695
  maxDate.getTime() != defaultDateValue.getTime()) {
696
- console.warn('Maximum expiry date should be equal to default date value');
696
+ console.warn("Maximum expiry date should be equal to default date value");
697
697
  isCorrect = false;
698
698
  break;
699
699
  }
700
700
  if (!queryResult.expiry_date.gte &&
701
701
  !queryResult.expiry_date.range &&
702
702
  minDate.getTime() != defaultDateValue.getTime()) {
703
- console.warn('Minimum expiry date should be equal to default date value');
703
+ console.warn("Minimum expiry date should be equal to default date value");
704
704
  isCorrect = false;
705
705
  break;
706
706
  }
707
707
  }
708
708
  else {
709
- console.warn('Expiry date is not set in the query result');
709
+ console.warn("Expiry date is not set in the query result");
710
710
  isCorrect = false;
711
711
  break;
712
712
  }
713
713
  uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10);
714
714
  }
715
- else if (proof.name === 'exclusion_check_country') {
715
+ else if (proof.name === "exclusion_check_country") {
716
716
  commitmentIn = getCommitmentInFromDisclosureProof(proofData);
717
717
  if (commitmentIn !== commitmentOut) {
718
- console.warn('Failed to check the link between the validity of the ID and the country exclusion check');
718
+ console.warn("Failed to check the link between the validity of the ID and the country exclusion check");
719
719
  isCorrect = false;
720
720
  break;
721
721
  }
@@ -724,22 +724,22 @@ export class ZKPassport {
724
724
  queryResult.nationality.out &&
725
725
  queryResult.nationality.out.result) {
726
726
  if (!queryResult.nationality.out.expected?.every((country) => countryList.includes(country))) {
727
- console.warn('Country exclusion list does not match the one from the query results');
727
+ console.warn("Country exclusion list does not match the one from the query results");
728
728
  isCorrect = false;
729
729
  break;
730
730
  }
731
731
  }
732
732
  else if (!queryResult.nationality || !queryResult.nationality.out) {
733
- console.warn('Nationality exclusion is not set in the query result');
733
+ console.warn("Nationality exclusion is not set in the query result");
734
734
  isCorrect = false;
735
735
  break;
736
736
  }
737
737
  uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10);
738
738
  }
739
- else if (proof.name === 'inclusion_check_country') {
739
+ else if (proof.name === "inclusion_check_country") {
740
740
  commitmentIn = getCommitmentInFromDisclosureProof(proofData);
741
741
  if (commitmentIn !== commitmentOut) {
742
- console.warn('Failed to check the link between the validity of the ID and the country inclusion check');
742
+ console.warn("Failed to check the link between the validity of the ID and the country inclusion check");
743
743
  isCorrect = false;
744
744
  break;
745
745
  }
@@ -748,13 +748,13 @@ export class ZKPassport {
748
748
  queryResult.nationality.in &&
749
749
  queryResult.nationality.in.result) {
750
750
  if (!queryResult.nationality.in.expected?.every((country) => countryList.includes(country))) {
751
- console.warn('Country inclusion list does not match the one from the query results');
751
+ console.warn("Country inclusion list does not match the one from the query results");
752
752
  isCorrect = false;
753
753
  break;
754
754
  }
755
755
  }
756
756
  else if (!queryResult.nationality || !queryResult.nationality.in) {
757
- console.warn('Nationality inclusion is not set in the query result');
757
+ console.warn("Nationality inclusion is not set in the query result");
758
758
  isCorrect = false;
759
759
  break;
760
760
  }
@@ -773,13 +773,17 @@ export class ZKPassport {
773
773
  */
774
774
  async verify(requestId, proofs, queryResult) {
775
775
  let proofsToVerify = proofs;
776
- if (!proofs) {
776
+ // There is a minimum of 4 subproofs to make a complete proof
777
+ if (!proofs || proofs.length < 4) {
777
778
  proofsToVerify = this.topicToProofs[requestId];
778
- if (!proofsToVerify || proofsToVerify.length === 0) {
779
- throw new Error('No proofs to verify');
779
+ if (!proofsToVerify || proofsToVerify.length < 4) {
780
+ // It may happen that a request returns a result without proofs
781
+ // Meaning the ID is supported yet by ZKPassport circuits,
782
+ // so the results has to be trusted and cannot be independently verified
783
+ return { uniqueIdentifier: undefined, verified: false };
780
784
  }
781
785
  }
782
- const { BarretenbergVerifier } = await import('@aztec/bb.js');
786
+ const { BarretenbergVerifier } = await import("@aztec/bb.js");
783
787
  const verifier = new BarretenbergVerifier();
784
788
  /*if (!this.wasmVerifierInit) {
785
789
  await this.initWasmVerifier()
@@ -796,12 +800,12 @@ export class ZKPassport {
796
800
  for (const proof of proofsToVerify) {
797
801
  const proofData = getProofData(proof.proof, true);
798
802
  const hostedPackagedCircuit = await getHostedPackagedCircuitByName(proof.version, proof.name);
799
- const vkeyBytes = Buffer.from(hostedPackagedCircuit.vkey, 'base64');
803
+ const vkeyBytes = Buffer.from(hostedPackagedCircuit.vkey, "base64");
800
804
  try {
801
805
  verified = await verifier.verifyUltraHonkProof(proofData, new Uint8Array(vkeyBytes));
802
806
  }
803
807
  catch (e) {
804
- console.warn('Error verifying proof', e);
808
+ console.warn("Error verifying proof", e);
805
809
  verified = false;
806
810
  }
807
811
  if (!verified) {
@@ -821,8 +825,8 @@ export class ZKPassport {
821
825
  */
822
826
  getUrl(requestId) {
823
827
  const pubkey = bytesToHex(this.topicToKeyPair[requestId].publicKey);
824
- const base64Config = Buffer.from(JSON.stringify(this.topicToConfig[requestId])).toString('base64');
825
- const base64Service = Buffer.from(JSON.stringify(this.topicToService[requestId])).toString('base64');
828
+ const base64Config = Buffer.from(JSON.stringify(this.topicToConfig[requestId])).toString("base64");
829
+ const base64Service = Buffer.from(JSON.stringify(this.topicToService[requestId])).toString("base64");
826
830
  return `https://zkpassport.id/r?d=${this.domain}&t=${requestId}&c=${base64Config}&s=${base64Service}&p=${pubkey}`;
827
831
  }
828
832
  /**