@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/esm/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { randomBytes } from "crypto";
2
2
  import { getAlpha3Code, registerLocale } from "i18n-iso-countries";
3
- import { getProofData, getCommitmentFromDSCProof, getCommitmentInFromIDDataProof, getCommitmentOutFromIDDataProof, getNullifierFromDisclosureProof, getCommitmentInFromIntegrityProof, getCommitmentOutFromIntegrityProof, getCommitmentInFromDisclosureProof, getMerkleRootFromDSCProof, getCurrentDateFromIntegrityProof, DisclosedData, formatName, getHostedPackagedCircuitByName, getNumberOfPublicInputs, getParameterCommitmentFromDisclosureProof, getCountryParameterCommitment, getDiscloseParameterCommitment, getDateParameterCommitment, getCertificateRegistryRootFromOuterProof, getParamCommitmentsFromOuterProof, getCurrentDateFromCommittedInputs, getMinAgeFromCommittedInputs, getMaxAgeFromCommittedInputs, getAgeParameterCommitment, getMinDateFromCommittedInputs, getMaxDateFromCommittedInputs, getCurrentDateFromOuterProof, getNullifierFromOuterProof, getAgeEVMParameterCommitment, getDateEVMParameterCommitment, getDiscloseEVMParameterCommitment, getCountryEVMParameterCommitment, rightPadArrayWithZeros, getCommittedInputCount, ProofType, } from "@zkpassport/utils";
3
+ import { getProofData, getCommitmentFromDSCProof, getCommitmentInFromIDDataProof, getCommitmentOutFromIDDataProof, getNullifierFromDisclosureProof, getCommitmentInFromIntegrityProof, getCommitmentOutFromIntegrityProof, getCommitmentInFromDisclosureProof, getMerkleRootFromDSCProof, getCurrentDateFromIntegrityProof, DisclosedData, formatName, getHostedPackagedCircuitByName, getNumberOfPublicInputs, getParameterCommitmentFromDisclosureProof, getCountryParameterCommitment, getDiscloseParameterCommitment, getDateParameterCommitment, getCertificateRegistryRootFromOuterProof, getParamCommitmentsFromOuterProof, getCurrentDateFromCommittedInputs, getMinAgeFromCommittedInputs, getMaxAgeFromCommittedInputs, getAgeParameterCommitment, getMinDateFromCommittedInputs, getMaxDateFromCommittedInputs, getCurrentDateFromOuterProof, getNullifierFromOuterProof, getAgeEVMParameterCommitment, getDateEVMParameterCommitment, getDiscloseEVMParameterCommitment, getCountryEVMParameterCommitment, rightPadArrayWithZeros, getCommittedInputCount, ProofType, getScopeHash, getScopeFromOuterProof, getSubscopeFromOuterProof, } from "@zkpassport/utils";
4
4
  import { bytesToHex } from "@noble/ciphers/utils";
5
5
  import { getWebSocketClient } from "./websocket";
6
6
  import { createEncryptedJsonRpcRequest } from "./json-rpc";
@@ -95,6 +95,7 @@ export class ZKPassport {
95
95
  proofs: this.topicToProofs[topic],
96
96
  queryResult: result,
97
97
  validity: this.topicToLocalConfig[topic]?.validity,
98
+ scope: this.topicToService[topic]?.scope,
98
99
  });
99
100
  delete this.topicToProofs[topic];
100
101
  const hasFailedProofs = this.topicToFailedProofCount[topic] > 0;
@@ -1234,7 +1235,29 @@ export class ZKPassport {
1234
1235
  }
1235
1236
  return { isCorrect, queryResultErrors };
1236
1237
  }
