@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.
package/src/index.ts CHANGED
@@ -53,6 +53,10 @@ import {
53
53
  getCommittedInputCount,
54
54
  ProofMode,
55
55
  ProofType,
56
+ getScopeHash,
57
+ ProofData,
58
+ getScopeFromOuterProof,
59
+ getSubscopeFromOuterProof,
56
60
  } from "@zkpassport/utils"
57
61
  import { bytesToHex } from "@noble/ciphers/utils"
58
62
  import { getWebSocketClient, WebSocketClient } from "./websocket"
@@ -62,9 +66,10 @@ import { noLogger as logger } from "./logger"
62
66
  import { inflate } from "pako"
63
67
  import i18en from "i18n-iso-countries/langs/en.json"
64
68
  import { Buffer } from "buffer/"
65
- import { sha256 } from "@noble/hashes/sha256"
69
+ import { sha256 } from "@noble/hashes/sha2"
66
70
  import { hexToBytes } from "@noble/hashes/utils"
67
71
  import ZKPassportVerifierAbi from "./assets/abi/ZKPassportVerifier.json"
72
+ import { RegistryClient } from "@zkpassport/registry"
68
73
 
69
74
  const DEFAULT_DATE_VALUE = new Date(1111, 10, 11)
70
75
 
@@ -101,6 +106,7 @@ export type QueryResultErrors = {
101
106
  commitment?: QueryResultError<string>
102
107
  date?: QueryResultError<string>
103
108
  certificate?: QueryResultError<string>
109
+ scope?: QueryResultError<string>
104
110
  }
105
111
  }
106
112
 
@@ -111,6 +117,9 @@ export type SolidityVerifierParameters = {
111
117
  committedInputs: string
112
118
  committedInputCounts: number[]
113
119
  validityPeriodInDays: number
120
+ scope: string
121
+ subscope: string
122
+ devMode: boolean
114
123
  }
115
124
 
116
125
  export type EVMChain = "ethereum_sepolia" | "local_anvil"
@@ -135,9 +144,12 @@ function hasRequestedAccessToField(credentialsRequest: Query, field: IDCredentia
135
144
  }
136
145
 
137
146
  function normalizeCountry(country: CountryName | Alpha3Code) {
138
- let normalizedCountry: Alpha3Code | undefined
139
- const alpha3 = getAlpha3Code(country, "en") as Alpha3Code | undefined
140
- normalizedCountry = alpha3 || (country as Alpha3Code)
147
+ if (country === "Zero Knowledge Republic") {
148
+ return "ZKR"
149
+ }
150
+ let normalizedCountry: Alpha3Code | "ZKR" | undefined
151
+ const alpha3 = getAlpha3Code(country as CountryName, "en") as Alpha3Code | "ZKR" | undefined
152
+ normalizedCountry = alpha3 || (country as Alpha3Code) || "ZKR"
141
153
  return normalizedCountry
142
154
  }
143
155
 
@@ -336,6 +348,7 @@ export class ZKPassport {
336
348
  {
337
349
  validity: number
338
350
  mode: ProofMode
351
+ devMode: boolean
339
352
  }
340
353
  > = {}
341
354
  private topicToKeyPair: Record<string, { privateKey: Uint8Array; publicKey: Uint8Array }> = {}
@@ -386,6 +399,8 @@ export class ZKPassport {
386
399
  proofs: this.topicToProofs[topic],
387
400
  queryResult: result,
388
401
  validity: this.topicToLocalConfig[topic]?.validity,
402
+ scope: this.topicToService[topic]?.scope,
403
+ devMode: this.topicToLocalConfig[topic]?.devMode,
389
404
  })
390
405
  delete this.topicToProofs[topic]
391
406
  const hasFailedProofs = this.topicToFailedProofCount[topic] > 0
