@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/dist/cjs/assets/abi/ZKPassportVerifier.json +178 -31
- package/dist/cjs/index.d.ts +21 -4
- package/dist/cjs/index.js +154 -55
- package/dist/esm/assets/abi/ZKPassportVerifier.json +178 -31
- package/dist/esm/index.d.ts +21 -4
- package/dist/esm/index.js +154 -55
- package/package.json +3 -2
- package/src/assets/abi/ZKPassportVerifier.json +178 -31
- package/src/index.ts +215 -53
package/dist/cjs/index.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export type QueryResultErrors = {
|
|
|
17
17
|
commitment?: QueryResultError<string>;
|
|
18
18
|
date?: QueryResultError<string>;
|
|
19
19
|
certificate?: QueryResultError<string>;
|
|
20
|
+
scope?: QueryResultError<string>;
|
|
20
21
|
};
|
|
21
22
|
};
|
|
22
23
|
export type SolidityVerifierParameters = {
|
|
@@ -26,6 +27,9 @@ export type SolidityVerifierParameters = {
|
|
|
26
27
|
committedInputs: string;
|
|
27
28
|
committedInputCounts: number[];
|
|
28
29
|
validityPeriodInDays: number;
|
|
30
|
+
scope: string;
|
|
31
|
+
subscope: string;
|
|
32
|
+
devMode: boolean;
|
|
29
33
|
};
|
|
30
34
|
export type EVMChain = "ethereum_sepolia" | "local_anvil";
|
|
31
35
|
export type * from "@zkpassport/utils";
|
|
@@ -192,15 +196,17 @@ export declare class ZKPassport {
|
|
|
192
196
|
* @param purpose To explain what you want to do with the user's data
|
|
193
197
|
* @param scope Scope this request to a specific use case
|
|
194
198
|
* @param validity How many days ago should have the ID been last scanned by the user?
|
|
199
|
+
* @param devMode Whether to enable dev mode. This will allow you to verify mock proofs (i.e. from ZKR)
|
|
195
200
|
* @returns The query builder object.
|
|
196
201
|
*/
|
|
197
|
-
request({ name, logo, purpose, scope, mode, validity, topicOverride, keyPairOverride, }: {
|
|
202
|
+
request({ name, logo, purpose, scope, mode, validity, devMode, topicOverride, keyPairOverride, }: {
|
|
198
203
|
name: string;
|
|
199
204
|
logo: string;
|
|
200
205
|
purpose: string;
|
|
201
206
|
scope?: string;
|
|
202
207
|
mode?: ProofMode;
|
|
203
208
|
validity?: number;
|
|
209
|
+
devMode?: boolean;
|
|
204
210
|
topicOverride?: string;
|
|
205
211
|
keyPairOverride?: {
|
|
206
212
|
privateKey: Uint8Array;
|
|
@@ -215,6 +221,8 @@ export declare class ZKPassport {
|
|
|
215
221
|
private checkIssuingCountryExclusionPublicInputs;
|
|
216
222
|
private checkNationalityInclusionPublicInputs;
|
|
217
223
|
private checkIssuingCountryInclusionPublicInputs;
|
|
224
|
+
private checkScopeFromDisclosureProof;
|
|
225
|
+
private checkCertificateRegistryRoot;
|
|
218
226
|
private checkPublicInputs;
|
|
219
227
|
/**
|
|
220
228
|
* @notice Verify the proofs received from the mobile app.
|
|
@@ -224,17 +232,20 @@ export declare class ZKPassport {
|
|
|
224
232
|
* @returns An object containing the unique identifier associated to the user
|
|
225
233
|
* and a boolean indicating whether the proofs were successfully verified.
|
|
226
234
|
*/
|
|
227
|
-
verify({ proofs, queryResult, validity, }: {
|
|
235
|
+
verify({ proofs, queryResult, validity, scope, devMode, }: {
|
|
228
236
|
proofs: Array<ProofResult>;
|
|
229
237
|
queryResult: QueryResult;
|
|
230
238
|
validity?: number;
|
|
239
|
+
scope?: string;
|
|
240
|
+
devMode?: boolean;
|
|
231
241
|
}): Promise<{
|
|
232
242
|
uniqueIdentifier: string | undefined;
|
|
233
243
|
verified: boolean;
|
|
234
244
|
queryResultErrors?: QueryResultErrors;
|
|
235
245
|
}>;
|
|
236
246
|
getSolidityVerifierDetails(network: EVMChain): {
|
|
237
|
-
address: string
|
|
247
|
+
address: `0x${string}`;
|
|
248
|
+
functionName: string;
|
|
238
249
|
abi: {
|
|
239
250
|
type: "function" | "event" | "constructor";
|
|
240
251
|
name: string;
|
|
@@ -250,7 +261,13 @@ export declare class ZKPassport {
|
|
|
250
261
|
}[];
|
|
251
262
|
}[];
|
|
252
263
|
};
|
|
253
|
-
getSolidityVerifierParameters(proof
|
|
264
|
+
getSolidityVerifierParameters({ proof, validityPeriodInDays, domain, scope, devMode, }: {
|
|
265
|
+
proof: ProofResult;
|
|
266
|
+
validityPeriodInDays?: number;
|
|
267
|
+
domain?: string;
|
|
268
|
+
scope?: string;
|
|
269
|
+
devMode?: boolean;
|
|
270
|
+
}): SolidityVerifierParameters;
|
|
254
271
|
/**
|
|
255
272
|
* @notice Returns the URL of the request.
|
|
256
273
|
* @param requestId The request ID.
|
package/dist/cjs/index.js
CHANGED
|
@@ -13,9 +13,10 @@ const logger_1 = require("./logger");
|
|
|
13
13
|
const pako_1 = require("pako");
|
|
14
14
|
const en_json_1 = tslib_1.__importDefault(require("i18n-iso-countries/langs/en.json"));
|
|
15
15
|
const buffer_1 = require("buffer/");
|
|
16
|
-
const
|
|
16
|
+
const sha2_1 = require("@noble/hashes/sha2");
|
|
17
17
|
const utils_3 = require("@noble/hashes/utils");
|
|
18
18
|
const ZKPassportVerifier_json_1 = tslib_1.__importDefault(require("./assets/abi/ZKPassportVerifier.json"));
|
|
19
|
+
const registry_1 = require("@zkpassport/registry");
|
|
19
20
|
const DEFAULT_DATE_VALUE = new Date(1111, 10, 11);
|
|
20
21
|
// If Buffer is not defined, then we use the Buffer from the buffer package
|
|
21
22
|
if (typeof globalThis.Buffer === "undefined") {
|
|
@@ -40,9 +41,12 @@ function hasRequestedAccessToField(credentialsRequest, field) {
|
|
|
40
41
|
return false;
|
|
41
42
|
}
|
|
42
43
|
function normalizeCountry(country) {
|
|
44
|
+
if (country === "Zero Knowledge Republic") {
|
|
45
|
+
return "ZKR";
|
|
46
|
+
}
|
|
43
47
|
let normalizedCountry;
|
|
44
48
|
const alpha3 = (0, i18n_iso_countries_1.getAlpha3Code)(country, "en");
|
|
45
|
-
normalizedCountry = alpha3 || country;
|
|
49
|
+
normalizedCountry = alpha3 || country || "ZKR";
|
|
46
50
|
return normalizedCountry;
|
|
47
51
|
}
|
|
48
52
|
function numericalCompare(fnName, key, value, requestId, requestIdToConfig) {
|
|
@@ -105,6 +109,8 @@ class ZKPassport {
|
|
|
105
109
|
proofs: this.topicToProofs[topic],
|
|
106
110
|
queryResult: result,
|
|
107
111
|
validity: this.topicToLocalConfig[topic]?.validity,
|
|
112
|
+
scope: this.topicToService[topic]?.scope,
|
|
113
|
+
devMode: this.topicToLocalConfig[topic]?.devMode,
|
|
108
114
|
});
|
|
109
115
|
delete this.topicToProofs[topic];
|
|
110
116
|
const hasFailedProofs = this.topicToFailedProofCount[topic] > 0;
|
|
@@ -351,9 +357,10 @@ class ZKPassport {
|
|
|
351
357
|
* @param purpose To explain what you want to do with the user's data
|
|
352
358
|
* @param scope Scope this request to a specific use case
|
|
353
359
|
* @param validity How many days ago should have the ID been last scanned by the user?
|
|
360
|
+
* @param devMode Whether to enable dev mode. This will allow you to verify mock proofs (i.e. from ZKR)
|
|
354
361
|
* @returns The query builder object.
|
|
355
362
|
*/
|
|
356
|
-
async request({ name, logo, purpose, scope, mode, validity, topicOverride, keyPairOverride, }) {
|
|
363
|
+
async request({ name, logo, purpose, scope, mode, validity, devMode, topicOverride, keyPairOverride, }) {
|
|
357
364
|
const topic = topicOverride || (0, crypto_1.randomBytes)(16).toString("hex");
|
|
358
365
|
const keyPair = keyPairOverride || (await (0, encryption_1.generateECDHKeyPair)());
|
|
359
366
|
this.topicToKeyPair[topic] = {
|
|
@@ -368,6 +375,7 @@ class ZKPassport {
|
|
|
368
375
|
// Default to 6 months
|
|
369
376
|
validity: validity || 6 * 30,
|
|
370
377
|
mode: mode || "fast",
|
|
378
|
+
devMode: devMode || false,
|
|
371
379
|
};
|
|
372
380
|
this.onRequestReceivedCallbacks[topic] = [];
|
|
373
381
|
this.onGeneratingProofCallbacks[topic] = [];
|
|
@@ -1244,16 +1252,61 @@ class ZKPassport {
|
|
|
1244
1252
|
}
|
|
1245
1253
|
return { isCorrect, queryResultErrors };
|
|
1246
1254
|
}
|
|
1247
|
-
|
|
1255
|
+
checkScopeFromDisclosureProof(proofData, queryResultErrors, key, scope) {
|
|
1256
|
+
let isCorrect = true;
|
|
1257
|
+
if (this.domain && (0, utils_1.getScopeHash)(this.domain) !== BigInt(proofData.publicInputs[1])) {
|
|
1258
|
+
console.warn("The proof comes from a different domain than the one expected");
|
|
1259
|
+
isCorrect = false;
|
|
1260
|
+
queryResultErrors[key].scope = {
|
|
1261
|
+
expected: `Scope: ${(0, utils_1.getScopeHash)(this.domain).toString()}`,
|
|
1262
|
+
received: `Scope: ${BigInt(proofData.publicInputs[1]).toString()}`,
|
|
1263
|
+
message: "The proof comes from a different domain than the one expected",
|
|
1264
|
+
};
|
|
1265
|
+
}
|
|
1266
|
+
if (scope && (0, utils_1.getScopeHash)(scope) !== BigInt(proofData.publicInputs[2])) {
|
|
1267
|
+
console.warn("The proof uses a different scope than the one expected");
|
|
1268
|
+
isCorrect = false;
|
|
1269
|
+
queryResultErrors[key].scope = {
|
|
1270
|
+
expected: `Scope: ${(0, utils_1.getScopeHash)(scope).toString()}`,
|
|
1271
|
+
received: `Scope: ${BigInt(proofData.publicInputs[2]).toString()}`,
|
|
1272
|
+
message: "The proof uses a different scope than the one expected",
|
|
1273
|
+
};
|
|
1274
|
+
}
|
|
1275
|
+
return { isCorrect, queryResultErrors };
|
|
1276
|
+
}
|
|
1277
|
+
async checkCertificateRegistryRoot(root, queryResultErrors, outer) {
|
|
1278
|
+
let isCorrect = true;
|
|
1279
|
+
try {
|
|
1280
|
+
// Maintained certificate registry settled onchain
|
|
1281
|
+
// Here we use Ethereum Sepolia
|
|
1282
|
+
const registryClient = new registry_1.RegistryClient({ chainId: 11155111 });
|
|
1283
|
+
await registryClient.getCertificates(`0x${root}`);
|
|
1284
|
+
}
|
|
1285
|
+
catch (error) {
|
|
1286
|
+
console.warn(error);
|
|
1287
|
+
// Check the legacy static roots that were used before the registry was deployed onchain
|
|
1288
|
+
const VALID_CERTIFICATE_REGISTRY_ROOT = [
|
|
1289
|
+
BigInt("20192042006788880778219739574377003123593792072535937278552252195461520776494"),
|
|
1290
|
+
BigInt("21301853597069384763054217328384418971999152625381818922211526730996340553696"),
|
|
1291
|
+
BigInt("10839898448097753834842514286432152806152415606387598803678317315409344029817"),
|
|
1292
|
+
];
|
|
1293
|
+
if (!VALID_CERTIFICATE_REGISTRY_ROOT.includes(BigInt(root))) {
|
|
1294
|
+
console.warn("The ID was signed by an unrecognized root certificate");
|
|
1295
|
+
isCorrect = false;
|
|
1296
|
+
queryResultErrors[outer ? "outer" : "sig_check_dsc"].certificate = {
|
|
1297
|
+
expected: `A valid root from ZKPassport Registry`,
|
|
1298
|
+
received: `Got invalid certificate registry root: ${root}`,
|
|
1299
|
+
message: "The ID was signed by an unrecognized root certificate",
|
|
1300
|
+
};
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
return { isCorrect, queryResultErrors };
|
|
1304
|
+
}
|
|
1305
|
+
async checkPublicInputs(proofs, queryResult, validity, scope) {
|
|
1248
1306
|
let commitmentIn;
|
|
1249
1307
|
let commitmentOut;
|
|
1250
1308
|
let isCorrect = true;
|
|
1251
1309
|
let uniqueIdentifier;
|
|
1252
|
-
const VALID_CERTIFICATE_REGISTRY_ROOT = [
|
|
1253
|
-
BigInt("20192042006788880778219739574377003123593792072535937278552252195461520776494"),
|
|
1254
|
-
BigInt("21301853597069384763054217328384418971999152625381818922211526730996340553696"),
|
|
1255
|
-
BigInt("10839898448097753834842514286432152806152415606387598803678317315409344029817"),
|
|
1256
|
-
];
|
|
1257
1310
|
const currentTime = new Date();
|
|
1258
1311
|
const today = new Date(currentTime.getFullYear(), currentTime.getMonth(), currentTime.getDate(), 0, 0, 0, 0);
|
|
1259
1312
|
let queryResultErrors = {
|
|
@@ -1301,15 +1354,12 @@ class ZKPassport {
|
|
|
1301
1354
|
if (proof.name?.startsWith("outer")) {
|
|
1302
1355
|
const isForEVM = proof.name?.startsWith("outer_evm");
|
|
1303
1356
|
const certificateRegistryRoot = (0, utils_1.getCertificateRegistryRootFromOuterProof)(proofData);
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
queryResultErrors
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
message: "The ID was signed by an unrecognized root certificate",
|
|
1311
|
-
};
|
|
1312
|
-
}
|
|
1357
|
+
const { isCorrect: isCorrectCertificateRegistryRoot, queryResultErrors: queryResultErrorsCertificateRegistryRoot, } = await this.checkCertificateRegistryRoot(certificateRegistryRoot.toString(16), queryResultErrors, true);
|
|
1358
|
+
isCorrect = isCorrect && isCorrectCertificateRegistryRoot;
|
|
1359
|
+
queryResultErrors = {
|
|
1360
|
+
...queryResultErrors,
|
|
1361
|
+
...queryResultErrorsCertificateRegistryRoot,
|
|
1362
|
+
};
|
|
1313
1363
|
const currentDate = (0, utils_1.getCurrentDateFromOuterProof)(proofData);
|
|
1314
1364
|
const todayToCurrentDate = today.getTime() - currentDate.getTime();
|
|
1315
1365
|
const differenceInDays = validity ?? 180;
|
|
@@ -1337,6 +1387,24 @@ class ZKPassport {
|
|
|
1337
1387
|
message: "The proof does not verify all the requested conditions and information",
|
|
1338
1388
|
};
|
|
1339
1389
|
}
|
|
1390
|
+
if (this.domain && (0, utils_1.getScopeHash)(this.domain) !== (0, utils_1.getScopeFromOuterProof)(proofData)) {
|
|
1391
|
+
console.warn("The proof comes from a different domain than the one expected");
|
|
1392
|
+
isCorrect = false;
|
|
1393
|
+
queryResultErrors.outer.scope = {
|
|
1394
|
+
expected: `Scope: ${(0, utils_1.getScopeHash)(this.domain).toString()}`,
|
|
1395
|
+
received: `Scope: ${(0, utils_1.getScopeFromOuterProof)(proofData).toString()}`,
|
|
1396
|
+
message: "The proof comes from a different domain than the one expected",
|
|
1397
|
+
};
|
|
1398
|
+
}
|
|
1399
|
+
if (scope && (0, utils_1.getScopeHash)(scope) !== (0, utils_1.getSubscopeFromOuterProof)(proofData)) {
|
|
1400
|
+
console.warn("The proof uses a different scope than the one expected");
|
|
1401
|
+
isCorrect = false;
|
|
1402
|
+
queryResultErrors.outer.scope = {
|
|
1403
|
+
expected: `Scope: ${(0, utils_1.getScopeHash)(scope).toString()}`,
|
|
1404
|
+
received: `Scope: ${(0, utils_1.getSubscopeFromOuterProof)(proofData).toString()}`,
|
|
1405
|
+
message: "The proof uses a different scope than the one expected",
|
|
1406
|
+
};
|
|
1407
|
+
}
|
|
1340
1408
|
if (!!committedInputs?.compare_age) {
|
|
1341
1409
|
const ageCommittedInputs = committedInputs?.compare_age;
|
|
1342
1410
|
const ageParameterCommitment = isForEVM
|
|
@@ -1514,15 +1582,12 @@ class ZKPassport {
|
|
|
1514
1582
|
else if (proof.name?.startsWith("sig_check_dsc")) {
|
|
1515
1583
|
commitmentOut = (0, utils_1.getCommitmentFromDSCProof)(proofData);
|
|
1516
1584
|
const merkleRoot = (0, utils_1.getMerkleRootFromDSCProof)(proofData);
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
queryResultErrors
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
message: "The ID was signed by an unrecognized root certificate",
|
|
1524
|
-
};
|
|
1525
|
-
}
|
|
1585
|
+
const { isCorrect: isCorrectCertificateRegistryRoot, queryResultErrors: queryResultErrorsCertificateRegistryRoot, } = await this.checkCertificateRegistryRoot(merkleRoot.toString(16), queryResultErrors, false);
|
|
1586
|
+
isCorrect = isCorrect && isCorrectCertificateRegistryRoot;
|
|
1587
|
+
queryResultErrors = {
|
|
1588
|
+
...queryResultErrors,
|
|
1589
|
+
...queryResultErrorsCertificateRegistryRoot,
|
|
1590
|
+
};
|
|
1526
1591
|
}
|
|
1527
1592
|
else if (proof.name?.startsWith("sig_check_id_data")) {
|
|
1528
1593
|
commitmentIn = (0, utils_1.getCommitmentInFromIDDataProof)(proofData);
|
|
@@ -1587,11 +1652,18 @@ class ZKPassport {
|
|
|
1587
1652
|
message: "The disclosed data does not match the data committed by the proof",
|
|
1588
1653
|
};
|
|
1589
1654
|
}
|
|
1655
|
+
const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "disclose", scope);
|
|
1656
|
+
isCorrect = isCorrect && isCorrectScope;
|
|
1657
|
+
queryResultErrors = {
|
|
1658
|
+
...queryResultErrors,
|
|
1659
|
+
...queryResultErrorsScope,
|
|
1660
|
+
};
|
|
1590
1661
|
const { isCorrect: isCorrectDisclose, queryResultErrors: queryResultErrorsDisclose } = this.checkDiscloseBytesPublicInputs(proof, queryResult);
|
|
1591
|
-
isCorrect = isCorrect && isCorrectDisclose;
|
|
1662
|
+
isCorrect = isCorrect && isCorrectDisclose && isCorrectScope;
|
|
1592
1663
|
queryResultErrors = {
|
|
1593
1664
|
...queryResultErrors,
|
|
1594
1665
|
...queryResultErrorsDisclose,
|
|
1666
|
+
...queryResultErrorsScope,
|
|
1595
1667
|
};
|
|
1596
1668
|
uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
|
|
1597
1669
|
}
|
|
@@ -1618,11 +1690,13 @@ class ZKPassport {
|
|
|
1618
1690
|
message: "The conditions for the age check do not match the conditions checked by the proof",
|
|
1619
1691
|
};
|
|
1620
1692
|
}
|
|
1693
|
+
const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "age", scope);
|
|
1621
1694
|
const { isCorrect: isCorrectAge, queryResultErrors: queryResultErrorsAge } = this.checkAgePublicInputs(proof, queryResult);
|
|
1622
|
-
isCorrect = isCorrect && isCorrectAge;
|
|
1695
|
+
isCorrect = isCorrect && isCorrectAge && isCorrectScope;
|
|
1623
1696
|
queryResultErrors = {
|
|
1624
1697
|
...queryResultErrors,
|
|
1625
1698
|
...queryResultErrorsAge,
|
|
1699
|
+
...queryResultErrorsScope,
|
|
1626
1700
|
};
|
|
1627
1701
|
uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
|
|
1628
1702
|
}
|
|
@@ -1649,11 +1723,13 @@ class ZKPassport {
|
|
|
1649
1723
|
message: "The conditions for the birthdate check do not match the conditions checked by the proof",
|
|
1650
1724
|
};
|
|
1651
1725
|
}
|
|
1726
|
+
const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "birthdate", scope);
|
|
1652
1727
|
const { isCorrect: isCorrectBirthdate, queryResultErrors: queryResultErrorsBirthdate } = this.checkBirthdatePublicInputs(proof, queryResult);
|
|
1653
|
-
isCorrect = isCorrect && isCorrectBirthdate;
|
|
1728
|
+
isCorrect = isCorrect && isCorrectBirthdate && isCorrectScope;
|
|
1654
1729
|
queryResultErrors = {
|
|
1655
1730
|
...queryResultErrors,
|
|
1656
1731
|
...queryResultErrorsBirthdate,
|
|
1732
|
+
...queryResultErrorsScope,
|
|
1657
1733
|
};
|
|
1658
1734
|
uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
|
|
1659
1735
|
}
|
|
@@ -1680,11 +1756,13 @@ class ZKPassport {
|
|
|
1680
1756
|
message: "The conditions for the expiry date check do not match the conditions checked by the proof",
|
|
1681
1757
|
};
|
|
1682
1758
|
}
|
|
1759
|
+
const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "expiry_date", scope);
|
|
1683
1760
|
const { isCorrect: isCorrectExpiryDate, queryResultErrors: queryResultErrorsExpiryDate } = this.checkExpiryDatePublicInputs(proof, queryResult);
|
|
1684
|
-
isCorrect = isCorrect && isCorrectExpiryDate;
|
|
1761
|
+
isCorrect = isCorrect && isCorrectExpiryDate && isCorrectScope;
|
|
1685
1762
|
queryResultErrors = {
|
|
1686
1763
|
...queryResultErrors,
|
|
1687
1764
|
...queryResultErrorsExpiryDate,
|
|
1765
|
+
...queryResultErrorsScope,
|
|
1688
1766
|
};
|
|
1689
1767
|
uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
|
|
1690
1768
|
}
|
|
@@ -1711,11 +1789,13 @@ class ZKPassport {
|
|
|
1711
1789
|
message: "The committed country list for the exclusion check does not match the one from the proof",
|
|
1712
1790
|
};
|
|
1713
1791
|
}
|
|
1792
|
+
const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "nationality", scope);
|
|
1714
1793
|
const { isCorrect: isCorrectNationalityExclusion, queryResultErrors: queryResultErrorsNationalityExclusion, } = this.checkNationalityExclusionPublicInputs(queryResult, countryList);
|
|
1715
|
-
isCorrect = isCorrect && isCorrectNationalityExclusion;
|
|
1794
|
+
isCorrect = isCorrect && isCorrectNationalityExclusion && isCorrectScope;
|
|
1716
1795
|
queryResultErrors = {
|
|
1717
1796
|
...queryResultErrors,
|
|
1718
1797
|
...queryResultErrorsNationalityExclusion,
|
|
1798
|
+
...queryResultErrorsScope,
|
|
1719
1799
|
};
|
|
1720
1800
|
uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
|
|
1721
1801
|
}
|
|
@@ -1742,11 +1822,13 @@ class ZKPassport {
|
|
|
1742
1822
|
message: "The committed country list for the issuing country exclusion check does not match the one from the proof",
|
|
1743
1823
|
};
|
|
1744
1824
|
}
|
|
1825
|
+
const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "nationality", scope);
|
|
1745
1826
|
const { isCorrect: isCorrectIssuingCountryExclusion, queryResultErrors: queryResultErrorsIssuingCountryExclusion, } = this.checkIssuingCountryExclusionPublicInputs(queryResult, countryList);
|
|
1746
|
-
isCorrect = isCorrect && isCorrectIssuingCountryExclusion;
|
|
1827
|
+
isCorrect = isCorrect && isCorrectIssuingCountryExclusion && isCorrectScope;
|
|
1747
1828
|
queryResultErrors = {
|
|
1748
1829
|
...queryResultErrors,
|
|
1749
1830
|
...queryResultErrorsIssuingCountryExclusion,
|
|
1831
|
+
...queryResultErrorsScope,
|
|
1750
1832
|
};
|
|
1751
1833
|
uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
|
|
1752
1834
|
}
|
|
@@ -1773,11 +1855,13 @@ class ZKPassport {
|
|
|
1773
1855
|
message: "The committed country list for the nationality inclusion check does not match the one from the proof",
|
|
1774
1856
|
};
|
|
1775
1857
|
}
|
|
1858
|
+
const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "nationality", scope);
|
|
1776
1859
|
const { isCorrect: isCorrectNationalityInclusion, queryResultErrors: queryResultErrorsNationalityInclusion, } = this.checkNationalityInclusionPublicInputs(queryResult, countryList);
|
|
1777
|
-
isCorrect = isCorrect && isCorrectNationalityInclusion;
|
|
1860
|
+
isCorrect = isCorrect && isCorrectNationalityInclusion && isCorrectScope;
|
|
1778
1861
|
queryResultErrors = {
|
|
1779
1862
|
...queryResultErrors,
|
|
1780
1863
|
...queryResultErrorsNationalityInclusion,
|
|
1864
|
+
...queryResultErrorsScope,
|
|
1781
1865
|
};
|
|
1782
1866
|
uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
|
|
1783
1867
|
}
|
|
@@ -1804,11 +1888,13 @@ class ZKPassport {
|
|
|
1804
1888
|
message: "The committed country list for the issuing country inclusion check does not match the one from the proof",
|
|
1805
1889
|
};
|
|
1806
1890
|
}
|
|
1891
|
+
const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "nationality", scope);
|
|
1807
1892
|
const { isCorrect: isCorrectIssuingCountryInclusion, queryResultErrors: queryResultErrorsIssuingCountryInclusion, } = this.checkIssuingCountryInclusionPublicInputs(queryResult, countryList);
|
|
1808
|
-
isCorrect = isCorrect && isCorrectIssuingCountryInclusion;
|
|
1893
|
+
isCorrect = isCorrect && isCorrectIssuingCountryInclusion && isCorrectScope;
|
|
1809
1894
|
queryResultErrors = {
|
|
1810
1895
|
...queryResultErrors,
|
|
1811
1896
|
...queryResultErrorsIssuingCountryInclusion,
|
|
1897
|
+
...queryResultErrorsScope,
|
|
1812
1898
|
};
|
|
1813
1899
|
uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
|
|
1814
1900
|
}
|
|
@@ -1823,7 +1909,7 @@ class ZKPassport {
|
|
|
1823
1909
|
* @returns An object containing the unique identifier associated to the user
|
|
1824
1910
|
* and a boolean indicating whether the proofs were successfully verified.
|
|
1825
1911
|
*/
|
|
1826
|
-
async verify({ proofs, queryResult, validity, }) {
|
|
1912
|
+
async verify({ proofs, queryResult, validity, scope, devMode = false, }) {
|
|
1827
1913
|
const formattedResult = queryResult;
|
|
1828
1914
|
// Make sure to reconvert the dates to Date objects
|
|
1829
1915
|
if (formattedResult.birthdate && formattedResult.birthdate.disclose) {
|
|
@@ -1837,10 +1923,17 @@ class ZKPassport {
|
|
|
1837
1923
|
let verified = true;
|
|
1838
1924
|
let uniqueIdentifier;
|
|
1839
1925
|
let queryResultErrors;
|
|
1840
|
-
const { isCorrect, uniqueIdentifier: uniqueIdentifierFromPublicInputs, queryResultErrors: queryResultErrorsFromPublicInputs, } = await this.checkPublicInputs(proofs, formattedResult, validity);
|
|
1926
|
+
const { isCorrect, uniqueIdentifier: uniqueIdentifierFromPublicInputs, queryResultErrors: queryResultErrorsFromPublicInputs, } = await this.checkPublicInputs(proofs, formattedResult, validity, scope);
|
|
1841
1927
|
uniqueIdentifier = uniqueIdentifierFromPublicInputs;
|
|
1842
1928
|
verified = isCorrect;
|
|
1843
1929
|
queryResultErrors = isCorrect ? undefined : queryResultErrorsFromPublicInputs;
|
|
1930
|
+
if (uniqueIdentifier && BigInt(uniqueIdentifier) === BigInt(0) && !devMode) {
|
|
1931
|
+
// If the unique identifier is 0 and it is not in dev mode,
|
|
1932
|
+
// the proofs are considered invalid as these are mock proofs only meant
|
|
1933
|
+
// for testing purposes
|
|
1934
|
+
verified = false;
|
|
1935
|
+
console.warn("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.");
|
|
1936
|
+
}
|
|
1844
1937
|
// Only proceed with the proof verification if the public inputs are correct
|
|
1845
1938
|
if (verified) {
|
|
1846
1939
|
for (const proof of proofs) {
|
|
@@ -1850,24 +1943,23 @@ class ZKPassport {
|
|
|
1850
1943
|
try {
|
|
1851
1944
|
const { createPublicClient, http } = await Promise.resolve().then(() => tslib_1.__importStar(require("viem")));
|
|
1852
1945
|
const { sepolia } = await Promise.resolve().then(() => tslib_1.__importStar(require("viem/chains")));
|
|
1853
|
-
const
|
|
1946
|
+
const { address, abi, functionName } = this.getSolidityVerifierDetails("ethereum_sepolia");
|
|
1854
1947
|
const client = createPublicClient({
|
|
1855
1948
|
chain: sepolia,
|
|
1856
1949
|
transport: http("https://ethereum-sepolia-rpc.publicnode.com"),
|
|
1857
1950
|
});
|
|
1858
|
-
const params = this.getSolidityVerifierParameters(
|
|
1951
|
+
const params = this.getSolidityVerifierParameters({
|
|
1952
|
+
proof,
|
|
1953
|
+
validityPeriodInDays: validity,
|
|
1954
|
+
domain: this.domain,
|
|
1955
|
+
scope,
|
|
1956
|
+
devMode,
|
|
1957
|
+
});
|
|
1859
1958
|
const result = await client.readContract({
|
|
1860
|
-
address
|
|
1861
|
-
abi
|
|
1862
|
-
functionName
|
|
1863
|
-
args: [
|
|
1864
|
-
params.vkeyHash,
|
|
1865
|
-
params.proof,
|
|
1866
|
-
params.publicInputs,
|
|
1867
|
-
params.committedInputs,
|
|
1868
|
-
params.committedInputCounts,
|
|
1869
|
-
params.validityPeriodInDays,
|
|
1870
|
-
],
|
|
1959
|
+
address,
|
|
1960
|
+
abi,
|
|
1961
|
+
functionName,
|
|
1962
|
+
args: [params],
|
|
1871
1963
|
});
|
|
1872
1964
|
const isVerified = Array.isArray(result) ? Boolean(result[0]) : false;
|
|
1873
1965
|
verified = isVerified;
|
|
@@ -1902,21 +1994,25 @@ class ZKPassport {
|
|
|
1902
1994
|
return { uniqueIdentifier, verified, queryResultErrors };
|
|
1903
1995
|
}
|
|
1904
1996
|
getSolidityVerifierDetails(network) {
|
|
1997
|
+
const baseConfig = {
|
|
1998
|
+
functionName: "verifyProof",
|
|
1999
|
+
abi: ZKPassportVerifier_json_1.default.abi,
|
|
2000
|
+
};
|
|
1905
2001
|
if (network === "ethereum_sepolia") {
|
|
1906
2002
|
return {
|
|
1907
|
-
|
|
1908
|
-
|
|
2003
|
+
...baseConfig,
|
|
2004
|
+
address: "0x8c6982D77f7a8f60aE3133cA9b2FAA6f3e78c394",
|
|
1909
2005
|
};
|
|
1910
2006
|
}
|
|
1911
2007
|
else if (network === "local_anvil") {
|
|
1912
2008
|
return {
|
|
2009
|
+
...baseConfig,
|
|
1913
2010
|
address: "0x0",
|
|
1914
|
-
abi: ZKPassportVerifier_json_1.default.abi,
|
|
1915
2011
|
};
|
|
1916
2012
|
}
|
|
1917
2013
|
throw new Error(`Unsupported network: ${network}`);
|
|
1918
2014
|
}
|
|
1919
|
-
getSolidityVerifierParameters(proof, validityPeriodInDays = 7) {
|
|
2015
|
+
getSolidityVerifierParameters({ proof, validityPeriodInDays = 7, domain, scope, devMode = false, }) {
|
|
1920
2016
|
if (!proof.name?.startsWith("outer_evm")) {
|
|
1921
2017
|
throw new Error("This proof cannot be verified on an EVM chain. Please make sure to use the `compressed-evm` mode.");
|
|
1922
2018
|
}
|
|
@@ -2008,7 +2104,7 @@ class ZKPassport {
|
|
|
2008
2104
|
let committedInputCountsArray = [];
|
|
2009
2105
|
for (const commitment of parameterCommitments) {
|
|
2010
2106
|
const committedInput = committedInputs.find((x) => {
|
|
2011
|
-
const rawHashedInputs = (0,
|
|
2107
|
+
const rawHashedInputs = (0, sha2_1.sha256)((0, utils_3.hexToBytes)(x.inputs));
|
|
2012
2108
|
// Shift the hash 8 bits to the right (1 byte)
|
|
2013
2109
|
// as one byte is dropped in the circuit to fit in the 254-bit field size
|
|
2014
2110
|
const hashedInputs = new Uint8Array(rawHashedInputs.length);
|
|
@@ -2042,6 +2138,9 @@ class ZKPassport {
|
|
|
2042
2138
|
committedInputs: `0x${compressedCommittedInputs}`,
|
|
2043
2139
|
committedInputCounts: committedInputCountsArray,
|
|
2044
2140
|
validityPeriodInDays,
|
|
2141
|
+
scope: domain ?? this.domain,
|
|
2142
|
+
subscope: scope ?? "",
|
|
2143
|
+
devMode,
|
|
2045
2144
|
};
|
|
2046
2145
|
return params;
|
|
2047
2146
|
}
|