@zkpassport/sdk 0.3.0 → 0.3.1

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,8 @@ export type SolidityVerifierParameters = {
26
27
  committedInputs: string;
27
28
  committedInputCounts: number[];
28
29
  validityPeriodInDays: number;
30
+ scope: string;
31
+ subscope: string;
29
32
  };
30
33
  export type EVMChain = "ethereum_sepolia" | "local_anvil";
31
34
  export type * from "@zkpassport/utils";
@@ -215,6 +218,7 @@ export declare class ZKPassport {
215
218
  private checkIssuingCountryExclusionPublicInputs;
216
219
  private checkNationalityInclusionPublicInputs;
217
220
  private checkIssuingCountryInclusionPublicInputs;
221
+ private checkScopeFromDisclosureProof;
218
222
  private checkPublicInputs;
219
223
  /**
220
224
  * @notice Verify the proofs received from the mobile app.
@@ -224,17 +228,19 @@ export declare class ZKPassport {
224
228
  * @returns An object containing the unique identifier associated to the user
225
229
  * and a boolean indicating whether the proofs were successfully verified.
226
230
  */
227
- verify({ proofs, queryResult, validity, }: {
231
+ verify({ proofs, queryResult, validity, scope, }: {
228
232
  proofs: Array<ProofResult>;
229
233
  queryResult: QueryResult;
230
234
  validity?: number;
235
+ scope?: string;
231
236
  }): Promise<{
232
237
  uniqueIdentifier: string | undefined;
233
238
  verified: boolean;
234
239
  queryResultErrors?: QueryResultErrors;
235
240
  }>;
236
241
  getSolidityVerifierDetails(network: EVMChain): {
237
- address: string;
242
+ address: `0x${string}`;
243
+ functionName: string;
238
244
  abi: {
239
245
  type: "function" | "event" | "constructor";
240
246
  name: string;
@@ -250,7 +256,12 @@ export declare class ZKPassport {
250
256
  }[];
251
257
  }[];
252
258
  };
253
- getSolidityVerifierParameters(proof: ProofResult, validityPeriodInDays?: number): SolidityVerifierParameters;
259
+ getSolidityVerifierParameters({ proof, validityPeriodInDays, domain, scope, }: {
260
+ proof: ProofResult;
261
+ validityPeriodInDays?: number;
262
+ domain?: string;
263
+ scope?: string;
264
+ }): SolidityVerifierParameters;
254
265
  /**
255
266
  * @notice Returns the URL of the request.
256
267
  * @param requestId The request ID.
package/dist/cjs/index.js CHANGED
@@ -105,6 +105,7 @@ class ZKPassport {
105
105
  proofs: this.topicToProofs[topic],
106
106
  queryResult: result,
107
107
  validity: this.topicToLocalConfig[topic]?.validity,
108
+ scope: this.topicToService[topic]?.scope,
108
109
  });
109
110
  delete this.topicToProofs[topic];
110
111
  const hasFailedProofs = this.topicToFailedProofCount[topic] > 0;
@@ -1244,7 +1245,29 @@ class ZKPassport {
1244
1245
  }
1245
1246
  return { isCorrect, queryResultErrors };
1246
1247
  }
1247
- async checkPublicInputs(proofs, queryResult, validity) {
1248
+ checkScopeFromDisclosureProof(proofData, queryResultErrors, key, scope) {
1249
+ let isCorrect = true;
1250
+ if (this.domain && (0, utils_1.getScopeHash)(this.domain) !== BigInt(proofData.publicInputs[1])) {
1251
+ console.warn("The proof comes from a different domain than the one expected");
1252
+ isCorrect = false;
1253
+ queryResultErrors[key].scope = {
1254
+ expected: `Scope: ${(0, utils_1.getScopeHash)(this.domain).toString()}`,
1255
+ received: `Scope: ${BigInt(proofData.publicInputs[1]).toString()}`,
1256
+ message: "The proof comes from a different domain than the one expected",
1257
+ };
1258
+ }
1259
+ if (scope && (0, utils_1.getScopeHash)(scope) !== BigInt(proofData.publicInputs[2])) {
1260
+ console.warn("The proof uses a different scope than the one expected");
1261
+ isCorrect = false;
1262
+ queryResultErrors[key].scope = {
1263
+ expected: `Scope: ${(0, utils_1.getScopeHash)(scope).toString()}`,
1264
+ received: `Scope: ${BigInt(proofData.publicInputs[2]).toString()}`,
1265
+ message: "The proof uses a different scope than the one expected",
1266
+ };
1267
+ }
1268
+ return { isCorrect, queryResultErrors };
1269
+ }
1270
+ async checkPublicInputs(proofs, queryResult, validity, scope) {
1248
1271
  let commitmentIn;
1249
1272
  let commitmentOut;
1250
1273
  let isCorrect = true;
@@ -1337,6 +1360,24 @@ class ZKPassport {
1337
1360
  message: "The proof does not verify all the requested conditions and information",
1338
1361
  };
1339
1362
  }
1363
+ if (this.domain && (0, utils_1.getScopeHash)(this.domain) !== (0, utils_1.getScopeFromOuterProof)(proofData)) {
1364
+ console.warn("The proof comes from a different domain than the one expected");
1365
+ isCorrect = false;
1366
+ queryResultErrors.outer.scope = {
1367
+ expected: `Scope: ${(0, utils_1.getScopeHash)(this.domain).toString()}`,
1368
+ received: `Scope: ${(0, utils_1.getScopeFromOuterProof)(proofData).toString()}`,
1369
+ message: "The proof comes from a different domain than the one expected",
1370
+ };
1371
+ }
1372
+ if (scope && (0, utils_1.getScopeHash)(scope) !== (0, utils_1.getSubscopeFromOuterProof)(proofData)) {
1373
+ console.warn("The proof uses a different scope than the one expected");
1374
+ isCorrect = false;
1375
+ queryResultErrors.outer.scope = {
1376
+ expected: `Scope: ${(0, utils_1.getScopeHash)(scope).toString()}`,
1377
+ received: `Scope: ${(0, utils_1.getSubscopeFromOuterProof)(proofData).toString()}`,
1378
+ message: "The proof uses a different scope than the one expected",
1379
+ };
1380
+ }
1340
1381
  if (!!committedInputs?.compare_age) {
1341
1382
  const ageCommittedInputs = committedInputs?.compare_age;
1342
1383
  const ageParameterCommitment = isForEVM
@@ -1587,11 +1628,18 @@ class ZKPassport {
1587
1628
  message: "The disclosed data does not match the data committed by the proof",
1588
1629
  };
1589
1630
  }
1631
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "disclose", scope);
1632
+ isCorrect = isCorrect && isCorrectScope;
1633
+ queryResultErrors = {
1634
+ ...queryResultErrors,
1635
+ ...queryResultErrorsScope,
1636
+ };
1590
1637
  const { isCorrect: isCorrectDisclose, queryResultErrors: queryResultErrorsDisclose } = this.checkDiscloseBytesPublicInputs(proof, queryResult);
1591
- isCorrect = isCorrect && isCorrectDisclose;
1638
+ isCorrect = isCorrect && isCorrectDisclose && isCorrectScope;
1592
1639
  queryResultErrors = {
1593
1640
  ...queryResultErrors,
1594
1641
  ...queryResultErrorsDisclose,
1642
+ ...queryResultErrorsScope,
1595
1643
  };
1596
1644
  uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
1597
1645
  }
@@ -1618,11 +1666,13 @@ class ZKPassport {
1618
1666
  message: "The conditions for the age check do not match the conditions checked by the proof",
1619
1667
  };
1620
1668
  }
1669
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "age", scope);
1621
1670
  const { isCorrect: isCorrectAge, queryResultErrors: queryResultErrorsAge } = this.checkAgePublicInputs(proof, queryResult);
1622
- isCorrect = isCorrect && isCorrectAge;
1671
+ isCorrect = isCorrect && isCorrectAge && isCorrectScope;
1623
1672
  queryResultErrors = {
1624
1673
  ...queryResultErrors,
1625
1674
  ...queryResultErrorsAge,
1675
+ ...queryResultErrorsScope,
1626
1676
  };
1627
1677
  uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
1628
1678
  }
@@ -1649,11 +1699,13 @@ class ZKPassport {
1649
1699
  message: "The conditions for the birthdate check do not match the conditions checked by the proof",
1650
1700
  };
1651
1701
  }
1702
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "birthdate", scope);
1652
1703
  const { isCorrect: isCorrectBirthdate, queryResultErrors: queryResultErrorsBirthdate } = this.checkBirthdatePublicInputs(proof, queryResult);
1653
- isCorrect = isCorrect && isCorrectBirthdate;
1704
+ isCorrect = isCorrect && isCorrectBirthdate && isCorrectScope;
1654
1705
  queryResultErrors = {
1655
1706
  ...queryResultErrors,
1656
1707
  ...queryResultErrorsBirthdate,
1708
+ ...queryResultErrorsScope,
1657
1709
  };
1658
1710
  uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
1659
1711
  }
@@ -1680,11 +1732,13 @@ class ZKPassport {
1680
1732
  message: "The conditions for the expiry date check do not match the conditions checked by the proof",
1681
1733
  };
1682
1734
  }
1735
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "expiry_date", scope);
1683
1736
  const { isCorrect: isCorrectExpiryDate, queryResultErrors: queryResultErrorsExpiryDate } = this.checkExpiryDatePublicInputs(proof, queryResult);
1684
- isCorrect = isCorrect && isCorrectExpiryDate;
1737
+ isCorrect = isCorrect && isCorrectExpiryDate && isCorrectScope;
1685
1738
  queryResultErrors = {
1686
1739
  ...queryResultErrors,
1687
1740
  ...queryResultErrorsExpiryDate,
1741
+ ...queryResultErrorsScope,
1688
1742
  };
1689
1743
  uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
1690
1744
  }
@@ -1711,11 +1765,13 @@ class ZKPassport {
1711
1765
  message: "The committed country list for the exclusion check does not match the one from the proof",
1712
1766
  };
1713
1767
  }
1768
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "nationality", scope);
1714
1769
  const { isCorrect: isCorrectNationalityExclusion, queryResultErrors: queryResultErrorsNationalityExclusion, } = this.checkNationalityExclusionPublicInputs(queryResult, countryList);
1715
- isCorrect = isCorrect && isCorrectNationalityExclusion;
1770
+ isCorrect = isCorrect && isCorrectNationalityExclusion && isCorrectScope;
1716
1771
  queryResultErrors = {
1717
1772
  ...queryResultErrors,
1718
1773
  ...queryResultErrorsNationalityExclusion,
1774
+ ...queryResultErrorsScope,
1719
1775
  };
1720
1776
  uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
1721
1777
  }
@@ -1742,11 +1798,13 @@ class ZKPassport {
1742
1798
  message: "The committed country list for the issuing country exclusion check does not match the one from the proof",
1743
1799
  };
1744
1800
  }
1801
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "nationality", scope);
1745
1802
  const { isCorrect: isCorrectIssuingCountryExclusion, queryResultErrors: queryResultErrorsIssuingCountryExclusion, } = this.checkIssuingCountryExclusionPublicInputs(queryResult, countryList);
1746
- isCorrect = isCorrect && isCorrectIssuingCountryExclusion;
1803
+ isCorrect = isCorrect && isCorrectIssuingCountryExclusion && isCorrectScope;
1747
1804
  queryResultErrors = {
1748
1805
  ...queryResultErrors,
1749
1806
  ...queryResultErrorsIssuingCountryExclusion,
1807
+ ...queryResultErrorsScope,
1750
1808
  };
1751
1809
  uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
1752
1810
  }
@@ -1773,11 +1831,13 @@ class ZKPassport {
1773
1831
  message: "The committed country list for the nationality inclusion check does not match the one from the proof",
1774
1832
  };
1775
1833
  }
1834
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "nationality", scope);
1776
1835
  const { isCorrect: isCorrectNationalityInclusion, queryResultErrors: queryResultErrorsNationalityInclusion, } = this.checkNationalityInclusionPublicInputs(queryResult, countryList);
1777
- isCorrect = isCorrect && isCorrectNationalityInclusion;
1836
+ isCorrect = isCorrect && isCorrectNationalityInclusion && isCorrectScope;
1778
1837
  queryResultErrors = {
1779
1838
  ...queryResultErrors,
1780
1839
  ...queryResultErrorsNationalityInclusion,
1840
+ ...queryResultErrorsScope,
1781
1841
  };
1782
1842
  uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
1783
1843
  }
@@ -1804,11 +1864,13 @@ class ZKPassport {
1804
1864
  message: "The committed country list for the issuing country inclusion check does not match the one from the proof",
1805
1865
  };
1806
1866
  }
1867
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "nationality", scope);
1807
1868
  const { isCorrect: isCorrectIssuingCountryInclusion, queryResultErrors: queryResultErrorsIssuingCountryInclusion, } = this.checkIssuingCountryInclusionPublicInputs(queryResult, countryList);
1808
- isCorrect = isCorrect && isCorrectIssuingCountryInclusion;
1869
+ isCorrect = isCorrect && isCorrectIssuingCountryInclusion && isCorrectScope;
1809
1870
  queryResultErrors = {
1810
1871
  ...queryResultErrors,
1811
1872
  ...queryResultErrorsIssuingCountryInclusion,
1873
+ ...queryResultErrorsScope,
1812
1874
  };
1813
1875
  uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
1814
1876
  }
@@ -1823,7 +1885,7 @@ class ZKPassport {
1823
1885
  * @returns An object containing the unique identifier associated to the user
1824
1886
  * and a boolean indicating whether the proofs were successfully verified.
1825
1887
  */
1826
- async verify({ proofs, queryResult, validity, }) {
1888
+ async verify({ proofs, queryResult, validity, scope, }) {
1827
1889
  const formattedResult = queryResult;
1828
1890
  // Make sure to reconvert the dates to Date objects
1829
1891
  if (formattedResult.birthdate && formattedResult.birthdate.disclose) {
@@ -1837,7 +1899,7 @@ class ZKPassport {
1837
1899
  let verified = true;
1838
1900
  let uniqueIdentifier;
1839
1901
  let queryResultErrors;
1840
- const { isCorrect, uniqueIdentifier: uniqueIdentifierFromPublicInputs, queryResultErrors: queryResultErrorsFromPublicInputs, } = await this.checkPublicInputs(proofs, formattedResult, validity);
1902
+ const { isCorrect, uniqueIdentifier: uniqueIdentifierFromPublicInputs, queryResultErrors: queryResultErrorsFromPublicInputs, } = await this.checkPublicInputs(proofs, formattedResult, validity, scope);
1841
1903
  uniqueIdentifier = uniqueIdentifierFromPublicInputs;
1842
1904
  verified = isCorrect;
1843
1905
  queryResultErrors = isCorrect ? undefined : queryResultErrorsFromPublicInputs;
@@ -1850,24 +1912,22 @@ class ZKPassport {
1850
1912
  try {
1851
1913
  const { createPublicClient, http } = await Promise.resolve().then(() => tslib_1.__importStar(require("viem")));
1852
1914
  const { sepolia } = await Promise.resolve().then(() => tslib_1.__importStar(require("viem/chains")));
1853
- const verifierDetails = this.getSolidityVerifierDetails("ethereum_sepolia");
1915
+ const { address, abi, functionName } = this.getSolidityVerifierDetails("ethereum_sepolia");
1854
1916
  const client = createPublicClient({
1855
1917
  chain: sepolia,
1856
1918
  transport: http("https://ethereum-sepolia-rpc.publicnode.com"),
1857
1919
  });
1858
- const params = this.getSolidityVerifierParameters(proof);
1920
+ const params = this.getSolidityVerifierParameters({
1921
+ proof,
1922
+ validityPeriodInDays: validity,
1923
+ domain: this.domain,
1924
+ scope,
1925
+ });
1859
1926
  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
- ],
1927
+ address,
1928
+ abi,
1929
+ functionName,
1930
+ args: [params],
1871
1931
  });
1872
1932
  const isVerified = Array.isArray(result) ? Boolean(result[0]) : false;
1873
1933
  verified = isVerified;
@@ -1902,21 +1962,25 @@ class ZKPassport {
1902
1962
  return { uniqueIdentifier, verified, queryResultErrors };
1903
1963
  }
1904
1964
  getSolidityVerifierDetails(network) {
1965
+ const baseConfig = {
1966
+ functionName: "verifyProof",
1967
+ abi: ZKPassportVerifier_json_1.default.abi,
1968
+ };
1905
1969
  if (network === "ethereum_sepolia") {
1906
1970
  return {
1907
- address: "0xca644D3424c2ee577FaaF2b56C0f9D1937E8e87C",
1908
- abi: ZKPassportVerifier_json_1.default.abi,
1971
+ ...baseConfig,
1972
+ address: "0x21E12Fa30a1F98699F242ac062Db4a8e7b344B5d",
1909
1973
  };
1910
1974
  }
1911
1975
  else if (network === "local_anvil") {
1912
1976
  return {
1913
- address: "0x0",
1914
- abi: ZKPassportVerifier_json_1.default.abi,
1977
+ ...baseConfig,
1978
+ address: "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6",
1915
1979
  };
1916
1980
  }
1917
1981
  throw new Error(`Unsupported network: ${network}`);
1918
1982
  }
1919
- getSolidityVerifierParameters(proof, validityPeriodInDays = 7) {
1983
+ getSolidityVerifierParameters({ proof, validityPeriodInDays = 7, domain, scope, }) {
1920
1984
  if (!proof.name?.startsWith("outer_evm")) {
1921
1985
  throw new Error("This proof cannot be verified on an EVM chain. Please make sure to use the `compressed-evm` mode.");
1922
1986
  }
@@ -2042,6 +2106,8 @@ class ZKPassport {
2042
2106
  committedInputs: `0x${compressedCommittedInputs}`,
2043
2107
  committedInputCounts: committedInputCountsArray,
2044
2108
  validityPeriodInDays,
2109
+ scope: domain ?? this.domain,
2110
+ subscope: scope ?? "",
2045
2111
  };
2046
2112
  return params;
2047
2113
  }