@@ -674,6 +689,7 @@ export class ZKPassport {
674
689
  * @param purpose To explain what you want to do with the user's data
675
690
  * @param scope Scope this request to a specific use case
676
691
  * @param validity How many days ago should have the ID been last scanned by the user?
692
+ * @param devMode Whether to enable dev mode. This will allow you to verify mock proofs (i.e. from ZKR)
677
693
  * @returns The query builder object.
678
694
  */
679
695
  public async request({
@@ -683,6 +699,7 @@ export class ZKPassport {
683
699
  scope,
684
700
  mode,
685
701
  validity,
702
+ devMode,
686
703
  topicOverride,
687
704
  keyPairOverride,
688
705
  }: {
@@ -692,6 +709,7 @@ export class ZKPassport {
692
709
  scope?: string
693
710
  mode?: ProofMode
694
711
  validity?: number
712
+ devMode?: boolean
695
713
  topicOverride?: string
696
714
  keyPairOverride?: { privateKey: Uint8Array; publicKey: Uint8Array }
697
715
  }): Promise<QueryBuilder> {
@@ -711,6 +729,7 @@ export class ZKPassport {
711
729
  // Default to 6 months
712
730
  validity: validity || 6 * 30,
713
731
  mode: mode || "fast",
732
+ devMode: devMode || false,
714
733
  }
715
734
 
716
735
  this.onRequestReceivedCallbacks[topic] = []
@@ -1756,20 +1775,76 @@ export class ZKPassport {
1756
1775
  return { isCorrect, queryResultErrors }
1757
1776
  }
1758
1777
 
1778
+ private checkScopeFromDisclosureProof(
1779
+ proofData: ProofData,
1780
+ queryResultErrors: QueryResultErrors,
1781
+ key: string,
1782
+ scope?: string,
1783
+ ) {
1784
+ let isCorrect = true
1785
+ if (this.domain && getScopeHash(this.domain) !== BigInt(proofData.publicInputs[1])) {
1786
+ console.warn("The proof comes from a different domain than the one expected")
1787
+ isCorrect = false
1788
+ queryResultErrors[key as keyof QueryResultErrors].scope = {
1789
+ expected: `Scope: ${getScopeHash(this.domain).toString()}`,
1790
+ received: `Scope: ${BigInt(proofData.publicInputs[1]).toString()}`,
1791
+ message: "The proof comes from a different domain than the one expected",
1792
+ }
1793
+ }
1794
+ if (scope && getScopeHash(scope) !== BigInt(proofData.publicInputs[2])) {
1795
+ console.warn("The proof uses a different scope than the one expected")
1796
+ isCorrect = false
1797
+ queryResultErrors[key as keyof QueryResultErrors].scope = {
1798
+ expected: `Scope: ${getScopeHash(scope).toString()}`,
1799
+ received: `Scope: ${BigInt(proofData.publicInputs[2]).toString()}`,
1800
+ message: "The proof uses a different scope than the one expected",
1801
+ }
1802
+ }
1803
+ return { isCorrect, queryResultErrors }
1804
+ }
1805
+
1806
+ private async checkCertificateRegistryRoot(
1807
+ root: string,
1808
+ queryResultErrors: any,
1809
+ outer?: boolean,
1810
+ ) {
1811
+ let isCorrect = true
1812
+ try {
1813
+ // Maintained certificate registry settled onchain
1814
+ // Here we use Ethereum Sepolia
1815
+ const registryClient = new RegistryClient({ chainId: 11155111 })
1816
+ await registryClient.getCertificates(`0x${root}`)
1817
+ } catch (error) {
1818
+ console.warn(error)
1819
+ // Check the legacy static roots that were used before the registry was deployed onchain
1820
+ const VALID_CERTIFICATE_REGISTRY_ROOT = [
1821
+ BigInt("20192042006788880778219739574377003123593792072535937278552252195461520776494"),
1822
+ BigInt("21301853597069384763054217328384418971999152625381818922211526730996340553696"),
1823
+ BigInt("10839898448097753834842514286432152806152415606387598803678317315409344029817"),
1824
+ ]
1825
+ if (!VALID_CERTIFICATE_REGISTRY_ROOT.includes(BigInt(root))) {
1826
+ console.warn("The ID was signed by an unrecognized root certificate")
1827
+ isCorrect = false
1828
+ queryResultErrors[outer ? "outer" : "sig_check_dsc"].certificate = {
1829
+ expected: `A valid root from ZKPassport Registry`,
1830
+ received: `Got invalid certificate registry root: ${root}`,
1831
+ message: "The ID was signed by an unrecognized root certificate",
1832
+ }
1833
+ }
1834
+ }
1835
+ return { isCorrect, queryResultErrors }
1836
+ }
1837
+
1759
1838
  private async checkPublicInputs(
1760
1839
  proofs: Array<ProofResult>,
1761
1840
  queryResult: QueryResult,
1762
1841
  validity?: number,
1842
+ scope?: string,
1763
1843
  ) {
1764
1844
  let commitmentIn: bigint | undefined
1765
1845
  let commitmentOut: bigint | undefined
1766
1846
  let isCorrect = true
1767
1847
  let uniqueIdentifier: string | undefined
1768
- const VALID_CERTIFICATE_REGISTRY_ROOT = [
1769
- BigInt("20192042006788880778219739574377003123593792072535937278552252195461520776494"),
1770
- BigInt("21301853597069384763054217328384418971999152625381818922211526730996340553696"),
1771
- BigInt("10839898448097753834842514286432152806152415606387598803678317315409344029817"),
1772
- ]
1773
1848
  const currentTime = new Date()
1774
1849
  const today = new Date(
1775
1850
  currentTime.getFullYear(),
@@ -1827,14 +1902,18 @@ export class ZKPassport {
1827
1902
  if (proof.name?.startsWith("outer")) {
1828
1903
  const isForEVM = proof.name?.startsWith("outer_evm")
1829
1904
  const certificateRegistryRoot = getCertificateRegistryRootFromOuterProof(proofData)
1830
- if (!VALID_CERTIFICATE_REGISTRY_ROOT.includes(certificateRegistryRoot)) {
1831
- console.warn("The ID was signed by an unrecognized root certificate")
1832
- isCorrect = false
1833
- queryResultErrors.outer.certificate = {
1834
- expected: `Certificate registry root: ${VALID_CERTIFICATE_REGISTRY_ROOT.join(", ")}`,
1835
- received: `Certificate registry root: ${certificateRegistryRoot.toString()}`,
1836
- message: "The ID was signed by an unrecognized root certificate",
1837
- }
1905
+ const {
1906
+ isCorrect: isCorrectCertificateRegistryRoot,
1907
+ queryResultErrors: queryResultErrorsCertificateRegistryRoot,
1908
+ } = await this.checkCertificateRegistryRoot(
1909
+ certificateRegistryRoot.toString(16),
1910
+ queryResultErrors,
1911
+ true,
1912
+ )
1913
+ isCorrect = isCorrect && isCorrectCertificateRegistryRoot
1914
+ queryResultErrors = {
1915
+ ...queryResultErrors,
1916
+ ...queryResultErrorsCertificateRegistryRoot,
1838
1917
  }
1839
1918
  const currentDate = getCurrentDateFromOuterProof(proofData)
1840
1919
  const todayToCurrentDate = today.getTime() - currentDate.getTime()
@@ -1866,6 +1945,24 @@ export class ZKPassport {
1866
1945
  message: "The proof does not verify all the requested conditions and information",
1867
1946
  }
1868
1947
  }
1948
+ if (this.domain && getScopeHash(this.domain) !== getScopeFromOuterProof(proofData)) {
1949
+ console.warn("The proof comes from a different domain than the one expected")
1950
+ isCorrect = false
1951
+ queryResultErrors.outer.scope = {
1952
+ expected: `Scope: ${getScopeHash(this.domain).toString()}`,
1953
+ received: `Scope: ${getScopeFromOuterProof(proofData).toString()}`,
1954
+ message: "The proof comes from a different domain than the one expected",
1955
+ }
1956
+ }
1957
+ if (scope && getScopeHash(scope) !== getSubscopeFromOuterProof(proofData)) {
1958
+ console.warn("The proof uses a different scope than the one expected")
1959
+ isCorrect = false
1960
+ queryResultErrors.outer.scope = {
1961
+ expected: `Scope: ${getScopeHash(scope).toString()}`,
1962
+ received: `Scope: ${getSubscopeFromOuterProof(proofData).toString()}`,
1963
+ message: "The proof uses a different scope than the one expected",
1964
+ }
1965
+ }
1869
1966
  if (!!committedInputs?.compare_age) {
1870
1967
  const ageCommittedInputs = committedInputs?.compare_age as AgeCommittedInputs
1871
1968
  const ageParameterCommitment = isForEVM
@@ -2113,14 +2210,18 @@ export class ZKPassport {
2113
2210
  } else if (proof.name?.startsWith("sig_check_dsc")) {
2114
2211
  commitmentOut = getCommitmentFromDSCProof(proofData)
2115
2212
  const merkleRoot = getMerkleRootFromDSCProof(proofData)
2116
- if (!VALID_CERTIFICATE_REGISTRY_ROOT.includes(merkleRoot)) {
2117
- console.warn("The ID was signed by an unrecognized root certificate")
2118
- isCorrect = false
2119
- queryResultErrors.sig_check_dsc.certificate = {
2120
- expected: `Certificate registry root: ${VALID_CERTIFICATE_REGISTRY_ROOT.join(", ")}`,
2121
- received: `Certificate registry root: ${merkleRoot.toString()}`,
2122
- message: "The ID was signed by an unrecognized root certificate",
2123
- }
2213
+ const {
2214
+ isCorrect: isCorrectCertificateRegistryRoot,
2215
+ queryResultErrors: queryResultErrorsCertificateRegistryRoot,
2216
+ } = await this.checkCertificateRegistryRoot(
2217
+ merkleRoot.toString(16),
2218
+ queryResultErrors,
2219
+ false,
2220
+ )
2221
+ isCorrect = isCorrect && isCorrectCertificateRegistryRoot
2222
+ queryResultErrors = {
2223
+ ...queryResultErrors,
2224
+ ...queryResultErrorsCertificateRegistryRoot,
2124
2225
  }
2125
2226
  } else if (proof.name?.startsWith("sig_check_id_data")) {
2126
2227
  commitmentIn = getCommitmentInFromIDDataProof(proofData)
@@ -2194,12 +2295,20 @@ export class ZKPassport {
2194
2295
  message: "The disclosed data does not match the data committed by the proof",
2195
2296
  }
2196
2297
  }
2298
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } =
2299
+ this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "disclose", scope)
2300
+ isCorrect = isCorrect && isCorrectScope
2301
+ queryResultErrors = {
2302
+ ...queryResultErrors,
2303
+ ...queryResultErrorsScope,
2304
+ }
2197
2305
  const { isCorrect: isCorrectDisclose, queryResultErrors: queryResultErrorsDisclose } =
2198
2306
  this.checkDiscloseBytesPublicInputs(proof, queryResult)
2199
- isCorrect = isCorrect && isCorrectDisclose
2307
+ isCorrect = isCorrect && isCorrectDisclose && isCorrectScope
2200
2308
  queryResultErrors = {
2201
2309
  ...queryResultErrors,
2202
2310
  ...queryResultErrorsDisclose,
2311
+ ...queryResultErrorsScope,
2203
2312
  }
2204
2313
  uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10)
2205
2314
  } else if (proof.name === "compare_age") {
@@ -2235,12 +2344,15 @@ export class ZKPassport {
2235
2344
  "The conditions for the age check do not match the conditions checked by the proof",
2236
2345
  }
2237
2346
  }
2347
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } =
2348
+ this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "age", scope)
2238
2349
  const { isCorrect: isCorrectAge, queryResultErrors: queryResultErrorsAge } =
2239
2350
  this.checkAgePublicInputs(proof, queryResult)
2240
- isCorrect = isCorrect && isCorrectAge
2351
+ isCorrect = isCorrect && isCorrectAge && isCorrectScope
2241
2352
  queryResultErrors = {
2242
2353
  ...queryResultErrors,
2243
2354
  ...queryResultErrorsAge,
2355
+ ...queryResultErrorsScope,
2244
2356
  }
2245
2357
  uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10)
2246
2358
  } else if (proof.name === "compare_birthdate") {
@@ -2277,12 +2389,15 @@ export class ZKPassport {
2277
2389
  "The conditions for the birthdate check do not match the conditions checked by the proof",
2278
2390
  }
2279
2391
  }
2392
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } =
2393
+ this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "birthdate", scope)
2280
2394
  const { isCorrect: isCorrectBirthdate, queryResultErrors: queryResultErrorsBirthdate } =
