@zkpassport/sdk 0.3.1 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.ts CHANGED
@@ -66,9 +66,10 @@ import { noLogger as logger } from "./logger"
66
66
  import { inflate } from "pako"
67
67
  import i18en from "i18n-iso-countries/langs/en.json"
68
68
  import { Buffer } from "buffer/"
69
- import { sha256 } from "@noble/hashes/sha256"
69
+ import { sha256 } from "@noble/hashes/sha2"
70
70
  import { hexToBytes } from "@noble/hashes/utils"
71
71
  import ZKPassportVerifierAbi from "./assets/abi/ZKPassportVerifier.json"
72
+ import { RegistryClient } from "@zkpassport/registry"
72
73
 
73
74
  const DEFAULT_DATE_VALUE = new Date(1111, 10, 11)
74
75
 
@@ -118,6 +119,7 @@ export type SolidityVerifierParameters = {
118
119
  validityPeriodInDays: number
119
120
  scope: string
120
121
  subscope: string
122
+ devMode: boolean
121
123
  }
122
124
 
123
125
  export type EVMChain = "ethereum_sepolia" | "local_anvil"
@@ -142,9 +144,12 @@ function hasRequestedAccessToField(credentialsRequest: Query, field: IDCredentia
142
144
  }
143
145
 
144
146
  function normalizeCountry(country: CountryName | Alpha3Code) {
145
- let normalizedCountry: Alpha3Code | undefined
146
- const alpha3 = getAlpha3Code(country, "en") as Alpha3Code | undefined
147
- 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"
148
153
  return normalizedCountry
149
154
  }
150
155
 
@@ -343,6 +348,7 @@ export class ZKPassport {
343
348
  {
344
349
  validity: number
345
350
  mode: ProofMode
351
+ devMode: boolean
346
352
  }
347
353
  > = {}
348
354
  private topicToKeyPair: Record<string, { privateKey: Uint8Array; publicKey: Uint8Array }> = {}
@@ -394,6 +400,7 @@ export class ZKPassport {
394
400
  queryResult: result,
395
401
  validity: this.topicToLocalConfig[topic]?.validity,
396
402
  scope: this.topicToService[topic]?.scope,
403
+ devMode: this.topicToLocalConfig[topic]?.devMode,
397
404
  })
398
405
  delete this.topicToProofs[topic]
399
406
  const hasFailedProofs = this.topicToFailedProofCount[topic] > 0
@@ -682,6 +689,7 @@ export class ZKPassport {
682
689
  * @param purpose To explain what you want to do with the user's data
683
690
  * @param scope Scope this request to a specific use case
684
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)
685
693
  * @returns The query builder object.
686
694
  */
