@zkpassport/sdk 0.3.0 → 0.3.2

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.
@@ -17,6 +17,7 @@ export type QueryResultErrors = {
17
17
  commitment?: QueryResultError<string>;
18
18
  date?: QueryResultError<string>;
19
19
  certificate?: QueryResultError<string>;
20
+ scope?: QueryResultError<string>;
20
21
  };
21
22
  };
22
23
  export type SolidityVerifierParameters = {
@@ -26,6 +27,9 @@ export type SolidityVerifierParameters = {
26
27
  committedInputs: string;
27
28
  committedInputCounts: number[];
28
29
  validityPeriodInDays: number;
30
+ scope: string;
31
+ subscope: string;
32
+ devMode: boolean;
29
33
  };
30
34
  export type EVMChain = "ethereum_sepolia" | "local_anvil";
31
35
  export type * from "@zkpassport/utils";
@@ -192,15 +196,17 @@ export declare class ZKPassport {
192
196
  * @param purpose To explain what you want to do with the user's data
193
197
  * @param scope Scope this request to a specific use case
194
198
  * @param validity How many days ago should have the ID been last scanned by the user?
199
+ * @param devMode Whether to enable dev mode. This will allow you to verify mock proofs (i.e. from ZKR)
195
200
  * @returns The query builder object.
196
201
  */
197
- request({ name, logo, purpose, scope, mode, validity, topicOverride, keyPairOverride, }: {
202
+ request({ name, logo, purpose, scope, mode, validity, devMode, topicOverride, keyPairOverride, }: {
198
203
  name: string;
199
204
  logo: string;
200
205
  purpose: string;
201
206
  scope?: string;
202
207
  mode?: ProofMode;
203
208
  validity?: number;
209
+ devMode?: boolean;
204
210
  topicOverride?: string;
205
211
  keyPairOverride?: {
206
212
  privateKey: Uint8Array;
@@ -215,6 +221,8 @@ export declare class ZKPassport {
215
221
  private checkIssuingCountryExclusionPublicInputs;
216
222
  private checkNationalityInclusionPublicInputs;
217
223
  private checkIssuingCountryInclusionPublicInputs;
224
+ private checkScopeFromDisclosureProof;
225
+ private checkCertificateRegistryRoot;
218
226
  private checkPublicInputs;
219
227
  /**
220
228
  * @notice Verify the proofs received from the mobile app.
@@ -224,17 +232,20 @@ export declare class ZKPassport {
224
232
  * @returns An object containing the unique identifier associated to the user
225
233
  * and a boolean indicating whether the proofs were successfully verified.
226
234
  */
227
- verify({ proofs, queryResult, validity, }: {
235
+ verify({ proofs, queryResult, validity, scope, devMode, }: {
228
236
  proofs: Array<ProofResult>;
229
237
  queryResult: QueryResult;
230
238
  validity?: number;
239
+ scope?: string;
240
+ devMode?: boolean;
231
241
  }): Promise<{
232
242
  uniqueIdentifier: string | undefined;
233
243
  verified: boolean;
234
244
  queryResultErrors?: QueryResultErrors;
235
245
  }>;
236
246
  getSolidityVerifierDetails(network: EVMChain): {
237
- address: string;
247
+ address: `0x${string}`;
248
+ functionName: string;
238
249
  abi: {
239
250
  type: "function" | "event" | "constructor";
240
251
  name: string;
@@ -250,7 +261,13 @@ export declare class ZKPassport {
250
261
  }[];
251
262
  }[];
252
263
  };
253
- getSolidityVerifierParameters(proof: ProofResult, validityPeriodInDays?: number): SolidityVerifierParameters;
264
+ getSolidityVerifierParameters({ proof, validityPeriodInDays, domain, scope, devMode, }: {
265
+ proof: ProofResult;
266
+ validityPeriodInDays?: number;
267
+ domain?: string;
268
+ scope?: string;
269
+ devMode?: boolean;
270
+ }): SolidityVerifierParameters;
254
271
  /**
255
272
  * @notice Returns the URL of the request.
256
273
  * @param requestId The request ID.
package/dist/cjs/index.js CHANGED
@@ -13,9 +13,10 @@ const logger_1 = require("./logger");
13
13
  const pako_1 = require("pako");
14
14
  const en_json_1 = tslib_1.__importDefault(require("i18n-iso-countries/langs/en.json"));
15
15
  const buffer_1 = require("buffer/");
16
- const sha256_1 = require("@noble/hashes/sha256");
16
+ const sha2_1 = require("@noble/hashes/sha2");
17
17
  const utils_3 = require("@noble/hashes/utils");
18
18
  const ZKPassportVerifier_json_1 = tslib_1.__importDefault(require("./assets/abi/ZKPassportVerifier.json"));
19
+ const registry_1 = require("@zkpassport/registry");
19
20
  const DEFAULT_DATE_VALUE = new Date(1111, 10, 11);
20
21
  // If Buffer is not defined, then we use the Buffer from the buffer package
21
22
  if (typeof globalThis.Buffer === "undefined") {
@@ -40,9 +41,12 @@ function hasRequestedAccessToField(credentialsRequest, field) {
40
41
  return false;
41
42
  }
42
43
  function normalizeCountry(country) {
44
+ if (country === "Zero Knowledge Republic") {
45
+ return "ZKR";
46
+ }
43
47
  let normalizedCountry;
44
48
  const alpha3 = (0, i18n_iso_countries_1.getAlpha3Code)(country, "en");
45
- normalizedCountry = alpha3 || country;
49
+ normalizedCountry = alpha3 || country || "ZKR";
46
50
  return normalizedCountry;
47
51
  }
48
52
  function numericalCompare(fnName, key, value, requestId, requestIdToConfig) {
@@ -105,6 +109,8 @@ class ZKPassport {
105
109
  proofs: this.topicToProofs[topic],
106
110
  queryResult: result,
107
111
  validity: this.topicToLocalConfig[topic]?.validity,
112
+ scope: this.topicToService[topic]?.scope,
113
+ devMode: this.topicToLocalConfig[topic]?.devMode,
108
114
  });
109
115
  delete this.topicToProofs[topic];
110
116
  const hasFailedProofs = this.topicToFailedProofCount[topic] > 0;
@@ -351,9 +357,10 @@ class ZKPassport {
351
357
  * @param purpose To explain what you want to do with the user's data
352
358
  * @param scope Scope this request to a specific use case
353
359
  * @param validity How many days ago should have the ID been last scanned by the user?
360
+ * @param devMode Whether to enable dev mode. This will allow you to verify mock proofs (i.e. from ZKR)
354
361
  * @returns The query builder object.
355
362
  */
356
- async request({ name, logo, purpose, scope, mode, validity, topicOverride, keyPairOverride, }) {
363
+ async request({ name, logo, purpose, scope, mode, validity, devMode, topicOverride, keyPairOverride, }) {
357
364
  const topic = topicOverride || (0, crypto_1.randomBytes)(16).toString("hex");
358
365
  const keyPair = keyPairOverride || (await (0, encryption_1.generateECDHKeyPair)());
359
366
  this.topicToKeyPair[topic] = {
@@ -368,6 +375,7 @@ class ZKPassport {
368
375
  // Default to 6 months
369
376
  validity: validity || 6 * 30,
370
377
  mode: mode || "fast",
378
+ devMode: devMode || false,
371
379
  };
372
380
  this.onRequestReceivedCallbacks[topic] = [];
373
381
  this.onGeneratingProofCallbacks[topic] = [];
@@ -1244,16 +1252,61 @@ class ZKPassport {
1244
1252
  }
1245
1253
  return { isCorrect, queryResultErrors };
1246
1254
  }
1247
- async checkPublicInputs(proofs, queryResult, validity) {
1255
+ checkScopeFromDisclosureProof(proofData, queryResultErrors, key, scope) {
1256
+ let isCorrect = true;
1257
+ if (this.domain && (0, utils_1.getScopeHash)(this.domain) !== BigInt(proofData.publicInputs[1])) {
1258
+ console.warn("The proof comes from a different domain than the one expected");
1259
+ isCorrect = false;
1260
+ queryResultErrors[key].scope = {
1261
+ expected: `Scope: ${(0, utils_1.getScopeHash)(this.domain).toString()}`,
1262
+ received: `Scope: ${BigInt(proofData.publicInputs[1]).toString()}`,
1263
+ message: "The proof comes from a different domain than the one expected",
1264
+ };
1265
+ }
1266
+ if (scope && (0, utils_1.getScopeHash)(scope) !== BigInt(proofData.publicInputs[2])) {
1267
+ console.warn("The proof uses a different scope than the one expected");
1268
+ isCorrect = false;
1269
+ queryResultErrors[key].scope = {
1270
+ expected: `Scope: ${(0, utils_1.getScopeHash)(scope).toString()}`,
1271
+ received: `Scope: ${BigInt(proofData.publicInputs[2]).toString()}`,
1272
+ message: "The proof uses a different scope than the one expected",
1273
+ };
1274
+ }
1275
+ return { isCorrect, queryResultErrors };
1276
+ }
1277
+ async checkCertificateRegistryRoot(root, queryResultErrors, outer) {
1278
+ let isCorrect = true;
1279
+ try {
1280
+ // Maintained certificate registry settled onchain
1281
+ // Here we use Ethereum Sepolia
1282
+ const registryClient = new registry_1.RegistryClient({ chainId: 11155111 });
1283
+ await registryClient.getCertificates(`0x${root}`);
1284
+ }
1285
+ catch (error) {
1286
+ console.warn(error);
1287
+ // Check the legacy static roots that were used before the registry was deployed onchain
1288
+ const VALID_CERTIFICATE_REGISTRY_ROOT = [
1289
+ BigInt("20192042006788880778219739574377003123593792072535937278552252195461520776494"),
1290
+ BigInt("21301853597069384763054217328384418971999152625381818922211526730996340553696"),
1291
+ BigInt("10839898448097753834842514286432152806152415606387598803678317315409344029817"),
1292
+ ];
1293
+ if (!VALID_CERTIFICATE_REGISTRY_ROOT.includes(BigInt(root))) {
1294
+ console.warn("The ID was signed by an unrecognized root certificate");
1295
+ isCorrect = false;
1296
+ queryResultErrors[outer ? "outer" : "sig_check_dsc"].certificate = {
1297
+ expected: `A valid root from ZKPassport Registry`,
1298
+ received: `Got invalid certificate registry root: ${root}`,
1299
+ message: "The ID was signed by an unrecognized root certificate",
1300
+ };
1301
+ }
1302
+ }
1303
+ return { isCorrect, queryResultErrors };
1304
+ }
1305
+ async checkPublicInputs(proofs, queryResult, validity, scope) {
1248
1306
  let commitmentIn;
1249
1307
  let commitmentOut;
1250
1308
  let isCorrect = true;
1251
1309
  let uniqueIdentifier;
1252
- const VALID_CERTIFICATE_REGISTRY_ROOT = [
1253
- BigInt("20192042006788880778219739574377003123593792072535937278552252195461520776494"),
1254
- BigInt("21301853597069384763054217328384418971999152625381818922211526730996340553696"),
1255
- BigInt("10839898448097753834842514286432152806152415606387598803678317315409344029817"),
1256
- ];
1257
1310
  const currentTime = new Date();
1258
1311
  const today = new Date(currentTime.getFullYear(), currentTime.getMonth(), currentTime.getDate(), 0, 0, 0, 0);
1259
1312
  let queryResultErrors = {
@@ -1301,15 +1354,12 @@ class ZKPassport {
1301
1354
  if (proof.name?.startsWith("outer")) {
1302
1355
  const isForEVM = proof.name?.startsWith("outer_evm");
1303
1356
  const certificateRegistryRoot = (0, utils_1.getCertificateRegistryRootFromOuterProof)(proofData);
1304
- if (!VALID_CERTIFICATE_REGISTRY_ROOT.includes(certificateRegistryRoot)) {
1305
- console.warn("The ID was signed by an unrecognized root certificate");
1306
- isCorrect = false;
1307
- queryResultErrors.outer.certificate = {
1308
- expected: `Certificate registry root: ${VALID_CERTIFICATE_REGISTRY_ROOT.join(", ")}`,
1309
- received: `Certificate registry root: ${certificateRegistryRoot.toString()}`,
1310
- message: "The ID was signed by an unrecognized root certificate",
1311
- };
1312
- }
1357
+ const { isCorrect: isCorrectCertificateRegistryRoot, queryResultErrors: queryResultErrorsCertificateRegistryRoot, } = await this.checkCertificateRegistryRoot(certificateRegistryRoot.toString(16), queryResultErrors, true);
1358
+ isCorrect = isCorrect && isCorrectCertificateRegistryRoot;
1359
+ queryResultErrors = {
1360
+ ...queryResultErrors,
1361
+ ...queryResultErrorsCertificateRegistryRoot,
1362
+ };
1313
1363
  const currentDate = (0, utils_1.getCurrentDateFromOuterProof)(proofData);
1314
1364
  const todayToCurrentDate = today.getTime() - currentDate.getTime();
1315
1365
  const differenceInDays = validity ?? 180;
@@ -1337,6 +1387,24 @@ class ZKPassport {
1337
1387
  message: "The proof does not verify all the requested conditions and information",
1338
1388
  };
1339
1389
  }
1390
+ if (this.domain && (0, utils_1.getScopeHash)(this.domain) !== (0, utils_1.getScopeFromOuterProof)(proofData)) {
1391
+ console.warn("The proof comes from a different domain than the one expected");
1392
+ isCorrect = false;
1393
+ queryResultErrors.outer.scope = {
1394
+ expected: `Scope: ${(0, utils_1.getScopeHash)(this.domain).toString()}`,
1395
+ received: `Scope: ${(0, utils_1.getScopeFromOuterProof)(proofData).toString()}`,
1396
+ message: "The proof comes from a different domain than the one expected",
1397
+ };
1398
+ }
1399
+ if (scope && (0, utils_1.getScopeHash)(scope) !== (0, utils_1.getSubscopeFromOuterProof)(proofData)) {
1400
+ console.warn("The proof uses a different scope than the one expected");
1401
+ isCorrect = false;
1402
+ queryResultErrors.outer.scope = {
1403
+ expected: `Scope: ${(0, utils_1.getScopeHash)(scope).toString()}`,
1404
+ received: `Scope: ${(0, utils_1.getSubscopeFromOuterProof)(proofData).toString()}`,
1405
+ message: "The proof uses a different scope than the one expected",
1406
+ };
1407
+ }
1340
1408
  if (!!committedInputs?.compare_age) {
1341
1409
  const ageCommittedInputs = committedInputs?.compare_age;
1342
1410
  const ageParameterCommitment = isForEVM
@@ -1514,15 +1582,12 @@ class ZKPassport {
1514
1582
  else if (proof.name?.startsWith("sig_check_dsc")) {
1515
1583
  commitmentOut = (0, utils_1.getCommitmentFromDSCProof)(proofData);
1516
1584
  const merkleRoot = (0, utils_1.getMerkleRootFromDSCProof)(proofData);
1517
- if (!VALID_CERTIFICATE_REGISTRY_ROOT.includes(merkleRoot)) {
1518
- console.warn("The ID was signed by an unrecognized root certificate");
1519
- isCorrect = false;
1520
- queryResultErrors.sig_check_dsc.certificate = {
1521
- expected: `Certificate registry root: ${VALID_CERTIFICATE_REGISTRY_ROOT.join(", ")}`,
1522
- received: `Certificate registry root: ${merkleRoot.toString()}`,
1523
- message: "The ID was signed by an unrecognized root certificate",
1524
- };
1525
- }
1585
+ const { isCorrect: isCorrectCertificateRegistryRoot, queryResultErrors: queryResultErrorsCertificateRegistryRoot, } = await this.checkCertificateRegistryRoot(merkleRoot.toString(16), queryResultErrors, false);
1586
+ isCorrect = isCorrect && isCorrectCertificateRegistryRoot;
1587
+ queryResultErrors = {
1588
+ ...queryResultErrors,
1589
+ ...queryResultErrorsCertificateRegistryRoot,
1590
+ };
1526
1591
  }
1527
1592
  else if (proof.name?.startsWith("sig_check_id_data")) {
1528
1593
  commitmentIn = (0, utils_1.getCommitmentInFromIDDataProof)(proofData);
@@ -1587,11 +1652,18 @@ class ZKPassport {
1587
1652
  message: "The disclosed data does not match the data committed by the proof",
1588
1653
  };
1589
1654
  }
1655
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "disclose", scope);
1656
+ isCorrect = isCorrect && isCorrectScope;
1657
+ queryResultErrors = {
1658
+ ...queryResultErrors,
1659
+ ...queryResultErrorsScope,
1660
+ };
1590
1661
  const { isCorrect: isCorrectDisclose, queryResultErrors: queryResultErrorsDisclose } = this.checkDiscloseBytesPublicInputs(proof, queryResult);
1591
- isCorrect = isCorrect && isCorrectDisclose;
1662
+ isCorrect = isCorrect && isCorrectDisclose && isCorrectScope;
1592
1663
  queryResultErrors = {
1593
1664
  ...queryResultErrors,
1594
1665
  ...queryResultErrorsDisclose,
1666
+ ...queryResultErrorsScope,
1595
1667
  };
1596
1668
  uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
1597
1669
  }
@@ -1618,11 +1690,13 @@ class ZKPassport {
1618
1690
  message: "The conditions for the age check do not match the conditions checked by the proof",
1619
1691
  };
1620
1692
  }
1693
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "age", scope);
1621
1694
  const { isCorrect: isCorrectAge, queryResultErrors: queryResultErrorsAge } = this.checkAgePublicInputs(proof, queryResult);
1622
- isCorrect = isCorrect && isCorrectAge;
1695
+ isCorrect = isCorrect && isCorrectAge && isCorrectScope;
1623
1696
  queryResultErrors = {
1624
1697
  ...queryResultErrors,
1625
1698
  ...queryResultErrorsAge,
1699
+ ...queryResultErrorsScope,
1626
1700
  };
1627
1701
  uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
1628
1702
  }
@@ -1649,11 +1723,13 @@ class ZKPassport {
1649
1723
  message: "The conditions for the birthdate check do not match the conditions checked by the proof",
1650
1724
  };
1651
1725
  }
1726
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "birthdate", scope);
1652
1727
  const { isCorrect: isCorrectBirthdate, queryResultErrors: queryResultErrorsBirthdate } = this.checkBirthdatePublicInputs(proof, queryResult);
1653
- isCorrect = isCorrect && isCorrectBirthdate;
1728
+ isCorrect = isCorrect && isCorrectBirthdate && isCorrectScope;
1654
1729
  queryResultErrors = {
1655
1730
  ...queryResultErrors,
1656
1731
  ...queryResultErrorsBirthdate,
1732
+ ...queryResultErrorsScope,
1657
1733
  };
1658
1734
  uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
1659
1735
  }
@@ -1680,11 +1756,13 @@ class ZKPassport {
1680
1756
  message: "The conditions for the expiry date check do not match the conditions checked by the proof",
1681
1757
  };
1682
1758
  }
1759
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "expiry_date", scope);
1683
1760
  const { isCorrect: isCorrectExpiryDate, queryResultErrors: queryResultErrorsExpiryDate } = this.checkExpiryDatePublicInputs(proof, queryResult);
1684
- isCorrect = isCorrect && isCorrectExpiryDate;
1761
+ isCorrect = isCorrect && isCorrectExpiryDate && isCorrectScope;
1685
1762
  queryResultErrors = {
1686
1763
  ...queryResultErrors,
1687
1764
  ...queryResultErrorsExpiryDate,
1765
+ ...queryResultErrorsScope,
1688
1766
  };
1689
1767
  uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
1690
1768
  }
@@ -1711,11 +1789,13 @@ class ZKPassport {
1711
1789
  message: "The committed country list for the exclusion check does not match the one from the proof",
1712
1790
  };
1713
1791
  }
1792
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "nationality", scope);
1714
1793
  const { isCorrect: isCorrectNationalityExclusion, queryResultErrors: queryResultErrorsNationalityExclusion, } = this.checkNationalityExclusionPublicInputs(queryResult, countryList);
1715
- isCorrect = isCorrect && isCorrectNationalityExclusion;
1794
+ isCorrect = isCorrect && isCorrectNationalityExclusion && isCorrectScope;
1716
1795
  queryResultErrors = {
1717
1796
  ...queryResultErrors,
1718
1797
  ...queryResultErrorsNationalityExclusion,
1798
+ ...queryResultErrorsScope,
1719
1799
  };
1720
1800
  uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
1721
1801
  }
@@ -1742,11 +1822,13 @@ class ZKPassport {
1742
1822
  message: "The committed country list for the issuing country exclusion check does not match the one from the proof",
1743
1823
  };
1744
1824
  }
1825
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "nationality", scope);
1745
1826
  const { isCorrect: isCorrectIssuingCountryExclusion, queryResultErrors: queryResultErrorsIssuingCountryExclusion, } = this.checkIssuingCountryExclusionPublicInputs(queryResult, countryList);
1746
- isCorrect = isCorrect && isCorrectIssuingCountryExclusion;
1827
+ isCorrect = isCorrect && isCorrectIssuingCountryExclusion && isCorrectScope;
1747
1828
  queryResultErrors = {
1748
1829
  ...queryResultErrors,
1749
1830
  ...queryResultErrorsIssuingCountryExclusion,
1831
+ ...queryResultErrorsScope,
1750
1832
  };
1751
1833
  uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
1752
1834
  }
@@ -1773,11 +1855,13 @@ class ZKPassport {
1773
1855
  message: "The committed country list for the nationality inclusion check does not match the one from the proof",
1774
1856
  };
1775
1857
  }