2281
2395
  this.checkBirthdatePublicInputs(proof, queryResult)
2282
- isCorrect = isCorrect && isCorrectBirthdate
2396
+ isCorrect = isCorrect && isCorrectBirthdate && isCorrectScope
2283
2397
  queryResultErrors = {
2284
2398
  ...queryResultErrors,
2285
2399
  ...queryResultErrorsBirthdate,
2400
+ ...queryResultErrorsScope,
2286
2401
  }
2287
2402
  uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10)
2288
2403
  } else if (proof.name === "compare_expiry") {
@@ -2318,12 +2433,15 @@ export class ZKPassport {
2318
2433
  "The conditions for the expiry date check do not match the conditions checked by the proof",
2319
2434
  }
2320
2435
  }
2436
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } =
2437
+ this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "expiry_date", scope)
2321
2438
  const { isCorrect: isCorrectExpiryDate, queryResultErrors: queryResultErrorsExpiryDate } =
2322
2439
  this.checkExpiryDatePublicInputs(proof, queryResult)
2323
- isCorrect = isCorrect && isCorrectExpiryDate
2440
+ isCorrect = isCorrect && isCorrectExpiryDate && isCorrectScope
2324
2441
  queryResultErrors = {
2325
2442
  ...queryResultErrors,
2326
2443
  ...queryResultErrorsExpiryDate,
2444
+ ...queryResultErrorsScope,
2327
2445
  }
