@zkpassport/sdk 0.4.0 → 0.4.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/dist/cjs/assets/abi/ZKPassportVerifier.json +51 -9
- package/dist/cjs/index.d.ts +13 -3
- package/dist/cjs/index.js +129 -10
- package/dist/esm/assets/abi/ZKPassportVerifier.json +51 -9
- package/dist/esm/index.d.ts +13 -3
- package/dist/esm/index.js +130 -11
- package/package.json +4 -4
- package/src/assets/abi/ZKPassportVerifier.json +51 -9
- package/src/index.ts +160 -23
package/src/index.ts
CHANGED
|
@@ -57,10 +57,15 @@ import {
|
|
|
57
57
|
getScopeFromOuterProof,
|
|
58
58
|
getSubscopeFromOuterProof,
|
|
59
59
|
getServiceScopeHash,
|
|
60
|
+
BoundData,
|
|
61
|
+
BindCommittedInputs,
|
|
62
|
+
getBindEVMParameterCommitment,
|
|
63
|
+
getBindParameterCommitment,
|
|
64
|
+
formatBoundData,
|
|
65
|
+
Service,
|
|
60
66
|
} from "@zkpassport/utils"
|
|
61
67
|
import { bytesToHex } from "@noble/ciphers/utils"
|
|
62
68
|
import { noLogger as logger } from "./logger"
|
|
63
|
-
import { inflate } from "pako"
|
|
64
69
|
import i18en from "i18n-iso-countries/langs/en.json"
|
|
65
70
|
import { Buffer } from "buffer/"
|
|
66
71
|
import { sha256 } from "@noble/hashes/sha2"
|
|
@@ -69,6 +74,8 @@ import ZKPassportVerifierAbi from "./assets/abi/ZKPassportVerifier.json"
|
|
|
69
74
|
import { RegistryClient } from "@zkpassport/registry"
|
|
70
75
|
import { Bridge, BridgeInterface } from "@obsidion/bridge"
|
|
71
76
|
|
|
77
|
+
const VERSION = "0.4.2"
|
|
78
|
+
|
|
72
79
|
const DEFAULT_DATE_VALUE = new Date(1111, 10, 11)
|
|
73
80
|
|
|
74
81
|
// If Buffer is not defined, then we use the Buffer from the buffer package
|
|
@@ -92,7 +99,8 @@ export type QueryResultErrors = {
|
|
|
92
99
|
| "sig_check_id_data"
|
|
93
100
|
| "data_check_integrity"
|
|
94
101
|
| "outer"
|
|
95
|
-
| "disclose"
|
|
102
|
+
| "disclose"
|
|
103
|
+
| "bind"]: {
|
|
96
104
|
disclose?: QueryResultError<string | number | Date>
|
|
97
105
|
gte?: QueryResultError<number | Date>
|
|
98
106
|
lte?: QueryResultError<number | Date>
|
|
@@ -346,6 +354,12 @@ export type QueryBuilder = {
|
|
|
346
354
|
* @param key The attribute to disclose.
|
|
347
355
|
*/
|
|
348
356
|
disclose: (key: DisclosableIDCredential) => QueryBuilder
|
|
357
|
+
/**
|
|
358
|
+
* Binds a value to the request.
|
|
359
|
+
* @param key The key of the value to bind.
|
|
360
|
+
* @param value The value to bind the request to.
|
|
361
|
+
*/
|
|
362
|
+
bind: (key: keyof BoundData, value: BoundData[keyof BoundData]) => QueryBuilder
|
|
349
363
|
/**
|
|
350
364
|
* Builds the request.
|
|
351
365
|
*
|
|
@@ -370,10 +384,7 @@ export class ZKPassport {
|
|
|
370
384
|
private topicToPublicKey: Record<string, string> = {}
|
|
371
385
|
private topicToBridge: Record<string, BridgeInterface> = {}
|
|
372
386
|
private topicToRequestReceived: Record<string, boolean> = {}
|
|
373
|
-
private topicToService: Record<
|
|
374
|
-
string,
|
|
375
|
-
{ name: string; logo: string; purpose: string; scope?: string; chainId?: number }
|
|
376
|
-
> = {}
|
|
387
|
+
private topicToService: Record<string, Service> = {}
|
|
377
388
|
private topicToProofs: Record<string, Array<ProofResult>> = {}
|
|
378
389
|
private topicToExpectedProofCount: Record<string, number> = {}
|
|
379
390
|
private topicToFailedProofCount: Record<string, number> = {}
|
|
@@ -503,6 +514,9 @@ export class ZKPassport {
|
|
|
503
514
|
}
|
|
504
515
|
}
|
|
505
516
|
}
|
|
517
|
+
if ((this.topicToConfig[topic] as Query).bind) {
|
|
518
|
+
neededCircuits.push("bind")
|
|
519
|
+
}
|
|
506
520
|
// From the circuits needed, determine the expected proof count
|
|
507
521
|
// There are at least 4 proofs, 3 base proofs and 1 disclosure proof minimum
|
|
508
522
|
// Each separate needed circuit adds 1 disclosure proof
|
|
@@ -636,17 +650,17 @@ export class ZKPassport {
|
|
|
636
650
|
}
|
|
637
651
|
return this.getZkPassportRequest(topic)
|
|
638
652
|
},
|
|
653
|
+
bind: (key: keyof BoundData, value: BoundData[keyof BoundData]) => {
|
|
654
|
+
this.topicToConfig[topic].bind = {
|
|
655
|
+
...this.topicToConfig[topic].bind,
|
|
656
|
+
[key]: value,
|
|
657
|
+
}
|
|
658
|
+
return this.getZkPassportRequest(topic)
|
|
659
|
+
},
|
|
639
660
|
done: () => {
|
|
640
|
-
const base64Config = Buffer.from(JSON.stringify(this.topicToConfig[topic])).toString(
|
|
641
|
-
"base64",
|
|
642
|
-
)
|
|
643
|
-
const base64Service = Buffer.from(JSON.stringify(this.topicToService[topic])).toString(
|
|
644
|
-
"base64",
|
|
645
|
-
)
|
|
646
|
-
const pubkey = this.topicToPublicKey[topic]
|
|
647
661
|
this.setExpectedProofCount(topic)
|
|
648
662
|
return {
|
|
649
|
-
url:
|
|
663
|
+
url: this._getUrl(topic),
|
|
650
664
|
requestId: topic,
|
|
651
665
|
onRequestReceived: (callback: () => void) =>
|
|
652
666
|
this.onRequestReceivedCallbacks[topic].push(callback),
|
|
@@ -696,6 +710,8 @@ export class ZKPassport {
|
|
|
696
710
|
devMode,
|
|
697
711
|
topicOverride,
|
|
698
712
|
keyPairOverride,
|
|
713
|
+
cloudProverUrl,
|
|
714
|
+
bridgeUrl,
|
|
699
715
|
}: {
|
|
700
716
|
name: string
|
|
701
717
|
logo: string
|
|
@@ -707,10 +723,13 @@ export class ZKPassport {
|
|
|
707
723
|
devMode?: boolean
|
|
708
724
|
topicOverride?: string
|
|
709
725
|
keyPairOverride?: { privateKey: Uint8Array; publicKey: Uint8Array }
|
|
726
|
+
cloudProverUrl?: string
|
|
727
|
+
bridgeUrl?: string
|
|
710
728
|
}): Promise<QueryBuilder> {
|
|
711
729
|
const bridge = await Bridge.create({
|
|
712
730
|
keyPair: keyPairOverride,
|
|
713
731
|
bridgeId: topicOverride,
|
|
732
|
+
bridgeUrl,
|
|
714
733
|
})
|
|
715
734
|
|
|
716
735
|
const topic = bridge.connection.getBridgeId()
|
|
@@ -722,6 +741,8 @@ export class ZKPassport {
|
|
|
722
741
|
purpose,
|
|
723
742
|
scope,
|
|
724
743
|
chainId: evmChain ? getChainIdFromEVMChain(evmChain) : undefined,
|
|
744
|
+
cloudProverUrl,
|
|
745
|
+
bridgeUrl,
|
|
725
746
|
}
|
|
726
747
|
this.topicToProofs[topic] = []
|
|
727
748
|
this.topicToExpectedProofCount[topic] = 0
|
|
@@ -777,6 +798,7 @@ export class ZKPassport {
|
|
|
777
798
|
fullname: {},
|
|
778
799
|
document_number: {},
|
|
779
800
|
outer: {},
|
|
801
|
+
bind: {},
|
|
780
802
|
}
|
|
781
803
|
let isCorrect = true
|
|
782
804
|
// We can't be certain that the disclosed data is for a passport or an ID card
|
|
@@ -1138,6 +1160,7 @@ export class ZKPassport {
|
|
|
1138
1160
|
fullname: {},
|
|
1139
1161
|
document_number: {},
|
|
1140
1162
|
outer: {},
|
|
1163
|
+
bind: {},
|
|
1141
1164
|
}
|
|
1142
1165
|
let isCorrect = true
|
|
1143
1166
|
const currentTime = new Date()
|
|
@@ -1271,6 +1294,7 @@ export class ZKPassport {
|
|
|
1271
1294
|
fullname: {},
|
|
1272
1295
|
document_number: {},
|
|
1273
1296
|
outer: {},
|
|
1297
|
+
bind: {},
|
|
1274
1298
|
}
|
|
1275
1299
|
let isCorrect = true
|
|
1276
1300
|
const currentTime = new Date()
|
|
@@ -1399,6 +1423,7 @@ export class ZKPassport {
|
|
|
1399
1423
|
fullname: {},
|
|
1400
1424
|
document_number: {},
|
|
1401
1425
|
outer: {},
|
|
1426
|
+
bind: {},
|
|
1402
1427
|
}
|
|
1403
1428
|
let isCorrect = true
|
|
1404
1429
|
const currentTime = new Date()
|
|
@@ -1527,6 +1552,7 @@ export class ZKPassport {
|
|
|
1527
1552
|
fullname: {},
|
|
1528
1553
|
document_number: {},
|
|
1529
1554
|
outer: {},
|
|
1555
|
+
bind: {},
|
|
1530
1556
|
}
|
|
1531
1557
|
let isCorrect = true
|
|
1532
1558
|
if (
|
|
@@ -1591,6 +1617,7 @@ export class ZKPassport {
|
|
|
1591
1617
|
fullname: {},
|
|
1592
1618
|
document_number: {},
|
|
1593
1619
|
outer: {},
|
|
1620
|
+
bind: {},
|
|
1594
1621
|
}
|
|
1595
1622
|
let isCorrect = true
|
|
1596
1623
|
|
|
@@ -1653,6 +1680,7 @@ export class ZKPassport {
|
|
|
1653
1680
|
fullname: {},
|
|
1654
1681
|
document_number: {},
|
|
1655
1682
|
outer: {},
|
|
1683
|
+
bind: {},
|
|
1656
1684
|
}
|
|
1657
1685
|
let isCorrect = true
|
|
1658
1686
|
if (
|
|
@@ -1700,6 +1728,7 @@ export class ZKPassport {
|
|
|
1700
1728
|
fullname: {},
|
|
1701
1729
|
document_number: {},
|
|
1702
1730
|
outer: {},
|
|
1731
|
+
bind: {},
|
|
1703
1732
|
}
|
|
1704
1733
|
let isCorrect = true
|
|
1705
1734
|
|
|
@@ -1793,6 +1822,57 @@ export class ZKPassport {
|
|
|
1793
1822
|
return { isCorrect, queryResultErrors }
|
|
1794
1823
|
}
|
|
1795
1824
|
|
|
1825
|
+
private checkBindPublicInputs(queryResult: QueryResult, boundData: BoundData) {
|
|
1826
|
+
const queryResultErrors: QueryResultErrors = {
|
|
1827
|
+
sig_check_dsc: {},
|
|
1828
|
+
sig_check_id_data: {},
|
|
1829
|
+
data_check_integrity: {},
|
|
1830
|
+
disclose: {},
|
|
1831
|
+
age: {},
|
|
1832
|
+
birthdate: {},
|
|
1833
|
+
expiry_date: {},
|
|
1834
|
+
document_type: {},
|
|
1835
|
+
issuing_country: {},
|
|
1836
|
+
gender: {},
|
|
1837
|
+
nationality: {},
|
|
1838
|
+
firstname: {},
|
|
1839
|
+
lastname: {},
|
|
1840
|
+
fullname: {},
|
|
1841
|
+
document_number: {},
|
|
1842
|
+
outer: {},
|
|
1843
|
+
bind: {},
|
|
1844
|
+
}
|
|
1845
|
+
let isCorrect = true
|
|
1846
|
+
|
|
1847
|
+
if (queryResult.bind) {
|
|
1848
|
+
if (
|
|
1849
|
+
queryResult.bind.user_address?.toLowerCase().replace("0x", "") !==
|
|
1850
|
+
boundData.user_address?.toLowerCase().replace("0x", "")
|
|
1851
|
+
) {
|
|
1852
|
+
console.warn("Bound user address does not match the one from the query results")
|
|
1853
|
+
isCorrect = false
|
|
1854
|
+
queryResultErrors.bind.eq = {
|
|
1855
|
+
expected: queryResult.bind.user_address,
|
|
1856
|
+
received: boundData.user_address,
|
|
1857
|
+
message: "Bound user address does not match the one from the query results",
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
if (
|
|
1861
|
+
queryResult.bind.custom_data?.trim().toLowerCase() !==
|
|
1862
|
+
boundData.custom_data?.trim().toLowerCase()
|
|
1863
|
+
) {
|
|
1864
|
+
console.warn("Bound custom data does not match the one from the query results")
|
|
1865
|
+
isCorrect = false
|
|
1866
|
+
queryResultErrors.bind.eq = {
|
|
1867
|
+
expected: queryResult.bind.custom_data,
|
|
1868
|
+
received: boundData.custom_data,
|
|
1869
|
+
message: "Bound custom data does not match the one from the query results",
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
return { isCorrect, queryResultErrors }
|
|
1874
|
+
}
|
|
1875
|
+
|
|
1796
1876
|
private async checkPublicInputs(
|
|
1797
1877
|
proofs: Array<ProofResult>,
|
|
1798
1878
|
queryResult: QueryResult,
|
|
@@ -1831,6 +1911,7 @@ export class ZKPassport {
|
|
|
1831
1911
|
fullname: {},
|
|
1832
1912
|
document_number: {},
|
|
1833
1913
|
outer: {},
|
|
1914
|
+
bind: {},
|
|
1834
1915
|
}
|
|
1835
1916
|
|
|
1836
1917
|
// Since the order is important for the commitments, we need to sort the proofs
|
|
@@ -1848,6 +1929,7 @@ export class ZKPassport {
|
|
|
1848
1929
|
"inclusion_check_nationality",
|
|
1849
1930
|
"exclusion_check_issuing_country",
|
|
1850
1931
|
"inclusion_check_issuing_country",
|
|
1932
|
+
"bind",
|
|
1851
1933
|
]
|
|
1852
1934
|
const getIndex = (proof: ProofResult) => {
|
|
1853
1935
|
const name = proof.name || ""
|
|
@@ -2167,6 +2249,27 @@ export class ZKPassport {
|
|
|
2167
2249
|
...queryResultErrors,
|
|
2168
2250
|
...queryResultErrorsIssuingCountryExclusion,
|
|
2169
2251
|
}
|
|
2252
|
+
} else if (!!committedInputs?.bind) {
|
|
2253
|
+
const bindCommittedInputs = committedInputs?.bind as BindCommittedInputs
|
|
2254
|
+
const bindParameterCommitment = isForEVM
|
|
2255
|
+
? await getBindEVMParameterCommitment(formatBoundData(bindCommittedInputs.data))
|
|
2256
|
+
: await getBindParameterCommitment(formatBoundData(bindCommittedInputs.data))
|
|
2257
|
+
if (!paramCommitments.includes(bindParameterCommitment)) {
|
|
2258
|
+
console.warn("This proof does not verify the bound data")
|
|
2259
|
+
isCorrect = false
|
|
2260
|
+
queryResultErrors.bind.commitment = {
|
|
2261
|
+
expected: `Bind parameter commitment: ${bindParameterCommitment.toString()}`,
|
|
2262
|
+
received: `Parameter commitments included: ${paramCommitments.join(", ")}`,
|
|
2263
|
+
message: "This proof does not verify the bound data",
|
|
2264
|
+
}
|
|
2265
|
+
}
|
|
2266
|
+
const { isCorrect: isCorrectBind, queryResultErrors: queryResultErrorsBind } =
|
|
2267
|
+
this.checkBindPublicInputs(queryResult, bindCommittedInputs.data)
|
|
2268
|
+
isCorrect = isCorrect && isCorrectBind
|
|
2269
|
+
queryResultErrors = {
|
|
2270
|
+
...queryResultErrors,
|
|
2271
|
+
...queryResultErrorsBind,
|
|
2272
|
+
}
|
|
2170
2273
|
}
|
|
2171
2274
|
uniqueIdentifier = getNullifierFromOuterProof(proofData).toString(10)
|
|
2172
2275
|
} else if (proof.name?.startsWith("sig_check_dsc")) {
|
|
@@ -2598,6 +2701,29 @@ export class ZKPassport {
|
|
|
2598
2701
|
...queryResultErrorsScope,
|
|
2599
2702
|
}
|
|
2600
2703
|
uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10)
|
|
2704
|
+
} else if (proof.name === "bind") {
|
|
2705
|
+
const bindCommittedInputs = proof.committedInputs?.bind as BindCommittedInputs
|
|
2706
|
+
const paramCommittment = getParameterCommitmentFromDisclosureProof(proofData)
|
|
2707
|
+
const calculatedParamCommitment = await getBindParameterCommitment(
|
|
2708
|
+
formatBoundData(bindCommittedInputs.data),
|
|
2709
|
+
)
|
|
2710
|
+
if (paramCommittment !== calculatedParamCommitment) {
|
|
2711
|
+
console.warn("The bound data does not match the one from the proof")
|
|
2712
|
+
isCorrect = false
|
|
2713
|
+
queryResultErrors.bind.commitment = {
|
|
2714
|
+
expected: `Commitment: ${calculatedParamCommitment}`,
|
|
2715
|
+
received: `Commitment: ${paramCommittment}`,
|
|
2716
|
+
message: "The bound data does not match the one from the proof",
|
|
2717
|
+
}
|
|
2718
|
+
}
|
|
2719
|
+
const { isCorrect: isCorrectBind, queryResultErrors: queryResultErrorsBind } =
|
|
2720
|
+
this.checkBindPublicInputs(queryResult, bindCommittedInputs.data)
|
|
2721
|
+
isCorrect = isCorrect && isCorrectBind
|
|
2722
|
+
queryResultErrors = {
|
|
2723
|
+
...queryResultErrors,
|
|
2724
|
+
...queryResultErrorsBind,
|
|
2725
|
+
}
|
|
2726
|
+
uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10)
|
|
2601
2727
|
}
|
|
2602
2728
|
}
|
|
2603
2729
|
return { isCorrect, uniqueIdentifier, queryResultErrors }
|
|
@@ -2758,7 +2884,7 @@ export class ZKPassport {
|
|
|
2758
2884
|
if (network === "ethereum_sepolia") {
|
|
2759
2885
|
return {
|
|
2760
2886
|
...baseConfig,
|
|
2761
|
-
address: "
|
|
2887
|
+
address: "0x5e4B11F7B7995F5Cee0134692a422b045091112F",
|
|
2762
2888
|
}
|
|
2763
2889
|
} else if (network === "local_anvil") {
|
|
2764
2890
|
return {
|
|
@@ -2869,6 +2995,13 @@ export class ZKPassport {
|
|
|
2869
2995
|
ProofType.DISCLOSE.toString(16).padStart(2, "0") +
|
|
2870
2996
|
value.discloseMask.map((x) => x.toString(16).padStart(2, "0")).join("") +
|
|
2871
2997
|
value.disclosedBytes.map((x) => x.toString(16).padStart(2, "0")).join("")
|
|
2998
|
+
} else if (circuitName === "bind_evm") {
|
|
2999
|
+
const value = proof.committedInputs[circuitName] as BindCommittedInputs
|
|
3000
|
+
compressedCommittedInputs =
|
|
3001
|
+
ProofType.BIND.toString(16).padStart(2, "0") +
|
|
3002
|
+
rightPadArrayWithZeros(formatBoundData(value.data), 500)
|
|
3003
|
+
.map((x) => x.toString(16).padStart(2, "0"))
|
|
3004
|
+
.join("")
|
|
2872
3005
|
} else {
|
|
2873
3006
|
throw new Error(`Unsupported circuit for EVM verification: ${circuitName}`)
|
|
2874
3007
|
}
|
|
@@ -2921,20 +3054,24 @@ export class ZKPassport {
|
|
|
2921
3054
|
return params
|
|
2922
3055
|
}
|
|
2923
3056
|
|
|
2924
|
-
|
|
2925
|
-
* @notice Returns the URL of the request.
|
|
2926
|
-
* @param requestId The request ID.
|
|
2927
|
-
* @returns The URL of the request.
|
|
2928
|
-
*/
|
|
2929
|
-
public getUrl(requestId: string) {
|
|
2930
|
-
const pubkey = this.topicToPublicKey[requestId]
|
|
3057
|
+
private _getUrl(requestId: string) {
|
|
2931
3058
|
const base64Config = Buffer.from(JSON.stringify(this.topicToConfig[requestId])).toString(
|
|
2932
3059
|
"base64",
|
|
2933
3060
|
)
|
|
2934
3061
|
const base64Service = Buffer.from(JSON.stringify(this.topicToService[requestId])).toString(
|
|
2935
3062
|
"base64",
|
|
2936
3063
|
)
|
|
2937
|
-
|
|
3064
|
+
const pubkey = this.topicToPublicKey[requestId]
|
|
3065
|
+
return `https://zkpassport.id/r?d=${this.domain}&t=${requestId}&c=${base64Config}&s=${base64Service}&p=${pubkey}&m=${this.topicToLocalConfig[requestId].mode}&v=${VERSION}`
|
|
3066
|
+
}
|
|
3067
|
+
|
|
3068
|
+
/**
|
|
3069
|
+
* @notice Returns the URL of the request.
|
|
3070
|
+
* @param requestId The request ID.
|
|
3071
|
+
* @returns The URL of the request.
|
|
3072
|
+
*/
|
|
3073
|
+
public getUrl(requestId: string) {
|
|
3074
|
+
return this._getUrl(requestId)
|
|
2938
3075
|
}
|
|
2939
3076
|
|
|
2940
3077
|
/**
|