@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.
@@ -1,11 +1,11 @@
1
- import { type DisclosableIDCredential, type IDCredential, type IDCredentialValue, type NumericalIDCredential, type ProofResult, type QueryResult, ProofMode } from "@zkpassport/utils";
1
+ import { type DisclosableIDCredential, type IDCredential, type IDCredentialValue, type NumericalIDCredential, type ProofResult, type QueryResult, ProofMode, BoundData } from "@zkpassport/utils";
2
2
  export type QueryResultError<T> = {
3
3
  expected?: T;
4
4
  received?: T;
5
5
  message: string;
6
6
  };
7
7
  export type QueryResultErrors = {
8
- [key in IDCredential | "sig_check_dsc" | "sig_check_id_data" | "data_check_integrity" | "outer" | "disclose"]: {
8
+ [key in IDCredential | "sig_check_dsc" | "sig_check_id_data" | "data_check_integrity" | "outer" | "disclose" | "bind"]: {
9
9
  disclose?: QueryResultError<string | number | Date>;
10
10
  gte?: QueryResultError<number | Date>;
11
11
  lte?: QueryResultError<number | Date>;
@@ -150,6 +150,12 @@ export type QueryBuilder = {
150
150
  * @param key The attribute to disclose.
151
151
  */
152
152
  disclose: (key: DisclosableIDCredential) => QueryBuilder;
153
+ /**
154
+ * Binds a value to the request.
155
+ * @param key The key of the value to bind.
156
+ * @param value The value to bind the request to.
157
+ */
158
+ bind: (key: keyof BoundData, value: BoundData[keyof BoundData]) => QueryBuilder;
153
159
  /**
154
160
  * Builds the request.
155
161
  *
@@ -224,6 +230,7 @@ export declare class ZKPassport {
224
230
  private checkIssuingCountryInclusionPublicInputs;
225
231
  private checkScopeFromDisclosureProof;
226
232
  private checkCertificateRegistryRoot;
233
+ private checkBindPublicInputs;
227
234
  private checkPublicInputs;
228
235
  /**
229
236
  * @notice Verify the proofs received from the mobile app.
package/dist/esm/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { getAlpha3Code, registerLocale } from "i18n-iso-countries";
2
- import { getProofData, getCommitmentFromDSCProof, getCommitmentInFromIDDataProof, getCommitmentOutFromIDDataProof, getNullifierFromDisclosureProof, getCommitmentInFromIntegrityProof, getCommitmentOutFromIntegrityProof, getCommitmentInFromDisclosureProof, getMerkleRootFromDSCProof, getCurrentDateFromIntegrityProof, DisclosedData, formatName, getHostedPackagedCircuitByName, getNumberOfPublicInputs, getParameterCommitmentFromDisclosureProof, getCountryParameterCommitment, getDiscloseParameterCommitment, getDateParameterCommitment, getCertificateRegistryRootFromOuterProof, getParamCommitmentsFromOuterProof, getCurrentDateFromCommittedInputs, getMinAgeFromCommittedInputs, getMaxAgeFromCommittedInputs, getAgeParameterCommitment, getMinDateFromCommittedInputs, getMaxDateFromCommittedInputs, getCurrentDateFromOuterProof, getNullifierFromOuterProof, getAgeEVMParameterCommitment, getDateEVMParameterCommitment, getDiscloseEVMParameterCommitment, getCountryEVMParameterCommitment, rightPadArrayWithZeros, getCommittedInputCount, ProofType, getScopeHash, getScopeFromOuterProof, getSubscopeFromOuterProof, getServiceScopeHash, } from "@zkpassport/utils";
2
+ import { getProofData, getCommitmentFromDSCProof, getCommitmentInFromIDDataProof, getCommitmentOutFromIDDataProof, getNullifierFromDisclosureProof, getCommitmentInFromIntegrityProof, getCommitmentOutFromIntegrityProof, getCommitmentInFromDisclosureProof, getMerkleRootFromDSCProof, getCurrentDateFromIntegrityProof, DisclosedData, formatName, getHostedPackagedCircuitByName, getNumberOfPublicInputs, getParameterCommitmentFromDisclosureProof, getCountryParameterCommitment, getDiscloseParameterCommitment, getDateParameterCommitment, getCertificateRegistryRootFromOuterProof, getParamCommitmentsFromOuterProof, getCurrentDateFromCommittedInputs, getMinAgeFromCommittedInputs, getMaxAgeFromCommittedInputs, getAgeParameterCommitment, getMinDateFromCommittedInputs, getMaxDateFromCommittedInputs, getCurrentDateFromOuterProof, getNullifierFromOuterProof, getAgeEVMParameterCommitment, getDateEVMParameterCommitment, getDiscloseEVMParameterCommitment, getCountryEVMParameterCommitment, rightPadArrayWithZeros, getCommittedInputCount, ProofType, getScopeHash, getScopeFromOuterProof, getSubscopeFromOuterProof, getServiceScopeHash, getBindEVMParameterCommitment, getBindParameterCommitment, formatBoundData, } from "@zkpassport/utils";
3
3
  import { bytesToHex } from "@noble/ciphers/utils";
4
4
  import { noLogger as logger } from "./logger";
5
5
  import i18en from "i18n-iso-countries/langs/en.json";
@@ -191,6 +191,9 @@ export class ZKPassport {
191
191
  }
192
192
  }
193
193
  }
194
+ if (this.topicToConfig[topic].bind) {
195
+ neededCircuits.push("bind");
196
+ }
194
197
  // From the circuits needed, determine the expected proof count
195
198
  // There are at least 4 proofs, 3 base proofs and 1 disclosure proof minimum
196
199
  // Each separate needed circuit adds 1 disclosure proof
@@ -313,6 +316,13 @@ export class ZKPassport {
313
316
  };
314
317
  return this.getZkPassportRequest(topic);
315
318
  },
319
+ bind: (key, value) => {
320
+ this.topicToConfig[topic].bind = {
321
+ ...this.topicToConfig[topic].bind,
322
+ [key]: value,
323
+ };
324
+ return this.getZkPassportRequest(topic);
325
+ },
316
326
  done: () => {
317
327
  const base64Config = Buffer.from(JSON.stringify(this.topicToConfig[topic])).toString("base64");
318
328
  const base64Service = Buffer.from(JSON.stringify(this.topicToService[topic])).toString("base64");
@@ -409,6 +419,7 @@ export class ZKPassport {
409
419
  fullname: {},
410
420
  document_number: {},
411
421
  outer: {},
422
+ bind: {},
412
423
  };
413
424
  let isCorrect = true;
414
425
  // We can't be certain that the disclosed data is for a passport or an ID card
@@ -721,6 +732,7 @@ export class ZKPassport {
721
732
  fullname: {},
722
733
  document_number: {},
723
734
  outer: {},
735
+ bind: {},
724
736
  };
725
737
  let isCorrect = true;
726
738
  const currentTime = new Date();
@@ -830,6 +842,7 @@ export class ZKPassport {
830
842
  fullname: {},
831
843
  document_number: {},
832
844
  outer: {},
845
+ bind: {},
833
846
  };
834
847
  let isCorrect = true;
835
848
  const currentTime = new Date();
@@ -933,6 +946,7 @@ export class ZKPassport {
933
946
  fullname: {},
934
947
  document_number: {},
935
948
  outer: {},
949
+ bind: {},
936
950
  };
937
951
  let isCorrect = true;
938
952
  const currentTime = new Date();
@@ -1036,6 +1050,7 @@ export class ZKPassport {
1036
1050
  fullname: {},
1037
1051
  document_number: {},
1038
1052
  outer: {},
1053
+ bind: {},
1039
1054
  };
1040
1055
  let isCorrect = true;
1041
1056
  if (queryResult.nationality &&
@@ -1090,6 +1105,7 @@ export class ZKPassport {
1090
1105
  fullname: {},
1091
1106
  document_number: {},
1092
1107
  outer: {},
1108
+ bind: {},
1093
1109
  };
1094
1110
  let isCorrect = true;
1095
1111
  if (queryResult.issuing_country &&
@@ -1144,6 +1160,7 @@ export class ZKPassport {
1144
1160
  fullname: {},
1145
1161
  document_number: {},
1146
1162
  outer: {},
1163
+ bind: {},
1147
1164
  };
1148
1165
  let isCorrect = true;
1149
1166
  if (queryResult.nationality &&
@@ -1186,6 +1203,7 @@ export class ZKPassport {
1186
1203
  fullname: {},
1187
1204
  document_number: {},
1188
1205
  outer: {},
1206
+ bind: {},
1189
1207
  };
1190
1208
  let isCorrect = true;
1191
1209
  if (queryResult.issuing_country &&
@@ -1261,6 +1279,51 @@ export class ZKPassport {
1261
1279
  }
1262
1280
  return { isCorrect, queryResultErrors };
1263
1281
  }
1282
+ checkBindPublicInputs(queryResult, boundData) {
1283
+ const queryResultErrors = {
1284
+ sig_check_dsc: {},
1285
+ sig_check_id_data: {},
1286
+ data_check_integrity: {},
1287
+ disclose: {},
1288
+ age: {},
1289
+ birthdate: {},
1290
+ expiry_date: {},
1291
+ document_type: {},
1292
+ issuing_country: {},
1293
+ gender: {},
1294
+ nationality: {},
1295
+ firstname: {},
1296
+ lastname: {},
1297
+ fullname: {},
1298
+ document_number: {},
1299
+ outer: {},
1300
+ bind: {},
1301
+ };
1302
+ let isCorrect = true;
1303
+ if (queryResult.bind) {
1304
+ if (queryResult.bind.user_address?.toLowerCase().replace("0x", "") !==
1305
+ boundData.user_address?.toLowerCase().replace("0x", "")) {
1306
+ console.warn("Bound user address does not match the one from the query results");
1307
+ isCorrect = false;
1308
+ queryResultErrors.bind.eq = {
1309
+ expected: queryResult.bind.user_address,
1310
+ received: boundData.user_address,
1311
+ message: "Bound user address does not match the one from the query results",
1312
+ };
1313
+ }
1314
+ if (queryResult.bind.custom_data?.trim().toLowerCase() !==
1315
+ boundData.custom_data?.trim().toLowerCase()) {
1316
+ console.warn("Bound custom data does not match the one from the query results");
1317
+ isCorrect = false;
1318
+ queryResultErrors.bind.eq = {
1319
+ expected: queryResult.bind.custom_data,
1320
+ received: boundData.custom_data,
1321
+ message: "Bound custom data does not match the one from the query results",
1322
+ };
1323
+ }
1324
+ }
1325
+ return { isCorrect, queryResultErrors };
1326
+ }
1264
1327
  async checkPublicInputs(proofs, queryResult, validity, scope, chainId) {
1265
1328
  let commitmentIn;
1266
1329
  let commitmentOut;
@@ -1285,6 +1348,7 @@ export class ZKPassport {
1285
1348
  fullname: {},
1286
1349
  document_number: {},
1287
1350
  outer: {},
1351
+ bind: {},
1288
1352
  };
1289
1353
  // Since the order is important for the commitments, we need to sort the proofs
1290
1354
  // by their expected order: root signature check -> ID signature check -> integrity check -> disclosure
@@ -1301,6 +1365,7 @@ export class ZKPassport {
1301
1365
  "inclusion_check_nationality",
1302
1366
  "exclusion_check_issuing_country",
1303
1367
  "inclusion_check_issuing_country",
1368
+ "bind",
1304
1369
  ];
1305
1370
  const getIndex = (proof) => {
1306
1371
  const name = proof.name || "";
@@ -1537,6 +1602,27 @@ export class ZKPassport {
1537
1602
  ...queryResultErrorsIssuingCountryExclusion,
1538
1603
  };
1539
1604
  }
1605
+ else if (!!committedInputs?.bind) {
1606
+ const bindCommittedInputs = committedInputs?.bind;
1607
+ const bindParameterCommitment = isForEVM
1608
+ ? await getBindEVMParameterCommitment(formatBoundData(bindCommittedInputs.data))
1609
+ : await getBindParameterCommitment(formatBoundData(bindCommittedInputs.data));
1610
+ if (!paramCommitments.includes(bindParameterCommitment)) {
1611
+ console.warn("This proof does not verify the bound data");
1612
+ isCorrect = false;
1613
+ queryResultErrors.bind.commitment = {
1614
+ expected: `Bind parameter commitment: ${bindParameterCommitment.toString()}`,
1615
+ received: `Parameter commitments included: ${paramCommitments.join(", ")}`,
1616
+ message: "This proof does not verify the bound data",
1617
+ };
1618
+ }
1619
+ const { isCorrect: isCorrectBind, queryResultErrors: queryResultErrorsBind } = this.checkBindPublicInputs(queryResult, bindCommittedInputs.data);
1620
+ isCorrect = isCorrect && isCorrectBind;
1621
+ queryResultErrors = {
1622
+ ...queryResultErrors,
1623
+ ...queryResultErrorsBind,
1624
+ };
1625
+ }
1540
1626
  uniqueIdentifier = getNullifierFromOuterProof(proofData).toString(10);
1541
1627
  }
1542
1628
  else if (proof.name?.startsWith("sig_check_dsc")) {
@@ -1858,6 +1944,27 @@ export class ZKPassport {
1858
1944
  };
1859
1945
  uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10);
1860
1946
  }
1947
+ else if (proof.name === "bind") {
1948
+ const bindCommittedInputs = proof.committedInputs?.bind;
1949
+ const paramCommittment = getParameterCommitmentFromDisclosureProof(proofData);
1950
+ const calculatedParamCommitment = await getBindParameterCommitment(formatBoundData(bindCommittedInputs.data));
1951
+ if (paramCommittment !== calculatedParamCommitment) {
1952
+ console.warn("The bound data does not match the one from the proof");
1953
+ isCorrect = false;
1954
+ queryResultErrors.bind.commitment = {
1955
+ expected: `Commitment: ${calculatedParamCommitment}`,
1956
+ received: `Commitment: ${paramCommittment}`,
1957
+ message: "The bound data does not match the one from the proof",
1958
+ };
1959
+ }
1960
+ const { isCorrect: isCorrectBind, queryResultErrors: queryResultErrorsBind } = this.checkBindPublicInputs(queryResult, bindCommittedInputs.data);
1961
+ isCorrect = isCorrect && isCorrectBind;
1962
+ queryResultErrors = {
1963
+ ...queryResultErrors,
1964
+ ...queryResultErrorsBind,
1965
+ };
1966
+ uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10);
1967
+ }
1861
1968
  }
1862
1969
  return { isCorrect, uniqueIdentifier, queryResultErrors };
1863
1970
  }
@@ -1973,7 +2080,7 @@ export class ZKPassport {
1973
2080
  if (network === "ethereum_sepolia") {
1974
2081
  return {
1975
2082
  ...baseConfig,
1976
- address: "0xDfE02DFd5c208854884B58bFf6522De5c42F73E3",
2083
+ address: "0x5e4B11F7B7995F5Cee0134692a422b045091112F",
1977
2084
  };
1978
2085
  }
1979
2086
  else if (network === "local_anvil") {
@@ -2066,6 +2173,14 @@ export class ZKPassport {
2066
2173
  value.discloseMask.map((x) => x.toString(16).padStart(2, "0")).join("") +
2067
2174
  value.disclosedBytes.map((x) => x.toString(16).padStart(2, "0")).join("");
2068
2175
  }
2176
+ else if (circuitName === "bind_evm") {
2177
+ const value = proof.committedInputs[circuitName];
2178
+ compressedCommittedInputs =
2179
+ ProofType.BIND.toString(16).padStart(2, "0") +
2180
+ rightPadArrayWithZeros(formatBoundData(value.data), 500)
2181
+ .map((x) => x.toString(16).padStart(2, "0"))
2182
+ .join("");
2183
+ }
2069
2184
  else {
2070
2185
  throw new Error(`Unsupported circuit for EVM verification: ${circuitName}`);
2071
2186
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zkpassport/sdk",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
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",
@@ -44,7 +44,7 @@
44
44
  "@noble/secp256k1": "^2.2.3",
45
45
  "@obsidion/bridge": "^0.9.0",
46
46
  "@zkpassport/registry": "^0.1.9",
47
- "@zkpassport/utils": "^0.8.2",
47
+ "@zkpassport/utils": "^0.9.4",
48
48
  "buffer": "^6.0.3",
49
49
  "i18n-iso-countries": "^7.12.0",
50
50
  "pako": "^2.1.0",