687
695
  public async request({
@@ -691,6 +699,7 @@ export class ZKPassport {
691
699
  scope,
692
700
  mode,
693
701
  validity,
702
+ devMode,
694
703
  topicOverride,
695
704
  keyPairOverride,
696
705
  }: {
@@ -700,6 +709,7 @@ export class ZKPassport {
700
709
  scope?: string
701
710
  mode?: ProofMode
702
711
  validity?: number
712
+ devMode?: boolean
703
713
  topicOverride?: string
704
714
  keyPairOverride?: { privateKey: Uint8Array; publicKey: Uint8Array }
705
715
  }): Promise<QueryBuilder> {
@@ -719,6 +729,7 @@ export class ZKPassport {
719
729
  // Default to 6 months
720
730
  validity: validity || 6 * 30,
721
731
  mode: mode || "fast",
732
+ devMode: devMode || false,
722
733
  }
723
734
 
724
735
  this.onRequestReceivedCallbacks[topic] = []
@@ -1792,6 +1803,38 @@ export class ZKPassport {
1792
1803
  return { isCorrect, queryResultErrors }
1793
1804
  }
1794
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
+
1795
1838
  private async checkPublicInputs(
1796
1839
  proofs: Array<ProofResult>,
1797
1840
  queryResult: QueryResult,
@@ -1802,11 +1845,6 @@ export class ZKPassport {
1802
1845
  let commitmentOut: bigint | undefined
1803
1846
  let isCorrect = true
1804
1847
  let uniqueIdentifier: string | undefined
1805
- const VALID_CERTIFICATE_REGISTRY_ROOT = [
1806
- BigInt("20192042006788880778219739574377003123593792072535937278552252195461520776494"),
1807
- BigInt("21301853597069384763054217328384418971999152625381818922211526730996340553696"),
1808
- BigInt("10839898448097753834842514286432152806152415606387598803678317315409344029817"),
1809
- ]
1810
1848
  const currentTime = new Date()
1811
1849
  const today = new Date(
1812
1850
  currentTime.getFullYear(),
@@ -1864,14 +1902,18 @@ export class ZKPassport {
1864
1902
  if (proof.name?.startsWith("outer")) {
1865
1903
  const isForEVM = proof.name?.startsWith("outer_evm")
1866
1904
  const certificateRegistryRoot = getCertificateRegistryRootFromOuterProof(proofData)
1867
- if (!VALID_CERTIFICATE_REGISTRY_ROOT.includes(certificateRegistryRoot)) {
1868
- console.warn("The ID was signed by an unrecognized root certificate")
1869
- isCorrect = false
1870
- queryResultErrors.outer.certificate = {
1871
- expected: `Certificate registry root: ${VALID_CERTIFICATE_REGISTRY_ROOT.join(", ")}`,
1872
- received: `Certificate registry root: ${certificateRegistryRoot.toString()}`,
1873
- message: "The ID was signed by an unrecognized root certificate",
1874
- }
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,
1875
1917
  }
1876
1918
  const currentDate = getCurrentDateFromOuterProof(proofData)
1877
1919
  const todayToCurrentDate = today.getTime() - currentDate.getTime()
@@ -2168,14 +2210,18 @@ export class ZKPassport {
2168
2210
  } else if (proof.name?.startsWith("sig_check_dsc")) {
2169
2211
  commitmentOut = getCommitmentFromDSCProof(proofData)
2170
2212
  const merkleRoot = getMerkleRootFromDSCProof(proofData)
2171
- if (!VALID_CERTIFICATE_REGISTRY_ROOT.includes(merkleRoot)) {
2172
- console.warn("The ID was signed by an unrecognized root certificate")
2173
- isCorrect = false
2174
- queryResultErrors.sig_check_dsc.certificate = {
2175
- expected: `Certificate registry root: ${VALID_CERTIFICATE_REGISTRY_ROOT.join(", ")}`,
2176
- received: `Certificate registry root: ${merkleRoot.toString()}`,
2177
- message: "The ID was signed by an unrecognized root certificate",
2178
- }
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,
2179
2225
  }
2180
2226
  } else if (proof.name?.startsWith("sig_check_id_data")) {
2181
2227
  commitmentIn = getCommitmentInFromIDDataProof(proofData)
@@ -2608,11 +2654,13 @@ export class ZKPassport {
2608
2654
  queryResult,
2609
2655
  validity,
2610
2656
  scope,
2657
+ devMode = false,
2611
2658
  }: {
2612
2659
  proofs: Array<ProofResult>
2613
2660
  queryResult: QueryResult
2614
2661
  validity?: number
2615
2662
  scope?: string
2663
+ devMode?: boolean
2616
2664
  }): Promise<{
2617
2665
  uniqueIdentifier: string | undefined
2618
2666
  verified: boolean
@@ -2644,6 +2692,15 @@ export class ZKPassport {
2644
2692
  uniqueIdentifier = uniqueIdentifierFromPublicInputs
2645
2693
  verified = isCorrect
2646
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
+ }
2647
2704
  // Only proceed with the proof verification if the public inputs are correct
2648
2705
  if (verified) {
2649
2706
  for (const proof of proofs) {
@@ -2667,6 +2724,7 @@ export class ZKPassport {
2667
2724
  validityPeriodInDays: validity,
2668
2725
  domain: this.domain,
2669
2726
  scope,
2727
+ devMode,
2670
2728
  })
2671
2729
  const result = await client.readContract({
2672
2730
  address,
@@ -2724,12 +2782,12 @@ export class ZKPassport {
2724
2782
  if (network === "ethereum_sepolia") {
2725
2783
  return {
2726
2784
  ...baseConfig,
2727
- address: "0x21E12Fa30a1F98699F242ac062Db4a8e7b344B5d",
2785
+ address: "0x8c6982D77f7a8f60aE3133cA9b2FAA6f3e78c394",
2728
2786
  }
2729
2787
  } else if (network === "local_anvil") {
2730
2788
  return {
2731
2789
  ...baseConfig,
2732
- address: "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6",
2790
+ address: "0x0",
2733
2791
  }
2734
2792
  }
2735
2793
  throw new Error(`Unsupported network: ${network}`)
@@ -2740,11 +2798,13 @@ export class ZKPassport {
2740
2798
  validityPeriodInDays = 7,
2741
2799
  domain,
2742
2800
  scope,
2801
+ devMode = false,
2743
2802
  }: {
2744
2803
  proof: ProofResult
2745
2804
  validityPeriodInDays?: number
2746
2805
  domain?: string
2747
2806
  scope?: string
2807
+ devMode?: boolean
2748
2808
  }) {
2749
2809
  if (!proof.name?.startsWith("outer_evm")) {
2750
2810
  throw new Error(
@@ -2880,6 +2940,7 @@ export class ZKPassport {
2880
2940
  validityPeriodInDays,
2881
2941
  scope: domain ?? this.domain,
2882
2942
  subscope: scope ?? "",
2943
+ devMode,
2883
2944
  }
2884
2945
  return params
2885
2946
  }