2328
2446
  uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10)
2329
2447
  } else if (proof.name === "exclusion_check_nationality") {
@@ -2361,15 +2479,17 @@ export class ZKPassport {
2361
2479
  "The committed country list for the exclusion check does not match the one from the proof",
2362
2480
  }
2363
2481
  }
2364
-
2482
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } =
2483
+ this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "nationality", scope)
2365
2484
  const {
2366
2485
  isCorrect: isCorrectNationalityExclusion,
2367
2486
  queryResultErrors: queryResultErrorsNationalityExclusion,
2368
2487
  } = this.checkNationalityExclusionPublicInputs(queryResult, countryList)
2369
- isCorrect = isCorrect && isCorrectNationalityExclusion
2488
+ isCorrect = isCorrect && isCorrectNationalityExclusion && isCorrectScope
2370
2489
  queryResultErrors = {
2371
2490
  ...queryResultErrors,
2372
2491
  ...queryResultErrorsNationalityExclusion,
2492
+ ...queryResultErrorsScope,
2373
2493
  }
2374
2494
  uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10)
2375
2495
  } else if (proof.name === "exclusion_check_issuing_country") {
@@ -2407,14 +2527,17 @@ export class ZKPassport {
2407
2527
  "The committed country list for the issuing country exclusion check does not match the one from the proof",
2408
2528
  }
2409
2529
  }
