@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.
@@ -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 sha256_1 = require("@noble/hashes/sha256");
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
- if (!VALID_CERTIFICATE_REGISTRY_ROOT.includes(certificateRegistryRoot)) {
1328
- console.warn("The ID was signed by an unrecognized root certificate");
1329
- isCorrect = false;
1330
- queryResultErrors.outer.certificate = {
1331
- expected: `Certificate registry root: ${VALID_CERTIFICATE_REGISTRY_ROOT.join(", ")}`,
1332
- received: `Certificate registry root: ${certificateRegistryRoot.toString()}`,
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
- if (!VALID_CERTIFICATE_REGISTRY_ROOT.includes(merkleRoot)) {
1559
- console.warn("The ID was signed by an unrecognized root certificate");
1560
- isCorrect = false;
1561
- queryResultErrors.sig_check_dsc.certificate = {
1562
- expected: `Certificate registry root: ${VALID_CERTIFICATE_REGISTRY_ROOT.join(", ")}`,
1563
- received: `Certificate registry root: ${merkleRoot.toString()}`,
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: "0x21E12Fa30a1F98699F242ac062Db4a8e7b344B5d",
2004
+ address: "0x8c6982D77f7a8f60aE3133cA9b2FAA6f3e78c394",
1973
2005
  };
1974
2006
  }
1975
2007
  else if (network === "local_anvil") {
1976
2008
  return {
1977
2009
  ...baseConfig,
1978
- address: "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6",
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, sha256_1.sha256)((0, utils_3.hexToBytes)(x.inputs));
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
  }