@zkpassport/sdk 0.2.14 → 0.3.0
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 +555 -0
- package/dist/cjs/index.d.ts +39 -3
- package/dist/cjs/index.js +1428 -676
- package/dist/esm/assets/abi/ZKPassportVerifier.json +555 -0
- package/dist/esm/index.d.ts +39 -3
- package/dist/esm/index.js +1422 -670
- package/package.json +5 -3
- package/src/assets/abi/ZKPassportVerifier.json +555 -0
- package/src/index.ts +1828 -821
package/src/index.ts
CHANGED
|
@@ -20,17 +20,39 @@ import {
|
|
|
20
20
|
getCommitmentInFromDisclosureProof,
|
|
21
21
|
getMerkleRootFromDSCProof,
|
|
22
22
|
getCurrentDateFromIntegrityProof,
|
|
23
|
-
getMaxAgeFromProof,
|
|
24
|
-
getMinAgeFromProof,
|
|
25
|
-
getCurrentDateFromAgeProof,
|
|
26
|
-
getMinDateFromProof,
|
|
27
|
-
getMaxDateFromProof,
|
|
28
|
-
getCountryListFromExclusionProof,
|
|
29
|
-
getCountryListFromInclusionProof,
|
|
30
23
|
DisclosedData,
|
|
31
24
|
formatName,
|
|
32
25
|
getHostedPackagedCircuitByName,
|
|
33
26
|
Query,
|
|
27
|
+
getNumberOfPublicInputs,
|
|
28
|
+
getParameterCommitmentFromDisclosureProof,
|
|
29
|
+
getCountryParameterCommitment,
|
|
30
|
+
getDiscloseParameterCommitment,
|
|
31
|
+
getDateParameterCommitment,
|
|
32
|
+
getFormattedDate,
|
|
33
|
+
getCertificateRegistryRootFromOuterProof,
|
|
34
|
+
getParamCommitmentsFromOuterProof,
|
|
35
|
+
AgeCommittedInputs,
|
|
36
|
+
DiscloseCommittedInputs,
|
|
37
|
+
getCurrentDateFromCommittedInputs,
|
|
38
|
+
getMinAgeFromCommittedInputs,
|
|
39
|
+
getMaxAgeFromCommittedInputs,
|
|
40
|
+
getAgeParameterCommitment,
|
|
41
|
+
DateCommittedInputs,
|
|
42
|
+
CountryCommittedInputs,
|
|
43
|
+
getMinDateFromCommittedInputs,
|
|
44
|
+
getMaxDateFromCommittedInputs,
|
|
45
|
+
getCurrentDateFromOuterProof,
|
|
46
|
+
getNullifierFromOuterProof,
|
|
47
|
+
DisclosureCircuitName,
|
|
48
|
+
getAgeEVMParameterCommitment,
|
|
49
|
+
getDateEVMParameterCommitment,
|
|
50
|
+
getDiscloseEVMParameterCommitment,
|
|
51
|
+
getCountryEVMParameterCommitment,
|
|
52
|
+
rightPadArrayWithZeros,
|
|
53
|
+
getCommittedInputCount,
|
|
54
|
+
ProofMode,
|
|
55
|
+
ProofType,
|
|
34
56
|
} from "@zkpassport/utils"
|
|
35
57
|
import { bytesToHex } from "@noble/ciphers/utils"
|
|
36
58
|
import { getWebSocketClient, WebSocketClient } from "./websocket"
|
|
@@ -40,6 +62,11 @@ import { noLogger as logger } from "./logger"
|
|
|
40
62
|
import { inflate } from "pako"
|
|
41
63
|
import i18en from "i18n-iso-countries/langs/en.json"
|
|
42
64
|
import { Buffer } from "buffer/"
|
|
65
|
+
import { sha256 } from "@noble/hashes/sha256"
|
|
66
|
+
import { hexToBytes } from "@noble/hashes/utils"
|
|
67
|
+
import ZKPassportVerifierAbi from "./assets/abi/ZKPassportVerifier.json"
|
|
68
|
+
|
|
69
|
+
const DEFAULT_DATE_VALUE = new Date(1111, 10, 11)
|
|
43
70
|
|
|
44
71
|
// If Buffer is not defined, then we use the Buffer from the buffer package
|
|
45
72
|
if (typeof globalThis.Buffer === "undefined") {
|
|
@@ -61,6 +88,7 @@ export type QueryResultErrors = {
|
|
|
61
88
|
| "sig_check_dsc"
|
|
62
89
|
| "sig_check_id_data"
|
|
63
90
|
| "data_check_integrity"
|
|
91
|
+
| "outer"
|
|
64
92
|
| "disclose"]: {
|
|
65
93
|
disclose?: QueryResultError<string | number | Date>
|
|
66
94
|
gte?: QueryResultError<number | Date>
|
|
@@ -76,6 +104,17 @@ export type QueryResultErrors = {
|
|
|
76
104
|
}
|
|
77
105
|
}
|
|
78
106
|
|
|
107
|
+
export type SolidityVerifierParameters = {
|
|
108
|
+
vkeyHash: string
|
|
109
|
+
proof: string
|
|
110
|
+
publicInputs: string[]
|
|
111
|
+
committedInputs: string
|
|
112
|
+
committedInputCounts: number[]
|
|
113
|
+
validityPeriodInDays: number
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export type EVMChain = "ethereum_sepolia" | "local_anvil"
|
|
117
|
+
|
|
79
118
|
registerLocale(i18en)
|
|
80
119
|
|
|
81
120
|
function hasRequestedAccessToField(credentialsRequest: Query, field: IDCredential): boolean {
|
|
@@ -296,6 +335,7 @@ export class ZKPassport {
|
|
|
296
335
|
string,
|
|
297
336
|
{
|
|
298
337
|
validity: number
|
|
338
|
+
mode: ProofMode
|
|
299
339
|
}
|
|
300
340
|
> = {}
|
|
301
341
|
private topicToKeyPair: Record<string, { privateKey: Uint8Array; publicKey: Uint8Array }> = {}
|
|
@@ -367,6 +407,11 @@ export class ZKPassport {
|
|
|
367
407
|
}
|
|
368
408
|
|
|
369
409
|
private setExpectedProofCount(topic: string) {
|
|
410
|
+
// If the mode is not fast, we'll receive only 1 compressed proof
|
|
411
|
+
if (this.topicToLocalConfig[topic].mode !== "fast") {
|
|
412
|
+
this.topicToExpectedProofCount[topic] = 1
|
|
413
|
+
return
|
|
414
|
+
}
|
|
370
415
|
const fields = Object.keys(this.topicToConfig[topic] as Query).filter((key) =>
|
|
371
416
|
hasRequestedAccessToField(this.topicToConfig[topic] as Query, key as IDCredential),
|
|
372
417
|
)
|
|
@@ -454,7 +499,13 @@ export class ZKPassport {
|
|
|
454
499
|
logger.debug(`User generated proof`)
|
|
455
500
|
// Uncompress the proof and convert it to a hex string
|
|
456
501
|
const bytesProof = Buffer.from(request.params.proof, "base64")
|
|
502
|
+
const bytesCommittedInputs = request.params.committedInputs
|
|
503
|
+
? Buffer.from(request.params.committedInputs, "base64")
|
|
504
|
+
: null
|
|
457
505
|
const uncompressedProof = inflate(bytesProof)
|
|
506
|
+
const uncompressedCommittedInputs = bytesCommittedInputs
|
|
507
|
+
? inflate(bytesCommittedInputs)
|
|
508
|
+
: null
|
|
458
509
|
// The gzip lib in the app compress the proof as ASCII
|
|
459
510
|
// and since the app passes the proof as a hex string, we can
|
|
460
511
|
// just decode the bytes as hex characters using the TextDecoder
|
|
@@ -464,6 +515,9 @@ export class ZKPassport {
|
|
|
464
515
|
vkeyHash: request.params.vkeyHash,
|
|
465
516
|
name: request.params.name,
|
|
466
517
|
version: request.params.version,
|
|
518
|
+
committedInputs: uncompressedCommittedInputs
|
|
519
|
+
? JSON.parse(new TextDecoder().decode(uncompressedCommittedInputs))
|
|
520
|
+
: undefined,
|
|
467
521
|
}
|
|
468
522
|
this.topicToProofs[topic].push(processedProof)
|
|
469
523
|
await Promise.all(
|
|
@@ -585,7 +639,7 @@ export class ZKPassport {
|
|
|
585
639
|
const pubkey = bytesToHex(this.topicToKeyPair[topic].publicKey)
|
|
586
640
|
this.setExpectedProofCount(topic)
|
|
587
641
|
return {
|
|
588
|
-
url: `https://zkpassport.id/r?d=${this.domain}&t=${topic}&c=${base64Config}&s=${base64Service}&p=${pubkey}`,
|
|
642
|
+
url: `https://zkpassport.id/r?d=${this.domain}&t=${topic}&c=${base64Config}&s=${base64Service}&p=${pubkey}&m=${this.topicToLocalConfig[topic].mode}`,
|
|
589
643
|
requestId: topic,
|
|
590
644
|
onRequestReceived: (callback: () => void) =>
|
|
591
645
|
this.onRequestReceivedCallbacks[topic].push(callback),
|
|
@@ -627,6 +681,7 @@ export class ZKPassport {
|
|
|
627
681
|
logo,
|
|
628
682
|
purpose,
|
|
629
683
|
scope,
|
|
684
|
+
mode,
|
|
630
685
|
validity,
|
|
631
686
|
topicOverride,
|
|
632
687
|
keyPairOverride,
|
|
@@ -635,6 +690,7 @@ export class ZKPassport {
|
|
|
635
690
|
logo: string
|
|
636
691
|
purpose: string
|
|
637
692
|
scope?: string
|
|
693
|
+
mode?: ProofMode
|
|
638
694
|
validity?: number
|
|
639
695
|
topicOverride?: string
|
|
640
696
|
keyPairOverride?: { privateKey: Uint8Array; publicKey: Uint8Array }
|
|
@@ -654,6 +710,7 @@ export class ZKPassport {
|
|
|
654
710
|
this.topicToLocalConfig[topic] = {
|
|
655
711
|
// Default to 6 months
|
|
656
712
|
validity: validity || 6 * 30,
|
|
713
|
+
mode: mode || "fast",
|
|
657
714
|
}
|
|
658
715
|
|
|
659
716
|
this.onRequestReceivedCallbacks[topic] = []
|
|
@@ -729,31 +786,7 @@ export class ZKPassport {
|
|
|
729
786
|
return this.getZkPassportRequest(topic)
|
|
730
787
|
}
|
|
731
788
|
|
|
732
|
-
private
|
|
733
|
-
proofs: Array<ProofResult>,
|
|
734
|
-
queryResult: QueryResult,
|
|
735
|
-
validity?: number,
|
|
736
|
-
) {
|
|
737
|
-
let commitmentIn: bigint | undefined
|
|
738
|
-
let commitmentOut: bigint | undefined
|
|
739
|
-
let isCorrect = true
|
|
740
|
-
let uniqueIdentifier: string | undefined
|
|
741
|
-
const VALID_CERTIFICATE_REGISTRY_ROOT = [
|
|
742
|
-
BigInt("20192042006788880778219739574377003123593792072535937278552252195461520776494"),
|
|
743
|
-
BigInt("21301853597069384763054217328384418971999152625381818922211526730996340553696"),
|
|
744
|
-
BigInt("10839898448097753834842514286432152806152415606387598803678317315409344029817"),
|
|
745
|
-
]
|
|
746
|
-
const defaultDateValue = new Date(1111, 10, 11)
|
|
747
|
-
const currentTime = new Date()
|
|
748
|
-
const today = new Date(
|
|
749
|
-
currentTime.getFullYear(),
|
|
750
|
-
currentTime.getMonth(),
|
|
751
|
-
currentTime.getDate(),
|
|
752
|
-
0,
|
|
753
|
-
0,
|
|
754
|
-
0,
|
|
755
|
-
0,
|
|
756
|
-
)
|
|
789
|
+
private checkDiscloseBytesPublicInputs(proof: ProofResult, queryResult: QueryResult) {
|
|
757
790
|
const queryResultErrors: QueryResultErrors = {
|
|
758
791
|
sig_check_dsc: {},
|
|
759
792
|
sig_check_id_data: {},
|
|
@@ -770,553 +803,1445 @@ export class ZKPassport {
|
|
|
770
803
|
lastname: {},
|
|
771
804
|
fullname: {},
|
|
772
805
|
document_number: {},
|
|
806
|
+
outer: {},
|
|
773
807
|
}
|
|
774
|
-
|
|
775
|
-
//
|
|
776
|
-
//
|
|
777
|
-
const
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
808
|
+
let isCorrect = true
|
|
809
|
+
// We can't be certain that the disclosed data is for a passport or an ID card
|
|
810
|
+
// so we need to check both (unless the document type is revealed)
|
|
811
|
+
const disclosedDataPassport = DisclosedData.fromDisclosedBytes(
|
|
812
|
+
(proof.committedInputs?.disclose_bytes as DiscloseCommittedInputs).disclosedBytes!,
|
|
813
|
+
"passport",
|
|
814
|
+
)
|
|
815
|
+
const disclosedDataIDCard = DisclosedData.fromDisclosedBytes(
|
|
816
|
+
(proof.committedInputs?.disclose_bytes as DiscloseCommittedInputs).disclosedBytes!,
|
|
817
|
+
"id_card",
|
|
818
|
+
)
|
|
819
|
+
if (queryResult.document_type) {
|
|
820
|
+
// Document type is always at the same index in the disclosed data
|
|
821
|
+
if (
|
|
822
|
+
queryResult.document_type.eq &&
|
|
823
|
+
queryResult.document_type.eq.result &&
|
|
824
|
+
queryResult.document_type.eq.expected !== disclosedDataPassport.documentType
|
|
825
|
+
) {
|
|
826
|
+
console.warn("Document type does not match the expected document type")
|
|
827
|
+
isCorrect = false
|
|
828
|
+
queryResultErrors.document_type.eq = {
|
|
829
|
+
expected: `${queryResult.document_type.eq.expected}`,
|
|
830
|
+
received: `${disclosedDataPassport.documentType ?? disclosedDataIDCard.documentType}`,
|
|
831
|
+
message: "Document type does not match the expected document type",
|
|
832
|
+
}
|
|
794
833
|
}
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
const merkleRoot = getMerkleRootFromDSCProof(proofData)
|
|
803
|
-
if (!VALID_CERTIFICATE_REGISTRY_ROOT.includes(merkleRoot)) {
|
|
804
|
-
console.warn("The ID was signed by an unrecognized root certificate")
|
|
805
|
-
isCorrect = false
|
|
806
|
-
queryResultErrors.sig_check_dsc.certificate = {
|
|
807
|
-
expected: `Certificate registry root: ${VALID_CERTIFICATE_REGISTRY_ROOT.join(", ")}`,
|
|
808
|
-
received: `Certificate registry root: ${merkleRoot.toString()}`,
|
|
809
|
-
message: "The ID was signed by an unrecognized root certificate",
|
|
810
|
-
}
|
|
834
|
+
if (queryResult.document_type.disclose?.result !== disclosedDataIDCard.documentType) {
|
|
835
|
+
console.warn("Document type does not match the disclosed document type in query result")
|
|
836
|
+
isCorrect = false
|
|
837
|
+
queryResultErrors.document_type.disclose = {
|
|
838
|
+
expected: `${queryResult.document_type.disclose?.result}`,
|
|
839
|
+
received: `${disclosedDataIDCard.documentType ?? disclosedDataPassport.documentType}`,
|
|
840
|
+
message: "Document type does not match the disclosed document type in query result",
|
|
811
841
|
}
|
|
812
|
-
}
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
if (queryResult.birthdate) {
|
|
845
|
+
const birthdatePassport = disclosedDataPassport.dateOfBirth
|
|
846
|
+
const birthdateIDCard = disclosedDataIDCard.dateOfBirth
|
|
847
|
+
if (
|
|
848
|
+
queryResult.birthdate.eq &&
|
|
849
|
+
queryResult.birthdate.eq.result &&
|
|
850
|
+
queryResult.birthdate.eq.expected.getTime() !== birthdatePassport.getTime() &&
|
|
851
|
+
queryResult.birthdate.eq.expected.getTime() !== birthdateIDCard.getTime()
|
|
852
|
+
) {
|
|
853
|
+
console.warn("Birthdate does not match the expected birthdate")
|
|
854
|
+
isCorrect = false
|
|
855
|
+
queryResultErrors.birthdate.eq = {
|
|
856
|
+
expected: `${queryResult.birthdate.eq.expected.toISOString()}`,
|
|
857
|
+
received: `${birthdatePassport?.toISOString() ?? birthdateIDCard?.toISOString()}`,
|
|
858
|
+
message: "Birthdate does not match the expected birthdate",
|
|
824
859
|
}
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
}
|
|
860
|
+
}
|
|
861
|
+
if (
|
|
862
|
+
queryResult.birthdate.disclose &&
|
|
863
|
+
queryResult.birthdate.disclose.result.getTime() !== birthdatePassport.getTime() &&
|
|
864
|
+
queryResult.birthdate.disclose.result.getTime() !== birthdateIDCard.getTime()
|
|
865
|
+
) {
|
|
866
|
+
console.warn("Birthdate does not match the disclosed birthdate in query result")
|
|
867
|
+
isCorrect = false
|
|
868
|
+
queryResultErrors.birthdate.disclose = {
|
|
869
|
+
expected: `${queryResult.birthdate.disclose.result.toISOString()}`,
|
|
870
|
+
received: `${birthdatePassport?.toISOString() ?? birthdateIDCard?.toISOString()}`,
|
|
871
|
+
message: "Birthdate does not match the disclosed birthdate in query result",
|
|
836
872
|
}
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
}
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
if (queryResult.expiry_date) {
|
|
876
|
+
const expiryDatePassport = disclosedDataPassport.dateOfExpiry
|
|
877
|
+
const expiryDateIDCard = disclosedDataIDCard.dateOfExpiry
|
|
878
|
+
if (
|
|
879
|
+
queryResult.expiry_date.eq &&
|
|
880
|
+
queryResult.expiry_date.eq.result &&
|
|
881
|
+
queryResult.expiry_date.eq.expected.getTime() !== expiryDatePassport.getTime() &&
|
|
882
|
+
queryResult.expiry_date.eq.expected.getTime() !== expiryDateIDCard.getTime()
|
|
883
|
+
) {
|
|
884
|
+
console.warn("Expiry date does not match the expected expiry date")
|
|
885
|
+
isCorrect = false
|
|
886
|
+
queryResultErrors.expiry_date.eq = {
|
|
887
|
+
expected: `${queryResult.expiry_date.eq.expected.toISOString()}`,
|
|
888
|
+
received: `${expiryDatePassport?.toISOString() ?? expiryDateIDCard?.toISOString()}`,
|
|
889
|
+
message: "Expiry date does not match the expected expiry date",
|
|
855
890
|
}
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
}
|
|
891
|
+
}
|
|
892
|
+
if (
|
|
893
|
+
queryResult.expiry_date.disclose &&
|
|
894
|
+
queryResult.expiry_date.disclose.result.getTime() !== expiryDatePassport.getTime() &&
|
|
895
|
+
queryResult.expiry_date.disclose.result.getTime() !== expiryDateIDCard.getTime()
|
|
896
|
+
) {
|
|
897
|
+
console.warn("Expiry date does not match the disclosed expiry date in query result")
|
|
898
|
+
isCorrect = false
|
|
899
|
+
queryResultErrors.expiry_date.disclose = {
|
|
900
|
+
expected: `${queryResult.expiry_date.disclose.result.toISOString()}`,
|
|
901
|
+
received: `${expiryDatePassport?.toISOString() ?? expiryDateIDCard?.toISOString()}`,
|
|
902
|
+
message: "Expiry date does not match the disclosed expiry date in query result",
|
|
869
903
|
}
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
}
|
|
888
|
-
}
|
|
889
|
-
if (queryResult.document_type.disclose?.result !== disclosedDataIDCard.documentType) {
|
|
890
|
-
console.warn("Document type does not match the disclosed document type in query result")
|
|
891
|
-
isCorrect = false
|
|
892
|
-
queryResultErrors.document_type.disclose = {
|
|
893
|
-
expected: `${queryResult.document_type.disclose?.result}`,
|
|
894
|
-
received: `${disclosedDataIDCard.documentType ?? disclosedDataPassport.documentType}`,
|
|
895
|
-
message: "Document type does not match the disclosed document type in query result",
|
|
896
|
-
}
|
|
897
|
-
}
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
if (queryResult.nationality) {
|
|
907
|
+
const nationalityPassport = disclosedDataPassport.nationality
|
|
908
|
+
const nationalityIDCard = disclosedDataIDCard.nationality
|
|
909
|
+
if (
|
|
910
|
+
queryResult.nationality.eq &&
|
|
911
|
+
queryResult.nationality.eq.result &&
|
|
912
|
+
queryResult.nationality.eq.expected !== nationalityPassport &&
|
|
913
|
+
queryResult.nationality.eq.expected !== nationalityIDCard
|
|
914
|
+
) {
|
|
915
|
+
console.warn("Nationality does not match the expected nationality")
|
|
916
|
+
isCorrect = false
|
|
917
|
+
queryResultErrors.nationality.eq = {
|
|
918
|
+
expected: `${queryResult.nationality.eq.expected}`,
|
|
919
|
+
received: `${nationalityPassport ?? nationalityIDCard}`,
|
|
920
|
+
message: "Nationality does not match the expected nationality",
|
|
898
921
|
}
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
expected: `${queryResult.birthdate.eq.expected.toISOString()}`,
|
|
912
|
-
received: `${birthdatePassport?.toISOString() ?? birthdateIDCard?.toISOString()}`,
|
|
913
|
-
message: "Birthdate does not match the expected birthdate",
|
|
914
|
-
}
|
|
915
|
-
}
|
|
916
|
-
if (
|
|
917
|
-
queryResult.birthdate.disclose &&
|
|
918
|
-
queryResult.birthdate.disclose.result.getTime() !== birthdatePassport.getTime() &&
|
|
919
|
-
queryResult.birthdate.disclose.result.getTime() !== birthdateIDCard.getTime()
|
|
920
|
-
) {
|
|
921
|
-
console.warn("Birthdate does not match the disclosed birthdate in query result")
|
|
922
|
-
isCorrect = false
|
|
923
|
-
queryResultErrors.birthdate.disclose = {
|
|
924
|
-
expected: `${queryResult.birthdate.disclose.result.toISOString()}`,
|
|
925
|
-
received: `${birthdatePassport?.toISOString() ?? birthdateIDCard?.toISOString()}`,
|
|
926
|
-
message: "Birthdate does not match the disclosed birthdate in query result",
|
|
927
|
-
}
|
|
928
|
-
}
|
|
922
|
+
}
|
|
923
|
+
if (
|
|
924
|
+
queryResult.nationality.disclose &&
|
|
925
|
+
queryResult.nationality.disclose.result !== nationalityPassport &&
|
|
926
|
+
queryResult.nationality.disclose.result !== nationalityIDCard
|
|
927
|
+
) {
|
|
928
|
+
console.warn("Nationality does not match the disclosed nationality in query result")
|
|
929
|
+
isCorrect = false
|
|
930
|
+
queryResultErrors.nationality.disclose = {
|
|
931
|
+
expected: `${queryResult.nationality.disclose.result}`,
|
|
932
|
+
received: `${nationalityPassport ?? nationalityIDCard}`,
|
|
933
|
+
message: "Nationality does not match the disclosed nationality in query result",
|
|
929
934
|
}
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
if (
|
|
948
|
-
queryResult.expiry_date.disclose &&
|
|
949
|
-
queryResult.expiry_date.disclose.result.getTime() !== expiryDatePassport.getTime() &&
|
|
950
|
-
queryResult.expiry_date.disclose.result.getTime() !== expiryDateIDCard.getTime()
|
|
951
|
-
) {
|
|
952
|
-
console.warn("Expiry date does not match the disclosed expiry date in query result")
|
|
953
|
-
isCorrect = false
|
|
954
|
-
queryResultErrors.expiry_date.disclose = {
|
|
955
|
-
expected: `${queryResult.expiry_date.disclose.result.toISOString()}`,
|
|
956
|
-
received: `${expiryDatePassport?.toISOString() ?? expiryDateIDCard?.toISOString()}`,
|
|
957
|
-
message: "Expiry date does not match the disclosed expiry date in query result",
|
|
958
|
-
}
|
|
959
|
-
}
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
if (queryResult.document_number) {
|
|
938
|
+
const documentNumberPassport = disclosedDataPassport.documentNumber
|
|
939
|
+
const documentNumberIDCard = disclosedDataIDCard.documentNumber
|
|
940
|
+
if (
|
|
941
|
+
queryResult.document_number.eq &&
|
|
942
|
+
queryResult.document_number.eq.result &&
|
|
943
|
+
queryResult.document_number.eq.expected !== documentNumberPassport &&
|
|
944
|
+
queryResult.document_number.eq.expected !== documentNumberIDCard
|
|
945
|
+
) {
|
|
946
|
+
console.warn("Document number does not match the expected document number")
|
|
947
|
+
isCorrect = false
|
|
948
|
+
queryResultErrors.document_number.eq = {
|
|
949
|
+
expected: `${queryResult.document_number.eq.expected}`,
|
|
950
|
+
received: `${documentNumberPassport ?? documentNumberIDCard}`,
|
|
951
|
+
message: "Document number does not match the expected document number",
|
|
960
952
|
}
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
expected: `${queryResult.nationality.eq.expected}`,
|
|
974
|
-
received: `${nationalityPassport ?? nationalityIDCard}`,
|
|
975
|
-
message: "Nationality does not match the expected nationality",
|
|
976
|
-
}
|
|
977
|
-
}
|
|
978
|
-
if (
|
|
979
|
-
queryResult.nationality.disclose &&
|
|
980
|
-
queryResult.nationality.disclose.result !== nationalityPassport &&
|
|
981
|
-
queryResult.nationality.disclose.result !== nationalityIDCard
|
|
982
|
-
) {
|
|
983
|
-
console.warn("Nationality does not match the disclosed nationality in query result")
|
|
984
|
-
isCorrect = false
|
|
985
|
-
queryResultErrors.nationality.disclose = {
|
|
986
|
-
expected: `${queryResult.nationality.disclose.result}`,
|
|
987
|
-
received: `${nationalityPassport ?? nationalityIDCard}`,
|
|
988
|
-
message: "Nationality does not match the disclosed nationality in query result",
|
|
989
|
-
}
|
|
990
|
-
}
|
|
953
|
+
}
|
|
954
|
+
if (
|
|
955
|
+
queryResult.document_number.disclose &&
|
|
956
|
+
queryResult.document_number.disclose.result !== documentNumberPassport &&
|
|
957
|
+
queryResult.document_number.disclose.result !== documentNumberIDCard
|
|
958
|
+
) {
|
|
959
|
+
console.warn("Document number does not match the disclosed document number in query result")
|
|
960
|
+
isCorrect = false
|
|
961
|
+
queryResultErrors.document_number.disclose = {
|
|
962
|
+
expected: `${queryResult.document_number.disclose.result}`,
|
|
963
|
+
received: `${documentNumberPassport ?? documentNumberIDCard}`,
|
|
964
|
+
message: "Document number does not match the disclosed document number in query result",
|
|
991
965
|
}
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
if (
|
|
1010
|
-
queryResult.document_number.disclose &&
|
|
1011
|
-
queryResult.document_number.disclose.result !== documentNumberPassport &&
|
|
1012
|
-
queryResult.document_number.disclose.result !== documentNumberIDCard
|
|
1013
|
-
) {
|
|
1014
|
-
console.warn(
|
|
1015
|
-
"Document number does not match the disclosed document number in query result",
|
|
1016
|
-
)
|
|
1017
|
-
isCorrect = false
|
|
1018
|
-
queryResultErrors.document_number.disclose = {
|
|
1019
|
-
expected: `${queryResult.document_number.disclose.result}`,
|
|
1020
|
-
received: `${documentNumberPassport ?? documentNumberIDCard}`,
|
|
1021
|
-
message:
|
|
1022
|
-
"Document number does not match the disclosed document number in query result",
|
|
1023
|
-
}
|
|
1024
|
-
}
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
if (queryResult.gender) {
|
|
969
|
+
const genderPassport = disclosedDataPassport.gender
|
|
970
|
+
const genderIDCard = disclosedDataIDCard.gender
|
|
971
|
+
if (
|
|
972
|
+
queryResult.gender.eq &&
|
|
973
|
+
queryResult.gender.eq.result &&
|
|
974
|
+
queryResult.gender.eq.expected !== genderPassport &&
|
|
975
|
+
queryResult.gender.eq.expected !== genderIDCard
|
|
976
|
+
) {
|
|
977
|
+
console.warn("Gender does not match the expected gender")
|
|
978
|
+
isCorrect = false
|
|
979
|
+
queryResultErrors.gender.eq = {
|
|
980
|
+
expected: `${queryResult.gender.eq.expected}`,
|
|
981
|
+
received: `${genderPassport ?? genderIDCard}`,
|
|
982
|
+
message: "Gender does not match the expected gender",
|
|
1025
983
|
}
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
expected: `${queryResult.gender.eq.expected}`,
|
|
1039
|
-
received: `${genderPassport ?? genderIDCard}`,
|
|
1040
|
-
message: "Gender does not match the expected gender",
|
|
1041
|
-
}
|
|
1042
|
-
}
|
|
1043
|
-
if (
|
|
1044
|
-
queryResult.gender.disclose &&
|
|
1045
|
-
queryResult.gender.disclose.result !== genderPassport &&
|
|
1046
|
-
queryResult.gender.disclose.result !== genderIDCard
|
|
1047
|
-
) {
|
|
1048
|
-
console.warn("Gender does not match the disclosed gender in query result")
|
|
1049
|
-
isCorrect = false
|
|
1050
|
-
queryResultErrors.gender.disclose = {
|
|
1051
|
-
expected: `${queryResult.gender.disclose.result}`,
|
|
1052
|
-
received: `${genderPassport ?? genderIDCard}`,
|
|
1053
|
-
message: "Gender does not match the disclosed gender in query result",
|
|
1054
|
-
}
|
|
1055
|
-
}
|
|
984
|
+
}
|
|
985
|
+
if (
|
|
986
|
+
queryResult.gender.disclose &&
|
|
987
|
+
queryResult.gender.disclose.result !== genderPassport &&
|
|
988
|
+
queryResult.gender.disclose.result !== genderIDCard
|
|
989
|
+
) {
|
|
990
|
+
console.warn("Gender does not match the disclosed gender in query result")
|
|
991
|
+
isCorrect = false
|
|
992
|
+
queryResultErrors.gender.disclose = {
|
|
993
|
+
expected: `${queryResult.gender.disclose.result}`,
|
|
994
|
+
received: `${genderPassport ?? genderIDCard}`,
|
|
995
|
+
message: "Gender does not match the disclosed gender in query result",
|
|
1056
996
|
}
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
if (
|
|
1075
|
-
queryResult.issuing_country.disclose &&
|
|
1076
|
-
queryResult.issuing_country.disclose.result !== issuingCountryPassport &&
|
|
1077
|
-
queryResult.issuing_country.disclose.result !== issuingCountryIDCard
|
|
1078
|
-
) {
|
|
1079
|
-
console.warn(
|
|
1080
|
-
"Issuing country does not match the disclosed issuing country in query result",
|
|
1081
|
-
)
|
|
1082
|
-
isCorrect = false
|
|
1083
|
-
queryResultErrors.issuing_country.disclose = {
|
|
1084
|
-
expected: `${queryResult.issuing_country.disclose.result}`,
|
|
1085
|
-
received: `${issuingCountryPassport ?? issuingCountryIDCard}`,
|
|
1086
|
-
message:
|
|
1087
|
-
"Issuing country does not match the disclosed issuing country in query result",
|
|
1088
|
-
}
|
|
1089
|
-
}
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
if (queryResult.issuing_country) {
|
|
1000
|
+
const issuingCountryPassport = disclosedDataPassport.issuingCountry
|
|
1001
|
+
const issuingCountryIDCard = disclosedDataIDCard.issuingCountry
|
|
1002
|
+
if (
|
|
1003
|
+
queryResult.issuing_country.eq &&
|
|
1004
|
+
queryResult.issuing_country.eq.result &&
|
|
1005
|
+
queryResult.issuing_country.eq.expected !== issuingCountryPassport &&
|
|
1006
|
+
queryResult.issuing_country.eq.expected !== issuingCountryIDCard
|
|
1007
|
+
) {
|
|
1008
|
+
console.warn("Issuing country does not match the expected issuing country")
|
|
1009
|
+
isCorrect = false
|
|
1010
|
+
queryResultErrors.issuing_country.eq = {
|
|
1011
|
+
expected: `${queryResult.issuing_country.eq.expected}`,
|
|
1012
|
+
received: `${issuingCountryPassport ?? issuingCountryIDCard}`,
|
|
1013
|
+
message: "Issuing country does not match the expected issuing country",
|
|
1090
1014
|
}
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
isCorrect = false
|
|
1104
|
-
queryResultErrors.fullname.eq = {
|
|
1105
|
-
expected: `${queryResult.fullname.eq.expected}`,
|
|
1106
|
-
received: `${fullnamePassport ?? fullnameIDCard}`,
|
|
1107
|
-
message: "Fullname does not match the expected fullname",
|
|
1108
|
-
}
|
|
1109
|
-
}
|
|
1110
|
-
if (
|
|
1111
|
-
queryResult.fullname.disclose &&
|
|
1112
|
-
formatName(queryResult.fullname.disclose.result).toLowerCase() !==
|
|
1113
|
-
fullnamePassport.toLowerCase() &&
|
|
1114
|
-
formatName(queryResult.fullname.disclose.result).toLowerCase() !==
|
|
1115
|
-
fullnameIDCard.toLowerCase()
|
|
1116
|
-
) {
|
|
1117
|
-
console.warn("Fullname does not match the disclosed fullname in query result")
|
|
1118
|
-
isCorrect = false
|
|
1119
|
-
queryResultErrors.fullname.disclose = {
|
|
1120
|
-
expected: `${queryResult.fullname.disclose.result}`,
|
|
1121
|
-
received: `${fullnamePassport ?? fullnameIDCard}`,
|
|
1122
|
-
message: "Fullname does not match the disclosed fullname in query result",
|
|
1123
|
-
}
|
|
1124
|
-
}
|
|
1015
|
+
}
|
|
1016
|
+
if (
|
|
1017
|
+
queryResult.issuing_country.disclose &&
|
|
1018
|
+
queryResult.issuing_country.disclose.result !== issuingCountryPassport &&
|
|
1019
|
+
queryResult.issuing_country.disclose.result !== issuingCountryIDCard
|
|
1020
|
+
) {
|
|
1021
|
+
console.warn("Issuing country does not match the disclosed issuing country in query result")
|
|
1022
|
+
isCorrect = false
|
|
1023
|
+
queryResultErrors.issuing_country.disclose = {
|
|
1024
|
+
expected: `${queryResult.issuing_country.disclose.result}`,
|
|
1025
|
+
received: `${issuingCountryPassport ?? issuingCountryIDCard}`,
|
|
1026
|
+
message: "Issuing country does not match the disclosed issuing country in query result",
|
|
1125
1027
|
}
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
console.warn("Firstname does not match the expected firstname")
|
|
1145
|
-
isCorrect = false
|
|
1146
|
-
queryResultErrors.firstname.eq = {
|
|
1147
|
-
expected: `${queryResult.firstname.eq.expected}`,
|
|
1148
|
-
received: `${firstnamePassport ?? firstnameIDCard}`,
|
|
1149
|
-
message: "Firstname does not match the expected firstname",
|
|
1150
|
-
}
|
|
1151
|
-
}
|
|
1152
|
-
if (
|
|
1153
|
-
queryResult.firstname.disclose &&
|
|
1154
|
-
formatName(queryResult.firstname.disclose.result).toLowerCase() !==
|
|
1155
|
-
firstnamePassport.toLowerCase() &&
|
|
1156
|
-
formatName(queryResult.firstname.disclose.result).toLowerCase() !==
|
|
1157
|
-
firstnameIDCard.toLowerCase()
|
|
1158
|
-
) {
|
|
1159
|
-
console.warn("Firstname does not match the disclosed firstname in query result")
|
|
1160
|
-
isCorrect = false
|
|
1161
|
-
queryResultErrors.firstname.disclose = {
|
|
1162
|
-
expected: `${queryResult.firstname.disclose.result}`,
|
|
1163
|
-
received: `${firstnamePassport ?? firstnameIDCard}`,
|
|
1164
|
-
message: "Firstname does not match the disclosed firstname in query result",
|
|
1165
|
-
}
|
|
1166
|
-
}
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
if (queryResult.fullname) {
|
|
1031
|
+
const fullnamePassport = disclosedDataPassport.name
|
|
1032
|
+
const fullnameIDCard = disclosedDataIDCard.name
|
|
1033
|
+
if (
|
|
1034
|
+
queryResult.fullname.eq &&
|
|
1035
|
+
queryResult.fullname.eq.result &&
|
|
1036
|
+
formatName(queryResult.fullname.eq.expected).toLowerCase() !==
|
|
1037
|
+
fullnamePassport.toLowerCase() &&
|
|
1038
|
+
formatName(queryResult.fullname.eq.expected).toLowerCase() !== fullnameIDCard.toLowerCase()
|
|
1039
|
+
) {
|
|
1040
|
+
console.warn("Fullname does not match the expected fullname")
|
|
1041
|
+
isCorrect = false
|
|
1042
|
+
queryResultErrors.fullname.eq = {
|
|
1043
|
+
expected: `${queryResult.fullname.eq.expected}`,
|
|
1044
|
+
received: `${fullnamePassport ?? fullnameIDCard}`,
|
|
1045
|
+
message: "Fullname does not match the expected fullname",
|
|
1167
1046
|
}
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
lastnamePassport.toLowerCase() &&
|
|
1183
|
-
formatName(queryResult.lastname.eq.expected).toLowerCase() !==
|
|
1184
|
-
lastnameIDCard.toLowerCase()
|
|
1185
|
-
) {
|
|
1186
|
-
console.warn("Lastname does not match the expected lastname")
|
|
1187
|
-
isCorrect = false
|
|
1188
|
-
queryResultErrors.lastname.eq = {
|
|
1189
|
-
expected: `${queryResult.lastname.eq.expected}`,
|
|
1190
|
-
received: `${lastnamePassport ?? lastnameIDCard}`,
|
|
1191
|
-
message: "Lastname does not match the expected lastname",
|
|
1192
|
-
}
|
|
1193
|
-
}
|
|
1194
|
-
if (
|
|
1195
|
-
queryResult.lastname.disclose &&
|
|
1196
|
-
formatName(queryResult.lastname.disclose.result).toLowerCase() !==
|
|
1197
|
-
lastnamePassport.toLowerCase() &&
|
|
1198
|
-
formatName(queryResult.lastname.disclose.result).toLowerCase() !==
|
|
1199
|
-
lastnameIDCard.toLowerCase()
|
|
1200
|
-
) {
|
|
1201
|
-
console.warn("Lastname does not match the disclosed lastname in query result")
|
|
1202
|
-
isCorrect = false
|
|
1203
|
-
queryResultErrors.lastname.disclose = {
|
|
1204
|
-
expected: `${queryResult.lastname.disclose.result}`,
|
|
1205
|
-
received: `${lastnamePassport ?? lastnameIDCard}`,
|
|
1206
|
-
message: "Lastname does not match the disclosed lastname in query result",
|
|
1207
|
-
}
|
|
1208
|
-
}
|
|
1047
|
+
}
|
|
1048
|
+
if (
|
|
1049
|
+
queryResult.fullname.disclose &&
|
|
1050
|
+
formatName(queryResult.fullname.disclose.result).toLowerCase() !==
|
|
1051
|
+
fullnamePassport.toLowerCase() &&
|
|
1052
|
+
formatName(queryResult.fullname.disclose.result).toLowerCase() !==
|
|
1053
|
+
fullnameIDCard.toLowerCase()
|
|
1054
|
+
) {
|
|
1055
|
+
console.warn("Fullname does not match the disclosed fullname in query result")
|
|
1056
|
+
isCorrect = false
|
|
1057
|
+
queryResultErrors.fullname.disclose = {
|
|
1058
|
+
expected: `${queryResult.fullname.disclose.result}`,
|
|
1059
|
+
received: `${fullnamePassport ?? fullnameIDCard}`,
|
|
1060
|
+
message: "Fullname does not match the disclosed fullname in query result",
|
|
1209
1061
|
}
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
if (queryResult.firstname) {
|
|
1065
|
+
// If fullname was not revealed, then the name could be either the first name or last name
|
|
1066
|
+
const firstnamePassport =
|
|
1067
|
+
disclosedDataPassport.firstName && disclosedDataPassport.firstName.length > 0
|
|
1068
|
+
? disclosedDataPassport.firstName
|
|
1069
|
+
: disclosedDataPassport.name
|
|
1070
|
+
const firstnameIDCard =
|
|
1071
|
+
disclosedDataIDCard.firstName && disclosedDataIDCard.firstName.length > 0
|
|
1072
|
+
? disclosedDataIDCard.firstName
|
|
1073
|
+
: disclosedDataIDCard.name
|
|
1074
|
+
if (
|
|
1075
|
+
queryResult.firstname.eq &&
|
|
1076
|
+
queryResult.firstname.eq.result &&
|
|
1077
|
+
formatName(queryResult.firstname.eq.expected).toLowerCase() !==
|
|
1078
|
+
firstnamePassport.toLowerCase() &&
|
|
1079
|
+
formatName(queryResult.firstname.eq.expected).toLowerCase() !==
|
|
1080
|
+
firstnameIDCard.toLowerCase()
|
|
1081
|
+
) {
|
|
1082
|
+
console.warn("Firstname does not match the expected firstname")
|
|
1083
|
+
isCorrect = false
|
|
1084
|
+
queryResultErrors.firstname.eq = {
|
|
1085
|
+
expected: `${queryResult.firstname.eq.expected}`,
|
|
1086
|
+
received: `${firstnamePassport ?? firstnameIDCard}`,
|
|
1087
|
+
message: "Firstname does not match the expected firstname",
|
|
1224
1088
|
}
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1089
|
+
}
|
|
1090
|
+
if (
|
|
1091
|
+
queryResult.firstname.disclose &&
|
|
1092
|
+
formatName(queryResult.firstname.disclose.result).toLowerCase() !==
|
|
1093
|
+
firstnamePassport.toLowerCase() &&
|
|
1094
|
+
formatName(queryResult.firstname.disclose.result).toLowerCase() !==
|
|
1095
|
+
firstnameIDCard.toLowerCase()
|
|
1096
|
+
) {
|
|
1097
|
+
console.warn("Firstname does not match the disclosed firstname in query result")
|
|
1098
|
+
isCorrect = false
|
|
1099
|
+
queryResultErrors.firstname.disclose = {
|
|
1100
|
+
expected: `${queryResult.firstname.disclose.result}`,
|
|
1101
|
+
received: `${firstnamePassport ?? firstnameIDCard}`,
|
|
1102
|
+
message: "Firstname does not match the disclosed firstname in query result",
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
if (queryResult.lastname) {
|
|
1107
|
+
// If fullname was not revealed, then the name could be either the first name or last name
|
|
1108
|
+
const lastnamePassport =
|
|
1109
|
+
disclosedDataPassport.lastName && disclosedDataPassport.lastName.length > 0
|
|
1110
|
+
? disclosedDataPassport.lastName
|
|
1111
|
+
: disclosedDataPassport.name
|
|
1112
|
+
const lastnameIDCard =
|
|
1113
|
+
disclosedDataIDCard.lastName && disclosedDataIDCard.lastName.length > 0
|
|
1114
|
+
? disclosedDataIDCard.lastName
|
|
1115
|
+
: disclosedDataIDCard.name
|
|
1116
|
+
if (
|
|
1117
|
+
queryResult.lastname.eq &&
|
|
1118
|
+
queryResult.lastname.eq.result &&
|
|
1119
|
+
formatName(queryResult.lastname.eq.expected).toLowerCase() !==
|
|
1120
|
+
lastnamePassport.toLowerCase() &&
|
|
1121
|
+
formatName(queryResult.lastname.eq.expected).toLowerCase() !== lastnameIDCard.toLowerCase()
|
|
1122
|
+
) {
|
|
1123
|
+
console.warn("Lastname does not match the expected lastname")
|
|
1124
|
+
isCorrect = false
|
|
1125
|
+
queryResultErrors.lastname.eq = {
|
|
1126
|
+
expected: `${queryResult.lastname.eq.expected}`,
|
|
1127
|
+
received: `${lastnamePassport ?? lastnameIDCard}`,
|
|
1128
|
+
message: "Lastname does not match the expected lastname",
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
if (
|
|
1132
|
+
queryResult.lastname.disclose &&
|
|
1133
|
+
formatName(queryResult.lastname.disclose.result).toLowerCase() !==
|
|
1134
|
+
lastnamePassport.toLowerCase() &&
|
|
1135
|
+
formatName(queryResult.lastname.disclose.result).toLowerCase() !==
|
|
1136
|
+
lastnameIDCard.toLowerCase()
|
|
1137
|
+
) {
|
|
1138
|
+
console.warn("Lastname does not match the disclosed lastname in query result")
|
|
1139
|
+
isCorrect = false
|
|
1140
|
+
queryResultErrors.lastname.disclose = {
|
|
1141
|
+
expected: `${queryResult.lastname.disclose.result}`,
|
|
1142
|
+
received: `${lastnamePassport ?? lastnameIDCard}`,
|
|
1143
|
+
message: "Lastname does not match the disclosed lastname in query result",
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
return { isCorrect, queryResultErrors }
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
private checkAgePublicInputs(proof: ProofResult, queryResult: QueryResult) {
|
|
1151
|
+
const queryResultErrors: QueryResultErrors = {
|
|
1152
|
+
sig_check_dsc: {},
|
|
1153
|
+
sig_check_id_data: {},
|
|
1154
|
+
data_check_integrity: {},
|
|
1155
|
+
disclose: {},
|
|
1156
|
+
age: {},
|
|
1157
|
+
birthdate: {},
|
|
1158
|
+
expiry_date: {},
|
|
1159
|
+
document_type: {},
|
|
1160
|
+
issuing_country: {},
|
|
1161
|
+
gender: {},
|
|
1162
|
+
nationality: {},
|
|
1163
|
+
firstname: {},
|
|
1164
|
+
lastname: {},
|
|
1165
|
+
fullname: {},
|
|
1166
|
+
document_number: {},
|
|
1167
|
+
outer: {},
|
|
1168
|
+
}
|
|
1169
|
+
let isCorrect = true
|
|
1170
|
+
const currentTime = new Date()
|
|
1171
|
+
const today = new Date(
|
|
1172
|
+
currentTime.getFullYear(),
|
|
1173
|
+
currentTime.getMonth(),
|
|
1174
|
+
currentTime.getDate(),
|
|
1175
|
+
0,
|
|
1176
|
+
0,
|
|
1177
|
+
0,
|
|
1178
|
+
0,
|
|
1179
|
+
)
|
|
1180
|
+
const minAge = getMinAgeFromCommittedInputs(
|
|
1181
|
+
proof.committedInputs?.compare_age as AgeCommittedInputs,
|
|
1182
|
+
)
|
|
1183
|
+
const maxAge = getMaxAgeFromCommittedInputs(
|
|
1184
|
+
proof.committedInputs?.compare_age as AgeCommittedInputs,
|
|
1185
|
+
)
|
|
1186
|
+
if (queryResult.age) {
|
|
1187
|
+
if (
|
|
1188
|
+
queryResult.age.gte &&
|
|
1189
|
+
queryResult.age.gte.result &&
|
|
1190
|
+
minAge < (queryResult.age.gte.expected as number)
|
|
1191
|
+
) {
|
|
1192
|
+
console.warn("Age is not greater than or equal to the expected age")
|
|
1193
|
+
isCorrect = false
|
|
1194
|
+
queryResultErrors.age.gte = {
|
|
1195
|
+
expected: queryResult.age.gte.expected,
|
|
1196
|
+
received: minAge,
|
|
1197
|
+
message: "Age is not greater than or equal to the expected age",
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
if (
|
|
1201
|
+
queryResult.age.lt &&
|
|
1202
|
+
queryResult.age.lt.result &&
|
|
1203
|
+
maxAge >= (queryResult.age.lt.expected as number)
|
|
1204
|
+
) {
|
|
1205
|
+
console.warn("Age is not less than the expected age")
|
|
1206
|
+
isCorrect = false
|
|
1207
|
+
queryResultErrors.age.lt = {
|
|
1208
|
+
expected: queryResult.age.lt.expected,
|
|
1209
|
+
received: maxAge,
|
|
1210
|
+
message: "Age is not less than the expected age",
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
if (queryResult.age.range) {
|
|
1214
|
+
if (
|
|
1215
|
+
queryResult.age.range.result &&
|
|
1216
|
+
(minAge < (queryResult.age.range.expected[0] as number) ||
|
|
1217
|
+
maxAge >= (queryResult.age.range.expected[1] as number))
|
|
1218
|
+
) {
|
|
1219
|
+
console.warn("Age is not in the expected range")
|
|
1220
|
+
isCorrect = false
|
|
1221
|
+
queryResultErrors.age.range = {
|
|
1222
|
+
expected: queryResult.age.range.expected,
|
|
1223
|
+
received: [minAge, maxAge],
|
|
1224
|
+
message: "Age is not in the expected range",
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
if (!queryResult.age.lt && !queryResult.age.range && maxAge != 0) {
|
|
1229
|
+
console.warn("Maximum age should be equal to 0")
|
|
1230
|
+
isCorrect = false
|
|
1231
|
+
queryResultErrors.age.disclose = {
|
|
1232
|
+
expected: 0,
|
|
1233
|
+
received: maxAge,
|
|
1234
|
+
message: "Maximum age should be equal to 0",
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
if (!queryResult.age.gte && !queryResult.age.range && minAge != 0) {
|
|
1238
|
+
console.warn("Minimum age should be equal to 0")
|
|
1239
|
+
isCorrect = false
|
|
1240
|
+
queryResultErrors.age.disclose = {
|
|
1241
|
+
expected: 0,
|
|
1242
|
+
received: minAge,
|
|
1243
|
+
message: "Minimum age should be equal to 0",
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
if (
|
|
1247
|
+
queryResult.age.disclose &&
|
|
1248
|
+
(queryResult.age.disclose.result !== minAge || queryResult.age.disclose.result !== maxAge)
|
|
1249
|
+
) {
|
|
1250
|
+
console.warn("Age does not match the disclosed age in query result")
|
|
1251
|
+
isCorrect = false
|
|
1252
|
+
queryResultErrors.age.disclose = {
|
|
1253
|
+
expected: `${minAge}`,
|
|
1254
|
+
received: `${queryResult.age.disclose.result}`,
|
|
1255
|
+
message: "Age does not match the disclosed age in query result",
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
} else {
|
|
1259
|
+
console.warn("Age is not set in the query result")
|
|
1260
|
+
isCorrect = false
|
|
1261
|
+
queryResultErrors.age.disclose = {
|
|
1262
|
+
message: "Age is not set in the query result",
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
const currentDate = getCurrentDateFromCommittedInputs(
|
|
1266
|
+
proof.committedInputs?.compare_age as AgeCommittedInputs,
|
|
1267
|
+
)
|
|
1268
|
+
if (
|
|
1269
|
+
currentDate.getTime() !== today.getTime() &&
|
|
1270
|
+
currentDate.getTime() !== today.getTime() - 86400000
|
|
1271
|
+
) {
|
|
1272
|
+
console.warn("Current date in the proof is too old")
|
|
1273
|
+
isCorrect = false
|
|
1274
|
+
queryResultErrors.age.disclose = {
|
|
1275
|
+
expected: `${today.toISOString()}`,
|
|
1276
|
+
received: `${currentDate.toISOString()}`,
|
|
1277
|
+
message: "Current date in the proof is too old",
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
return { isCorrect, queryResultErrors }
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
private checkBirthdatePublicInputs(proof: ProofResult, queryResult: QueryResult) {
|
|
1284
|
+
const queryResultErrors: QueryResultErrors = {
|
|
1285
|
+
sig_check_dsc: {},
|
|
1286
|
+
sig_check_id_data: {},
|
|
1287
|
+
data_check_integrity: {},
|
|
1288
|
+
disclose: {},
|
|
1289
|
+
age: {},
|
|
1290
|
+
birthdate: {},
|
|
1291
|
+
expiry_date: {},
|
|
1292
|
+
document_type: {},
|
|
1293
|
+
issuing_country: {},
|
|
1294
|
+
gender: {},
|
|
1295
|
+
nationality: {},
|
|
1296
|
+
firstname: {},
|
|
1297
|
+
lastname: {},
|
|
1298
|
+
fullname: {},
|
|
1299
|
+
document_number: {},
|
|
1300
|
+
outer: {},
|
|
1301
|
+
}
|
|
1302
|
+
let isCorrect = true
|
|
1303
|
+
const currentTime = new Date()
|
|
1304
|
+
const today = new Date(
|
|
1305
|
+
currentTime.getFullYear(),
|
|
1306
|
+
currentTime.getMonth(),
|
|
1307
|
+
currentTime.getDate(),
|
|
1308
|
+
0,
|
|
1309
|
+
0,
|
|
1310
|
+
0,
|
|
1311
|
+
)
|
|
1312
|
+
const minDate = getMinDateFromCommittedInputs(
|
|
1313
|
+
proof.committedInputs?.compare_birthdate as DateCommittedInputs,
|
|
1314
|
+
)
|
|
1315
|
+
const maxDate = getMaxDateFromCommittedInputs(
|
|
1316
|
+
proof.committedInputs?.compare_birthdate as DateCommittedInputs,
|
|
1317
|
+
)
|
|
1318
|
+
const currentDate = getCurrentDateFromCommittedInputs(
|
|
1319
|
+
proof.committedInputs?.compare_birthdate as DateCommittedInputs,
|
|
1320
|
+
)
|
|
1321
|
+
if (queryResult.birthdate) {
|
|
1322
|
+
if (
|
|
1323
|
+
queryResult.birthdate.gte &&
|
|
1324
|
+
queryResult.birthdate.gte.result &&
|
|
1325
|
+
minDate < queryResult.birthdate.gte.expected
|
|
1326
|
+
) {
|
|
1327
|
+
console.warn("Birthdate is not greater than or equal to the expected birthdate")
|
|
1328
|
+
isCorrect = false
|
|
1329
|
+
queryResultErrors.birthdate.gte = {
|
|
1330
|
+
expected: queryResult.birthdate.gte.expected,
|
|
1331
|
+
received: minDate,
|
|
1332
|
+
message: "Birthdate is not greater than or equal to the expected birthdate",
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
if (
|
|
1336
|
+
queryResult.birthdate.lte &&
|
|
1337
|
+
queryResult.birthdate.lte.result &&
|
|
1338
|
+
maxDate > queryResult.birthdate.lte.expected
|
|
1339
|
+
) {
|
|
1340
|
+
console.warn("Birthdate is not less than the expected birthdate")
|
|
1341
|
+
isCorrect = false
|
|
1342
|
+
queryResultErrors.birthdate.lte = {
|
|
1343
|
+
expected: queryResult.birthdate.lte.expected,
|
|
1344
|
+
received: maxDate,
|
|
1345
|
+
message: "Birthdate is not less than the expected birthdate",
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
if (queryResult.birthdate.range) {
|
|
1349
|
+
if (
|
|
1350
|
+
queryResult.birthdate.range.result &&
|
|
1351
|
+
(minDate < queryResult.birthdate.range.expected[0] ||
|
|
1352
|
+
maxDate > queryResult.birthdate.range.expected[1])
|
|
1353
|
+
) {
|
|
1354
|
+
console.warn("Birthdate is not in the expected range")
|
|
1355
|
+
isCorrect = false
|
|
1356
|
+
queryResultErrors.birthdate.range = {
|
|
1357
|
+
expected: queryResult.birthdate.range.expected,
|
|
1358
|
+
received: [minDate, maxDate],
|
|
1359
|
+
message: "Birthdate is not in the expected range",
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
if (
|
|
1364
|
+
!queryResult.birthdate.lte &&
|
|
1365
|
+
!queryResult.birthdate.range &&
|
|
1366
|
+
maxDate.getTime() != DEFAULT_DATE_VALUE.getTime()
|
|
1367
|
+
) {
|
|
1368
|
+
console.warn("Maximum birthdate should be equal to default date value")
|
|
1369
|
+
isCorrect = false
|
|
1370
|
+
queryResultErrors.birthdate.disclose = {
|
|
1371
|
+
expected: `${DEFAULT_DATE_VALUE.toISOString()}`,
|
|
1372
|
+
received: `${maxDate.toISOString()}`,
|
|
1373
|
+
message: "Maximum birthdate should be equal to default date value",
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
if (
|
|
1377
|
+
!queryResult.birthdate.gte &&
|
|
1378
|
+
!queryResult.birthdate.range &&
|
|
1379
|
+
minDate.getTime() != DEFAULT_DATE_VALUE.getTime()
|
|
1380
|
+
) {
|
|
1381
|
+
console.warn("Minimum birthdate should be equal to default date value")
|
|
1382
|
+
isCorrect = false
|
|
1383
|
+
queryResultErrors.birthdate.disclose = {
|
|
1384
|
+
expected: `${DEFAULT_DATE_VALUE.toISOString()}`,
|
|
1385
|
+
received: `${minDate.toISOString()}`,
|
|
1386
|
+
message: "Minimum birthdate should be equal to default date value",
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
} else {
|
|
1390
|
+
console.warn("Birthdate is not set in the query result")
|
|
1391
|
+
isCorrect = false
|
|
1392
|
+
queryResultErrors.birthdate.disclose = {
|
|
1393
|
+
message: "Birthdate is not set in the query result",
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
if (
|
|
1397
|
+
currentDate.getTime() !== today.getTime() &&
|
|
1398
|
+
currentDate.getTime() !== today.getTime() - 86400000
|
|
1399
|
+
) {
|
|
1400
|
+
console.warn("Current date in the proof is too old")
|
|
1401
|
+
isCorrect = false
|
|
1402
|
+
queryResultErrors.age.disclose = {
|
|
1403
|
+
expected: `${today.toISOString()}`,
|
|
1404
|
+
received: `${currentDate.toISOString()}`,
|
|
1405
|
+
message: "Current date in the proof is too old",
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
return { isCorrect, queryResultErrors }
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
private checkExpiryDatePublicInputs(proof: ProofResult, queryResult: QueryResult) {
|
|
1412
|
+
const queryResultErrors: QueryResultErrors = {
|
|
1413
|
+
sig_check_dsc: {},
|
|
1414
|
+
sig_check_id_data: {},
|
|
1415
|
+
data_check_integrity: {},
|
|
1416
|
+
disclose: {},
|
|
1417
|
+
age: {},
|
|
1418
|
+
birthdate: {},
|
|
1419
|
+
expiry_date: {},
|
|
1420
|
+
document_type: {},
|
|
1421
|
+
issuing_country: {},
|
|
1422
|
+
gender: {},
|
|
1423
|
+
nationality: {},
|
|
1424
|
+
firstname: {},
|
|
1425
|
+
lastname: {},
|
|
1426
|
+
fullname: {},
|
|
1427
|
+
document_number: {},
|
|
1428
|
+
outer: {},
|
|
1429
|
+
}
|
|
1430
|
+
let isCorrect = true
|
|
1431
|
+
const currentTime = new Date()
|
|
1432
|
+
const today = new Date(
|
|
1433
|
+
currentTime.getFullYear(),
|
|
1434
|
+
currentTime.getMonth(),
|
|
1435
|
+
currentTime.getDate(),
|
|
1436
|
+
0,
|
|
1437
|
+
0,
|
|
1438
|
+
0,
|
|
1439
|
+
)
|
|
1440
|
+
const minDate = getMinDateFromCommittedInputs(
|
|
1441
|
+
proof.committedInputs?.compare_expiry as DateCommittedInputs,
|
|
1442
|
+
)
|
|
1443
|
+
const maxDate = getMaxDateFromCommittedInputs(
|
|
1444
|
+
proof.committedInputs?.compare_expiry as DateCommittedInputs,
|
|
1445
|
+
)
|
|
1446
|
+
const currentDate = getCurrentDateFromCommittedInputs(
|
|
1447
|
+
proof.committedInputs?.compare_expiry as DateCommittedInputs,
|
|
1448
|
+
)
|
|
1449
|
+
if (queryResult.expiry_date) {
|
|
1450
|
+
if (
|
|
1451
|
+
queryResult.expiry_date.gte &&
|
|
1452
|
+
queryResult.expiry_date.gte.result &&
|
|
1453
|
+
minDate < queryResult.expiry_date.gte.expected
|
|
1454
|
+
) {
|
|
1455
|
+
console.warn("Expiry date is not greater than or equal to the expected expiry date")
|
|
1456
|
+
isCorrect = false
|
|
1457
|
+
queryResultErrors.expiry_date.gte = {
|
|
1458
|
+
expected: queryResult.expiry_date.gte.expected,
|
|
1459
|
+
received: minDate,
|
|
1460
|
+
message: "Expiry date is not greater than or equal to the expected expiry date",
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
if (
|
|
1464
|
+
queryResult.expiry_date.lte &&
|
|
1465
|
+
queryResult.expiry_date.lte.result &&
|
|
1466
|
+
maxDate > queryResult.expiry_date.lte.expected
|
|
1467
|
+
) {
|
|
1468
|
+
console.warn("Expiry date is not less than the expected expiry date")
|
|
1469
|
+
isCorrect = false
|
|
1470
|
+
queryResultErrors.expiry_date.lte = {
|
|
1471
|
+
expected: queryResult.expiry_date.lte.expected,
|
|
1472
|
+
received: maxDate,
|
|
1473
|
+
message: "Expiry date is not less than the expected expiry date",
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
if (queryResult.expiry_date.range) {
|
|
1477
|
+
if (
|
|
1478
|
+
queryResult.expiry_date.range.result &&
|
|
1479
|
+
(minDate < queryResult.expiry_date.range.expected[0] ||
|
|
1480
|
+
maxDate > queryResult.expiry_date.range.expected[1])
|
|
1481
|
+
) {
|
|
1482
|
+
console.warn("Expiry date is not in the expected range")
|
|
1483
|
+
isCorrect = false
|
|
1484
|
+
queryResultErrors.expiry_date.range = {
|
|
1485
|
+
expected: queryResult.expiry_date.range.expected,
|
|
1486
|
+
received: [minDate, maxDate],
|
|
1487
|
+
message: "Expiry date is not in the expected range",
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
if (
|
|
1492
|
+
!queryResult.expiry_date.lte &&
|
|
1493
|
+
!queryResult.expiry_date.range &&
|
|
1494
|
+
maxDate.getTime() != DEFAULT_DATE_VALUE.getTime()
|
|
1495
|
+
) {
|
|
1496
|
+
console.warn("Maximum expiry date should be equal to default date value")
|
|
1497
|
+
isCorrect = false
|
|
1498
|
+
queryResultErrors.expiry_date.disclose = {
|
|
1499
|
+
expected: `${DEFAULT_DATE_VALUE.toISOString()}`,
|
|
1500
|
+
received: `${maxDate.toISOString()}`,
|
|
1501
|
+
message: "Maximum expiry date should be equal to default date value",
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
if (
|
|
1505
|
+
!queryResult.expiry_date.gte &&
|
|
1506
|
+
!queryResult.expiry_date.range &&
|
|
1507
|
+
minDate.getTime() != DEFAULT_DATE_VALUE.getTime()
|
|
1508
|
+
) {
|
|
1509
|
+
console.warn("Minimum expiry date should be equal to default date value")
|
|
1510
|
+
isCorrect = false
|
|
1511
|
+
queryResultErrors.expiry_date.disclose = {
|
|
1512
|
+
expected: `${DEFAULT_DATE_VALUE.toISOString()}`,
|
|
1513
|
+
received: `${minDate.toISOString()}`,
|
|
1514
|
+
message: "Minimum expiry date should be equal to default date value",
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
} else {
|
|
1518
|
+
console.warn("Expiry date is not set in the query result")
|
|
1519
|
+
isCorrect = false
|
|
1520
|
+
queryResultErrors.expiry_date.disclose = {
|
|
1521
|
+
message: "Expiry date is not set in the query result",
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1524
|
+
if (
|
|
1525
|
+
currentDate.getTime() !== today.getTime() &&
|
|
1526
|
+
currentDate.getTime() !== today.getTime() - 86400000
|
|
1527
|
+
) {
|
|
1528
|
+
console.warn("Current date in the proof is too old")
|
|
1529
|
+
isCorrect = false
|
|
1530
|
+
queryResultErrors.age.disclose = {
|
|
1531
|
+
expected: `${today.toISOString()}`,
|
|
1532
|
+
received: `${currentDate.toISOString()}`,
|
|
1533
|
+
message: "Current date in the proof is too old",
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
return { isCorrect, queryResultErrors }
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
private checkNationalityExclusionPublicInputs(queryResult: QueryResult, countryList: string[]) {
|
|
1540
|
+
const queryResultErrors: QueryResultErrors = {
|
|
1541
|
+
sig_check_dsc: {},
|
|
1542
|
+
sig_check_id_data: {},
|
|
1543
|
+
data_check_integrity: {},
|
|
1544
|
+
disclose: {},
|
|
1545
|
+
age: {},
|
|
1546
|
+
birthdate: {},
|
|
1547
|
+
expiry_date: {},
|
|
1548
|
+
document_type: {},
|
|
1549
|
+
issuing_country: {},
|
|
1550
|
+
gender: {},
|
|
1551
|
+
nationality: {},
|
|
1552
|
+
firstname: {},
|
|
1553
|
+
lastname: {},
|
|
1554
|
+
fullname: {},
|
|
1555
|
+
document_number: {},
|
|
1556
|
+
outer: {},
|
|
1557
|
+
}
|
|
1558
|
+
let isCorrect = true
|
|
1559
|
+
if (
|
|
1560
|
+
queryResult.nationality &&
|
|
1561
|
+
queryResult.nationality.out &&
|
|
1562
|
+
queryResult.nationality.out.result
|
|
1563
|
+
) {
|
|
1564
|
+
if (
|
|
1565
|
+
!queryResult.nationality.out.expected?.every((country) => countryList.includes(country))
|
|
1566
|
+
) {
|
|
1567
|
+
console.warn("Nationality exclusion list does not match the one from the query results")
|
|
1568
|
+
isCorrect = false
|
|
1569
|
+
queryResultErrors.nationality.out = {
|
|
1570
|
+
expected: queryResult.nationality.out.expected,
|
|
1571
|
+
received: countryList,
|
|
1572
|
+
message: "Nationality exclusion list does not match the one from the query results",
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
} else if (!queryResult.nationality || !queryResult.nationality.out) {
|
|
1576
|
+
console.warn("Nationality exclusion is not set in the query result")
|
|
1577
|
+
isCorrect = false
|
|
1578
|
+
queryResultErrors.nationality.out = {
|
|
1579
|
+
message: "Nationality exclusion is not set in the query result",
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1582
|
+
// Check the countryList is in ascending order
|
|
1583
|
+
// If the prover doesn't use a sorted list then the proof cannot be trusted
|
|
1584
|
+
// as it is requirement in the circuit for the exclusion check to work
|
|
1585
|
+
for (let i = 1; i < countryList.length; i++) {
|
|
1586
|
+
if (countryList[i] < countryList[i - 1]) {
|
|
1587
|
+
console.warn(
|
|
1588
|
+
"The nationality exclusion list has not been sorted, and thus the proof cannot be trusted",
|
|
1589
|
+
)
|
|
1590
|
+
isCorrect = false
|
|
1591
|
+
queryResultErrors.nationality.out = {
|
|
1592
|
+
message:
|
|
1593
|
+
"The nationality exclusion list has not been sorted, and thus the proof cannot be trusted",
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
return { isCorrect, queryResultErrors }
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
private checkIssuingCountryExclusionPublicInputs(
|
|
1601
|
+
queryResult: QueryResult,
|
|
1602
|
+
countryList: string[],
|
|
1603
|
+
) {
|
|
1604
|
+
const queryResultErrors: QueryResultErrors = {
|
|
1605
|
+
sig_check_dsc: {},
|
|
1606
|
+
sig_check_id_data: {},
|
|
1607
|
+
data_check_integrity: {},
|
|
1608
|
+
disclose: {},
|
|
1609
|
+
age: {},
|
|
1610
|
+
birthdate: {},
|
|
1611
|
+
expiry_date: {},
|
|
1612
|
+
document_type: {},
|
|
1613
|
+
issuing_country: {},
|
|
1614
|
+
gender: {},
|
|
1615
|
+
nationality: {},
|
|
1616
|
+
firstname: {},
|
|
1617
|
+
lastname: {},
|
|
1618
|
+
fullname: {},
|
|
1619
|
+
document_number: {},
|
|
1620
|
+
outer: {},
|
|
1621
|
+
}
|
|
1622
|
+
let isCorrect = true
|
|
1623
|
+
|
|
1624
|
+
if (
|
|
1625
|
+
queryResult.issuing_country &&
|
|
1626
|
+
queryResult.issuing_country.out &&
|
|
1627
|
+
queryResult.issuing_country.out.result
|
|
1628
|
+
) {
|
|
1629
|
+
if (
|
|
1630
|
+
!queryResult.issuing_country.out.expected?.every((country) => countryList.includes(country))
|
|
1631
|
+
) {
|
|
1632
|
+
console.warn("Issuing country exclusion list does not match the one from the query results")
|
|
1633
|
+
isCorrect = false
|
|
1634
|
+
queryResultErrors.issuing_country.out = {
|
|
1635
|
+
expected: queryResult.issuing_country.out.expected,
|
|
1636
|
+
received: countryList,
|
|
1637
|
+
message: "Issuing country exclusion list does not match the one from the query results",
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
} else if (!queryResult.issuing_country || !queryResult.issuing_country.out) {
|
|
1641
|
+
console.warn("Issuing country exclusion is not set in the query result")
|
|
1642
|
+
isCorrect = false
|
|
1643
|
+
queryResultErrors.issuing_country.out = {
|
|
1644
|
+
message: "Issuing country exclusion is not set in the query result",
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
// Check the countryList is in ascending order
|
|
1648
|
+
// If the prover doesn't use a sorted list then the proof cannot be trusted
|
|
1649
|
+
// as it is requirement in the circuit for the exclusion check to work
|
|
1650
|
+
for (let i = 1; i < countryList.length; i++) {
|
|
1651
|
+
if (countryList[i] < countryList[i - 1]) {
|
|
1652
|
+
console.warn(
|
|
1653
|
+
"The issuing country exclusion list has not been sorted, and thus the proof cannot be trusted",
|
|
1654
|
+
)
|
|
1655
|
+
isCorrect = false
|
|
1656
|
+
queryResultErrors.issuing_country.out = {
|
|
1657
|
+
message:
|
|
1658
|
+
"The issuing country exclusion list has not been sorted, and thus the proof cannot be trusted",
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
return { isCorrect, queryResultErrors }
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
private checkNationalityInclusionPublicInputs(queryResult: QueryResult, countryList: string[]) {
|
|
1666
|
+
const queryResultErrors: QueryResultErrors = {
|
|
1667
|
+
sig_check_dsc: {},
|
|
1668
|
+
sig_check_id_data: {},
|
|
1669
|
+
data_check_integrity: {},
|
|
1670
|
+
disclose: {},
|
|
1671
|
+
age: {},
|
|
1672
|
+
birthdate: {},
|
|
1673
|
+
expiry_date: {},
|
|
1674
|
+
document_type: {},
|
|
1675
|
+
issuing_country: {},
|
|
1676
|
+
gender: {},
|
|
1677
|
+
nationality: {},
|
|
1678
|
+
firstname: {},
|
|
1679
|
+
lastname: {},
|
|
1680
|
+
fullname: {},
|
|
1681
|
+
document_number: {},
|
|
1682
|
+
outer: {},
|
|
1683
|
+
}
|
|
1684
|
+
let isCorrect = true
|
|
1685
|
+
if (
|
|
1686
|
+
queryResult.nationality &&
|
|
1687
|
+
queryResult.nationality.in &&
|
|
1688
|
+
queryResult.nationality.in.result
|
|
1689
|
+
) {
|
|
1690
|
+
if (!queryResult.nationality.in.expected?.every((country) => countryList.includes(country))) {
|
|
1691
|
+
console.warn("Nationality inclusion list does not match the one from the query results")
|
|
1692
|
+
isCorrect = false
|
|
1693
|
+
queryResultErrors.nationality.in = {
|
|
1694
|
+
expected: queryResult.nationality.in.expected,
|
|
1695
|
+
received: countryList,
|
|
1696
|
+
message: "Nationality inclusion list does not match the one from the query results",
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
} else if (!queryResult.nationality || !queryResult.nationality.in) {
|
|
1700
|
+
console.warn("Nationality inclusion is not set in the query result")
|
|
1701
|
+
isCorrect = false
|
|
1702
|
+
queryResultErrors.nationality.in = {
|
|
1703
|
+
message: "Nationality inclusion is not set in the query result",
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
return { isCorrect, queryResultErrors }
|
|
1707
|
+
}
|
|
1708
|
+
|
|
1709
|
+
private checkIssuingCountryInclusionPublicInputs(
|
|
1710
|
+
queryResult: QueryResult,
|
|
1711
|
+
countryList: string[],
|
|
1712
|
+
) {
|
|
1713
|
+
const queryResultErrors: QueryResultErrors = {
|
|
1714
|
+
sig_check_dsc: {},
|
|
1715
|
+
sig_check_id_data: {},
|
|
1716
|
+
data_check_integrity: {},
|
|
1717
|
+
disclose: {},
|
|
1718
|
+
age: {},
|
|
1719
|
+
birthdate: {},
|
|
1720
|
+
expiry_date: {},
|
|
1721
|
+
document_type: {},
|
|
1722
|
+
issuing_country: {},
|
|
1723
|
+
gender: {},
|
|
1724
|
+
nationality: {},
|
|
1725
|
+
firstname: {},
|
|
1726
|
+
lastname: {},
|
|
1727
|
+
fullname: {},
|
|
1728
|
+
document_number: {},
|
|
1729
|
+
outer: {},
|
|
1730
|
+
}
|
|
1731
|
+
let isCorrect = true
|
|
1732
|
+
|
|
1733
|
+
if (
|
|
1734
|
+
queryResult.issuing_country &&
|
|
1735
|
+
queryResult.issuing_country.in &&
|
|
1736
|
+
queryResult.issuing_country.in.result
|
|
1737
|
+
) {
|
|
1738
|
+
if (
|
|
1739
|
+
!queryResult.issuing_country.in.expected?.every((country) => countryList.includes(country))
|
|
1740
|
+
) {
|
|
1741
|
+
console.warn("Issuing country inclusion list does not match the one from the query results")
|
|
1742
|
+
isCorrect = false
|
|
1743
|
+
queryResultErrors.issuing_country.in = {
|
|
1744
|
+
expected: queryResult.issuing_country.in.expected,
|
|
1745
|
+
received: countryList,
|
|
1746
|
+
message: "Issuing country inclusion list does not match the one from the query results",
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
} else if (!queryResult.issuing_country || !queryResult.issuing_country.in) {
|
|
1750
|
+
console.warn("Issuing country inclusion is not set in the query result")
|
|
1751
|
+
isCorrect = false
|
|
1752
|
+
queryResultErrors.issuing_country.in = {
|
|
1753
|
+
message: "Issuing country inclusion is not set in the query result",
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
return { isCorrect, queryResultErrors }
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1759
|
+
private async checkPublicInputs(
|
|
1760
|
+
proofs: Array<ProofResult>,
|
|
1761
|
+
queryResult: QueryResult,
|
|
1762
|
+
validity?: number,
|
|
1763
|
+
) {
|
|
1764
|
+
let commitmentIn: bigint | undefined
|
|
1765
|
+
let commitmentOut: bigint | undefined
|
|
1766
|
+
let isCorrect = true
|
|
1767
|
+
let uniqueIdentifier: string | undefined
|
|
1768
|
+
const VALID_CERTIFICATE_REGISTRY_ROOT = [
|
|
1769
|
+
BigInt("20192042006788880778219739574377003123593792072535937278552252195461520776494"),
|
|
1770
|
+
BigInt("21301853597069384763054217328384418971999152625381818922211526730996340553696"),
|
|
1771
|
+
BigInt("10839898448097753834842514286432152806152415606387598803678317315409344029817"),
|
|
1772
|
+
]
|
|
1773
|
+
const currentTime = new Date()
|
|
1774
|
+
const today = new Date(
|
|
1775
|
+
currentTime.getFullYear(),
|
|
1776
|
+
currentTime.getMonth(),
|
|
1777
|
+
currentTime.getDate(),
|
|
1778
|
+
0,
|
|
1779
|
+
0,
|
|
1780
|
+
0,
|
|
1781
|
+
0,
|
|
1782
|
+
)
|
|
1783
|
+
let queryResultErrors: QueryResultErrors = {
|
|
1784
|
+
sig_check_dsc: {},
|
|
1785
|
+
sig_check_id_data: {},
|
|
1786
|
+
data_check_integrity: {},
|
|
1787
|
+
disclose: {},
|
|
1788
|
+
age: {},
|
|
1789
|
+
birthdate: {},
|
|
1790
|
+
expiry_date: {},
|
|
1791
|
+
document_type: {},
|
|
1792
|
+
issuing_country: {},
|
|
1793
|
+
gender: {},
|
|
1794
|
+
nationality: {},
|
|
1795
|
+
firstname: {},
|
|
1796
|
+
lastname: {},
|
|
1797
|
+
fullname: {},
|
|
1798
|
+
document_number: {},
|
|
1799
|
+
outer: {},
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1802
|
+
// Since the order is important for the commitments, we need to sort the proofs
|
|
1803
|
+
// by their expected order: root signature check -> ID signature check -> integrity check -> disclosure
|
|
1804
|
+
const sortedProofs = proofs.sort((a, b) => {
|
|
1805
|
+
const proofOrder = [
|
|
1806
|
+
"sig_check_dsc",
|
|
1807
|
+
"sig_check_id_data",
|
|
1808
|
+
"data_check_integrity",
|
|
1809
|
+
"disclose_bytes",
|
|
1810
|
+
"compare_age",
|
|
1811
|
+
"compare_birthdate",
|
|
1812
|
+
"compare_expiry",
|
|
1813
|
+
"exclusion_check_nationality",
|
|
1814
|
+
"inclusion_check_nationality",
|
|
1815
|
+
"exclusion_check_issuing_country",
|
|
1816
|
+
"inclusion_check_issuing_country",
|
|
1817
|
+
]
|
|
1818
|
+
const getIndex = (proof: ProofResult) => {
|
|
1819
|
+
const name = proof.name || ""
|
|
1820
|
+
return proofOrder.findIndex((p) => name.startsWith(p))
|
|
1821
|
+
}
|
|
1822
|
+
return getIndex(a) - getIndex(b)
|
|
1823
|
+
})
|
|
1824
|
+
|
|
1825
|
+
for (const proof of sortedProofs!) {
|
|
1826
|
+
const proofData = getProofData(proof.proof as string, getNumberOfPublicInputs(proof.name!))
|
|
1827
|
+
if (proof.name?.startsWith("outer")) {
|
|
1828
|
+
const isForEVM = proof.name?.startsWith("outer_evm")
|
|
1829
|
+
const certificateRegistryRoot = getCertificateRegistryRootFromOuterProof(proofData)
|
|
1830
|
+
if (!VALID_CERTIFICATE_REGISTRY_ROOT.includes(certificateRegistryRoot)) {
|
|
1831
|
+
console.warn("The ID was signed by an unrecognized root certificate")
|
|
1832
|
+
isCorrect = false
|
|
1833
|
+
queryResultErrors.outer.certificate = {
|
|
1834
|
+
expected: `Certificate registry root: ${VALID_CERTIFICATE_REGISTRY_ROOT.join(", ")}`,
|
|
1835
|
+
received: `Certificate registry root: ${certificateRegistryRoot.toString()}`,
|
|
1836
|
+
message: "The ID was signed by an unrecognized root certificate",
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1839
|
+
const currentDate = getCurrentDateFromOuterProof(proofData)
|
|
1840
|
+
const todayToCurrentDate = today.getTime() - currentDate.getTime()
|
|
1841
|
+
const differenceInDays = validity ?? 180
|
|
1842
|
+
const expectedDifference = differenceInDays * 86400000
|
|
1843
|
+
const actualDifference = today.getTime() - (today.getTime() - expectedDifference)
|
|
1844
|
+
// The ID should not expire within the next 6 months (or whatever the custom value is)
|
|
1845
|
+
if (todayToCurrentDate >= actualDifference) {
|
|
1846
|
+
console.warn(
|
|
1847
|
+
`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`,
|
|
1848
|
+
)
|
|
1849
|
+
isCorrect = false
|
|
1850
|
+
queryResultErrors.outer.date = {
|
|
1851
|
+
expected: `Difference: ${differenceInDays} days`,
|
|
1852
|
+
received: `Difference: ${Math.round(todayToCurrentDate / 86400000)} days`,
|
|
1853
|
+
message:
|
|
1854
|
+
"The date used to check the validity of the ID is older than the validity period",
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
const paramCommitments = getParamCommitmentsFromOuterProof(proofData)
|
|
1858
|
+
const committedInputs = proof.committedInputs
|
|
1859
|
+
const keysInCommittedInputs = Object.keys(committedInputs || {})
|
|
1860
|
+
if (keysInCommittedInputs.length !== paramCommitments.length) {
|
|
1861
|
+
console.warn("The proof does not verify all the requested conditions and information")
|
|
1862
|
+
isCorrect = false
|
|
1863
|
+
queryResultErrors.outer.commitment = {
|
|
1864
|
+
expected: `Number of parameter commitments: ${paramCommitments.length}`,
|
|
1865
|
+
received: `Number of disclosure proofs provided: ${keysInCommittedInputs.length}`,
|
|
1866
|
+
message: "The proof does not verify all the requested conditions and information",
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
if (!!committedInputs?.compare_age) {
|
|
1870
|
+
const ageCommittedInputs = committedInputs?.compare_age as AgeCommittedInputs
|
|
1871
|
+
const ageParameterCommitment = isForEVM
|
|
1872
|
+
? await getAgeEVMParameterCommitment(
|
|
1873
|
+
ageCommittedInputs.currentDate,
|
|
1874
|
+
ageCommittedInputs.minAge,
|
|
1875
|
+
ageCommittedInputs.maxAge,
|
|
1876
|
+
)
|
|
1877
|
+
: await getAgeParameterCommitment(
|
|
1878
|
+
ageCommittedInputs.currentDate,
|
|
1879
|
+
ageCommittedInputs.minAge,
|
|
1880
|
+
ageCommittedInputs.maxAge,
|
|
1881
|
+
)
|
|
1882
|
+
if (!paramCommitments.includes(ageParameterCommitment)) {
|
|
1883
|
+
console.warn("This proof does not verify the age")
|
|
1884
|
+
isCorrect = false
|
|
1885
|
+
queryResultErrors.age.commitment = {
|
|
1886
|
+
expected: `Age parameter commitment: ${ageParameterCommitment.toString()}`,
|
|
1887
|
+
received: `Parameter commitments included: ${paramCommitments.join(", ")}`,
|
|
1888
|
+
message: "This proof does not verify the age",
|
|
1252
1889
|
}
|
|
1253
1890
|
}
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1891
|
+
const { isCorrect: isCorrectAge, queryResultErrors: queryResultErrorsAge } =
|
|
1892
|
+
this.checkAgePublicInputs(proof, queryResult)
|
|
1893
|
+
isCorrect = isCorrect && isCorrectAge
|
|
1894
|
+
queryResultErrors = {
|
|
1895
|
+
...queryResultErrors,
|
|
1896
|
+
...queryResultErrorsAge,
|
|
1897
|
+
}
|
|
1898
|
+
} else if (!!committedInputs?.compare_birthdate) {
|
|
1899
|
+
const birthdateCommittedInputs = committedInputs?.compare_birthdate as DateCommittedInputs
|
|
1900
|
+
const birthdateParameterCommitment = isForEVM
|
|
1901
|
+
? await getDateEVMParameterCommitment(
|
|
1902
|
+
ProofType.BIRTHDATE,
|
|
1903
|
+
birthdateCommittedInputs.currentDate,
|
|
1904
|
+
birthdateCommittedInputs.minDate,
|
|
1905
|
+
birthdateCommittedInputs.maxDate,
|
|
1906
|
+
)
|
|
1907
|
+
: await getDateParameterCommitment(
|
|
1908
|
+
ProofType.BIRTHDATE,
|
|
1909
|
+
birthdateCommittedInputs.currentDate,
|
|
1910
|
+
birthdateCommittedInputs.minDate,
|
|
1911
|
+
birthdateCommittedInputs.maxDate,
|
|
1912
|
+
)
|
|
1913
|
+
if (!paramCommitments.includes(birthdateParameterCommitment)) {
|
|
1914
|
+
console.warn("This proof does not verify the birthdate")
|
|
1915
|
+
isCorrect = false
|
|
1916
|
+
queryResultErrors.birthdate.commitment = {
|
|
1917
|
+
expected: `Birthdate parameter commitment: ${birthdateParameterCommitment.toString()}`,
|
|
1918
|
+
received: `Parameter commitments included: ${paramCommitments.join(", ")}`,
|
|
1919
|
+
message: "This proof does not verify the birthdate",
|
|
1267
1920
|
}
|
|
1268
1921
|
}
|
|
1269
|
-
|
|
1270
|
-
|
|
1922
|
+
const { isCorrect: isCorrectBirthdate, queryResultErrors: queryResultErrorsBirthdate } =
|
|
1923
|
+
this.checkBirthdatePublicInputs(proof, queryResult)
|
|
1924
|
+
isCorrect = isCorrect && isCorrectBirthdate
|
|
1925
|
+
queryResultErrors = {
|
|
1926
|
+
...queryResultErrors,
|
|
1927
|
+
...queryResultErrorsBirthdate,
|
|
1928
|
+
}
|
|
1929
|
+
} else if (!!committedInputs?.compare_expiry) {
|
|
1930
|
+
const expiryCommittedInputs = committedInputs?.compare_expiry as DateCommittedInputs
|
|
1931
|
+
const expiryParameterCommitment = isForEVM
|
|
1932
|
+
? await getDateEVMParameterCommitment(
|
|
1933
|
+
ProofType.EXPIRY_DATE,
|
|
1934
|
+
expiryCommittedInputs.currentDate,
|
|
1935
|
+
expiryCommittedInputs.minDate,
|
|
1936
|
+
expiryCommittedInputs.maxDate,
|
|
1937
|
+
)
|
|
1938
|
+
: await getDateParameterCommitment(
|
|
1939
|
+
ProofType.EXPIRY_DATE,
|
|
1940
|
+
expiryCommittedInputs.currentDate,
|
|
1941
|
+
expiryCommittedInputs.minDate,
|
|
1942
|
+
expiryCommittedInputs.maxDate,
|
|
1943
|
+
)
|
|
1944
|
+
if (!paramCommitments.includes(expiryParameterCommitment)) {
|
|
1945
|
+
console.warn("This proof does not verify the expiry date")
|
|
1271
1946
|
isCorrect = false
|
|
1272
|
-
queryResultErrors.
|
|
1273
|
-
expected:
|
|
1274
|
-
received:
|
|
1275
|
-
message: "
|
|
1947
|
+
queryResultErrors.expiry_date.commitment = {
|
|
1948
|
+
expected: `Expiry date parameter commitment: ${expiryParameterCommitment.toString()}`,
|
|
1949
|
+
received: `Parameter commitments included: ${paramCommitments.join(", ")}`,
|
|
1950
|
+
message: "This proof does not verify the expiry date",
|
|
1276
1951
|
}
|
|
1277
1952
|
}
|
|
1278
|
-
|
|
1279
|
-
|
|
1953
|
+
const { isCorrect: isCorrectExpiryDate, queryResultErrors: queryResultErrorsExpiryDate } =
|
|
1954
|
+
this.checkExpiryDatePublicInputs(proof, queryResult)
|
|
1955
|
+
isCorrect = isCorrect && isCorrectExpiryDate
|
|
1956
|
+
queryResultErrors = {
|
|
1957
|
+
...queryResultErrors,
|
|
1958
|
+
...queryResultErrorsExpiryDate,
|
|
1959
|
+
}
|
|
1960
|
+
} else if (!!committedInputs?.disclose_bytes) {
|
|
1961
|
+
const discloseCommittedInputs = committedInputs?.disclose_bytes as DiscloseCommittedInputs
|
|
1962
|
+
const discloseParameterCommitment = isForEVM
|
|
1963
|
+
? await getDiscloseEVMParameterCommitment(
|
|
1964
|
+
discloseCommittedInputs.discloseMask,
|
|
1965
|
+
discloseCommittedInputs.disclosedBytes,
|
|
1966
|
+
)
|
|
1967
|
+
: await getDiscloseParameterCommitment(
|
|
1968
|
+
discloseCommittedInputs.discloseMask,
|
|
1969
|
+
discloseCommittedInputs.disclosedBytes,
|
|
1970
|
+
)
|
|
1971
|
+
if (!paramCommitments.includes(discloseParameterCommitment)) {
|
|
1972
|
+
console.warn("This proof does not verify any of the data disclosed")
|
|
1280
1973
|
isCorrect = false
|
|
1281
|
-
queryResultErrors.
|
|
1282
|
-
expected:
|
|
1283
|
-
received:
|
|
1284
|
-
message: "
|
|
1974
|
+
queryResultErrors.disclose.commitment = {
|
|
1975
|
+
expected: `Disclosure parameter commitment: ${discloseParameterCommitment.toString()}`,
|
|
1976
|
+
received: `Parameter commitments included: ${paramCommitments.join(", ")}`,
|
|
1977
|
+
message: "This proof does not verify any of the data disclosed",
|
|
1285
1978
|
}
|
|
1286
1979
|
}
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1980
|
+
const { isCorrect: isCorrectDisclose, queryResultErrors: queryResultErrorsDisclose } =
|
|
1981
|
+
this.checkDiscloseBytesPublicInputs(proof, queryResult)
|
|
1982
|
+
isCorrect = isCorrect && isCorrectDisclose
|
|
1983
|
+
queryResultErrors = {
|
|
1984
|
+
...queryResultErrors,
|
|
1985
|
+
...queryResultErrorsDisclose,
|
|
1986
|
+
}
|
|
1987
|
+
} else if (!!committedInputs?.inclusion_check_nationality) {
|
|
1988
|
+
const inclusionCheckNationalityCommittedInputs =
|
|
1989
|
+
committedInputs?.inclusion_check_nationality as CountryCommittedInputs
|
|
1990
|
+
const inclusionCheckNationalityParameterCommitment = isForEVM
|
|
1991
|
+
? await getCountryEVMParameterCommitment(
|
|
1992
|
+
ProofType.NATIONALITY_INCLUSION,
|
|
1993
|
+
inclusionCheckNationalityCommittedInputs.countries,
|
|
1994
|
+
)
|
|
1995
|
+
: await getCountryParameterCommitment(
|
|
1996
|
+
ProofType.NATIONALITY_INCLUSION,
|
|
1997
|
+
inclusionCheckNationalityCommittedInputs.countries,
|
|
1998
|
+
)
|
|
1999
|
+
if (!paramCommitments.includes(inclusionCheckNationalityParameterCommitment)) {
|
|
2000
|
+
console.warn("This proof does not verify the inclusion of the nationality")
|
|
1293
2001
|
isCorrect = false
|
|
1294
|
-
queryResultErrors.
|
|
1295
|
-
expected:
|
|
1296
|
-
received:
|
|
1297
|
-
message: "
|
|
2002
|
+
queryResultErrors.nationality.commitment = {
|
|
2003
|
+
expected: `Nationality parameter commitment: ${inclusionCheckNationalityParameterCommitment.toString()}`,
|
|
2004
|
+
received: `Parameter commitments included: ${paramCommitments.join(", ")}`,
|
|
2005
|
+
message: "This proof does not verify the inclusion of the nationality",
|
|
1298
2006
|
}
|
|
1299
2007
|
}
|
|
1300
|
-
|
|
1301
|
-
|
|
2008
|
+
const countryList = inclusionCheckNationalityCommittedInputs.countries
|
|
2009
|
+
const {
|
|
2010
|
+
isCorrect: isCorrectNationalityInclusion,
|
|
2011
|
+
queryResultErrors: queryResultErrorsNationalityInclusion,
|
|
2012
|
+
} = this.checkNationalityInclusionPublicInputs(queryResult, countryList)
|
|
2013
|
+
isCorrect = isCorrect && isCorrectNationalityInclusion
|
|
2014
|
+
queryResultErrors = {
|
|
2015
|
+
...queryResultErrors,
|
|
2016
|
+
...queryResultErrorsNationalityInclusion,
|
|
2017
|
+
}
|
|
2018
|
+
} else if (!!committedInputs?.inclusion_check_issuing_country) {
|
|
2019
|
+
const inclusionCheckIssuingCountryCommittedInputs =
|
|
2020
|
+
committedInputs?.inclusion_check_issuing_country as CountryCommittedInputs
|
|
2021
|
+
const inclusionCheckIssuingCountryParameterCommitment = isForEVM
|
|
2022
|
+
? await getCountryEVMParameterCommitment(
|
|
2023
|
+
ProofType.ISSUING_COUNTRY_INCLUSION,
|
|
2024
|
+
inclusionCheckIssuingCountryCommittedInputs.countries,
|
|
2025
|
+
)
|
|
2026
|
+
: await getCountryParameterCommitment(
|
|
2027
|
+
ProofType.ISSUING_COUNTRY_INCLUSION,
|
|
2028
|
+
inclusionCheckIssuingCountryCommittedInputs.countries,
|
|
2029
|
+
)
|
|
2030
|
+
if (!paramCommitments.includes(inclusionCheckIssuingCountryParameterCommitment)) {
|
|
2031
|
+
console.warn("This proof does not verify the inclusion of the issuing country")
|
|
2032
|
+
isCorrect = false
|
|
2033
|
+
queryResultErrors.issuing_country.commitment = {
|
|
2034
|
+
expected: `Issuing country parameter commitment: ${inclusionCheckIssuingCountryParameterCommitment.toString()}`,
|
|
2035
|
+
received: `Parameter commitments included: ${paramCommitments.join(", ")}`,
|
|
2036
|
+
message: "This proof does not verify the inclusion of the issuing country",
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
const countryList = inclusionCheckIssuingCountryCommittedInputs.countries
|
|
2040
|
+
const {
|
|
2041
|
+
isCorrect: isCorrectIssuingCountryInclusion,
|
|
2042
|
+
queryResultErrors: queryResultErrorsIssuingCountryInclusion,
|
|
2043
|
+
} = this.checkIssuingCountryInclusionPublicInputs(queryResult, countryList)
|
|
2044
|
+
isCorrect = isCorrect && isCorrectIssuingCountryInclusion
|
|
2045
|
+
queryResultErrors = {
|
|
2046
|
+
...queryResultErrors,
|
|
2047
|
+
...queryResultErrorsIssuingCountryInclusion,
|
|
2048
|
+
}
|
|
2049
|
+
} else if (!!committedInputs?.exclusion_check_nationality) {
|
|
2050
|
+
const exclusionCheckNationalityCommittedInputs =
|
|
2051
|
+
committedInputs?.exclusion_check_nationality as CountryCommittedInputs
|
|
2052
|
+
const exclusionCheckNationalityParameterCommitment = isForEVM
|
|
2053
|
+
? await getCountryEVMParameterCommitment(
|
|
2054
|
+
ProofType.NATIONALITY_EXCLUSION,
|
|
2055
|
+
exclusionCheckNationalityCommittedInputs.countries,
|
|
2056
|
+
)
|
|
2057
|
+
: await getCountryParameterCommitment(
|
|
2058
|
+
ProofType.NATIONALITY_EXCLUSION,
|
|
2059
|
+
exclusionCheckNationalityCommittedInputs.countries,
|
|
2060
|
+
)
|
|
2061
|
+
if (!paramCommitments.includes(exclusionCheckNationalityParameterCommitment)) {
|
|
2062
|
+
console.warn("This proof does not verify the exclusion of the nationality")
|
|
2063
|
+
isCorrect = false
|
|
2064
|
+
queryResultErrors.nationality.commitment = {
|
|
2065
|
+
expected: `Nationality parameter commitment: ${exclusionCheckNationalityParameterCommitment.toString()}`,
|
|
2066
|
+
received: `Parameter commitments included: ${paramCommitments.join(", ")}`,
|
|
2067
|
+
message: "This proof does not verify the exclusion of the nationality",
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
const countryList = exclusionCheckNationalityCommittedInputs.countries
|
|
2071
|
+
const {
|
|
2072
|
+
isCorrect: isCorrectNationalityExclusion,
|
|
2073
|
+
queryResultErrors: queryResultErrorsNationalityExclusion,
|
|
2074
|
+
} = this.checkNationalityExclusionPublicInputs(queryResult, countryList)
|
|
2075
|
+
isCorrect = isCorrect && isCorrectNationalityExclusion
|
|
2076
|
+
queryResultErrors = {
|
|
2077
|
+
...queryResultErrors,
|
|
2078
|
+
...queryResultErrorsNationalityExclusion,
|
|
2079
|
+
}
|
|
2080
|
+
} else if (!!committedInputs?.exclusion_check_issuing_country) {
|
|
2081
|
+
const exclusionCheckIssuingCountryCommittedInputs =
|
|
2082
|
+
committedInputs?.exclusion_check_issuing_country as CountryCommittedInputs
|
|
2083
|
+
const exclusionCheckIssuingCountryParameterCommitment = isForEVM
|
|
2084
|
+
? await getCountryEVMParameterCommitment(
|
|
2085
|
+
ProofType.ISSUING_COUNTRY_EXCLUSION,
|
|
2086
|
+
exclusionCheckIssuingCountryCommittedInputs.countries,
|
|
2087
|
+
)
|
|
2088
|
+
: await getCountryParameterCommitment(
|
|
2089
|
+
ProofType.ISSUING_COUNTRY_EXCLUSION,
|
|
2090
|
+
exclusionCheckIssuingCountryCommittedInputs.countries,
|
|
2091
|
+
)
|
|
2092
|
+
if (!paramCommitments.includes(exclusionCheckIssuingCountryParameterCommitment)) {
|
|
2093
|
+
console.warn("This proof does not verify the exclusion of the issuing country")
|
|
2094
|
+
isCorrect = false
|
|
2095
|
+
queryResultErrors.issuing_country.commitment = {
|
|
2096
|
+
expected: `Issuing country parameter commitment: ${exclusionCheckIssuingCountryParameterCommitment.toString()}`,
|
|
2097
|
+
received: `Parameter commitments included: ${paramCommitments.join(", ")}`,
|
|
2098
|
+
message: "This proof does not verify the exclusion of the issuing country",
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
const countryList = exclusionCheckIssuingCountryCommittedInputs.countries
|
|
2102
|
+
const {
|
|
2103
|
+
isCorrect: isCorrectIssuingCountryExclusion,
|
|
2104
|
+
queryResultErrors: queryResultErrorsIssuingCountryExclusion,
|
|
2105
|
+
} = this.checkIssuingCountryExclusionPublicInputs(queryResult, countryList)
|
|
2106
|
+
isCorrect = isCorrect && isCorrectIssuingCountryExclusion
|
|
2107
|
+
queryResultErrors = {
|
|
2108
|
+
...queryResultErrors,
|
|
2109
|
+
...queryResultErrorsIssuingCountryExclusion,
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2112
|
+
uniqueIdentifier = getNullifierFromOuterProof(proofData).toString(10)
|
|
2113
|
+
} else if (proof.name?.startsWith("sig_check_dsc")) {
|
|
2114
|
+
commitmentOut = getCommitmentFromDSCProof(proofData)
|
|
2115
|
+
const merkleRoot = getMerkleRootFromDSCProof(proofData)
|
|
2116
|
+
if (!VALID_CERTIFICATE_REGISTRY_ROOT.includes(merkleRoot)) {
|
|
2117
|
+
console.warn("The ID was signed by an unrecognized root certificate")
|
|
1302
2118
|
isCorrect = false
|
|
1303
|
-
queryResultErrors.
|
|
1304
|
-
|
|
2119
|
+
queryResultErrors.sig_check_dsc.certificate = {
|
|
2120
|
+
expected: `Certificate registry root: ${VALID_CERTIFICATE_REGISTRY_ROOT.join(", ")}`,
|
|
2121
|
+
received: `Certificate registry root: ${merkleRoot.toString()}`,
|
|
2122
|
+
message: "The ID was signed by an unrecognized root certificate",
|
|
1305
2123
|
}
|
|
1306
2124
|
}
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
2125
|
+
} else if (proof.name?.startsWith("sig_check_id_data")) {
|
|
2126
|
+
commitmentIn = getCommitmentInFromIDDataProof(proofData)
|
|
2127
|
+
if (commitmentIn !== commitmentOut) {
|
|
2128
|
+
console.warn(
|
|
2129
|
+
"Failed to check the link between the certificate signature and ID signature",
|
|
2130
|
+
)
|
|
2131
|
+
isCorrect = false
|
|
2132
|
+
queryResultErrors.sig_check_id_data.commitment = {
|
|
2133
|
+
expected: `Commitment: ${commitmentOut?.toString() || "undefined"}`,
|
|
2134
|
+
received: `Commitment: ${commitmentIn?.toString() || "undefined"}`,
|
|
2135
|
+
message: "Failed to check the link between the certificate signature and ID signature",
|
|
2136
|
+
}
|
|
2137
|
+
}
|
|
2138
|
+
commitmentOut = getCommitmentOutFromIDDataProof(proofData)
|
|
2139
|
+
} else if (proof.name?.startsWith("data_check_integrity")) {
|
|
2140
|
+
commitmentIn = getCommitmentInFromIntegrityProof(proofData)
|
|
2141
|
+
if (commitmentIn !== commitmentOut) {
|
|
2142
|
+
console.warn("Failed to check the link between the ID signature and the data signed")
|
|
2143
|
+
isCorrect = false
|
|
2144
|
+
queryResultErrors.data_check_integrity.commitment = {
|
|
2145
|
+
expected: `Commitment: ${commitmentOut?.toString() || "undefined"}`,
|
|
2146
|
+
received: `Commitment: ${commitmentIn?.toString() || "undefined"}`,
|
|
2147
|
+
message: "Failed to check the link between the ID signature and the data signed",
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
2150
|
+
commitmentOut = getCommitmentOutFromIntegrityProof(proofData)
|
|
2151
|
+
const currentDate = getCurrentDateFromIntegrityProof(proofData)
|
|
2152
|
+
const todayToCurrentDate = today.getTime() - currentDate.getTime()
|
|
2153
|
+
const differenceInDays = validity ?? 180
|
|
2154
|
+
const expectedDifference = differenceInDays * 86400000
|
|
2155
|
+
const actualDifference = today.getTime() - (today.getTime() - expectedDifference)
|
|
2156
|
+
// The ID should not expire within the next 6 months (or whatever the custom value is)
|
|
2157
|
+
if (todayToCurrentDate >= actualDifference) {
|
|
2158
|
+
console.warn(
|
|
2159
|
+
`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`,
|
|
2160
|
+
)
|
|
2161
|
+
isCorrect = false
|
|
2162
|
+
queryResultErrors.data_check_integrity.date = {
|
|
2163
|
+
expected: `Difference: ${differenceInDays} days`,
|
|
2164
|
+
received: `Difference: ${Math.round(todayToCurrentDate / 86400000)} days`,
|
|
2165
|
+
message:
|
|
2166
|
+
"The date used to check the validity of the ID is older than the validity period",
|
|
2167
|
+
}
|
|
2168
|
+
}
|
|
2169
|
+
} else if (proof.name === "disclose_bytes") {
|
|
2170
|
+
commitmentIn = getCommitmentInFromDisclosureProof(proofData)
|
|
2171
|
+
if (commitmentIn !== commitmentOut) {
|
|
2172
|
+
console.warn(
|
|
2173
|
+
"Failed to check the link between the validity of the ID and the data to disclose",
|
|
2174
|
+
)
|
|
2175
|
+
isCorrect = false
|
|
2176
|
+
queryResultErrors.disclose.commitment = {
|
|
2177
|
+
expected: `Commitment: ${commitmentOut?.toString() || "undefined"}`,
|
|
2178
|
+
received: `Commitment: ${commitmentIn?.toString() || "undefined"}`,
|
|
2179
|
+
message:
|
|
2180
|
+
"Failed to check the link between the validity of the ID and the data to disclose",
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
const paramCommitment = getParameterCommitmentFromDisclosureProof(proofData)
|
|
2184
|
+
const calculatedParamCommitment = await getDiscloseParameterCommitment(
|
|
2185
|
+
(proof.committedInputs?.disclose_bytes as DiscloseCommittedInputs).discloseMask!,
|
|
2186
|
+
(proof.committedInputs?.disclose_bytes as DiscloseCommittedInputs).disclosedBytes!,
|
|
2187
|
+
)
|
|
2188
|
+
if (paramCommitment !== calculatedParamCommitment) {
|
|
2189
|
+
console.warn("The disclosed data does not match the data committed by the proof")
|
|
2190
|
+
isCorrect = false
|
|
2191
|
+
queryResultErrors.disclose.commitment = {
|
|
2192
|
+
expected: `Commitment: ${calculatedParamCommitment}`,
|
|
2193
|
+
received: `Commitment: ${paramCommitment}`,
|
|
2194
|
+
message: "The disclosed data does not match the data committed by the proof",
|
|
2195
|
+
}
|
|
2196
|
+
}
|
|
2197
|
+
const { isCorrect: isCorrectDisclose, queryResultErrors: queryResultErrorsDisclose } =
|
|
2198
|
+
this.checkDiscloseBytesPublicInputs(proof, queryResult)
|
|
2199
|
+
isCorrect = isCorrect && isCorrectDisclose
|
|
2200
|
+
queryResultErrors = {
|
|
2201
|
+
...queryResultErrors,
|
|
2202
|
+
...queryResultErrorsDisclose,
|
|
2203
|
+
}
|
|
2204
|
+
uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10)
|
|
2205
|
+
} else if (proof.name === "compare_age") {
|
|
2206
|
+
commitmentIn = getCommitmentInFromDisclosureProof(proofData)
|
|
2207
|
+
if (commitmentIn !== commitmentOut) {
|
|
2208
|
+
console.warn(
|
|
2209
|
+
"Failed to check the link between the validity of the ID and the age derived from it",
|
|
2210
|
+
)
|
|
2211
|
+
isCorrect = false
|
|
2212
|
+
queryResultErrors.age.commitment = {
|
|
2213
|
+
expected: `Commitment: ${commitmentOut}`,
|
|
2214
|
+
received: `Commitment: ${commitmentIn}`,
|
|
2215
|
+
message:
|
|
2216
|
+
"Failed to check the link between the validity of the ID and the age derived from it",
|
|
2217
|
+
}
|
|
2218
|
+
}
|
|
2219
|
+
const paramCommitment = getParameterCommitmentFromDisclosureProof(proofData)
|
|
2220
|
+
const committedInputs = proof.committedInputs?.compare_age as AgeCommittedInputs
|
|
2221
|
+
const calculatedParamCommitment = await getAgeParameterCommitment(
|
|
2222
|
+
committedInputs.currentDate,
|
|
2223
|
+
committedInputs.minAge,
|
|
2224
|
+
committedInputs.maxAge,
|
|
2225
|
+
)
|
|
2226
|
+
if (paramCommitment !== calculatedParamCommitment) {
|
|
2227
|
+
console.warn(
|
|
2228
|
+
"The conditions for the age check do not match the conditions checked by the proof",
|
|
2229
|
+
)
|
|
1313
2230
|
isCorrect = false
|
|
1314
|
-
queryResultErrors.age.
|
|
1315
|
-
expected:
|
|
1316
|
-
received:
|
|
1317
|
-
message:
|
|
2231
|
+
queryResultErrors.age.commitment = {
|
|
2232
|
+
expected: `Commitment: ${calculatedParamCommitment}`,
|
|
2233
|
+
received: `Commitment: ${paramCommitment}`,
|
|
2234
|
+
message:
|
|
2235
|
+
"The conditions for the age check do not match the conditions checked by the proof",
|
|
1318
2236
|
}
|
|
1319
2237
|
}
|
|
2238
|
+
const { isCorrect: isCorrectAge, queryResultErrors: queryResultErrorsAge } =
|
|
2239
|
+
this.checkAgePublicInputs(proof, queryResult)
|
|
2240
|
+
isCorrect = isCorrect && isCorrectAge
|
|
2241
|
+
queryResultErrors = {
|
|
2242
|
+
...queryResultErrors,
|
|
2243
|
+
...queryResultErrorsAge,
|
|
2244
|
+
}
|
|
1320
2245
|
uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10)
|
|
1321
2246
|
} else if (proof.name === "compare_birthdate") {
|
|
1322
2247
|
commitmentIn = getCommitmentInFromDisclosureProof(proofData)
|
|
@@ -1332,83 +2257,33 @@ export class ZKPassport {
|
|
|
1332
2257
|
"Failed to check the link between the validity of the ID and the birthdate derived from it",
|
|
1333
2258
|
}
|
|
1334
2259
|
}
|
|
1335
|
-
const
|
|
1336
|
-
const
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
received: minDate,
|
|
1348
|
-
message: "Birthdate is not greater than or equal to the expected birthdate",
|
|
1349
|
-
}
|
|
1350
|
-
}
|
|
1351
|
-
if (
|
|
1352
|
-
queryResult.birthdate.lte &&
|
|
1353
|
-
queryResult.birthdate.lte.result &&
|
|
1354
|
-
maxDate > queryResult.birthdate.lte.expected
|
|
1355
|
-
) {
|
|
1356
|
-
console.warn("Birthdate is not less than the expected birthdate")
|
|
1357
|
-
isCorrect = false
|
|
1358
|
-
queryResultErrors.birthdate.lte = {
|
|
1359
|
-
expected: queryResult.birthdate.lte.expected,
|
|
1360
|
-
received: maxDate,
|
|
1361
|
-
message: "Birthdate is not less than the expected birthdate",
|
|
1362
|
-
}
|
|
1363
|
-
}
|
|
1364
|
-
if (queryResult.birthdate.range) {
|
|
1365
|
-
if (
|
|
1366
|
-
queryResult.birthdate.range.result &&
|
|
1367
|
-
(minDate < queryResult.birthdate.range.expected[0] ||
|
|
1368
|
-
maxDate > queryResult.birthdate.range.expected[1])
|
|
1369
|
-
) {
|
|
1370
|
-
console.warn("Birthdate is not in the expected range")
|
|
1371
|
-
isCorrect = false
|
|
1372
|
-
queryResultErrors.birthdate.range = {
|
|
1373
|
-
expected: queryResult.birthdate.range.expected,
|
|
1374
|
-
received: [minDate, maxDate],
|
|
1375
|
-
message: "Birthdate is not in the expected range",
|
|
1376
|
-
}
|
|
1377
|
-
}
|
|
1378
|
-
}
|
|
1379
|
-
if (
|
|
1380
|
-
!queryResult.birthdate.lte &&
|
|
1381
|
-
!queryResult.birthdate.range &&
|
|
1382
|
-
maxDate.getTime() != defaultDateValue.getTime()
|
|
1383
|
-
) {
|
|
1384
|
-
console.warn("Maximum birthdate should be equal to default date value")
|
|
1385
|
-
isCorrect = false
|
|
1386
|
-
queryResultErrors.birthdate.disclose = {
|
|
1387
|
-
expected: `${defaultDateValue.toISOString()}`,
|
|
1388
|
-
received: `${maxDate.toISOString()}`,
|
|
1389
|
-
message: "Maximum birthdate should be equal to default date value",
|
|
1390
|
-
}
|
|
1391
|
-
}
|
|
1392
|
-
if (
|
|
1393
|
-
!queryResult.birthdate.gte &&
|
|
1394
|
-
!queryResult.birthdate.range &&
|
|
1395
|
-
minDate.getTime() != defaultDateValue.getTime()
|
|
1396
|
-
) {
|
|
1397
|
-
console.warn("Minimum birthdate should be equal to default date value")
|
|
1398
|
-
isCorrect = false
|
|
1399
|
-
queryResultErrors.birthdate.disclose = {
|
|
1400
|
-
expected: `${defaultDateValue.toISOString()}`,
|
|
1401
|
-
received: `${minDate.toISOString()}`,
|
|
1402
|
-
message: "Minimum birthdate should be equal to default date value",
|
|
1403
|
-
}
|
|
1404
|
-
}
|
|
1405
|
-
} else {
|
|
1406
|
-
console.warn("Birthdate is not set in the query result")
|
|
2260
|
+
const paramCommitment = getParameterCommitmentFromDisclosureProof(proofData)
|
|
2261
|
+
const committedInputs = proof.committedInputs?.compare_birthdate as DateCommittedInputs
|
|
2262
|
+
const calculatedParamCommitment = await getDateParameterCommitment(
|
|
2263
|
+
ProofType.BIRTHDATE,
|
|
2264
|
+
committedInputs.currentDate,
|
|
2265
|
+
committedInputs.minDate,
|
|
2266
|
+
committedInputs.maxDate,
|
|
2267
|
+
)
|
|
2268
|
+
if (paramCommitment !== calculatedParamCommitment) {
|
|
2269
|
+
console.warn(
|
|
2270
|
+
"The conditions for the birthdate check do not match the conditions checked by the proof",
|
|
2271
|
+
)
|
|
1407
2272
|
isCorrect = false
|
|
1408
|
-
queryResultErrors.birthdate.
|
|
1409
|
-
|
|
2273
|
+
queryResultErrors.birthdate.commitment = {
|
|
2274
|
+
expected: `Commitment: ${calculatedParamCommitment}`,
|
|
2275
|
+
received: `Commitment: ${paramCommitment}`,
|
|
2276
|
+
message:
|
|
2277
|
+
"The conditions for the birthdate check do not match the conditions checked by the proof",
|
|
1410
2278
|
}
|
|
1411
2279
|
}
|
|
2280
|
+
const { isCorrect: isCorrectBirthdate, queryResultErrors: queryResultErrorsBirthdate } =
|
|
2281
|
+
this.checkBirthdatePublicInputs(proof, queryResult)
|
|
2282
|
+
isCorrect = isCorrect && isCorrectBirthdate
|
|
2283
|
+
queryResultErrors = {
|
|
2284
|
+
...queryResultErrors,
|
|
2285
|
+
...queryResultErrorsBirthdate,
|
|
2286
|
+
}
|
|
1412
2287
|
uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10)
|
|
1413
2288
|
} else if (proof.name === "compare_expiry") {
|
|
1414
2289
|
commitmentIn = getCommitmentInFromDisclosureProof(proofData)
|
|
@@ -1423,83 +2298,33 @@ export class ZKPassport {
|
|
|
1423
2298
|
message: "Failed to check the link between the validity of the ID and its expiry date",
|
|
1424
2299
|
}
|
|
1425
2300
|
}
|
|
1426
|
-
const
|
|
1427
|
-
const
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
received: minDate,
|
|
1439
|
-
message: "Expiry date is not greater than or equal to the expected expiry date",
|
|
1440
|
-
}
|
|
1441
|
-
}
|
|
1442
|
-
if (
|
|
1443
|
-
queryResult.expiry_date.lte &&
|
|
1444
|
-
queryResult.expiry_date.lte.result &&
|
|
1445
|
-
maxDate > queryResult.expiry_date.lte.expected
|
|
1446
|
-
) {
|
|
1447
|
-
console.warn("Expiry date is not less than the expected expiry date")
|
|
1448
|
-
isCorrect = false
|
|
1449
|
-
queryResultErrors.expiry_date.lte = {
|
|
1450
|
-
expected: queryResult.expiry_date.lte.expected,
|
|
1451
|
-
received: maxDate,
|
|
1452
|
-
message: "Expiry date is not less than the expected expiry date",
|
|
1453
|
-
}
|
|
1454
|
-
}
|
|
1455
|
-
if (queryResult.expiry_date.range) {
|
|
1456
|
-
if (
|
|
1457
|
-
queryResult.expiry_date.range.result &&
|
|
1458
|
-
(minDate < queryResult.expiry_date.range.expected[0] ||
|
|
1459
|
-
maxDate > queryResult.expiry_date.range.expected[1])
|
|
1460
|
-
) {
|
|
1461
|
-
console.warn("Expiry date is not in the expected range")
|
|
1462
|
-
isCorrect = false
|
|
1463
|
-
queryResultErrors.expiry_date.range = {
|
|
1464
|
-
expected: queryResult.expiry_date.range.expected,
|
|
1465
|
-
received: [minDate, maxDate],
|
|
1466
|
-
message: "Expiry date is not in the expected range",
|
|
1467
|
-
}
|
|
1468
|
-
}
|
|
1469
|
-
}
|
|
1470
|
-
if (
|
|
1471
|
-
!queryResult.expiry_date.lte &&
|
|
1472
|
-
!queryResult.expiry_date.range &&
|
|
1473
|
-
maxDate.getTime() != defaultDateValue.getTime()
|
|
1474
|
-
) {
|
|
1475
|
-
console.warn("Maximum expiry date should be equal to default date value")
|
|
1476
|
-
isCorrect = false
|
|
1477
|
-
queryResultErrors.expiry_date.disclose = {
|
|
1478
|
-
expected: `${defaultDateValue.toISOString()}`,
|
|
1479
|
-
received: `${maxDate.toISOString()}`,
|
|
1480
|
-
message: "Maximum expiry date should be equal to default date value",
|
|
1481
|
-
}
|
|
1482
|
-
}
|
|
1483
|
-
if (
|
|
1484
|
-
!queryResult.expiry_date.gte &&
|
|
1485
|
-
!queryResult.expiry_date.range &&
|
|
1486
|
-
minDate.getTime() != defaultDateValue.getTime()
|
|
1487
|
-
) {
|
|
1488
|
-
console.warn("Minimum expiry date should be equal to default date value")
|
|
1489
|
-
isCorrect = false
|
|
1490
|
-
queryResultErrors.expiry_date.disclose = {
|
|
1491
|
-
expected: `${defaultDateValue.toISOString()}`,
|
|
1492
|
-
received: `${minDate.toISOString()}`,
|
|
1493
|
-
message: "Minimum expiry date should be equal to default date value",
|
|
1494
|
-
}
|
|
1495
|
-
}
|
|
1496
|
-
} else {
|
|
1497
|
-
console.warn("Expiry date is not set in the query result")
|
|
2301
|
+
const paramCommitment = getParameterCommitmentFromDisclosureProof(proofData)
|
|
2302
|
+
const committedInputs = proof.committedInputs?.compare_expiry as DateCommittedInputs
|
|
2303
|
+
const calculatedParamCommitment = await getDateParameterCommitment(
|
|
2304
|
+
ProofType.EXPIRY_DATE,
|
|
2305
|
+
committedInputs.currentDate,
|
|
2306
|
+
committedInputs.minDate,
|
|
2307
|
+
committedInputs.maxDate,
|
|
2308
|
+
)
|
|
2309
|
+
if (paramCommitment !== calculatedParamCommitment) {
|
|
2310
|
+
console.warn(
|
|
2311
|
+
"The conditions for the expiry date check do not match the conditions checked by the proof",
|
|
2312
|
+
)
|
|
1498
2313
|
isCorrect = false
|
|
1499
|
-
queryResultErrors.expiry_date.
|
|
1500
|
-
|
|
2314
|
+
queryResultErrors.expiry_date.commitment = {
|
|
2315
|
+
expected: `Commitment: ${calculatedParamCommitment}`,
|
|
2316
|
+
received: `Commitment: ${paramCommitment}`,
|
|
2317
|
+
message:
|
|
2318
|
+
"The conditions for the expiry date check do not match the conditions checked by the proof",
|
|
1501
2319
|
}
|
|
1502
2320
|
}
|
|
2321
|
+
const { isCorrect: isCorrectExpiryDate, queryResultErrors: queryResultErrorsExpiryDate } =
|
|
2322
|
+
this.checkExpiryDatePublicInputs(proof, queryResult)
|
|
2323
|
+
isCorrect = isCorrect && isCorrectExpiryDate
|
|
2324
|
+
queryResultErrors = {
|
|
2325
|
+
...queryResultErrors,
|
|
2326
|
+
...queryResultErrorsExpiryDate,
|
|
2327
|
+
}
|
|
1503
2328
|
uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10)
|
|
1504
2329
|
} else if (proof.name === "exclusion_check_nationality") {
|
|
1505
2330
|
commitmentIn = getCommitmentInFromDisclosureProof(proofData)
|
|
@@ -1515,44 +2340,36 @@ export class ZKPassport {
|
|
|
1515
2340
|
"Failed to check the link between the validity of the ID and the nationality exclusion check",
|
|
1516
2341
|
}
|
|
1517
2342
|
}
|
|
1518
|
-
const countryList =
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
received: countryList,
|
|
1532
|
-
message: "Nationality exclusion list does not match the one from the query results",
|
|
1533
|
-
}
|
|
1534
|
-
}
|
|
1535
|
-
} else if (!queryResult.nationality || !queryResult.nationality.out) {
|
|
1536
|
-
console.warn("Nationality exclusion is not set in the query result")
|
|
2343
|
+
const countryList = (
|
|
2344
|
+
proof.committedInputs?.exclusion_check_nationality as CountryCommittedInputs
|
|
2345
|
+
).countries
|
|
2346
|
+
const paramCommittment = getParameterCommitmentFromDisclosureProof(proofData)
|
|
2347
|
+
const calculatedParamCommitment = await getCountryParameterCommitment(
|
|
2348
|
+
ProofType.NATIONALITY_EXCLUSION,
|
|
2349
|
+
countryList,
|
|
2350
|
+
true,
|
|
2351
|
+
)
|
|
2352
|
+
if (paramCommittment !== calculatedParamCommitment) {
|
|
2353
|
+
console.warn(
|
|
2354
|
+
"The committed country list for the exclusion check does not match the one from the proof",
|
|
2355
|
+
)
|
|
1537
2356
|
isCorrect = false
|
|
1538
|
-
queryResultErrors.nationality.
|
|
1539
|
-
|
|
2357
|
+
queryResultErrors.nationality.commitment = {
|
|
2358
|
+
expected: `Commitment: ${calculatedParamCommitment}`,
|
|
2359
|
+
received: `Commitment: ${paramCommittment}`,
|
|
2360
|
+
message:
|
|
2361
|
+
"The committed country list for the exclusion check does not match the one from the proof",
|
|
1540
2362
|
}
|
|
1541
2363
|
}
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
queryResultErrors.nationality.out = {
|
|
1552
|
-
message:
|
|
1553
|
-
"The nationality exclusion list has not been sorted, and thus the proof cannot be trusted",
|
|
1554
|
-
}
|
|
1555
|
-
}
|
|
2364
|
+
|
|
2365
|
+
const {
|
|
2366
|
+
isCorrect: isCorrectNationalityExclusion,
|
|
2367
|
+
queryResultErrors: queryResultErrorsNationalityExclusion,
|
|
2368
|
+
} = this.checkNationalityExclusionPublicInputs(queryResult, countryList)
|
|
2369
|
+
isCorrect = isCorrect && isCorrectNationalityExclusion
|
|
2370
|
+
queryResultErrors = {
|
|
2371
|
+
...queryResultErrors,
|
|
2372
|
+
...queryResultErrorsNationalityExclusion,
|
|
1556
2373
|
}
|
|
1557
2374
|
uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10)
|
|
1558
2375
|
} else if (proof.name === "exclusion_check_issuing_country") {
|
|
@@ -1569,49 +2386,35 @@ export class ZKPassport {
|
|
|
1569
2386
|
"Failed to check the link between the validity of the ID and the issuing country exclusion check",
|
|
1570
2387
|
}
|
|
1571
2388
|
}
|
|
1572
|
-
const countryList =
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
)
|
|
1586
|
-
isCorrect = false
|
|
1587
|
-
queryResultErrors.issuing_country.out = {
|
|
1588
|
-
expected: queryResult.issuing_country.out.expected,
|
|
1589
|
-
received: countryList,
|
|
1590
|
-
message:
|
|
1591
|
-
"Issuing country exclusion list does not match the one from the query results",
|
|
1592
|
-
}
|
|
1593
|
-
}
|
|
1594
|
-
} else if (!queryResult.issuing_country || !queryResult.issuing_country.out) {
|
|
1595
|
-
console.warn("Issuing country exclusion is not set in the query result")
|
|
2389
|
+
const countryList = (
|
|
2390
|
+
proof.committedInputs?.exclusion_check_issuing_country as CountryCommittedInputs
|
|
2391
|
+
).countries
|
|
2392
|
+
const paramCommittment = getParameterCommitmentFromDisclosureProof(proofData)
|
|
2393
|
+
const calculatedParamCommitment = await getCountryParameterCommitment(
|
|
2394
|
+
ProofType.ISSUING_COUNTRY_EXCLUSION,
|
|
2395
|
+
countryList,
|
|
2396
|
+
true,
|
|
2397
|
+
)
|
|
2398
|
+
if (paramCommittment !== calculatedParamCommitment) {
|
|
2399
|
+
console.warn(
|
|
2400
|
+
"The committed country list for the issuing country exclusion check does not match the one from the proof",
|
|
2401
|
+
)
|
|
1596
2402
|
isCorrect = false
|
|
1597
|
-
queryResultErrors.issuing_country.
|
|
1598
|
-
|
|
2403
|
+
queryResultErrors.issuing_country.commitment = {
|
|
2404
|
+
expected: `Commitment: ${calculatedParamCommitment}`,
|
|
2405
|
+
received: `Commitment: ${paramCommittment}`,
|
|
2406
|
+
message:
|
|
2407
|
+
"The committed country list for the issuing country exclusion check does not match the one from the proof",
|
|
1599
2408
|
}
|
|
1600
2409
|
}
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
isCorrect = false
|
|
1610
|
-
queryResultErrors.issuing_country.out = {
|
|
1611
|
-
message:
|
|
1612
|
-
"The issuing country exclusion list has not been sorted, and thus the proof cannot be trusted",
|
|
1613
|
-
}
|
|
1614
|
-
}
|
|
2410
|
+
const {
|
|
2411
|
+
isCorrect: isCorrectIssuingCountryExclusion,
|
|
2412
|
+
queryResultErrors: queryResultErrorsIssuingCountryExclusion,
|
|
2413
|
+
} = this.checkIssuingCountryExclusionPublicInputs(queryResult, countryList)
|
|
2414
|
+
isCorrect = isCorrect && isCorrectIssuingCountryExclusion
|
|
2415
|
+
queryResultErrors = {
|
|
2416
|
+
...queryResultErrors,
|
|
2417
|
+
...queryResultErrorsIssuingCountryExclusion,
|
|
1615
2418
|
}
|
|
1616
2419
|
uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10)
|
|
1617
2420
|
} else if (proof.name === "inclusion_check_nationality") {
|
|
@@ -1628,30 +2431,36 @@ export class ZKPassport {
|
|
|
1628
2431
|
"Failed to check the link between the validity of the ID and the nationality inclusion check",
|
|
1629
2432
|
}
|
|
1630
2433
|
}
|
|
1631
|
-
const countryList =
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
received: countryList,
|
|
1645
|
-
message: "Nationality inclusion list does not match the one from the query results",
|
|
1646
|
-
}
|
|
1647
|
-
}
|
|
1648
|
-
} else if (!queryResult.nationality || !queryResult.nationality.in) {
|
|
1649
|
-
console.warn("Nationality inclusion is not set in the query result")
|
|
2434
|
+
const countryList = (
|
|
2435
|
+
proof.committedInputs?.inclusion_check_nationality as CountryCommittedInputs
|
|
2436
|
+
).countries
|
|
2437
|
+
const paramCommittment = getParameterCommitmentFromDisclosureProof(proofData)
|
|
2438
|
+
const calculatedParamCommitment = await getCountryParameterCommitment(
|
|
2439
|
+
ProofType.NATIONALITY_INCLUSION,
|
|
2440
|
+
countryList,
|
|
2441
|
+
false,
|
|
2442
|
+
)
|
|
2443
|
+
if (paramCommittment !== calculatedParamCommitment) {
|
|
2444
|
+
console.warn(
|
|
2445
|
+
"The committed country list for the nationality inclusion check does not match the one from the proof",
|
|
2446
|
+
)
|
|
1650
2447
|
isCorrect = false
|
|
1651
|
-
queryResultErrors.nationality.
|
|
1652
|
-
|
|
2448
|
+
queryResultErrors.nationality.commitment = {
|
|
2449
|
+
expected: `Commitment: ${calculatedParamCommitment}`,
|
|
2450
|
+
received: `Commitment: ${paramCommittment}`,
|
|
2451
|
+
message:
|
|
2452
|
+
"The committed country list for the nationality inclusion check does not match the one from the proof",
|
|
1653
2453
|
}
|
|
1654
2454
|
}
|
|
2455
|
+
const {
|
|
2456
|
+
isCorrect: isCorrectNationalityInclusion,
|
|
2457
|
+
queryResultErrors: queryResultErrorsNationalityInclusion,
|
|
2458
|
+
} = this.checkNationalityInclusionPublicInputs(queryResult, countryList)
|
|
2459
|
+
isCorrect = isCorrect && isCorrectNationalityInclusion
|
|
2460
|
+
queryResultErrors = {
|
|
2461
|
+
...queryResultErrors,
|
|
2462
|
+
...queryResultErrorsNationalityInclusion,
|
|
2463
|
+
}
|
|
1655
2464
|
uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10)
|
|
1656
2465
|
} else if (proof.name === "inclusion_check_issuing_country") {
|
|
1657
2466
|
commitmentIn = getCommitmentInFromDisclosureProof(proofData)
|
|
@@ -1667,35 +2476,36 @@ export class ZKPassport {
|
|
|
1667
2476
|
"Failed to check the link between the validity of the ID and the issuing country inclusion check",
|
|
1668
2477
|
}
|
|
1669
2478
|
}
|
|
1670
|
-
const countryList =
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
)
|
|
1684
|
-
isCorrect = false
|
|
1685
|
-
queryResultErrors.issuing_country.in = {
|
|
1686
|
-
expected: queryResult.issuing_country.in.expected,
|
|
1687
|
-
received: countryList,
|
|
1688
|
-
message:
|
|
1689
|
-
"Issuing country inclusion list does not match the one from the query results",
|
|
1690
|
-
}
|
|
1691
|
-
}
|
|
1692
|
-
} else if (!queryResult.issuing_country || !queryResult.issuing_country.in) {
|
|
1693
|
-
console.warn("Issuing country inclusion is not set in the query result")
|
|
2479
|
+
const countryList = (
|
|
2480
|
+
proof.committedInputs?.inclusion_check_issuing_country as CountryCommittedInputs
|
|
2481
|
+
).countries
|
|
2482
|
+
const paramCommittment = getParameterCommitmentFromDisclosureProof(proofData)
|
|
2483
|
+
const calculatedParamCommitment = await getCountryParameterCommitment(
|
|
2484
|
+
ProofType.ISSUING_COUNTRY_INCLUSION,
|
|
2485
|
+
countryList,
|
|
2486
|
+
false,
|
|
2487
|
+
)
|
|
2488
|
+
if (paramCommittment !== calculatedParamCommitment) {
|
|
2489
|
+
console.warn(
|
|
2490
|
+
"The committed country list for the issuing country inclusion check does not match the one from the proof",
|
|
2491
|
+
)
|
|
1694
2492
|
isCorrect = false
|
|
1695
|
-
queryResultErrors.issuing_country.
|
|
1696
|
-
|
|
2493
|
+
queryResultErrors.issuing_country.commitment = {
|
|
2494
|
+
expected: `Commitment: ${calculatedParamCommitment}`,
|
|
2495
|
+
received: `Commitment: ${paramCommittment}`,
|
|
2496
|
+
message:
|
|
2497
|
+
"The committed country list for the issuing country inclusion check does not match the one from the proof",
|
|
1697
2498
|
}
|
|
1698
2499
|
}
|
|
2500
|
+
const {
|
|
2501
|
+
isCorrect: isCorrectIssuingCountryInclusion,
|
|
2502
|
+
queryResultErrors: queryResultErrorsIssuingCountryInclusion,
|
|
2503
|
+
} = this.checkIssuingCountryInclusionPublicInputs(queryResult, countryList)
|
|
2504
|
+
isCorrect = isCorrect && isCorrectIssuingCountryInclusion
|
|
2505
|
+
queryResultErrors = {
|
|
2506
|
+
...queryResultErrors,
|
|
2507
|
+
...queryResultErrorsIssuingCountryInclusion,
|
|
2508
|
+
}
|
|
1699
2509
|
uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10)
|
|
1700
2510
|
}
|
|
1701
2511
|
}
|
|
@@ -1752,17 +2562,54 @@ export class ZKPassport {
|
|
|
1752
2562
|
// Only proceed with the proof verification if the public inputs are correct
|
|
1753
2563
|
if (verified) {
|
|
1754
2564
|
for (const proof of proofs) {
|
|
1755
|
-
const proofData = getProofData(proof.proof as string,
|
|
2565
|
+
const proofData = getProofData(proof.proof as string, getNumberOfPublicInputs(proof.name!))
|
|
1756
2566
|
const hostedPackagedCircuit = await getHostedPackagedCircuitByName(
|
|
1757
2567
|
proof.version as any,
|
|
1758
2568
|
proof.name!,
|
|
1759
2569
|
)
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
2570
|
+
if (proof.name?.startsWith("outer_evm")) {
|
|
2571
|
+
try {
|
|
2572
|
+
const { createPublicClient, http } = await import("viem")
|
|
2573
|
+
const { sepolia } = await import("viem/chains")
|
|
2574
|
+
const verifierDetails = this.getSolidityVerifierDetails("ethereum_sepolia")
|
|
2575
|
+
const client = createPublicClient({
|
|
2576
|
+
chain: sepolia,
|
|
2577
|
+
transport: http("https://ethereum-sepolia-rpc.publicnode.com"),
|
|
2578
|
+
})
|
|
2579
|
+
const params = this.getSolidityVerifierParameters(proof)
|
|
2580
|
+
const result = await client.readContract({
|
|
2581
|
+
address: verifierDetails.address as `0x${string}`,
|
|
2582
|
+
abi: verifierDetails.abi,
|
|
2583
|
+
functionName: "verifyProof",
|
|
2584
|
+
args: [
|
|
2585
|
+
params.vkeyHash,
|
|
2586
|
+
params.proof,
|
|
2587
|
+
params.publicInputs,
|
|
2588
|
+
params.committedInputs,
|
|
2589
|
+
params.committedInputCounts,
|
|
2590
|
+
params.validityPeriodInDays,
|
|
2591
|
+
],
|
|
2592
|
+
})
|
|
2593
|
+
const isVerified = Array.isArray(result) ? Boolean(result[0]) : false
|
|
2594
|
+
verified = isVerified
|
|
2595
|
+
} catch (error) {
|
|
2596
|
+
console.warn("Error verifying proof", error)
|
|
2597
|
+
verified = false
|
|
2598
|
+
}
|
|
2599
|
+
} else {
|
|
2600
|
+
const vkeyBytes = Buffer.from(hostedPackagedCircuit.vkey, "base64")
|
|
2601
|
+
try {
|
|
2602
|
+
verified = await verifier.verifyUltraHonkProof(
|
|
2603
|
+
{
|
|
2604
|
+
proof: Buffer.from(proofData.proof.join(""), "hex"),
|
|
2605
|
+
publicInputs: proofData.publicInputs,
|
|
2606
|
+
},
|
|
2607
|
+
new Uint8Array(vkeyBytes),
|
|
2608
|
+
)
|
|
2609
|
+
} catch (e) {
|
|
2610
|
+
console.warn("Error verifying proof", e)
|
|
2611
|
+
verified = false
|
|
2612
|
+
}
|
|
1766
2613
|
}
|
|
1767
2614
|
if (!verified) {
|
|
1768
2615
|
// Break the loop if the proof is not valid
|
|
@@ -1776,6 +2623,166 @@ export class ZKPassport {
|
|
|
1776
2623
|
return { uniqueIdentifier, verified, queryResultErrors }
|
|
1777
2624
|
}
|
|
1778
2625
|
|
|
2626
|
+
public getSolidityVerifierDetails(network: EVMChain): {
|
|
2627
|
+
address: string
|
|
2628
|
+
abi: {
|
|
2629
|
+
type: "function" | "event" | "constructor"
|
|
2630
|
+
name: string
|
|
2631
|
+
inputs: { name: string; type: string; internalType: string }[]
|
|
2632
|
+
outputs: { name: string; type: string; internalType: string }[]
|
|
2633
|
+
}[]
|
|
2634
|
+
} {
|
|
2635
|
+
if (network === "ethereum_sepolia") {
|
|
2636
|
+
return {
|
|
2637
|
+
address: "0xca644D3424c2ee577FaaF2b56C0f9D1937E8e87C",
|
|
2638
|
+
abi: ZKPassportVerifierAbi.abi as any,
|
|
2639
|
+
}
|
|
2640
|
+
} else if (network === "local_anvil") {
|
|
2641
|
+
return {
|
|
2642
|
+
address: "0x0",
|
|
2643
|
+
abi: ZKPassportVerifierAbi.abi as any,
|
|
2644
|
+
}
|
|
2645
|
+
}
|
|
2646
|
+
throw new Error(`Unsupported network: ${network}`)
|
|
2647
|
+
}
|
|
2648
|
+
|
|
2649
|
+
public getSolidityVerifierParameters(proof: ProofResult, validityPeriodInDays: number = 7) {
|
|
2650
|
+
if (!proof.name?.startsWith("outer_evm")) {
|
|
2651
|
+
throw new Error(
|
|
2652
|
+
"This proof cannot be verified on an EVM chain. Please make sure to use the `compressed-evm` mode.",
|
|
2653
|
+
)
|
|
2654
|
+
}
|
|
2655
|
+
const proofData = getProofData(proof.proof as string, getNumberOfPublicInputs(proof.name!))
|
|
2656
|
+
// For EVM optimised proofs, the first 16 bytes of the proof are the aggregation object
|
|
2657
|
+
// and should be moved at the end of the public inputs
|
|
2658
|
+
const actualProof = proofData.proof.slice(16)
|
|
2659
|
+
const actualPublicInputs = proofData.publicInputs.concat(
|
|
2660
|
+
proofData.proof.slice(0, 16).map((x) => `0x${x}`),
|
|
2661
|
+
)
|
|
2662
|
+
let committedInputCounts: { circuitName: DisclosureCircuitName; count: number }[] = []
|
|
2663
|
+
let committedInputs: { circuitName: DisclosureCircuitName; inputs: string }[] = []
|
|
2664
|
+
for (const key in proof.committedInputs) {
|
|
2665
|
+
const committedInputCount = getCommittedInputCount(key as DisclosureCircuitName)
|
|
2666
|
+
const circuitName = key as DisclosureCircuitName
|
|
2667
|
+
committedInputCounts.push({ circuitName, count: committedInputCount })
|
|
2668
|
+
let compressedCommittedInputs = ""
|
|
2669
|
+
if (
|
|
2670
|
+
circuitName === "inclusion_check_issuing_country_evm" ||
|
|
2671
|
+
circuitName === "inclusion_check_nationality_evm" ||
|
|
2672
|
+
circuitName === "exclusion_check_issuing_country_evm" ||
|
|
2673
|
+
circuitName === "exclusion_check_nationality_evm"
|
|
2674
|
+
) {
|
|
2675
|
+
const value = proof.committedInputs[circuitName] as CountryCommittedInputs
|
|
2676
|
+
const formattedCountries = value.countries
|
|
2677
|
+
if (
|
|
2678
|
+
circuitName === "exclusion_check_issuing_country_evm" ||
|
|
2679
|
+
circuitName === "exclusion_check_nationality_evm"
|
|
2680
|
+
) {
|
|
2681
|
+
formattedCountries.sort((a, b) => a.localeCompare(b))
|
|
2682
|
+
}
|
|
2683
|
+
const proofType = (() => {
|
|
2684
|
+
switch (circuitName) {
|
|
2685
|
+
case "exclusion_check_issuing_country_evm":
|
|
2686
|
+
return ProofType.ISSUING_COUNTRY_EXCLUSION
|
|
2687
|
+
case "exclusion_check_nationality_evm":
|
|
2688
|
+
return ProofType.NATIONALITY_EXCLUSION
|
|
2689
|
+
case "inclusion_check_issuing_country_evm":
|
|
2690
|
+
return ProofType.ISSUING_COUNTRY_INCLUSION
|
|
2691
|
+
case "inclusion_check_nationality_evm":
|
|
2692
|
+
return ProofType.NATIONALITY_INCLUSION
|
|
2693
|
+
}
|
|
2694
|
+
})()
|
|
2695
|
+
compressedCommittedInputs =
|
|
2696
|
+
proofType.toString(16).padStart(2, "0") +
|
|
2697
|
+
rightPadArrayWithZeros(
|
|
2698
|
+
formattedCountries.map((c) => Array.from(new TextEncoder().encode(c))).flat(),
|
|
2699
|
+
600,
|
|
2700
|
+
)
|
|
2701
|
+
.map((x) => x.toString(16).padStart(2, "0"))
|
|
2702
|
+
.join("")
|
|
2703
|
+
} else if (circuitName === "compare_age_evm") {
|
|
2704
|
+
const value = proof.committedInputs[circuitName] as AgeCommittedInputs
|
|
2705
|
+
const currentDateBytes = Array.from(new TextEncoder().encode(value.currentDate))
|
|
2706
|
+
compressedCommittedInputs =
|
|
2707
|
+
ProofType.AGE.toString(16).padStart(2, "0") +
|
|
2708
|
+
currentDateBytes.map((x) => x.toString(16).padStart(2, "0")).join("") +
|
|
2709
|
+
value.minAge.toString(16).padStart(2, "0") +
|
|
2710
|
+
value.maxAge.toString(16).padStart(2, "0")
|
|
2711
|
+
} else if (circuitName === "compare_birthdate_evm") {
|
|
2712
|
+
const value = proof.committedInputs[circuitName] as DateCommittedInputs
|
|
2713
|
+
const currentDateBytes = Array.from(new TextEncoder().encode(value.currentDate))
|
|
2714
|
+
const minDateBytes = Array.from(new TextEncoder().encode(value.minDate))
|
|
2715
|
+
const maxDateBytes = Array.from(new TextEncoder().encode(value.maxDate))
|
|
2716
|
+
compressedCommittedInputs =
|
|
2717
|
+
ProofType.BIRTHDATE.toString(16).padStart(2, "0") +
|
|
2718
|
+
currentDateBytes.map((x) => x.toString(16).padStart(2, "0")).join("") +
|
|
2719
|
+
minDateBytes.map((x) => x.toString(16).padStart(2, "0")).join("") +
|
|
2720
|
+
maxDateBytes.map((x) => x.toString(16).padStart(2, "0")).join("")
|
|
2721
|
+
} else if (circuitName === "compare_expiry_evm") {
|
|
2722
|
+
const value = proof.committedInputs[circuitName] as DateCommittedInputs
|
|
2723
|
+
const currentDateBytes = Array.from(new TextEncoder().encode(value.currentDate))
|
|
2724
|
+
const minDateBytes = Array.from(new TextEncoder().encode(value.minDate))
|
|
2725
|
+
const maxDateBytes = Array.from(new TextEncoder().encode(value.maxDate))
|
|
2726
|
+
compressedCommittedInputs =
|
|
2727
|
+
ProofType.EXPIRY_DATE.toString(16).padStart(2, "0") +
|
|
2728
|
+
currentDateBytes.map((x) => x.toString(16).padStart(2, "0")).join("") +
|
|
2729
|
+
minDateBytes.map((x) => x.toString(16).padStart(2, "0")).join("") +
|
|
2730
|
+
maxDateBytes.map((x) => x.toString(16).padStart(2, "0")).join("")
|
|
2731
|
+
} else if (circuitName === "disclose_bytes_evm") {
|
|
2732
|
+
const value = proof.committedInputs[circuitName] as DiscloseCommittedInputs
|
|
2733
|
+
compressedCommittedInputs =
|
|
2734
|
+
ProofType.DISCLOSE.toString(16).padStart(2, "0") +
|
|
2735
|
+
value.discloseMask.map((x) => x.toString(16).padStart(2, "0")).join("") +
|
|
2736
|
+
value.disclosedBytes.map((x) => x.toString(16).padStart(2, "0")).join("")
|
|
2737
|
+
} else {
|
|
2738
|
+
throw new Error(`Unsupported circuit for EVM verification: ${circuitName}`)
|
|
2739
|
+
}
|
|
2740
|
+
committedInputs.push({ circuitName, inputs: compressedCommittedInputs })
|
|
2741
|
+
}
|
|
2742
|
+
const parameterCommitments = proofData.publicInputs.slice(11, proofData.publicInputs.length - 1)
|
|
2743
|
+
let compressedCommittedInputs = ""
|
|
2744
|
+
let committedInputCountsArray = []
|
|
2745
|
+
for (const commitment of parameterCommitments) {
|
|
2746
|
+
const committedInput = committedInputs.find((x) => {
|
|
2747
|
+
const rawHashedInputs = sha256(hexToBytes(x.inputs))
|
|
2748
|
+
// Shift the hash 8 bits to the right (1 byte)
|
|
2749
|
+
// as one byte is dropped in the circuit to fit in the 254-bit field size
|
|
2750
|
+
const hashedInputs = new Uint8Array(rawHashedInputs.length)
|
|
2751
|
+
// Move each byte 1 position to the right (shifting 8 bits)
|
|
2752
|
+
for (let i = 0; i < rawHashedInputs.length - 1; i++) {
|
|
2753
|
+
hashedInputs[i + 1] = rawHashedInputs[i]
|
|
2754
|
+
}
|
|
2755
|
+
// First byte becomes 0 (since we're shifting right)
|
|
2756
|
+
hashedInputs[0] = 0
|
|
2757
|
+
|
|
2758
|
+
return bytesToHex(hashedInputs) === commitment.replace("0x", "")
|
|
2759
|
+
})
|
|
2760
|
+
if (committedInput) {
|
|
2761
|
+
const count = committedInputCounts.find(
|
|
2762
|
+
(x) => x.circuitName === committedInput.circuitName,
|
|
2763
|
+
)?.count
|
|
2764
|
+
if (count) {
|
|
2765
|
+
committedInputCountsArray.push(count)
|
|
2766
|
+
compressedCommittedInputs += committedInput.inputs
|
|
2767
|
+
} else {
|
|
2768
|
+
throw new Error(`Unknown circuit name: ${committedInput.circuitName}`)
|
|
2769
|
+
}
|
|
2770
|
+
} else {
|
|
2771
|
+
throw new Error(`Invalid commitment: ${commitment}`)
|
|
2772
|
+
}
|
|
2773
|
+
}
|
|
2774
|
+
const params: SolidityVerifierParameters = {
|
|
2775
|
+
// Make sure the vkeyHash is 32 bytes
|
|
2776
|
+
vkeyHash: `0x${proof.vkeyHash!.replace("0x", "").padStart(64, "0")}`,
|
|
2777
|
+
proof: `0x${actualProof.join("")}`,
|
|
2778
|
+
publicInputs: actualPublicInputs,
|
|
2779
|
+
committedInputs: `0x${compressedCommittedInputs}`,
|
|
2780
|
+
committedInputCounts: committedInputCountsArray,
|
|
2781
|
+
validityPeriodInDays,
|
|
2782
|
+
}
|
|
2783
|
+
return params
|
|
2784
|
+
}
|
|
2785
|
+
|
|
1779
2786
|
/**
|
|
1780
2787
|
* @notice Returns the URL of the request.
|
|
1781
2788
|
* @param requestId The request ID.
|
|
@@ -1789,7 +2796,7 @@ export class ZKPassport {
|
|
|
1789
2796
|
const base64Service = Buffer.from(JSON.stringify(this.topicToService[requestId])).toString(
|
|
1790
2797
|
"base64",
|
|
1791
2798
|
)
|
|
1792
|
-
return `https://zkpassport.id/r?d=${this.domain}&t=${requestId}&c=${base64Config}&s=${base64Service}&p=${pubkey}`
|
|
2799
|
+
return `https://zkpassport.id/r?d=${this.domain}&t=${requestId}&c=${base64Config}&s=${base64Service}&p=${pubkey}&m=${this.topicToLocalConfig[requestId].mode}`
|
|
1793
2800
|
}
|
|
1794
2801
|
|
|
1795
2802
|
/**
|