2530
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } =
2531
+ this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "nationality", scope)
2410
2532
  const {
2411
2533
  isCorrect: isCorrectIssuingCountryExclusion,
2412
2534
  queryResultErrors: queryResultErrorsIssuingCountryExclusion,
2413
2535
  } = this.checkIssuingCountryExclusionPublicInputs(queryResult, countryList)
2414
- isCorrect = isCorrect && isCorrectIssuingCountryExclusion
2536
+ isCorrect = isCorrect && isCorrectIssuingCountryExclusion && isCorrectScope
2415
2537
  queryResultErrors = {
2416
2538
  ...queryResultErrors,
2417
2539
  ...queryResultErrorsIssuingCountryExclusion,
2540
+ ...queryResultErrorsScope,
2418
2541
  }
2419
2542
  uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10)
2420
2543
  } else if (proof.name === "inclusion_check_nationality") {
@@ -2452,14 +2575,17 @@ export class ZKPassport {
2452
2575
  "The committed country list for the nationality inclusion check does not match the one from the proof",
2453
2576
  }
2454
2577
  }
2578
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } =
2579
+ this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "nationality", scope)
2455
2580
  const {
2456
2581
  isCorrect: isCorrectNationalityInclusion,
2457
2582
  queryResultErrors: queryResultErrorsNationalityInclusion,
2458
2583
  } = this.checkNationalityInclusionPublicInputs(queryResult, countryList)
