@zkpassport/sdk 0.4.0 → 0.4.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.
- package/dist/cjs/assets/abi/ZKPassportVerifier.json +51 -9
- package/dist/cjs/index.d.ts +9 -2
- package/dist/cjs/index.js +116 -1
- package/dist/esm/assets/abi/ZKPassportVerifier.json +51 -9
- package/dist/esm/index.d.ts +9 -2
- package/dist/esm/index.js +117 -2
- package/package.json +2 -2
- package/src/assets/abi/ZKPassportVerifier.json +51 -9
- package/src/index.ts +136 -2
package/src/index.ts
CHANGED
|
@@ -57,6 +57,11 @@ import {
|
|
|
57
57
|
getScopeFromOuterProof,
|
|
58
58
|
getSubscopeFromOuterProof,
|
|
59
59
|
getServiceScopeHash,
|
|
60
|
+
BoundData,
|
|
61
|
+
BindCommittedInputs,
|
|
62
|
+
getBindEVMParameterCommitment,
|
|
63
|
+
getBindParameterCommitment,
|
|
64
|
+
formatBoundData,
|
|
60
65
|
} from "@zkpassport/utils"
|
|
61
66
|
import { bytesToHex } from "@noble/ciphers/utils"
|
|
62
67
|
import { noLogger as logger } from "./logger"
|
|
@@ -92,7 +97,8 @@ export type QueryResultErrors = {
|
|
|
92
97
|
| "sig_check_id_data"
|
|
93
98
|
| "data_check_integrity"
|
|
94
99
|
| "outer"
|
|
95
|
-
| "disclose"
|
|
100
|
+
| "disclose"
|
|
101
|
+
| "bind"]: {
|
|
96
102
|
disclose?: QueryResultError<string | number | Date>
|
|
97
103
|
gte?: QueryResultError<number | Date>
|
|
98
104
|
lte?: QueryResultError<number | Date>
|
|
@@ -346,6 +352,12 @@ export type QueryBuilder = {
|
|
|
346
352
|
* @param key The attribute to disclose.
|
|
347
353
|
*/
|
|
348
354
|
disclose: (key: DisclosableIDCredential) => QueryBuilder
|
|
355
|
+
/**
|
|
356
|
+
* Binds a value to the request.
|
|
357
|
+
* @param key The key of the value to bind.
|
|
358
|
+
* @param value The value to bind the request to.
|
|
359
|
+
*/
|
|
360
|
+
bind: (key: keyof BoundData, value: BoundData[keyof BoundData]) => QueryBuilder
|
|
349
361
|
/**
|
|
350
362
|
* Builds the request.
|
|
351
363
|
*
|
|
@@ -503,6 +515,9 @@ export class ZKPassport {
|
|
|
503
515
|
}
|
|
504
516
|
}
|
|
505
517
|
}
|
|
518
|
+
if ((this.topicToConfig[topic] as Query).bind) {
|
|
519
|
+
neededCircuits.push("bind")
|
|
520
|
+
}
|
|
506
521
|
// From the circuits needed, determine the expected proof count
|
|
507
522
|
// There are at least 4 proofs, 3 base proofs and 1 disclosure proof minimum
|
|
508
523
|
// Each separate needed circuit adds 1 disclosure proof
|
|
@@ -636,6 +651,13 @@ export class ZKPassport {
|
|
|
636
651
|
}
|
|
637
652
|
return this.getZkPassportRequest(topic)
|
|
638
653
|
},
|
|
654
|
+
bind: (key: keyof BoundData, value: BoundData[keyof BoundData]) => {
|
|
655
|
+
this.topicToConfig[topic].bind = {
|
|
656
|
+
...this.topicToConfig[topic].bind,
|
|
657
|
+
[key]: value,
|
|
658
|
+
}
|
|
659
|
+
return this.getZkPassportRequest(topic)
|
|
660
|
+
},
|
|
639
661
|
done: () => {
|
|
640
662
|
const base64Config = Buffer.from(JSON.stringify(this.topicToConfig[topic])).toString(
|
|
641
663
|
"base64",
|
|
@@ -777,6 +799,7 @@ export class ZKPassport {
|
|
|
777
799
|
fullname: {},
|
|
778
800
|
document_number: {},
|
|
779
801
|
outer: {},
|
|
802
|
+
bind: {},
|
|
780
803
|
}
|
|
781
804
|
let isCorrect = true
|
|
782
805
|
// We can't be certain that the disclosed data is for a passport or an ID card
|
|
@@ -1138,6 +1161,7 @@ export class ZKPassport {
|
|
|
1138
1161
|
fullname: {},
|
|
1139
1162
|
document_number: {},
|
|
1140
1163
|
outer: {},
|
|
1164
|
+
bind: {},
|
|
1141
1165
|
}
|
|
1142
1166
|
let isCorrect = true
|
|
1143
1167
|
const currentTime = new Date()
|
|
@@ -1271,6 +1295,7 @@ export class ZKPassport {
|
|
|
1271
1295
|
fullname: {},
|
|
1272
1296
|
document_number: {},
|
|
1273
1297
|
outer: {},
|
|
1298
|
+
bind: {},
|
|
1274
1299
|
}
|
|
1275
1300
|
let isCorrect = true
|
|
1276
1301
|
const currentTime = new Date()
|
|
@@ -1399,6 +1424,7 @@ export class ZKPassport {
|
|
|
1399
1424
|
fullname: {},
|
|
1400
1425
|
document_number: {},
|
|
1401
1426
|
outer: {},
|
|
1427
|
+
bind: {},
|
|
1402
1428
|
}
|
|
1403
1429
|
let isCorrect = true
|
|
1404
1430
|
const currentTime = new Date()
|
|
@@ -1527,6 +1553,7 @@ export class ZKPassport {
|
|
|
1527
1553
|
fullname: {},
|
|
1528
1554
|
document_number: {},
|
|
1529
1555
|
outer: {},
|
|
1556
|
+
bind: {},
|
|
1530
1557
|
}
|
|
1531
1558
|
let isCorrect = true
|
|
1532
1559
|
if (
|
|
@@ -1591,6 +1618,7 @@ export class ZKPassport {
|
|
|
1591
1618
|
fullname: {},
|
|
1592
1619
|
document_number: {},
|
|
1593
1620
|
outer: {},
|
|
1621
|
+
bind: {},
|
|
1594
1622
|
}
|
|
1595
1623
|
let isCorrect = true
|
|
1596
1624
|
|
|
@@ -1653,6 +1681,7 @@ export class ZKPassport {
|
|
|
1653
1681
|
fullname: {},
|
|
1654
1682
|
document_number: {},
|
|
1655
1683
|
outer: {},
|
|
1684
|
+
bind: {},
|
|
1656
1685
|
}
|
|
1657
1686
|
let isCorrect = true
|
|
1658
1687
|
if (
|
|
@@ -1700,6 +1729,7 @@ export class ZKPassport {
|
|
|
1700
1729
|
fullname: {},
|
|
1701
1730
|
document_number: {},
|
|
1702
1731
|
outer: {},
|
|
1732
|
+
bind: {},
|
|
1703
1733
|
}
|
|
1704
1734
|
let isCorrect = true
|
|
1705
1735
|
|
|
@@ -1793,6 +1823,57 @@ export class ZKPassport {
|
|
|
1793
1823
|
return { isCorrect, queryResultErrors }
|
|
1794
1824
|
}
|
|
1795
1825
|
|
|
1826
|
+
private checkBindPublicInputs(queryResult: QueryResult, boundData: BoundData) {
|
|
1827
|
+
const queryResultErrors: QueryResultErrors = {
|
|
1828
|
+
sig_check_dsc: {},
|
|
1829
|
+
sig_check_id_data: {},
|
|
1830
|
+
data_check_integrity: {},
|
|
1831
|
+
disclose: {},
|
|
1832
|
+
age: {},
|
|
1833
|
+
birthdate: {},
|
|
1834
|
+
expiry_date: {},
|
|
1835
|
+
document_type: {},
|
|
1836
|
+
issuing_country: {},
|
|
1837
|
+
gender: {},
|
|
1838
|
+
nationality: {},
|
|
1839
|
+
firstname: {},
|
|
1840
|
+
lastname: {},
|
|
1841
|
+
fullname: {},
|
|
1842
|
+
document_number: {},
|
|
1843
|
+
outer: {},
|
|
1844
|
+
bind: {},
|
|
1845
|
+
}
|
|
1846
|
+
let isCorrect = true
|
|
1847
|
+
|
|
1848
|
+
if (queryResult.bind) {
|
|
1849
|
+
if (
|
|
1850
|
+
queryResult.bind.user_address?.toLowerCase().replace("0x", "") !==
|
|
1851
|
+
boundData.user_address?.toLowerCase().replace("0x", "")
|
|
1852
|
+
) {
|
|
1853
|
+
console.warn("Bound user address does not match the one from the query results")
|
|
1854
|
+
isCorrect = false
|
|
1855
|
+
queryResultErrors.bind.eq = {
|
|
1856
|
+
expected: queryResult.bind.user_address,
|
|
1857
|
+
received: boundData.user_address,
|
|
1858
|
+
message: "Bound user address does not match the one from the query results",
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1861
|
+
if (
|
|
1862
|
+
queryResult.bind.custom_data?.trim().toLowerCase() !==
|
|
1863
|
+
boundData.custom_data?.trim().toLowerCase()
|
|
1864
|
+
) {
|
|
1865
|
+
console.warn("Bound custom data does not match the one from the query results")
|
|
1866
|
+
isCorrect = false
|
|
1867
|
+
queryResultErrors.bind.eq = {
|
|
1868
|
+
expected: queryResult.bind.custom_data,
|
|
1869
|
+
received: boundData.custom_data,
|
|
1870
|
+
message: "Bound custom data does not match the one from the query results",
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1874
|
+
return { isCorrect, queryResultErrors }
|
|
1875
|
+
}
|
|
1876
|
+
|
|
1796
1877
|
private async checkPublicInputs(
|
|
1797
1878
|
proofs: Array<ProofResult>,
|
|
1798
1879
|
queryResult: QueryResult,
|
|
@@ -1831,6 +1912,7 @@ export class ZKPassport {
|
|
|
1831
1912
|
fullname: {},
|
|
1832
1913
|
document_number: {},
|
|
1833
1914
|
outer: {},
|
|
1915
|
+
bind: {},
|
|
1834
1916
|
}
|
|
1835
1917
|
|
|
1836
1918
|
// Since the order is important for the commitments, we need to sort the proofs
|
|
@@ -1848,6 +1930,7 @@ export class ZKPassport {
|
|
|
1848
1930
|
"inclusion_check_nationality",
|
|
1849
1931
|
"exclusion_check_issuing_country",
|
|
1850
1932
|
"inclusion_check_issuing_country",
|
|
1933
|
+
"bind",
|
|
1851
1934
|
]
|
|
1852
1935
|
const getIndex = (proof: ProofResult) => {
|
|
1853
1936
|
const name = proof.name || ""
|
|
@@ -2167,6 +2250,27 @@ export class ZKPassport {
|
|
|
2167
2250
|
...queryResultErrors,
|
|
2168
2251
|
...queryResultErrorsIssuingCountryExclusion,
|
|
2169
2252
|
}
|
|
2253
|
+
} else if (!!committedInputs?.bind) {
|
|
2254
|
+
const bindCommittedInputs = committedInputs?.bind as BindCommittedInputs
|
|
2255
|
+
const bindParameterCommitment = isForEVM
|
|
2256
|
+
? await getBindEVMParameterCommitment(formatBoundData(bindCommittedInputs.data))
|
|
2257
|
+
: await getBindParameterCommitment(formatBoundData(bindCommittedInputs.data))
|
|
2258
|
+
if (!paramCommitments.includes(bindParameterCommitment)) {
|
|
2259
|
+
console.warn("This proof does not verify the bound data")
|
|
2260
|
+
isCorrect = false
|
|
2261
|
+
queryResultErrors.bind.commitment = {
|
|
2262
|
+
expected: `Bind parameter commitment: ${bindParameterCommitment.toString()}`,
|
|
2263
|
+
received: `Parameter commitments included: ${paramCommitments.join(", ")}`,
|
|
2264
|
+
message: "This proof does not verify the bound data",
|
|
2265
|
+
}
|
|
2266
|
+
}
|
|
2267
|
+
const { isCorrect: isCorrectBind, queryResultErrors: queryResultErrorsBind } =
|
|
2268
|
+
this.checkBindPublicInputs(queryResult, bindCommittedInputs.data)
|
|
2269
|
+
isCorrect = isCorrect && isCorrectBind
|
|
2270
|
+
queryResultErrors = {
|
|
2271
|
+
...queryResultErrors,
|
|
2272
|
+
...queryResultErrorsBind,
|
|
2273
|
+
}
|
|
2170
2274
|
}
|
|
2171
2275
|
uniqueIdentifier = getNullifierFromOuterProof(proofData).toString(10)
|
|
2172
2276
|
} else if (proof.name?.startsWith("sig_check_dsc")) {
|
|
@@ -2598,6 +2702,29 @@ export class ZKPassport {
|
|
|
2598
2702
|
...queryResultErrorsScope,
|
|
2599
2703
|
}
|
|
2600
2704
|
uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10)
|
|
2705
|
+
} else if (proof.name === "bind") {
|
|
2706
|
+
const bindCommittedInputs = proof.committedInputs?.bind as BindCommittedInputs
|
|
2707
|
+
const paramCommittment = getParameterCommitmentFromDisclosureProof(proofData)
|
|
2708
|
+
const calculatedParamCommitment = await getBindParameterCommitment(
|
|
2709
|
+
formatBoundData(bindCommittedInputs.data),
|
|
2710
|
+
)
|
|
2711
|
+
if (paramCommittment !== calculatedParamCommitment) {
|
|
2712
|
+
console.warn("The bound data does not match the one from the proof")
|
|
2713
|
+
isCorrect = false
|
|
2714
|
+
queryResultErrors.bind.commitment = {
|
|
2715
|
+
expected: `Commitment: ${calculatedParamCommitment}`,
|
|
2716
|
+
received: `Commitment: ${paramCommittment}`,
|
|
2717
|
+
message: "The bound data does not match the one from the proof",
|
|
2718
|
+
}
|
|
2719
|
+
}
|
|
2720
|
+
const { isCorrect: isCorrectBind, queryResultErrors: queryResultErrorsBind } =
|
|
2721
|
+
this.checkBindPublicInputs(queryResult, bindCommittedInputs.data)
|
|
2722
|
+
isCorrect = isCorrect && isCorrectBind
|
|
2723
|
+
queryResultErrors = {
|
|
2724
|
+
...queryResultErrors,
|
|
2725
|
+
...queryResultErrorsBind,
|
|
2726
|
+
}
|
|
2727
|
+
uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10)
|
|
2601
2728
|
}
|
|
2602
2729
|
}
|
|
2603
2730
|
return { isCorrect, uniqueIdentifier, queryResultErrors }
|
|
@@ -2758,7 +2885,7 @@ export class ZKPassport {
|
|
|
2758
2885
|
if (network === "ethereum_sepolia") {
|
|
2759
2886
|
return {
|
|
2760
2887
|
...baseConfig,
|
|
2761
|
-
address: "
|
|
2888
|
+
address: "0x5e4B11F7B7995F5Cee0134692a422b045091112F",
|
|
2762
2889
|
}
|
|
2763
2890
|
} else if (network === "local_anvil") {
|
|
2764
2891
|
return {
|
|
@@ -2869,6 +2996,13 @@ export class ZKPassport {
|
|
|
2869
2996
|
ProofType.DISCLOSE.toString(16).padStart(2, "0") +
|
|
2870
2997
|
value.discloseMask.map((x) => x.toString(16).padStart(2, "0")).join("") +
|
|
2871
2998
|
value.disclosedBytes.map((x) => x.toString(16).padStart(2, "0")).join("")
|
|
2999
|
+
} else if (circuitName === "bind_evm") {
|
|
3000
|
+
const value = proof.committedInputs[circuitName] as BindCommittedInputs
|
|
3001
|
+
compressedCommittedInputs =
|
|
3002
|
+
ProofType.BIND.toString(16).padStart(2, "0") +
|
|
3003
|
+
rightPadArrayWithZeros(formatBoundData(value.data), 500)
|
|
3004
|
+
.map((x) => x.toString(16).padStart(2, "0"))
|
|
3005
|
+
.join("")
|
|
2872
3006
|
} else {
|
|
2873
3007
|
throw new Error(`Unsupported circuit for EVM verification: ${circuitName}`)
|
|
2874
3008
|
}
|