@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/dist/cjs/index.d.ts
CHANGED
|
@@ -29,6 +29,7 @@ export type SolidityVerifierParameters = {
|
|
|
29
29
|
validityPeriodInDays: number;
|
|
30
30
|
scope: string;
|
|
31
31
|
subscope: string;
|
|
32
|
+
devMode: boolean;
|
|
32
33
|
};
|
|
33
34
|
export type EVMChain = "ethereum_sepolia" | "local_anvil";
|
|
34
35
|
export type * from "@zkpassport/utils";
|
|
@@ -195,15 +196,17 @@ export declare class ZKPassport {
|
|
|
195
196
|
* @param purpose To explain what you want to do with the user's data
|
|
196
197
|
* @param scope Scope this request to a specific use case
|
|
197
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)
|
|
198
200
|
* @returns The query builder object.
|
|
199
201
|
*/
|
|
200
|
-
request({ name, logo, purpose, scope, mode, validity, topicOverride, keyPairOverride, }: {
|
|
202
|
+
request({ name, logo, purpose, scope, mode, validity, devMode, topicOverride, keyPairOverride, }: {
|
|
201
203
|
name: string;
|
|
202
204
|
logo: string;
|
|
203
205
|
purpose: string;
|
|
204
206
|
scope?: string;
|
|
205
207
|
mode?: ProofMode;
|
|
206
208
|
validity?: number;
|
|
209
|
+
devMode?: boolean;
|
|
207
210
|
topicOverride?: string;
|
|
208
211
|
keyPairOverride?: {
|
|
209
212
|
privateKey: Uint8Array;
|
|
@@ -219,6 +222,7 @@ export declare class ZKPassport {
|
|
|
219
222
|
private checkNationalityInclusionPublicInputs;
|
|
220
223
|
private checkIssuingCountryInclusionPublicInputs;
|
|
221
224
|
private checkScopeFromDisclosureProof;
|
|
225
|
+
private checkCertificateRegistryRoot;
|
|
222
226
|
private checkPublicInputs;
|
|
223
227
|
/**
|
|
224
228
|
* @notice Verify the proofs received from the mobile app.
|
|
@@ -228,11 +232,12 @@ export declare class ZKPassport {
|
|
|
228
232
|
* @returns An object containing the unique identifier associated to the user
|
|
229
233
|
* and a boolean indicating whether the proofs were successfully verified.
|
|
230
234
|
*/
|
|
231
|
-
verify({ proofs, queryResult, validity, scope, }: {
|
|
235
|
+
verify({ proofs, queryResult, validity, scope, devMode, }: {
|
|
232
236
|
proofs: Array<ProofResult>;
|
|
233
237
|
queryResult: QueryResult;
|
|
234
238
|
validity?: number;
|
|
235
239
|
scope?: string;
|
|
240
|
+
devMode?: boolean;
|
|
236
241
|
}): Promise<{
|
|
237
242
|
uniqueIdentifier: string | undefined;
|
|
238
243
|
verified: boolean;
|
|
@@ -256,11 +261,12 @@ export declare class ZKPassport {
|
|
|
256
261
|
}[];
|
|
257
262
|
}[];
|
|
258
263
|
};
|
|
259
|
-
getSolidityVerifierParameters({ proof, validityPeriodInDays, domain, scope, }: {
|
|
264
|
+
getSolidityVerifierParameters({ proof, validityPeriodInDays, domain, scope, devMode, }: {
|
|
260
265
|
proof: ProofResult;
|
|
261
266
|
validityPeriodInDays?: number;
|
|
262
267
|
domain?: string;
|
|
263
268
|
scope?: string;
|
|
269
|
+
devMode?: boolean;
|
|
264
270
|
}): SolidityVerifierParameters;
|
|
265
271
|
/**
|
|
266
272
|
* @notice Returns the URL of the request.
|
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) {
|
|
@@ -106,6 +110,7 @@ class ZKPassport {
|
|
|
106
110
|
queryResult: result,
|
|
107
111
|
validity: this.topicToLocalConfig[topic]?.validity,
|
|
108
112
|
scope: this.topicToService[topic]?.scope,
|
|
113
|
+
devMode: this.topicToLocalConfig[topic]?.devMode,
|
|
109
114
|
});
|
|
110
115
|
delete this.topicToProofs[topic];
|
|
111
116
|
const hasFailedProofs = this.topicToFailedProofCount[topic] > 0;
|
|
@@ -352,9 +357,10 @@ class ZKPassport {
|
|
|
352
357
|
* @param purpose To explain what you want to do with the user's data
|
|
353
358
|
* @param scope Scope this request to a specific use case
|
|
354
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)
|
|
355
361
|
* @returns The query builder object.
|
|
356
362
|
*/
|
|
357
|
-
async request({ name, logo, purpose, scope, mode, validity, topicOverride, keyPairOverride, }) {
|
|
363
|
+
async request({ name, logo, purpose, scope, mode, validity, devMode, topicOverride, keyPairOverride, }) {
|
|
358
364
|
const topic = topicOverride || (0, crypto_1.randomBytes)(16).toString("hex");
|
|
359
365
|
const keyPair = keyPairOverride || (await (0, encryption_1.generateECDHKeyPair)());
|
|
360
366
|
this.topicToKeyPair[topic] = {
|
|
@@ -369,6 +375,7 @@ class ZKPassport {
|
|
|
369
375
|
// Default to 6 months
|
|
370
376
|
validity: validity || 6 * 30,
|
|
371
377
|
mode: mode || "fast",
|
|
378
|
+
devMode: devMode || false,
|
|
372
379
|
};
|
|
373
380
|
this.onRequestReceivedCallbacks[topic] = [];
|
|
374
381
|
this.onGeneratingProofCallbacks[topic] = [];
|
|
@@ -1267,16 +1274,39 @@ class ZKPassport {
|
|
|
1267
1274
|
}
|
|
1268
1275
|
return { isCorrect, queryResultErrors };
|
|
1269
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
|
+
}
|
|
1270
1305
|
async checkPublicInputs(proofs, queryResult, validity, scope) {
|
|
1271
1306
|
let commitmentIn;
|
|
1272
1307
|
let commitmentOut;
|
|
1273
1308
|
let isCorrect = true;
|
|
1274
1309
|
let uniqueIdentifier;
|
|
1275
|
-
const VALID_CERTIFICATE_REGISTRY_ROOT = [
|
|
1276
|
-
BigInt("20192042006788880778219739574377003123593792072535937278552252195461520776494"),
|
|
1277
|
-
BigInt("21301853597069384763054217328384418971999152625381818922211526730996340553696"),
|
|
1278
|
-
BigInt("10839898448097753834842514286432152806152415606387598803678317315409344029817"),
|
|
1279
|
-
];
|
|
1280
1310
|
const currentTime = new Date();
|
|
1281
1311
|
const today = new Date(currentTime.getFullYear(), currentTime.getMonth(), currentTime.getDate(), 0, 0, 0, 0);
|
|
1282
1312
|
let queryResultErrors = {
|
|
@@ -1324,15 +1354,12 @@ class ZKPassport {
|
|
|
1324
1354
|
if (proof.name?.startsWith("outer")) {
|
|
1325
1355
|
const isForEVM = proof.name?.startsWith("outer_evm");
|
|
1326
1356
|
const certificateRegistryRoot = (0, utils_1.getCertificateRegistryRootFromOuterProof)(proofData);
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
queryResultErrors
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
message: "The ID was signed by an unrecognized root certificate",
|
|
1334
|
-
};
|
|
1335
|
-
}
|
|
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
|
+
};
|
|
1336
1363
|
const currentDate = (0, utils_1.getCurrentDateFromOuterProof)(proofData);
|
|
1337
1364
|
const todayToCurrentDate = today.getTime() - currentDate.getTime();
|
|
1338
1365
|
const differenceInDays = validity ?? 180;
|
|
@@ -1555,15 +1582,12 @@ class ZKPassport {
|
|
|
1555
1582
|
else if (proof.name?.startsWith("sig_check_dsc")) {
|
|
1556
1583
|
commitmentOut = (0, utils_1.getCommitmentFromDSCProof)(proofData);
|
|
1557
1584
|
const merkleRoot = (0, utils_1.getMerkleRootFromDSCProof)(proofData);
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
queryResultErrors
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
message: "The ID was signed by an unrecognized root certificate",
|
|
1565
|
-
};
|
|
1566
|
-
}
|
|
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
|
+
};
|
|
1567
1591
|
}
|
|
1568
1592
|
else if (proof.name?.startsWith("sig_check_id_data")) {
|
|
1569
1593
|
commitmentIn = (0, utils_1.getCommitmentInFromIDDataProof)(proofData);
|
|
@@ -1885,7 +1909,7 @@ class ZKPassport {
|
|
|
1885
1909
|
* @returns An object containing the unique identifier associated to the user
|
|
1886
1910
|
* and a boolean indicating whether the proofs were successfully verified.
|
|
1887
1911
|
*/
|
|
1888
|
-
async verify({ proofs, queryResult, validity, scope, }) {
|
|
1912
|
+
async verify({ proofs, queryResult, validity, scope, devMode = false, }) {
|
|
1889
1913
|
const formattedResult = queryResult;
|
|
1890
1914
|
// Make sure to reconvert the dates to Date objects
|
|
1891
1915
|
if (formattedResult.birthdate && formattedResult.birthdate.disclose) {
|
|
@@ -1903,6 +1927,13 @@ class ZKPassport {
|
|
|
1903
1927
|
uniqueIdentifier = uniqueIdentifierFromPublicInputs;
|
|
1904
1928
|
verified = isCorrect;
|
|
1905
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
|
+
}
|
|
1906
1937
|
// Only proceed with the proof verification if the public inputs are correct
|
|
1907
1938
|
if (verified) {
|
|
1908
1939
|
for (const proof of proofs) {
|
|
@@ -1922,6 +1953,7 @@ class ZKPassport {
|
|
|
1922
1953
|
validityPeriodInDays: validity,
|
|
1923
1954
|
domain: this.domain,
|
|
1924
1955
|
scope,
|
|
1956
|
+
devMode,
|
|
1925
1957
|
});
|
|
1926
1958
|
const result = await client.readContract({
|
|
1927
1959
|
address,
|
|
@@ -1969,18 +2001,18 @@ class ZKPassport {
|
|
|
1969
2001
|
if (network === "ethereum_sepolia") {
|
|
1970
2002
|
return {
|
|
1971
2003
|
...baseConfig,
|
|
1972
|
-
address: "
|
|
2004
|
+
address: "0x8c6982D77f7a8f60aE3133cA9b2FAA6f3e78c394",
|
|
1973
2005
|
};
|
|
1974
2006
|
}
|
|
1975
2007
|
else if (network === "local_anvil") {
|
|
1976
2008
|
return {
|
|
1977
2009
|
...baseConfig,
|
|
1978
|
-
address: "
|
|
2010
|
+
address: "0x0",
|
|
1979
2011
|
};
|
|
1980
2012
|
}
|
|
1981
2013
|
throw new Error(`Unsupported network: ${network}`);
|
|
1982
2014
|
}
|
|
1983
|
-
getSolidityVerifierParameters({ proof, validityPeriodInDays = 7, domain, scope, }) {
|
|
2015
|
+
getSolidityVerifierParameters({ proof, validityPeriodInDays = 7, domain, scope, devMode = false, }) {
|
|
1984
2016
|
if (!proof.name?.startsWith("outer_evm")) {
|
|
1985
2017
|
throw new Error("This proof cannot be verified on an EVM chain. Please make sure to use the `compressed-evm` mode.");
|
|
1986
2018
|
}
|
|
@@ -2072,7 +2104,7 @@ class ZKPassport {
|
|
|
2072
2104
|
let committedInputCountsArray = [];
|
|
2073
2105
|
for (const commitment of parameterCommitments) {
|
|
2074
2106
|
const committedInput = committedInputs.find((x) => {
|
|
2075
|
-
const rawHashedInputs = (0,
|
|
2107
|
+
const rawHashedInputs = (0, sha2_1.sha256)((0, utils_3.hexToBytes)(x.inputs));
|
|
2076
2108
|
// Shift the hash 8 bits to the right (1 byte)
|
|
2077
2109
|
// as one byte is dropped in the circuit to fit in the 254-bit field size
|
|
2078
2110
|
const hashedInputs = new Uint8Array(rawHashedInputs.length);
|
|
@@ -2108,6 +2140,7 @@ class ZKPassport {
|
|
|
2108
2140
|
validityPeriodInDays,
|
|
2109
2141
|
scope: domain ?? this.domain,
|
|
2110
2142
|
subscope: scope ?? "",
|
|
2143
|
+
devMode,
|
|
2111
2144
|
};
|
|
2112
2145
|
return params;
|
|
2113
2146
|
}
|