@zkpassport/sdk 0.2.9 → 0.2.11

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/src/index.ts CHANGED
@@ -38,8 +38,6 @@ import { createEncryptedJsonRpcRequest } from "./json-rpc"
38
38
  import { decrypt, generateECDHKeyPair, getSharedSecret } from "./encryption"
39
39
  import { noLogger as logger } from "./logger"
40
40
  import { inflate } from "pako"
41
- //import initNoirC from '@noir-lang/noirc_abi'
42
- //import initACVM from '@noir-lang/acvm_js'
43
41
  import i18en from "i18n-iso-countries/langs/en.json"
44
42
  import { Buffer } from "buffer/"
45
43
 
@@ -263,13 +261,19 @@ export type QueryBuilder = {
263
261
  * @param key The attribute to compare.
264
262
  * @param value The list of values to check inclusion against.
265
263
  */
266
- in: <T extends "nationality">(key: T, value: IDCredentialValue<T>[]) => QueryBuilder
264
+ in: <T extends "nationality" | "issuing_country">(
265
+ key: T,
266
+ value: IDCredentialValue<T>[],
267
+ ) => QueryBuilder
267
268
  /**
268
269
  * Requires this attribute to be excluded from the provided list.
269
270
  * @param key The attribute to compare.
270
271
  * @param value The list of values to check exclusion against.
271
272
  */
272
- out: <T extends "nationality">(key: T, value: IDCredentialValue<T>[]) => QueryBuilder
273
+ out: <T extends "nationality" | "issuing_country">(
274
+ key: T,
275
+ value: IDCredentialValue<T>[],
276
+ ) => QueryBuilder
273
277
  /**
274
278
  * Requires this attribute to be disclosed.
275
279
  * @param key The attribute to disclose.
@@ -333,23 +337,17 @@ export class ZKPassport {
333
337
  this.domain = _domain || window.location.hostname
334
338
  }
335
339
 
336
- /*private async initWasmVerifier() {
337
- const acvm = await import('@noir-lang/acvm_js/web/acvm_js_bg.wasm')
338
- const noirc = await import('@noir-lang/noirc_abi/web/noirc_abi_wasm_bg.wasm')
339
- await Promise.all([initACVM(acvm), initNoirC(noirc)])
340
- this.wasmVerifierInit = true
341
- }*/
342
-
343
340
  private async handleResult(topic: string) {
344
341
  const result = this.topicToResults[topic]
345
342
  // Clear the results straight away to avoid concurrency issues
346
343
  delete this.topicToResults[topic]
347
344
  // Verify the proofs and extract the unique identifier (aka nullifier) and the verification result
348
- const { uniqueIdentifier, verified, queryResultErrors } = await this.verify(
349
- topic,
350
- this.topicToProofs[topic],
351
- result,
352
- )
345
+ const { uniqueIdentifier, verified, queryResultErrors } = await this.verify({
346
+ proofs: this.topicToProofs[topic],
347
+ queryResult: result,
348
+ validity: this.topicToLocalConfig[topic]?.validity,
349
+ })
350
+ delete this.topicToProofs[topic]
353
351
  const hasFailedProofs = this.topicToFailedProofCount[topic] > 0
354
352
  await Promise.all(
355
353
  this.onResultCallbacks[topic].map((callback) =>
@@ -399,13 +397,29 @@ export class ZKPassport {
399
397
  }
400
398
  break
401
399
  case "in":
402
- if (field === "nationality" && !neededCircuits.includes("inclusion_check_country")) {
403
- neededCircuits.push("inclusion_check_country")
400
+ if (
401
+ field === "nationality" &&
402
+ !neededCircuits.includes("inclusion_check_nationality")
403
+ ) {
404
+ neededCircuits.push("inclusion_check_nationality")
405
+ } else if (
406
+ field === "issuing_country" &&
407
+ !neededCircuits.includes("inclusion_check_issuing_country")
408
+ ) {
409
+ neededCircuits.push("inclusion_check_issuing_country")
404
410
  }
405
411
  break
406
412
  case "out":
407
- if (field === "nationality" && !neededCircuits.includes("exclusion_check_country")) {
408
- neededCircuits.push("exclusion_check_country")
413
+ if (
414
+ field === "nationality" &&
415
+ !neededCircuits.includes("exclusion_check_nationality")
416
+ ) {
417
+ neededCircuits.push("exclusion_check_nationality")
418
+ } else if (
419
+ field === "issuing_country" &&
420
+ !neededCircuits.includes("exclusion_check_issuing_country")
421
+ ) {
422
+ neededCircuits.push("exclusion_check_issuing_country")
409
423
  }
410
424
  break
411
425
  }
@@ -532,12 +546,12 @@ export class ZKPassport {
532
546
  rangeCompare(key, [start, end], topic, this.topicToConfig)
533
547
  return this.getZkPassportRequest(topic)
534
548
  },
535
- in: <T extends "nationality">(key: T, value: IDCredentialValue<T>[]) => {
549
+ in: <T extends "nationality" | "issuing_country">(key: T, value: IDCredentialValue<T>[]) => {
536
550
  value = value.map((v) => normalizeCountry(v as CountryName)) as IDCredentialValue<T>[]
537
551
  generalCompare("in", key, value, topic, this.topicToConfig)
538
552
  return this.getZkPassportRequest(topic)
539
553
  },
540
- out: <T extends "nationality">(key: T, value: IDCredentialValue<T>[]) => {
554
+ out: <T extends "nationality" | "issuing_country">(key: T, value: IDCredentialValue<T>[]) => {
541
555
  value = value.map((v) => normalizeCountry(v as CountryName)) as IDCredentialValue<T>[]
542
556
  generalCompare("out", key, value, topic, this.topicToConfig)
543
557
  return this.getZkPassportRequest(topic)
@@ -706,7 +720,7 @@ export class ZKPassport {
706
720
  private async checkPublicInputs(
707
721
  proofs: Array<ProofResult>,
708
722
  queryResult: QueryResult,
709
- topic: string,
723
+ validity?: number,
710
724
  ) {
711
725
  let commitmentIn: bigint | undefined
712
726
  let commitmentOut: bigint | undefined
@@ -755,8 +769,10 @@ export class ZKPassport {
755
769
  "compare_age",
756
770
  "compare_birthdate",
757
771
  "compare_expiry",
758
- "exclusion_check_country",
759
- "inclusion_check_country",
772
+ "exclusion_check_nationality",
773
+ "inclusion_check_nationality",
774
+ "exclusion_check_issuing_country",
775
+ "inclusion_check_issuing_country",
760
776
  ]
761
777
  const getIndex = (proof: ProofResult) => {
762
778
  const name = proof.name || ""
@@ -807,16 +823,17 @@ export class ZKPassport {
807
823
  commitmentOut = getCommitmentOutFromIntegrityProof(proofData)
808
824
  const currentDate = getCurrentDateFromIntegrityProof(proofData)
809
825
  const todayToCurrentDate = today.getTime() - currentDate.getTime()
810
- const expectedDifference = this.topicToLocalConfig[topic]?.validity * 86400000
826
+ const differenceInDays = validity ?? 180
827
+ const expectedDifference = differenceInDays * 86400000
811
828
  const actualDifference = today.getTime() - (today.getTime() - expectedDifference)
812
829
  // The ID should not expire within the next 6 months (or whatever the custom value is)
813
830
  if (todayToCurrentDate >= actualDifference) {
814
831
  console.warn(
815
- `The date used to check the validity of the ID is older than ${this.topicToLocalConfig[topic]?.validity} days. You can ask the user to rescan their ID or ask them to disclose their expiry date`,
832
+ `The date used to check the validity of the ID is older than ${differenceInDays} days. You can ask the user to rescan their ID or ask them to disclose their expiry date`,
816
833
  )
817
834
  isCorrect = false
818
835
  queryResultErrors.data_check_integrity.date = {
819
- expected: `Difference: ${this.topicToLocalConfig[topic]?.validity} days`,
836
+ expected: `Difference: ${differenceInDays} days`,
820
837
  received: `Difference: ${Math.round(todayToCurrentDate / 86400000)} days`,
821
838
  message:
822
839
  "The date used to check the validity of the ID is older than the validity period",
@@ -851,7 +868,7 @@ export class ZKPassport {
851
868
  isCorrect = false
852
869
  queryResultErrors.document_type.eq = {
853
870
  expected: `${queryResult.document_type.eq.expected}`,
854
- received: `${disclosedDataPassport.documentType}`,
871
+ received: `${disclosedDataPassport.documentType ?? disclosedDataIDCard.documentType}`,
855
872
  message: "Document type does not match the expected document type",
856
873
  }
857
874
  }
@@ -860,7 +877,7 @@ export class ZKPassport {
860
877
  isCorrect = false
861
878
  queryResultErrors.document_type.disclose = {
862
879
  expected: `${queryResult.document_type.disclose?.result}`,
863
- received: `${disclosedDataIDCard.documentType}`,
880
+ received: `${disclosedDataIDCard.documentType ?? disclosedDataPassport.documentType}`,
864
881
  message: "Document type does not match the disclosed document type in query result",
865
882
  }
866
883
  }
@@ -878,7 +895,7 @@ export class ZKPassport {
878
895
  isCorrect = false
879
896
  queryResultErrors.birthdate.eq = {
880
897
  expected: `${queryResult.birthdate.eq.expected.toISOString()}`,
881
- received: `${birthdatePassport.toISOString()}`,
898
+ received: `${birthdatePassport?.toISOString() ?? birthdateIDCard?.toISOString()}`,
882
899
  message: "Birthdate does not match the expected birthdate",
883
900
  }
884
901
  }
@@ -891,7 +908,7 @@ export class ZKPassport {
891
908
  isCorrect = false
892
909
  queryResultErrors.birthdate.disclose = {
893
910
  expected: `${queryResult.birthdate.disclose.result.toISOString()}`,
894
- received: `${birthdatePassport.toISOString()}`,
911
+ received: `${birthdatePassport?.toISOString() ?? birthdateIDCard?.toISOString()}`,
895
912
  message: "Birthdate does not match the disclosed birthdate in query result",
896
913
  }
897
914
  }
@@ -909,7 +926,7 @@ export class ZKPassport {
909
926
  isCorrect = false
910
927
  queryResultErrors.expiry_date.eq = {
911
928
  expected: `${queryResult.expiry_date.eq.expected.toISOString()}`,
912
- received: `${expiryDatePassport.toISOString()}`,
929
+ received: `${expiryDatePassport?.toISOString() ?? expiryDateIDCard?.toISOString()}`,
913
930
  message: "Expiry date does not match the expected expiry date",
914
931
  }
915
932
  }
@@ -922,7 +939,7 @@ export class ZKPassport {
922
939
  isCorrect = false
923
940
  queryResultErrors.expiry_date.disclose = {
924
941
  expected: `${queryResult.expiry_date.disclose.result.toISOString()}`,
925
- received: `${expiryDatePassport.toISOString()}`,
942
+ received: `${expiryDatePassport?.toISOString() ?? expiryDateIDCard?.toISOString()}`,
926
943
  message: "Expiry date does not match the disclosed expiry date in query result",
927
944
  }
928
945
  }
@@ -940,7 +957,7 @@ export class ZKPassport {
940
957
  isCorrect = false
941
958
  queryResultErrors.nationality.eq = {
942
959
  expected: `${queryResult.nationality.eq.expected}`,
943
- received: `${nationalityPassport}`,
960
+ received: `${nationalityPassport ?? nationalityIDCard}`,
944
961
  message: "Nationality does not match the expected nationality",
945
962
  }
946
963
  }
@@ -953,7 +970,7 @@ export class ZKPassport {
953
970
  isCorrect = false
954
971
  queryResultErrors.nationality.disclose = {
955
972
  expected: `${queryResult.nationality.disclose.result}`,
956
- received: `${nationalityPassport}`,
973
+ received: `${nationalityPassport ?? nationalityIDCard}`,
957
974
  message: "Nationality does not match the disclosed nationality in query result",
958
975
  }
959
976
  }
@@ -971,7 +988,7 @@ export class ZKPassport {
971
988
  isCorrect = false
972
989
  queryResultErrors.document_number.eq = {
973
990
  expected: `${queryResult.document_number.eq.expected}`,
974
- received: `${documentNumberPassport}`,
991
+ received: `${documentNumberPassport ?? documentNumberIDCard}`,
975
992
  message: "Document number does not match the expected document number",
976
993
  }
977
994
  }
@@ -986,7 +1003,7 @@ export class ZKPassport {
986
1003
  isCorrect = false
987
1004
  queryResultErrors.document_number.disclose = {
988
1005
  expected: `${queryResult.document_number.disclose.result}`,
989
- received: `${documentNumberPassport}`,
1006
+ received: `${documentNumberPassport ?? documentNumberIDCard}`,
990
1007
  message:
991
1008
  "Document number does not match the disclosed document number in query result",
992
1009
  }
@@ -1005,7 +1022,7 @@ export class ZKPassport {
1005
1022
  isCorrect = false
1006
1023
  queryResultErrors.gender.eq = {
1007
1024
  expected: `${queryResult.gender.eq.expected}`,
1008
- received: `${genderPassport}`,
1025
+ received: `${genderPassport ?? genderIDCard}`,
1009
1026
  message: "Gender does not match the expected gender",
1010
1027
  }
1011
1028
  }
@@ -1018,7 +1035,7 @@ export class ZKPassport {
1018
1035
  isCorrect = false
1019
1036
  queryResultErrors.gender.disclose = {
1020
1037
  expected: `${queryResult.gender.disclose.result}`,
1021
- received: `${genderPassport}`,
1038
+ received: `${genderPassport ?? genderIDCard}`,
1022
1039
  message: "Gender does not match the disclosed gender in query result",
1023
1040
  }
1024
1041
  }
@@ -1036,7 +1053,7 @@ export class ZKPassport {
1036
1053
  isCorrect = false
1037
1054
  queryResultErrors.issuing_country.eq = {
1038
1055
  expected: `${queryResult.issuing_country.eq.expected}`,
1039
- received: `${issuingCountryPassport}`,
1056
+ received: `${issuingCountryPassport ?? issuingCountryIDCard}`,
1040
1057
  message: "Issuing country does not match the expected issuing country",
1041
1058
  }
1042
1059
  }
@@ -1051,7 +1068,7 @@ export class ZKPassport {
1051
1068
  isCorrect = false
1052
1069
  queryResultErrors.issuing_country.disclose = {
1053
1070
  expected: `${queryResult.issuing_country.disclose.result}`,
1054
- received: `${issuingCountryPassport}`,
1071
+ received: `${issuingCountryPassport ?? issuingCountryIDCard}`,
1055
1072
  message:
1056
1073
  "Issuing country does not match the disclosed issuing country in query result",
1057
1074
  }
@@ -1072,7 +1089,7 @@ export class ZKPassport {
1072
1089
  isCorrect = false
1073
1090
  queryResultErrors.fullname.eq = {
1074
1091
  expected: `${queryResult.fullname.eq.expected}`,
1075
- received: `${fullnamePassport}`,
1092
+ received: `${fullnamePassport ?? fullnameIDCard}`,
1076
1093
  message: "Fullname does not match the expected fullname",
1077
1094
  }
1078
1095
  }
@@ -1087,7 +1104,7 @@ export class ZKPassport {
1087
1104
  isCorrect = false
1088
1105
  queryResultErrors.fullname.disclose = {
1089
1106
  expected: `${queryResult.fullname.disclose.result}`,
1090
- received: `${fullnamePassport}`,
1107
+ received: `${fullnamePassport ?? fullnameIDCard}`,
1091
1108
  message: "Fullname does not match the disclosed fullname in query result",
1092
1109
  }
1093
1110
  }
@@ -1114,7 +1131,7 @@ export class ZKPassport {
1114
1131
  isCorrect = false
1115
1132
  queryResultErrors.firstname.eq = {
1116
1133
  expected: `${queryResult.firstname.eq.expected}`,
1117
- received: `${firstnamePassport}`,
1134
+ received: `${firstnamePassport ?? firstnameIDCard}`,
1118
1135
  message: "Firstname does not match the expected firstname",
1119
1136
  }
1120
1137
  }
@@ -1129,7 +1146,7 @@ export class ZKPassport {
1129
1146
  isCorrect = false
1130
1147
  queryResultErrors.firstname.disclose = {
1131
1148
  expected: `${queryResult.firstname.disclose.result}`,
1132
- received: `${firstnamePassport}`,
1149
+ received: `${firstnamePassport ?? firstnameIDCard}`,
1133
1150
  message: "Firstname does not match the disclosed firstname in query result",
1134
1151
  }
1135
1152
  }
@@ -1156,7 +1173,7 @@ export class ZKPassport {
1156
1173
  isCorrect = false
1157
1174
  queryResultErrors.lastname.eq = {
1158
1175
  expected: `${queryResult.lastname.eq.expected}`,
1159
- received: `${lastnamePassport}`,
1176
+ received: `${lastnamePassport ?? lastnameIDCard}`,
1160
1177
  message: "Lastname does not match the expected lastname",
1161
1178
  }
1162
1179
  }
@@ -1171,7 +1188,7 @@ export class ZKPassport {
1171
1188
  isCorrect = false
1172
1189
  queryResultErrors.lastname.disclose = {
1173
1190
  expected: `${queryResult.lastname.disclose.result}`,
1174
- received: `${lastnamePassport}`,
1191
+ received: `${lastnamePassport ?? lastnameIDCard}`,
1175
1192
  message: "Lastname does not match the disclosed lastname in query result",
1176
1193
  }
1177
1194
  }
@@ -1286,7 +1303,7 @@ export class ZKPassport {
1286
1303
  message: "Current date in the proof is too old",
1287
1304
  }
1288
1305
  }
1289
- uniqueIdentifier = getCommitmentInFromDisclosureProof(proofData).toString(10)
1306
+ uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10)
1290
1307
  } else if (proof.name === "compare_birthdate") {
1291
1308
  commitmentIn = getCommitmentInFromDisclosureProof(proofData)
1292
1309
  if (commitmentIn !== commitmentOut) {
@@ -1378,7 +1395,7 @@ export class ZKPassport {
1378
1395
  message: "Birthdate is not set in the query result",
1379
1396
  }
1380
1397
  }
1381
- uniqueIdentifier = getCommitmentInFromDisclosureProof(proofData).toString(10)
1398
+ uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10)
1382
1399
  } else if (proof.name === "compare_expiry") {
1383
1400
  commitmentIn = getCommitmentInFromDisclosureProof(proofData)
1384
1401
  if (commitmentIn !== commitmentOut) {
@@ -1470,18 +1487,18 @@ export class ZKPassport {
1470
1487
  }
1471
1488
  }
1472
1489
  uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10)
1473
- } else if (proof.name === "exclusion_check_country") {
1490
+ } else if (proof.name === "exclusion_check_nationality") {
1474
1491
  commitmentIn = getCommitmentInFromDisclosureProof(proofData)
1475
1492
  if (commitmentIn !== commitmentOut) {
1476
1493
  console.warn(
1477
- "Failed to check the link between the validity of the ID and the country exclusion check",
1494
+ "Failed to check the link between the validity of the ID and the nationality exclusion check",
1478
1495
  )
1479
1496
  isCorrect = false
1480
1497
  queryResultErrors.nationality.commitment = {
1481
1498
  expected: `Commitment: ${commitmentOut}`,
1482
1499
  received: `Commitment: ${commitmentIn}`,
1483
1500
  message:
1484
- "Failed to check the link between the validity of the ID and the country exclusion check",
1501
+ "Failed to check the link between the validity of the ID and the nationality exclusion check",
1485
1502
  }
1486
1503
  }
1487
1504
  const countryList = getCountryListFromExclusionProof(proofData)
@@ -1493,12 +1510,12 @@ export class ZKPassport {
1493
1510
  if (
1494
1511
  !queryResult.nationality.out.expected?.every((country) => countryList.includes(country))
1495
1512
  ) {
1496
- console.warn("Country exclusion list does not match the one from the query results")
1513
+ console.warn("Nationality exclusion list does not match the one from the query results")
1497
1514
  isCorrect = false
1498
1515
  queryResultErrors.nationality.out = {
1499
1516
  expected: queryResult.nationality.out.expected,
1500
1517
  received: countryList,
1501
- message: "Country exclusion list does not match the one from the query results",
1518
+ message: "Nationality exclusion list does not match the one from the query results",
1502
1519
  }
1503
1520
  }
1504
1521
  } else if (!queryResult.nationality || !queryResult.nationality.out) {
@@ -1524,18 +1541,77 @@ export class ZKPassport {
1524
1541
  }
1525
1542
  }
1526
1543
  uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10)
1527
- } else if (proof.name === "inclusion_check_country") {
1544
+ } else if (proof.name === "exclusion_check_issuing_country") {
1528
1545
  commitmentIn = getCommitmentInFromDisclosureProof(proofData)
1529
1546
  if (commitmentIn !== commitmentOut) {
1530
1547
  console.warn(
1531
- "Failed to check the link between the validity of the ID and the country inclusion check",
1548
+ "Failed to check the link between the validity of the ID and the issuing country exclusion check",
1532
1549
  )
1533
1550
  isCorrect = false
1534
1551
  queryResultErrors.nationality.commitment = {
1535
1552
  expected: `Commitment: ${commitmentOut}`,
1536
1553
  received: `Commitment: ${commitmentIn}`,
1537
1554
  message:
1538
- "Failed to check the link between the validity of the ID and the country inclusion check",
1555
+ "Failed to check the link between the validity of the ID and the issuing country exclusion check",
1556
+ }
1557
+ }
1558
+ const countryList = getCountryListFromExclusionProof(proofData)
1559
+ if (
1560
+ queryResult.issuing_country &&
1561
+ queryResult.issuing_country.out &&
1562
+ queryResult.issuing_country.out.result
1563
+ ) {
1564
+ if (
1565
+ !queryResult.issuing_country.out.expected?.every((country) =>
1566
+ countryList.includes(country),
1567
+ )
1568
+ ) {
1569
+ console.warn(
1570
+ "Issuing country exclusion list does not match the one from the query results",
1571
+ )
1572
+ isCorrect = false
1573
+ queryResultErrors.issuing_country.out = {
1574
+ expected: queryResult.issuing_country.out.expected,
1575
+ received: countryList,
1576
+ message:
1577
+ "Issuing country exclusion list does not match the one from the query results",
1578
+ }
1579
+ }
1580
+ } else if (!queryResult.issuing_country || !queryResult.issuing_country.out) {
1581
+ console.warn("Issuing country exclusion is not set in the query result")
1582
+ isCorrect = false
1583
+ queryResultErrors.issuing_country.out = {
1584
+ message: "Issuing country exclusion is not set in the query result",
1585
+ }
1586
+ }
1587
+ // Check the countryList is in ascending order
1588
+ // If the prover doesn't use a sorted list then the proof cannot be trusted
1589
+ // as it is requirement in the circuit for the exclusion check to work
1590
+ for (let i = 1; i < countryList.length; i++) {
1591
+ if (countryList[i] < countryList[i - 1]) {
1592
+ console.warn(
1593
+ "The issuing country exclusion list has not been sorted, and thus the proof cannot be trusted",
1594
+ )
1595
+ isCorrect = false
1596
+ queryResultErrors.issuing_country.out = {
1597
+ message:
1598
+ "The issuing country exclusion list has not been sorted, and thus the proof cannot be trusted",
1599
+ }
1600
+ }
1601
+ }
1602
+ uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10)
1603
+ } else if (proof.name === "inclusion_check_nationality") {
1604
+ commitmentIn = getCommitmentInFromDisclosureProof(proofData)
1605
+ if (commitmentIn !== commitmentOut) {
1606
+ console.warn(
1607
+ "Failed to check the link between the validity of the ID and the nationality inclusion check",
1608
+ )
1609
+ isCorrect = false
1610
+ queryResultErrors.nationality.commitment = {
1611
+ expected: `Commitment: ${commitmentOut}`,
1612
+ received: `Commitment: ${commitmentIn}`,
1613
+ message:
1614
+ "Failed to check the link between the validity of the ID and the nationality inclusion check",
1539
1615
  }
1540
1616
  }
1541
1617
  const countryList = getCountryListFromInclusionProof(proofData)
@@ -1547,12 +1623,12 @@ export class ZKPassport {
1547
1623
  if (
1548
1624
  !queryResult.nationality.in.expected?.every((country) => countryList.includes(country))
1549
1625
  ) {
1550
- console.warn("Country inclusion list does not match the one from the query results")
1626
+ console.warn("Nationality inclusion list does not match the one from the query results")
1551
1627
  isCorrect = false
1552
1628
  queryResultErrors.nationality.in = {
1553
1629
  expected: queryResult.nationality.in.expected,
1554
1630
  received: countryList,
1555
- message: "Country inclusion list does not match the one from the query results",
1631
+ message: "Nationality inclusion list does not match the one from the query results",
1556
1632
  }
1557
1633
  }
1558
1634
  } else if (!queryResult.nationality || !queryResult.nationality.in) {
@@ -1563,6 +1639,50 @@ export class ZKPassport {
1563
1639
  }
1564
1640
  }
1565
1641
  uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10)
1642
+ } else if (proof.name === "inclusion_check_issuing_country") {
1643
+ commitmentIn = getCommitmentInFromDisclosureProof(proofData)
1644
+ if (commitmentIn !== commitmentOut) {
1645
+ console.warn(
1646
+ "Failed to check the link between the validity of the ID and the issuing country inclusion check",
1647
+ )
1648
+ isCorrect = false
1649
+ queryResultErrors.nationality.commitment = {
1650
+ expected: `Commitment: ${commitmentOut}`,
1651
+ received: `Commitment: ${commitmentIn}`,
1652
+ message:
1653
+ "Failed to check the link between the validity of the ID and the issuing country inclusion check",
1654
+ }
1655
+ }
1656
+ const countryList = getCountryListFromInclusionProof(proofData)
1657
+ if (
1658
+ queryResult.issuing_country &&
1659
+ queryResult.issuing_country.in &&
1660
+ queryResult.issuing_country.in.result
1661
+ ) {
1662
+ if (
1663
+ !queryResult.issuing_country.in.expected?.every((country) =>
1664
+ countryList.includes(country),
1665
+ )
1666
+ ) {
1667
+ console.warn(
1668
+ "Issuing country inclusion list does not match the one from the query results",
1669
+ )
1670
+ isCorrect = false
1671
+ queryResultErrors.issuing_country.in = {
1672
+ expected: queryResult.issuing_country.in.expected,
1673
+ received: countryList,
1674
+ message:
1675
+ "Issuing country inclusion list does not match the one from the query results",
1676
+ }
1677
+ }
1678
+ } else if (!queryResult.issuing_country || !queryResult.issuing_country.in) {
1679
+ console.warn("Issuing country inclusion is not set in the query result")
1680
+ isCorrect = false
1681
+ queryResultErrors.issuing_country.in = {
1682
+ message: "Issuing country inclusion is not set in the query result",
1683
+ }
1684
+ }
1685
+ uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10)
1566
1686
  }
1567
1687
  }
1568
1688
  return { isCorrect, uniqueIdentifier, queryResultErrors }
@@ -1570,47 +1690,41 @@ export class ZKPassport {
1570
1690
 
1571
1691
  /**
1572
1692
  * @notice Verify the proofs received from the mobile app.
1573
- * @param requestId The request ID.
1574
1693
  * @param proofs The proofs to verify.
1575
1694
  * @param queryResult The query result to verify against
1695
+ * @param validity How many days ago should have the ID been last scanned by the user?
1576
1696
  * @returns An object containing the unique identifier associated to the user
1577
1697
  * and a boolean indicating whether the proofs were successfully verified.
1578
1698
  */
1579
- public async verify(
1580
- requestId: string,
1581
- proofs?: Array<ProofResult>,
1582
- queryResult?: QueryResult,
1583
- ): Promise<{
1699
+ public async verify({
1700
+ proofs,
1701
+ queryResult,
1702
+ validity,
1703
+ }: {
1704
+ proofs: Array<ProofResult>
1705
+ queryResult: QueryResult
1706
+ validity?: number
1707
+ }): Promise<{
1584
1708
  uniqueIdentifier: string | undefined
1585
1709
  verified: boolean
1586
1710
  queryResultErrors?: QueryResultErrors
1587
1711
  }> {
1588
- let proofsToVerify = proofs
1589
- // There is a minimum of 4 subproofs to make a complete proof
1590
- if (!proofs || proofs.length < 4) {
1591
- proofsToVerify = this.topicToProofs[requestId]
1592
- }
1593
1712
  const { BarretenbergVerifier } = await import("@aztec/bb.js")
1594
1713
  const verifier = new BarretenbergVerifier()
1595
- /*if (!this.wasmVerifierInit) {
1596
- await this.initWasmVerifier()
1597
- }*/
1598
1714
  let verified = true
1599
1715
  let uniqueIdentifier: string | undefined
1600
1716
  let queryResultErrors: QueryResultErrors | undefined
1601
- if (queryResult) {
1602
- const {
1603
- isCorrect,
1604
- uniqueIdentifier: uniqueIdentifierFromPublicInputs,
1605
- queryResultErrors: queryResultErrorsFromPublicInputs,
1606
- } = await this.checkPublicInputs(proofsToVerify!, queryResult!, requestId)
1607
- uniqueIdentifier = uniqueIdentifierFromPublicInputs
1608
- verified = isCorrect
1609
- queryResultErrors = isCorrect ? undefined : queryResultErrorsFromPublicInputs
1610
- }
1717
+ const {
1718
+ isCorrect,
1719
+ uniqueIdentifier: uniqueIdentifierFromPublicInputs,
1720
+ queryResultErrors: queryResultErrorsFromPublicInputs,
1721
+ } = await this.checkPublicInputs(proofs, queryResult, validity)
1722
+ uniqueIdentifier = uniqueIdentifierFromPublicInputs
1723
+ verified = isCorrect
1724
+ queryResultErrors = isCorrect ? undefined : queryResultErrorsFromPublicInputs
1611
1725
  // Only proceed with the proof verification if the public inputs are correct
1612
- if (verified && queryResult) {
1613
- for (const proof of proofsToVerify!) {
1726
+ if (verified) {
1727
+ for (const proof of proofs) {
1614
1728
  const proofData = getProofData(proof.proof as string, true)
1615
1729
  const hostedPackagedCircuit = await getHostedPackagedCircuitByName(
1616
1730
  proof.version as any,
@@ -1630,7 +1744,8 @@ export class ZKPassport {
1630
1744
  }
1631
1745
  }
1632
1746
  }
1633
- this.topicToProofs[requestId] = []
1747
+ // If the proofs are not verified, we don't return the unique identifier
1748
+ uniqueIdentifier = verified ? uniqueIdentifier : undefined
1634
1749
  return { uniqueIdentifier, verified, queryResultErrors }
1635
1750
  }
1636
1751