1237
- async checkPublicInputs(proofs, queryResult, validity) {
1238
+ checkScopeFromDisclosureProof(proofData, queryResultErrors, key, scope) {
1239
+ let isCorrect = true;
1240
+ if (this.domain && getScopeHash(this.domain) !== BigInt(proofData.publicInputs[1])) {
1241
+ console.warn("The proof comes from a different domain than the one expected");
1242
+ isCorrect = false;
1243
+ queryResultErrors[key].scope = {
1244
+ expected: `Scope: ${getScopeHash(this.domain).toString()}`,
1245
+ received: `Scope: ${BigInt(proofData.publicInputs[1]).toString()}`,
1246
+ message: "The proof comes from a different domain than the one expected",
1247
+ };
1248
+ }
1249
+ if (scope && getScopeHash(scope) !== BigInt(proofData.publicInputs[2])) {
1250
+ console.warn("The proof uses a different scope than the one expected");
1251
+ isCorrect = false;
1252
+ queryResultErrors[key].scope = {
1253
+ expected: `Scope: ${getScopeHash(scope).toString()}`,
1254
+ received: `Scope: ${BigInt(proofData.publicInputs[2]).toString()}`,
1255
+ message: "The proof uses a different scope than the one expected",
1256
+ };
1257
+ }
1258
+ return { isCorrect, queryResultErrors };
1259
+ }
1260
+ async checkPublicInputs(proofs, queryResult, validity, scope) {
1238
1261
  let commitmentIn;
1239
1262
  let commitmentOut;
1240
1263
  let isCorrect = true;
@@ -1327,6 +1350,24 @@ export class ZKPassport {
1327
1350
  message: "The proof does not verify all the requested conditions and information",
1328
1351
  };
1329
1352
  }
1353
+ if (this.domain && getScopeHash(this.domain) !== getScopeFromOuterProof(proofData)) {
1354
+ console.warn("The proof comes from a different domain than the one expected");
1355
+ isCorrect = false;
1356
+ queryResultErrors.outer.scope = {
1357
+ expected: `Scope: ${getScopeHash(this.domain).toString()}`,
1358
+ received: `Scope: ${getScopeFromOuterProof(proofData).toString()}`,
1359
+ message: "The proof comes from a different domain than the one expected",
1360
+ };
1361
+ }
1362
+ if (scope && getScopeHash(scope) !== getSubscopeFromOuterProof(proofData)) {
1363
+ console.warn("The proof uses a different scope than the one expected");
1364
+ isCorrect = false;
1365
+ queryResultErrors.outer.scope = {
1366
+ expected: `Scope: ${getScopeHash(scope).toString()}`,
1367
+ received: `Scope: ${getSubscopeFromOuterProof(proofData).toString()}`,
1368
+ message: "The proof uses a different scope than the one expected",
1369
+ };
1370
+ }
1330
1371
  if (!!committedInputs?.compare_age) {
1331
1372
  const ageCommittedInputs = committedInputs?.compare_age;
1332
1373
  const ageParameterCommitment = isForEVM
@@ -1577,11 +1618,18 @@ export class ZKPassport {
1577
1618
  message: "The disclosed data does not match the data committed by the proof",
1578
1619
  };
1579
1620
  }
1621
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "disclose", scope);
1622
+ isCorrect = isCorrect && isCorrectScope;
1623
+ queryResultErrors = {
1624
+ ...queryResultErrors,
1625
+ ...queryResultErrorsScope,
1626
+ };
1580
1627
  const { isCorrect: isCorrectDisclose, queryResultErrors: queryResultErrorsDisclose } = this.checkDiscloseBytesPublicInputs(proof, queryResult);
1581
- isCorrect = isCorrect && isCorrectDisclose;
1628
+ isCorrect = isCorrect && isCorrectDisclose && isCorrectScope;
1582
1629
  queryResultErrors = {
1583
1630
  ...queryResultErrors,
1584
1631
  ...queryResultErrorsDisclose,
1632
+ ...queryResultErrorsScope,
1585
1633
  };
1586
1634
  uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10);
1587
1635
  }
@@ -1608,11 +1656,13 @@ export class ZKPassport {
1608
1656
  message: "The conditions for the age check do not match the conditions checked by the proof",
1609
1657
  };
1610
1658
  }
1659
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "age", scope);
1611
1660
  const { isCorrect: isCorrectAge, queryResultErrors: queryResultErrorsAge } = this.checkAgePublicInputs(proof, queryResult);
1612
- isCorrect = isCorrect && isCorrectAge;
1661
+ isCorrect = isCorrect && isCorrectAge && isCorrectScope;
1613
1662
  queryResultErrors = {
1614
1663
  ...queryResultErrors,
1615
1664
  ...queryResultErrorsAge,
1665
+ ...queryResultErrorsScope,
1616
1666
  };
1617
1667
  uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10);
1618
1668
  }
@@ -1639,11 +1689,13 @@ export class ZKPassport {
1639
1689
  message: "The conditions for the birthdate check do not match the conditions checked by the proof",
1640
1690
  };
1641
1691
  }
1692
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "birthdate", scope);
1642
1693
  const { isCorrect: isCorrectBirthdate, queryResultErrors: queryResultErrorsBirthdate } = this.checkBirthdatePublicInputs(proof, queryResult);
1643
- isCorrect = isCorrect && isCorrectBirthdate;
1694
+ isCorrect = isCorrect && isCorrectBirthdate && isCorrectScope;
1644
1695
  queryResultErrors = {
1645
1696
  ...queryResultErrors,
1646
1697
  ...queryResultErrorsBirthdate,
1698
+ ...queryResultErrorsScope,
1647
1699
  };
1648
1700
  uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10);
1649
1701
  }
@@ -1670,11 +1722,13 @@ export class ZKPassport {
1670
1722
  message: "The conditions for the expiry date check do not match the conditions checked by the proof",
1671
1723
  };
1672
1724
  }
