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