2459
- isCorrect = isCorrect && isCorrectNationalityInclusion
2584
+ isCorrect = isCorrect && isCorrectNationalityInclusion && isCorrectScope
2460
2585
  queryResultErrors = {
2461
2586
  ...queryResultErrors,
2462
2587
  ...queryResultErrorsNationalityInclusion,
2588
+ ...queryResultErrorsScope,
2463
2589
  }
2464
2590
  uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10)
2465
2591
  } else if (proof.name === "inclusion_check_issuing_country") {
@@ -2497,14 +2623,17 @@ export class ZKPassport {
2497
2623
  "The committed country list for the issuing country inclusion check does not match the one from the proof",
2498
2624
  }
2499
2625
  }
2626
+ const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } =
2627
+ this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "nationality", scope)
2500
2628
  const {
2501
2629
  isCorrect: isCorrectIssuingCountryInclusion,
2502
2630
  queryResultErrors: queryResultErrorsIssuingCountryInclusion,
2503
2631
  } = this.checkIssuingCountryInclusionPublicInputs(queryResult, countryList)
2504
- isCorrect = isCorrect && isCorrectIssuingCountryInclusion
2632
+ isCorrect = isCorrect && isCorrectIssuingCountryInclusion && isCorrectScope
2505
2633
  queryResultErrors = {
2506
2634
  ...queryResultErrors,
2507
2635
  ...queryResultErrorsIssuingCountryInclusion,
2636
+ ...queryResultErrorsScope,
2508
2637
  }
2509
2638
  uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10)
2510
2639
  }
@@ -2524,10 +2653,14 @@ export class ZKPassport {
2524
2653
  proofs,
2525
2654
  queryResult,
2526
2655
  validity,
2656
+ scope,
2657
+ devMode = false,
2527
2658
  }: {
2528
2659
  proofs: Array<ProofResult>
2529
2660
  queryResult: QueryResult
2530
2661
  validity?: number
2662
+ scope?: string
2663
+ devMode?: boolean
2531
2664
  }): Promise<{
2532
2665
  uniqueIdentifier: string | undefined
2533
2666
  verified: boolean
@@ -2555,10 +2688,19 @@ export class ZKPassport {
2555
2688
  isCorrect,
2556
2689
  uniqueIdentifier: uniqueIdentifierFromPublicInputs,
2557
2690
  queryResultErrors: queryResultErrorsFromPublicInputs,
2558
- } = await this.checkPublicInputs(proofs, formattedResult, validity)
2691
+ } = await this.checkPublicInputs(proofs, formattedResult, validity, scope)
2559
2692
  uniqueIdentifier = uniqueIdentifierFromPublicInputs
2560
2693
  verified = isCorrect
2561
2694
  queryResultErrors = isCorrect ? undefined : queryResultErrorsFromPublicInputs
2695
+ if (uniqueIdentifier && BigInt(uniqueIdentifier) === BigInt(0) && !devMode) {
2696
+ // If the unique identifier is 0 and it is not in dev mode,
2697
+ // the proofs are considered invalid as these are mock proofs only meant
2698
+ // for testing purposes
2699
+ verified = false
2700
+ console.warn(
2701
+ "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.",
2702
+ )
2703
+ }
2562
2704
  // Only proceed with the proof verification if the public inputs are correct