1725
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "expiry_date", scope);
1673
1726
  const { isCorrect: isCorrectExpiryDate, queryResultErrors: queryResultErrorsExpiryDate } = this.checkExpiryDatePublicInputs(proof, queryResult);
1674
- isCorrect = isCorrect && isCorrectExpiryDate;
1727
+ isCorrect = isCorrect && isCorrectExpiryDate && isCorrectScope;
1675
1728
  queryResultErrors = {
1676
1729
  ...queryResultErrors,
1677
1730
  ...queryResultErrorsExpiryDate,
1731
+ ...queryResultErrorsScope,
1678
1732
  };
1679
1733
  uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10);
1680
1734
  }
@@ -1701,11 +1755,13 @@ export class ZKPassport {
1701
1755
  message: "The committed country list for the exclusion check does not match the one from the proof",
1702
1756
  };
1703
1757
  }
1758
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "nationality", scope);
1704
1759
  const { isCorrect: isCorrectNationalityExclusion, queryResultErrors: queryResultErrorsNationalityExclusion, } = this.checkNationalityExclusionPublicInputs(queryResult, countryList);
1705
- isCorrect = isCorrect && isCorrectNationalityExclusion;
1760
+ isCorrect = isCorrect && isCorrectNationalityExclusion && isCorrectScope;
1706
1761
  queryResultErrors = {
1707
1762
  ...queryResultErrors,
1708
1763
  ...queryResultErrorsNationalityExclusion,
1764
+ ...queryResultErrorsScope,
1709
1765
  };
1710
1766
  uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10);
1711
1767
  }
@@ -1732,11 +1788,13 @@ export class ZKPassport {
1732
1788
  message: "The committed country list for the issuing country exclusion check does not match the one from the proof",
1733
1789
  };
1734
1790
  }
1791
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "nationality", scope);
1735
1792
  const { isCorrect: isCorrectIssuingCountryExclusion, queryResultErrors: queryResultErrorsIssuingCountryExclusion, } = this.checkIssuingCountryExclusionPublicInputs(queryResult, countryList);
1736
- isCorrect = isCorrect && isCorrectIssuingCountryExclusion;
1793
+ isCorrect = isCorrect && isCorrectIssuingCountryExclusion && isCorrectScope;
1737
1794
  queryResultErrors = {
1738
1795
  ...queryResultErrors,
1739
1796
  ...queryResultErrorsIssuingCountryExclusion,
1797
+ ...queryResultErrorsScope,
1740
1798
  };
1741
1799
  uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10);
1742
1800
  }
@@ -1763,11 +1821,13 @@ export class ZKPassport {
1763
1821
  message: "The committed country list for the nationality inclusion check does not match the one from the proof",
1764
1822
  };
1765
1823
  }
1824
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "nationality", scope);
1766
1825
  const { isCorrect: isCorrectNationalityInclusion, queryResultErrors: queryResultErrorsNationalityInclusion, } = this.checkNationalityInclusionPublicInputs(queryResult, countryList);
1767
- isCorrect = isCorrect && isCorrectNationalityInclusion;
1826
+ isCorrect = isCorrect && isCorrectNationalityInclusion && isCorrectScope;
1768
1827
  queryResultErrors = {
1769
1828
  ...queryResultErrors,
1770
1829
  ...queryResultErrorsNationalityInclusion,
1830
+ ...queryResultErrorsScope,
1771
1831
  };
1772
1832
  uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10);
1773
1833
  }
@@ -1794,11 +1854,13 @@ export class ZKPassport {
1794
1854
  message: "The committed country list for the issuing country inclusion check does not match the one from the proof",
1795
1855
  };
1796
1856
  }
1857
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "nationality", scope);
1797
1858
  const { isCorrect: isCorrectIssuingCountryInclusion, queryResultErrors: queryResultErrorsIssuingCountryInclusion, } = this.checkIssuingCountryInclusionPublicInputs(queryResult, countryList);
1798
- isCorrect = isCorrect && isCorrectIssuingCountryInclusion;
1859
+ isCorrect = isCorrect && isCorrectIssuingCountryInclusion && isCorrectScope;
1799
1860
  queryResultErrors = {
1800
1861
  ...queryResultErrors,
1801
1862
  ...queryResultErrorsIssuingCountryInclusion,
1863
+ ...queryResultErrorsScope,
1802
1864
  };
1803
1865
  uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10);
1804
1866
  }
