@zkpassport/sdk 0.3.1 → 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.
@@ -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/esm/index.js CHANGED
@@ -9,9 +9,10 @@ import { noLogger as logger } from "./logger";
9
9
  import { inflate } from "pako";
10
10
  import i18en from "i18n-iso-countries/langs/en.json";
11
11
  import { Buffer } from "buffer/";
12
- import { sha256 } from "@noble/hashes/sha256";
12
+ import { sha256 } from "@noble/hashes/sha2";
13
13
  import { hexToBytes } from "@noble/hashes/utils";
14
14
  import ZKPassportVerifierAbi from "./assets/abi/ZKPassportVerifier.json";
15
+ import { RegistryClient } from "@zkpassport/registry";
15
16
  const DEFAULT_DATE_VALUE = new Date(1111, 10, 11);
16
17
  // If Buffer is not defined, then we use the Buffer from the buffer package
17
18
  if (typeof globalThis.Buffer === "undefined") {
@@ -36,9 +37,12 @@ function hasRequestedAccessToField(credentialsRequest, field) {
36
37
  return false;
37
38
  }
38
39
  function normalizeCountry(country) {
40
+ if (country === "Zero Knowledge Republic") {
41
+ return "ZKR";
42
+ }
39
43
  let normalizedCountry;
40
44
  const alpha3 = getAlpha3Code(country, "en");
41
- normalizedCountry = alpha3 || country;
45
+ normalizedCountry = alpha3 || country || "ZKR";
42
46
  return normalizedCountry;
43
47
  }
44
48
  function numericalCompare(fnName, key, value, requestId, requestIdToConfig) {
@@ -96,6 +100,7 @@ export class ZKPassport {
96
100
  queryResult: result,
97
101
  validity: this.topicToLocalConfig[topic]?.validity,
98
102
  scope: this.topicToService[topic]?.scope,
103
+ devMode: this.topicToLocalConfig[topic]?.devMode,
99
104
  });
100
105
  delete this.topicToProofs[topic];
101
106
  const hasFailedProofs = this.topicToFailedProofCount[topic] > 0;
@@ -342,9 +347,10 @@ export class ZKPassport {
342
347
  * @param purpose To explain what you want to do with the user's data
343
348
  * @param scope Scope this request to a specific use case
344
349
  * @param validity How many days ago should have the ID been last scanned by the user?
350
+ * @param devMode Whether to enable dev mode. This will allow you to verify mock proofs (i.e. from ZKR)
345
351
  * @returns The query builder object.
346
352
  */
347
- async request({ name, logo, purpose, scope, mode, validity, topicOverride, keyPairOverride, }) {
353
+ async request({ name, logo, purpose, scope, mode, validity, devMode, topicOverride, keyPairOverride, }) {
348
354
  const topic = topicOverride || randomBytes(16).toString("hex");
349
355
  const keyPair = keyPairOverride || (await generateECDHKeyPair());
350
356
  this.topicToKeyPair[topic] = {
@@ -359,6 +365,7 @@ export class ZKPassport {
359
365
  // Default to 6 months
360
366
  validity: validity || 6 * 30,
361
367
  mode: mode || "fast",
368
+ devMode: devMode || false,
362
369
  };
363
370
  this.onRequestReceivedCallbacks[topic] = [];
364
371
  this.onGeneratingProofCallbacks[topic] = [];
@@ -1257,16 +1264,39 @@ export class ZKPassport {
1257
1264
  }
1258
1265
  return { isCorrect, queryResultErrors };
1259
1266
  }
1267
+ async checkCertificateRegistryRoot(root, queryResultErrors, outer) {
1268
+ let isCorrect = true;
1269
+ try {
1270
+ // Maintained certificate registry settled onchain
1271
+ // Here we use Ethereum Sepolia
1272
+ const registryClient = new RegistryClient({ chainId: 11155111 });
1273
+ await registryClient.getCertificates(`0x${root}`);
1274
+ }
1275
+ catch (error) {
1276
+ console.warn(error);
1277
+ // Check the legacy static roots that were used before the registry was deployed onchain
1278
+ const VALID_CERTIFICATE_REGISTRY_ROOT = [
1279
+ BigInt("20192042006788880778219739574377003123593792072535937278552252195461520776494"),
1280
+ BigInt("21301853597069384763054217328384418971999152625381818922211526730996340553696"),
1281
+ BigInt("10839898448097753834842514286432152806152415606387598803678317315409344029817"),
1282
+ ];
1283
+ if (!VALID_CERTIFICATE_REGISTRY_ROOT.includes(BigInt(root))) {
1284
+ console.warn("The ID was signed by an unrecognized root certificate");
1285
+ isCorrect = false;
1286
+ queryResultErrors[outer ? "outer" : "sig_check_dsc"].certificate = {
1287
+ expected: `A valid root from ZKPassport Registry`,
1288
+ received: `Got invalid certificate registry root: ${root}`,
1289
+ message: "The ID was signed by an unrecognized root certificate",
1290
+ };
1291
+ }
1292
+ }
1293
+ return { isCorrect, queryResultErrors };
1294
+ }
1260
1295
  async checkPublicInputs(proofs, queryResult, validity, scope) {
1261
1296
  let commitmentIn;
1262
1297
  let commitmentOut;
1263
1298
  let isCorrect = true;
1264
1299
  let uniqueIdentifier;
1265
- const VALID_CERTIFICATE_REGISTRY_ROOT = [
1266
- BigInt("20192042006788880778219739574377003123593792072535937278552252195461520776494"),
1267
- BigInt("21301853597069384763054217328384418971999152625381818922211526730996340553696"),
1268
- BigInt("10839898448097753834842514286432152806152415606387598803678317315409344029817"),
1269
- ];
1270
1300
  const currentTime = new Date();
1271
1301
  const today = new Date(currentTime.getFullYear(), currentTime.getMonth(), currentTime.getDate(), 0, 0, 0, 0);
1272
1302
  let queryResultErrors = {
@@ -1314,15 +1344,12 @@ export class ZKPassport {
1314
1344
  if (proof.name?.startsWith("outer")) {
1315
1345
  const isForEVM = proof.name?.startsWith("outer_evm");
1316
1346
  const certificateRegistryRoot = getCertificateRegistryRootFromOuterProof(proofData);
1317
- if (!VALID_CERTIFICATE_REGISTRY_ROOT.includes(certificateRegistryRoot)) {
1318
- console.warn("The ID was signed by an unrecognized root certificate");
1319
- isCorrect = false;
1320
- queryResultErrors.outer.certificate = {
1321
- expected: `Certificate registry root: ${VALID_CERTIFICATE_REGISTRY_ROOT.join(", ")}`,
1322
- received: `Certificate registry root: ${certificateRegistryRoot.toString()}`,
1323
- message: "The ID was signed by an unrecognized root certificate",
1324
- };
1325
- }
1347
+ const { isCorrect: isCorrectCertificateRegistryRoot, queryResultErrors: queryResultErrorsCertificateRegistryRoot, } = await this.checkCertificateRegistryRoot(certificateRegistryRoot.toString(16), queryResultErrors, true);
1348
+ isCorrect = isCorrect && isCorrectCertificateRegistryRoot;
1349
+ queryResultErrors = {
1350
+ ...queryResultErrors,
1351
+ ...queryResultErrorsCertificateRegistryRoot,
1352
+ };
1326
1353
  const currentDate = getCurrentDateFromOuterProof(proofData);
1327
1354
  const todayToCurrentDate = today.getTime() - currentDate.getTime();
1328
1355
  const differenceInDays = validity ?? 180;
@@ -1545,15 +1572,12 @@ export class ZKPassport {
1545
1572
  else if (proof.name?.startsWith("sig_check_dsc")) {
1546
1573
  commitmentOut = getCommitmentFromDSCProof(proofData);
1547
1574
  const merkleRoot = getMerkleRootFromDSCProof(proofData);
1548
- if (!VALID_CERTIFICATE_REGISTRY_ROOT.includes(merkleRoot)) {
1549
- console.warn("The ID was signed by an unrecognized root certificate");
1550
- isCorrect = false;
1551
- queryResultErrors.sig_check_dsc.certificate = {
1552
- expected: `Certificate registry root: ${VALID_CERTIFICATE_REGISTRY_ROOT.join(", ")}`,
1553
- received: `Certificate registry root: ${merkleRoot.toString()}`,
1554
- message: "The ID was signed by an unrecognized root certificate",
1555
- };
1556
- }
1575
+ const { isCorrect: isCorrectCertificateRegistryRoot, queryResultErrors: queryResultErrorsCertificateRegistryRoot, } = await this.checkCertificateRegistryRoot(merkleRoot.toString(16), queryResultErrors, false);
1576
+ isCorrect = isCorrect && isCorrectCertificateRegistryRoot;
1577
+ queryResultErrors = {
1578
+ ...queryResultErrors,
1579
+ ...queryResultErrorsCertificateRegistryRoot,
1580
+ };
1557
1581
  }
1558
1582
  else if (proof.name?.startsWith("sig_check_id_data")) {
1559
1583
  commitmentIn = getCommitmentInFromIDDataProof(proofData);
@@ -1875,7 +1899,7 @@ export class ZKPassport {
1875
1899
  * @returns An object containing the unique identifier associated to the user
1876
1900
  * and a boolean indicating whether the proofs were successfully verified.
1877
1901
  */
1878
- async verify({ proofs, queryResult, validity, scope, }) {
1902
+ async verify({ proofs, queryResult, validity, scope, devMode = false, }) {
1879
1903
  const formattedResult = queryResult;
1880
1904
  // Make sure to reconvert the dates to Date objects
1881
1905
  if (formattedResult.birthdate && formattedResult.birthdate.disclose) {
@@ -1893,6 +1917,13 @@ export class ZKPassport {
1893
1917
  uniqueIdentifier = uniqueIdentifierFromPublicInputs;
1894
1918
  verified = isCorrect;
1895
1919
  queryResultErrors = isCorrect ? undefined : queryResultErrorsFromPublicInputs;
1920
+ if (uniqueIdentifier && BigInt(uniqueIdentifier) === BigInt(0) && !devMode) {
1921
+ // If the unique identifier is 0 and it is not in dev mode,
1922
+ // the proofs are considered invalid as these are mock proofs only meant
1923
+ // for testing purposes
1924
+ verified = false;
1925
+ 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.");
1926
+ }
1896
1927
  // Only proceed with the proof verification if the public inputs are correct
1897
1928
  if (verified) {
1898
1929
  for (const proof of proofs) {
@@ -1912,6 +1943,7 @@ export class ZKPassport {
1912
1943
  validityPeriodInDays: validity,
1913
1944
  domain: this.domain,
1914
1945
  scope,
1946
+ devMode,
1915
1947
  });
1916
1948
  const result = await client.readContract({
1917
1949
  address,
@@ -1959,18 +1991,18 @@ export class ZKPassport {
1959
1991
  if (network === "ethereum_sepolia") {
1960
1992
  return {
1961
1993
  ...baseConfig,
1962
- address: "0x21E12Fa30a1F98699F242ac062Db4a8e7b344B5d",
1994
+ address: "0x8c6982D77f7a8f60aE3133cA9b2FAA6f3e78c394",
1963
1995
  };
1964
1996
  }
1965
1997
  else if (network === "local_anvil") {
1966
1998
  return {
1967
1999
  ...baseConfig,
1968
- address: "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6",
2000
+ address: "0x0",
1969
2001
  };
1970
2002
  }
1971
2003
  throw new Error(`Unsupported network: ${network}`);
1972
2004
  }
1973
- getSolidityVerifierParameters({ proof, validityPeriodInDays = 7, domain, scope, }) {
2005
+ getSolidityVerifierParameters({ proof, validityPeriodInDays = 7, domain, scope, devMode = false, }) {
1974
2006
  if (!proof.name?.startsWith("outer_evm")) {
1975
2007
  throw new Error("This proof cannot be verified on an EVM chain. Please make sure to use the `compressed-evm` mode.");
1976
2008
  }
@@ -2098,6 +2130,7 @@ export class ZKPassport {
2098
2130
  validityPeriodInDays,
2099
2131
  scope: domain ?? this.domain,
2100
2132
  subscope: scope ?? "",
2133
+ devMode,
2101
2134
  };
2102
2135
  return params;
2103
2136
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zkpassport/sdk",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "Privacy-preserving identity verification using passports and ID cards",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "module": "./dist/esm/index.js",
@@ -42,7 +42,8 @@
42
42
  "@noble/ciphers": "^1.2.1",
43
43
  "@noble/hashes": "^1.7.2",
44
44
  "@noble/secp256k1": "^2.2.3",
45
- "@zkpassport/utils": "^0.4.7",
45
+ "@zkpassport/registry": "^0.1.8",
46
+ "@zkpassport/utils": "^0.7.3",
46
47
  "buffer": "^6.0.3",
47
48
  "i18n-iso-countries": "^7.12.0",
48
49
  "pako": "^2.1.0",