1858
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "nationality", scope);
1776
1859
  const { isCorrect: isCorrectNationalityInclusion, queryResultErrors: queryResultErrorsNationalityInclusion, } = this.checkNationalityInclusionPublicInputs(queryResult, countryList);
1777
- isCorrect = isCorrect && isCorrectNationalityInclusion;
1860
+ isCorrect = isCorrect && isCorrectNationalityInclusion && isCorrectScope;
1778
1861
  queryResultErrors = {
1779
1862
  ...queryResultErrors,
1780
1863
  ...queryResultErrorsNationalityInclusion,
1864
+ ...queryResultErrorsScope,
1781
1865
  };
1782
1866
  uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
1783
1867
  }
@@ -1804,11 +1888,13 @@ class ZKPassport {
1804
1888
  message: "The committed country list for the issuing country inclusion check does not match the one from the proof",
1805
1889
  };
1806
1890
  }
1891
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "nationality", scope);
1807
1892
  const { isCorrect: isCorrectIssuingCountryInclusion, queryResultErrors: queryResultErrorsIssuingCountryInclusion, } = this.checkIssuingCountryInclusionPublicInputs(queryResult, countryList);
1808
- isCorrect = isCorrect && isCorrectIssuingCountryInclusion;
1893
+ isCorrect = isCorrect && isCorrectIssuingCountryInclusion && isCorrectScope;
1809
1894
  queryResultErrors = {
1810
1895
  ...queryResultErrors,
1811
1896
  ...queryResultErrorsIssuingCountryInclusion,
1897
+ ...queryResultErrorsScope,
1812
1898
  };