2563
2705
  if (verified) {
2564
2706
  for (const proof of proofs) {
@@ -2571,24 +2713,24 @@ export class ZKPassport {
2571
2713
  try {
2572
2714
  const { createPublicClient, http } = await import("viem")
2573
2715
  const { sepolia } = await import("viem/chains")
2574
- const verifierDetails = this.getSolidityVerifierDetails("ethereum_sepolia")
2716
+ const { address, abi, functionName } =
2717
+ this.getSolidityVerifierDetails("ethereum_sepolia")
2575
2718
  const client = createPublicClient({
2576
2719
  chain: sepolia,
2577
2720
  transport: http("https://ethereum-sepolia-rpc.publicnode.com"),
2578
2721
  })
2579
- const params = this.getSolidityVerifierParameters(proof)
2722
+ const params = this.getSolidityVerifierParameters({
2723
+ proof,
2724
+ validityPeriodInDays: validity,
2725
+ domain: this.domain,
2726
+ scope,
2727
+ devMode,
2728
+ })
2580
2729
  const result = await client.readContract({
2581
- address: verifierDetails.address as `0x${string}`,
2582
- abi: verifierDetails.abi,
2583
- functionName: "verifyProof",
2584
- args: [
2585
- params.vkeyHash,
2586
- params.proof,
2587
- params.publicInputs,
2588
- params.committedInputs,
2589
- params.committedInputCounts,
2590
- params.validityPeriodInDays,
2591
- ],
2730
+ address,
2731
+ abi,
2732
+ functionName,
2733
+ args: [params],
2592
2734
  })
2593
2735
  const isVerified = Array.isArray(result) ? Boolean(result[0]) : false
2594
2736
  verified = isVerified
@@ -2624,7 +2766,8 @@ export class ZKPassport {
2624
2766
  }
2625
2767
 
2626
2768
  public getSolidityVerifierDetails(network: EVMChain): {
2627
- address: string
2769
+ address: `0x${string}`
2770
+ functionName: string
2628
2771
  abi: {
2629
2772
  type: "function" | "event" | "constructor"
2630
2773
  name: string
@@ -2632,21 +2775,37 @@ export class ZKPassport {
2632
2775
  outputs: { name: string; type: string; internalType: string }[]
2633
2776
  }[]
2634
2777
  } {
2778
+ const baseConfig = {
2779
+ functionName: "verifyProof",
2780
+ abi: ZKPassportVerifierAbi.abi as any,
2781
+ }
2635
2782
  if (network === "ethereum_sepolia") {
2636
2783
  return {
2637
- address: "0xca644D3424c2ee577FaaF2b56C0f9D1937E8e87C",
2638
- abi: ZKPassportVerifierAbi.abi as any,
2784
+ ...baseConfig,
2785
+ address: "0x8c6982D77f7a8f60aE3133cA9b2FAA6f3e78c394",
2639
2786
  }
2640
2787
  } else if (network === "local_anvil") {
2641
2788
  return {
2789
+ ...baseConfig,
2642
2790
  address: "0x0",
2643
- abi: ZKPassportVerifierAbi.abi as any,
2644
2791
  }
2645
2792
  }
2646
2793
  throw new Error(`Unsupported network: ${network}`)
2647
2794
  }
2648
2795
 
2649
- public getSolidityVerifierParameters(proof: ProofResult, validityPeriodInDays: number = 7) {
2796
+ public getSolidityVerifierParameters({
2797
+ proof,
2798
+ validityPeriodInDays = 7,
2799
+ domain,
2800
+ scope,
2801
+ devMode = false,
2802
+ }: {
2803
+ proof: ProofResult
2804
+ validityPeriodInDays?: number
2805
+ domain?: string
2806
+ scope?: string
2807
+ devMode?: boolean
2808
+ }) {
2650
2809
  if (!proof.name?.startsWith("outer_evm")) {
2651
2810
  throw new Error(
2652
2811
  "This proof cannot be verified on an EVM chain. Please make sure to use the `compressed-evm` mode.",
@@ -2779,6 +2938,9 @@ export class ZKPassport {
2779
2938
  committedInputs: `0x${compressedCommittedInputs}`,
2780
2939
  committedInputCounts: committedInputCountsArray,
2781
2940
  validityPeriodInDays,
2941
+ scope: domain ?? this.domain,
2942
+ subscope: scope ?? "",
2943
+ devMode,
2782
2944
  }
2783
2945
  return params
2784
2946
  }