@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/dist/cjs/assets/abi/ZKPassportVerifier.json +110 -16
- package/dist/cjs/index.d.ts +9 -3
- package/dist/cjs/index.js +64 -31
- package/dist/esm/assets/abi/ZKPassportVerifier.json +110 -16
- package/dist/esm/index.d.ts +9 -3
- package/dist/esm/index.js +63 -30
- package/package.json +3 -2
- package/src/assets/abi/ZKPassportVerifier.json +110 -16
- package/src/index.ts +88 -27
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/
|
|
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
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
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
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
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: "
|
|
2785
|
+
address: "0x8c6982D77f7a8f60aE3133cA9b2FAA6f3e78c394",
|
|
2728
2786
|
}
|
|
2729
2787
|
} else if (network === "local_anvil") {
|
|
2730
2788
|
return {
|
|
2731
2789
|
...baseConfig,
|
|
2732
|
-
address: "
|
|
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
|
}
|