@@ -1813,7 +1875,7 @@ export class ZKPassport {
1813
1875
  * @returns An object containing the unique identifier associated to the user
1814
1876
  * and a boolean indicating whether the proofs were successfully verified.
1815
1877
  */
1816
- async verify({ proofs, queryResult, validity, }) {
1878
+ async verify({ proofs, queryResult, validity, scope, }) {
1817
1879
  const formattedResult = queryResult;
1818
1880
  // Make sure to reconvert the dates to Date objects
1819
1881
  if (formattedResult.birthdate && formattedResult.birthdate.disclose) {
@@ -1827,7 +1889,7 @@ export class ZKPassport {
1827
1889
  let verified = true;
1828
1890
  let uniqueIdentifier;
1829
1891
  let queryResultErrors;
1830
- const { isCorrect, uniqueIdentifier: uniqueIdentifierFromPublicInputs, queryResultErrors: queryResultErrorsFromPublicInputs, } = await this.checkPublicInputs(proofs, formattedResult, validity);
1892
+ const { isCorrect, uniqueIdentifier: uniqueIdentifierFromPublicInputs, queryResultErrors: queryResultErrorsFromPublicInputs, } = await this.checkPublicInputs(proofs, formattedResult, validity, scope);
1831
1893
  uniqueIdentifier = uniqueIdentifierFromPublicInputs;
1832
1894
  verified = isCorrect;
1833
1895
  queryResultErrors = isCorrect ? undefined : queryResultErrorsFromPublicInputs;
@@ -1840,24 +1902,22 @@ export class ZKPassport {
1840
1902
  try {
1841
1903
  const { createPublicClient, http } = await import("viem");
1842
1904
  const { sepolia } = await import("viem/chains");
1843
- const verifierDetails = this.getSolidityVerifierDetails("ethereum_sepolia");
1905
+ const { address, abi, functionName } = this.getSolidityVerifierDetails("ethereum_sepolia");
1844
1906
  const client = createPublicClient({
1845
1907
  chain: sepolia,
1846
1908
  transport: http("https://ethereum-sepolia-rpc.publicnode.com"),
1847
1909
  });
1848
- const params = this.getSolidityVerifierParameters(proof);
1910
+ const params = this.getSolidityVerifierParameters({
1911
+ proof,
1912
+ validityPeriodInDays: validity,
1913
+ domain: this.domain,
1914
+ scope,
1915
+ });
1849
1916
  const result = await client.readContract({
1850
- address: verifierDetails.address,
1851
- abi: verifierDetails.abi,
1852
- functionName: "verifyProof",
1853
- args: [
1854
- params.vkeyHash,
1855
- params.proof,
1856
- params.publicInputs,
1857
- params.committedInputs,
1858
- params.committedInputCounts,
1859
- params.validityPeriodInDays,
1860
- ],
1917
+ address,
1918
+ abi,
1919
+ functionName,
1920
+ args: [params],
1861
1921
  });
1862
1922
  const isVerified = Array.isArray(result) ? Boolean(result[0]) : false;
1863
1923
  verified = isVerified;
@@ -1892,21 +1952,25 @@ export class ZKPassport {
1892
1952
  return { uniqueIdentifier, verified, queryResultErrors };
1893
1953
  }
1894
1954
  getSolidityVerifierDetails(network) {
1955
+ const baseConfig = {
1956
+ functionName: "verifyProof",
1957
+ abi: ZKPassportVerifierAbi.abi,
1958
+ };
1895
1959
  if (network === "ethereum_sepolia") {
1896
1960
  return {
1897
- address: "0xca644D3424c2ee577FaaF2b56C0f9D1937E8e87C",
1898
- abi: ZKPassportVerifierAbi.abi,
1961
+ ...baseConfig,
1962
+ address: "0x21E12Fa30a1F98699F242ac062Db4a8e7b344B5d",
1899
1963
  };
1900
1964
  }
1901
1965
  else if (network === "local_anvil") {
1902
1966
  return {
1903
- address: "0x0",
1904
- abi: ZKPassportVerifierAbi.abi,
1967
+ ...baseConfig,
1968
+ address: "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6",
1905
1969
  };
1906
1970
  }
1907
1971
  throw new Error(`Unsupported network: ${network}`);
1908
1972
  }
1909
- getSolidityVerifierParameters(proof, validityPeriodInDays = 7) {
1973
+ getSolidityVerifierParameters({ proof, validityPeriodInDays = 7, domain, scope, }) {
1910
1974
  if (!proof.name?.startsWith("outer_evm")) {
1911
1975
  throw new Error("This proof cannot be verified on an EVM chain. Please make sure to use the `compressed-evm` mode.");
1912
1976
  }
@@ -2032,6 +2096,8 @@ export class ZKPassport {
2032
2096
  committedInputs: `0x${compressedCommittedInputs}`,
2033
2097
  committedInputCounts: committedInputCountsArray,
2034
2098
  validityPeriodInDays,
2099
+ scope: domain ?? this.domain,
2100
+ subscope: scope ?? "",
2035
2101
  };
2036
2102
  return params;
2037
2103
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zkpassport/sdk",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Privacy-preserving identity verification using passports and ID cards",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "module": "./dist/esm/index.js",