1813
1899
  uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
1814
1900
  }
@@ -1823,7 +1909,7 @@ class ZKPassport {
1823
1909
  * @returns An object containing the unique identifier associated to the user
1824
1910
  * and a boolean indicating whether the proofs were successfully verified.
1825
1911
  */
1826
- async verify({ proofs, queryResult, validity, }) {
1912
+ async verify({ proofs, queryResult, validity, scope, devMode = false, }) {
1827
1913
  const formattedResult = queryResult;
1828
1914
  // Make sure to reconvert the dates to Date objects
1829
1915
  if (formattedResult.birthdate && formattedResult.birthdate.disclose) {
@@ -1837,10 +1923,17 @@ class ZKPassport {
1837
1923
  let verified = true;
1838
1924
  let uniqueIdentifier;
1839
1925
  let queryResultErrors;
1840
- const { isCorrect, uniqueIdentifier: uniqueIdentifierFromPublicInputs, queryResultErrors: queryResultErrorsFromPublicInputs, } = await this.checkPublicInputs(proofs, formattedResult, validity);
1926
+ const { isCorrect, uniqueIdentifier: uniqueIdentifierFromPublicInputs, queryResultErrors: queryResultErrorsFromPublicInputs, } = await this.checkPublicInputs(proofs, formattedResult, validity, scope);
1841
1927
  uniqueIdentifier = uniqueIdentifierFromPublicInputs;
1842
1928
  verified = isCorrect;
1843
1929
  queryResultErrors = isCorrect ? undefined : queryResultErrorsFromPublicInputs;
1930
+ if (uniqueIdentifier && BigInt(uniqueIdentifier) === BigInt(0) && !devMode) {
1931
+ // If the unique identifier is 0 and it is not in dev mode,
1932
+ // the proofs are considered invalid as these are mock proofs only meant
1933
+ // for testing purposes
1934
+ verified = false;
1935
+ console.warn("You are trying to verify a mock proof. This is only allowed in dev mode. To enable dev mode, set the `devMode` parameter to `true` in the request function parameters.");
1936
+ }
1844
1937
  // Only proceed with the proof verification if the public inputs are correct
1845
1938
  if (verified) {
1846
1939
  for (const proof of proofs) {
@@ -1850,24 +1943,23 @@ class ZKPassport {
1850
1943
  try {
1851
1944
  const { createPublicClient, http } = await Promise.resolve().then(() => tslib_1.__importStar(require("viem")));
1852
1945
  const { sepolia } = await Promise.resolve().then(() => tslib_1.__importStar(require("viem/chains")));
1853
- const verifierDetails = this.getSolidityVerifierDetails("ethereum_sepolia");
1946
+ const { address, abi, functionName } = this.getSolidityVerifierDetails("ethereum_sepolia");
1854
1947
  const client = createPublicClient({
1855
1948
  chain: sepolia,
1856
1949
  transport: http("https://ethereum-sepolia-rpc.publicnode.com"),
1857
1950
  });
1858
- const params = this.getSolidityVerifierParameters(proof);
1951
+ const params = this.getSolidityVerifierParameters({
1952
+ proof,
1953
+ validityPeriodInDays: validity,
1954
+ domain: this.domain,
1955
+ scope,
1956
+ devMode,
1957
+ });
1859
1958
  const result = await client.readContract({
1860
- address: verifierDetails.address,
1861
- abi: verifierDetails.abi,
1862
- functionName: "verifyProof",
1863
- args: [
1864
- params.vkeyHash,
1865
- params.proof,
1866
- params.publicInputs,
1867
- params.committedInputs,
1868
- params.committedInputCounts,
1869
- params.validityPeriodInDays,
1870
- ],
1959
+ address,
1960
+ abi,
1961
+ functionName,
1962
+ args: [params],
1871
1963
  });
1872
1964
  const isVerified = Array.isArray(result) ? Boolean(result[0]) : false;
1873
1965
  verified = isVerified;
@@ -1902,21 +1994,25 @@ class ZKPassport {
1902
1994
  return { uniqueIdentifier, verified, queryResultErrors };
1903
1995
  }
1904
1996
  getSolidityVerifierDetails(network) {
1997
+ const baseConfig = {
1998
+ functionName: "verifyProof",
1999
+ abi: ZKPassportVerifier_json_1.default.abi,
2000
+ };
1905
2001
  if (network === "ethereum_sepolia") {
1906
2002
  return {
1907
- address: "0xca644D3424c2ee577FaaF2b56C0f9D1937E8e87C",
1908
- abi: ZKPassportVerifier_json_1.default.abi,
2003
+ ...baseConfig,
2004
+ address: "0x8c6982D77f7a8f60aE3133cA9b2FAA6f3e78c394",
1909
2005
  };
1910
2006
  }
1911
2007
  else if (network === "local_anvil") {
1912
2008
  return {
2009
+ ...baseConfig,
1913
2010
  address: "0x0",
1914
- abi: ZKPassportVerifier_json_1.default.abi,
1915
2011
  };
1916
2012
  }
1917
2013
  throw new Error(`Unsupported network: ${network}`);
1918
2014
  }
1919
- getSolidityVerifierParameters(proof, validityPeriodInDays = 7) {
2015
+ getSolidityVerifierParameters({ proof, validityPeriodInDays = 7, domain, scope, devMode = false, }) {
1920
2016
  if (!proof.name?.startsWith("outer_evm")) {
1921
2017
  throw new Error("This proof cannot be verified on an EVM chain. Please make sure to use the `compressed-evm` mode.");
1922
2018
  }
@@ -2008,7 +2104,7 @@ class ZKPassport {
2008
2104
  let committedInputCountsArray = [];
2009
2105
  for (const commitment of parameterCommitments) {
2010
2106
  const committedInput = committedInputs.find((x) => {
2011
- const rawHashedInputs = (0, sha256_1.sha256)((0, utils_3.hexToBytes)(x.inputs));
2107
+ const rawHashedInputs = (0, sha2_1.sha256)((0, utils_3.hexToBytes)(x.inputs));
2012
2108
  // Shift the hash 8 bits to the right (1 byte)
2013
2109
  // as one byte is dropped in the circuit to fit in the 254-bit field size
2014
2110
  const hashedInputs = new Uint8Array(rawHashedInputs.length);
@@ -2042,6 +2138,9 @@ class ZKPassport {
2042
2138
  committedInputs: `0x${compressedCommittedInputs}`,
2043
2139
  committedInputCounts: committedInputCountsArray,
2044
2140
  validityPeriodInDays,
2141
+ scope: domain ?? this.domain,
2142
+ subscope: scope ?? "",
2143
+ devMode,
2045
2144
  };
2046
2145
  return params;
2047
2146
  }