@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/dist/cjs/index.js
CHANGED
|
@@ -13,6 +13,10 @@ const logger_1 = require("./logger");
|
|
|
13
13
|
const pako_1 = require("pako");
|
|
14
14
|
const en_json_1 = tslib_1.__importDefault(require("i18n-iso-countries/langs/en.json"));
|
|
15
15
|
const buffer_1 = require("buffer/");
|
|
16
|
+
const sha256_1 = require("@noble/hashes/sha256");
|
|
17
|
+
const utils_3 = require("@noble/hashes/utils");
|
|
18
|
+
const ZKPassportVerifier_json_1 = tslib_1.__importDefault(require("./assets/abi/ZKPassportVerifier.json"));
|
|
19
|
+
const DEFAULT_DATE_VALUE = new Date(1111, 10, 11);
|
|
16
20
|
// If Buffer is not defined, then we use the Buffer from the buffer package
|
|
17
21
|
if (typeof globalThis.Buffer === "undefined") {
|
|
18
22
|
globalThis.Buffer = buffer_1.Buffer;
|
|
@@ -59,13 +63,13 @@ function generalCompare(fnName, key, value, requestId, requestIdToConfig) {
|
|
|
59
63
|
[fnName]: value,
|
|
60
64
|
};
|
|
61
65
|
}
|
|
62
|
-
var
|
|
63
|
-
Object.defineProperty(exports, "SANCTIONED_COUNTRIES", { enumerable: true, get: function () { return
|
|
64
|
-
Object.defineProperty(exports, "EU_COUNTRIES", { enumerable: true, get: function () { return
|
|
65
|
-
Object.defineProperty(exports, "EEA_COUNTRIES", { enumerable: true, get: function () { return
|
|
66
|
-
Object.defineProperty(exports, "SCHENGEN_COUNTRIES", { enumerable: true, get: function () { return
|
|
67
|
-
Object.defineProperty(exports, "ASEAN_COUNTRIES", { enumerable: true, get: function () { return
|
|
68
|
-
Object.defineProperty(exports, "MERCOSUR_COUNTRIES", { enumerable: true, get: function () { return
|
|
66
|
+
var utils_4 = require("@zkpassport/utils");
|
|
67
|
+
Object.defineProperty(exports, "SANCTIONED_COUNTRIES", { enumerable: true, get: function () { return utils_4.SANCTIONED_COUNTRIES; } });
|
|
68
|
+
Object.defineProperty(exports, "EU_COUNTRIES", { enumerable: true, get: function () { return utils_4.EU_COUNTRIES; } });
|
|
69
|
+
Object.defineProperty(exports, "EEA_COUNTRIES", { enumerable: true, get: function () { return utils_4.EEA_COUNTRIES; } });
|
|
70
|
+
Object.defineProperty(exports, "SCHENGEN_COUNTRIES", { enumerable: true, get: function () { return utils_4.SCHENGEN_COUNTRIES; } });
|
|
71
|
+
Object.defineProperty(exports, "ASEAN_COUNTRIES", { enumerable: true, get: function () { return utils_4.ASEAN_COUNTRIES; } });
|
|
72
|
+
Object.defineProperty(exports, "MERCOSUR_COUNTRIES", { enumerable: true, get: function () { return utils_4.MERCOSUR_COUNTRIES; } });
|
|
69
73
|
class ZKPassport {
|
|
70
74
|
//private wasmVerifierInit: boolean = false
|
|
71
75
|
constructor(_domain) {
|
|
@@ -101,6 +105,7 @@ class ZKPassport {
|
|
|
101
105
|
proofs: this.topicToProofs[topic],
|
|
102
106
|
queryResult: result,
|
|
103
107
|
validity: this.topicToLocalConfig[topic]?.validity,
|
|
108
|
+
scope: this.topicToService[topic]?.scope,
|
|
104
109
|
});
|
|
105
110
|
delete this.topicToProofs[topic];
|
|
106
111
|
const hasFailedProofs = this.topicToFailedProofCount[topic] > 0;
|
|
@@ -117,6 +122,11 @@ class ZKPassport {
|
|
|
117
122
|
delete this.topicToFailedProofCount[topic];
|
|
118
123
|
}
|
|
119
124
|
setExpectedProofCount(topic) {
|
|
125
|
+
// If the mode is not fast, we'll receive only 1 compressed proof
|
|
126
|
+
if (this.topicToLocalConfig[topic].mode !== "fast") {
|
|
127
|
+
this.topicToExpectedProofCount[topic] = 1;
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
120
130
|
const fields = Object.keys(this.topicToConfig[topic]).filter((key) => hasRequestedAccessToField(this.topicToConfig[topic], key));
|
|
121
131
|
const neededCircuits = [];
|
|
122
132
|
// Determine which circuits are needed based on the requested fields
|
|
@@ -196,7 +206,13 @@ class ZKPassport {
|
|
|
196
206
|
logger_1.noLogger.debug(`User generated proof`);
|
|
197
207
|
// Uncompress the proof and convert it to a hex string
|
|
198
208
|
const bytesProof = buffer_1.Buffer.from(request.params.proof, "base64");
|
|
209
|
+
const bytesCommittedInputs = request.params.committedInputs
|
|
210
|
+
? buffer_1.Buffer.from(request.params.committedInputs, "base64")
|
|
211
|
+
: null;
|
|
199
212
|
const uncompressedProof = (0, pako_1.inflate)(bytesProof);
|
|
213
|
+
const uncompressedCommittedInputs = bytesCommittedInputs
|
|
214
|
+
? (0, pako_1.inflate)(bytesCommittedInputs)
|
|
215
|
+
: null;
|
|
200
216
|
// The gzip lib in the app compress the proof as ASCII
|
|
201
217
|
// and since the app passes the proof as a hex string, we can
|
|
202
218
|
// just decode the bytes as hex characters using the TextDecoder
|
|
@@ -206,6 +222,9 @@ class ZKPassport {
|
|
|
206
222
|
vkeyHash: request.params.vkeyHash,
|
|
207
223
|
name: request.params.name,
|
|
208
224
|
version: request.params.version,
|
|
225
|
+
committedInputs: uncompressedCommittedInputs
|
|
226
|
+
? JSON.parse(new TextDecoder().decode(uncompressedCommittedInputs))
|
|
227
|
+
: undefined,
|
|
209
228
|
};
|
|
210
229
|
this.topicToProofs[topic].push(processedProof);
|
|
211
230
|
await Promise.all(this.onProofGeneratedCallbacks[topic].map((callback) => callback(processedProof)));
|
|
@@ -311,7 +330,7 @@ class ZKPassport {
|
|
|
311
330
|
const pubkey = (0, utils_2.bytesToHex)(this.topicToKeyPair[topic].publicKey);
|
|
312
331
|
this.setExpectedProofCount(topic);
|
|
313
332
|
return {
|
|
314
|
-
url: `https://zkpassport.id/r?d=${this.domain}&t=${topic}&c=${base64Config}&s=${base64Service}&p=${pubkey}`,
|
|
333
|
+
url: `https://zkpassport.id/r?d=${this.domain}&t=${topic}&c=${base64Config}&s=${base64Service}&p=${pubkey}&m=${this.topicToLocalConfig[topic].mode}`,
|
|
315
334
|
requestId: topic,
|
|
316
335
|
onRequestReceived: (callback) => this.onRequestReceivedCallbacks[topic].push(callback),
|
|
317
336
|
onGeneratingProof: (callback) => this.onGeneratingProofCallbacks[topic].push(callback),
|
|
@@ -335,7 +354,7 @@ class ZKPassport {
|
|
|
335
354
|
* @param validity How many days ago should have the ID been last scanned by the user?
|
|
336
355
|
* @returns The query builder object.
|
|
337
356
|
*/
|
|
338
|
-
async request({ name, logo, purpose, scope, validity, topicOverride, keyPairOverride, }) {
|
|
357
|
+
async request({ name, logo, purpose, scope, mode, validity, topicOverride, keyPairOverride, }) {
|
|
339
358
|
const topic = topicOverride || (0, crypto_1.randomBytes)(16).toString("hex");
|
|
340
359
|
const keyPair = keyPairOverride || (await (0, encryption_1.generateECDHKeyPair)());
|
|
341
360
|
this.topicToKeyPair[topic] = {
|
|
@@ -349,6 +368,7 @@ class ZKPassport {
|
|
|
349
368
|
this.topicToLocalConfig[topic] = {
|
|
350
369
|
// Default to 6 months
|
|
351
370
|
validity: validity || 6 * 30,
|
|
371
|
+
mode: mode || "fast",
|
|
352
372
|
};
|
|
353
373
|
this.onRequestReceivedCallbacks[topic] = [];
|
|
354
374
|
this.onGeneratingProofCallbacks[topic] = [];
|
|
@@ -406,19 +426,319 @@ class ZKPassport {
|
|
|
406
426
|
};
|
|
407
427
|
return this.getZkPassportRequest(topic);
|
|
408
428
|
}
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
429
|
+
checkDiscloseBytesPublicInputs(proof, queryResult) {
|
|
430
|
+
const queryResultErrors = {
|
|
431
|
+
sig_check_dsc: {},
|
|
432
|
+
sig_check_id_data: {},
|
|
433
|
+
data_check_integrity: {},
|
|
434
|
+
disclose: {},
|
|
435
|
+
age: {},
|
|
436
|
+
birthdate: {},
|
|
437
|
+
expiry_date: {},
|
|
438
|
+
document_type: {},
|
|
439
|
+
issuing_country: {},
|
|
440
|
+
gender: {},
|
|
441
|
+
nationality: {},
|
|
442
|
+
firstname: {},
|
|
443
|
+
lastname: {},
|
|
444
|
+
fullname: {},
|
|
445
|
+
document_number: {},
|
|
446
|
+
outer: {},
|
|
447
|
+
};
|
|
412
448
|
let isCorrect = true;
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
449
|
+
// We can't be certain that the disclosed data is for a passport or an ID card
|
|
450
|
+
// so we need to check both (unless the document type is revealed)
|
|
451
|
+
const disclosedDataPassport = utils_1.DisclosedData.fromDisclosedBytes((proof.committedInputs?.disclose_bytes).disclosedBytes, "passport");
|
|
452
|
+
const disclosedDataIDCard = utils_1.DisclosedData.fromDisclosedBytes((proof.committedInputs?.disclose_bytes).disclosedBytes, "id_card");
|
|
453
|
+
if (queryResult.document_type) {
|
|
454
|
+
// Document type is always at the same index in the disclosed data
|
|
455
|
+
if (queryResult.document_type.eq &&
|
|
456
|
+
queryResult.document_type.eq.result &&
|
|
457
|
+
queryResult.document_type.eq.expected !== disclosedDataPassport.documentType) {
|
|
458
|
+
console.warn("Document type does not match the expected document type");
|
|
459
|
+
isCorrect = false;
|
|
460
|
+
queryResultErrors.document_type.eq = {
|
|
461
|
+
expected: `${queryResult.document_type.eq.expected}`,
|
|
462
|
+
received: `${disclosedDataPassport.documentType ?? disclosedDataIDCard.documentType}`,
|
|
463
|
+
message: "Document type does not match the expected document type",
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
if (queryResult.document_type.disclose?.result !== disclosedDataIDCard.documentType) {
|
|
467
|
+
console.warn("Document type does not match the disclosed document type in query result");
|
|
468
|
+
isCorrect = false;
|
|
469
|
+
queryResultErrors.document_type.disclose = {
|
|
470
|
+
expected: `${queryResult.document_type.disclose?.result}`,
|
|
471
|
+
received: `${disclosedDataIDCard.documentType ?? disclosedDataPassport.documentType}`,
|
|
472
|
+
message: "Document type does not match the disclosed document type in query result",
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
if (queryResult.birthdate) {
|
|
477
|
+
const birthdatePassport = disclosedDataPassport.dateOfBirth;
|
|
478
|
+
const birthdateIDCard = disclosedDataIDCard.dateOfBirth;
|
|
479
|
+
if (queryResult.birthdate.eq &&
|
|
480
|
+
queryResult.birthdate.eq.result &&
|
|
481
|
+
queryResult.birthdate.eq.expected.getTime() !== birthdatePassport.getTime() &&
|
|
482
|
+
queryResult.birthdate.eq.expected.getTime() !== birthdateIDCard.getTime()) {
|
|
483
|
+
console.warn("Birthdate does not match the expected birthdate");
|
|
484
|
+
isCorrect = false;
|
|
485
|
+
queryResultErrors.birthdate.eq = {
|
|
486
|
+
expected: `${queryResult.birthdate.eq.expected.toISOString()}`,
|
|
487
|
+
received: `${birthdatePassport?.toISOString() ?? birthdateIDCard?.toISOString()}`,
|
|
488
|
+
message: "Birthdate does not match the expected birthdate",
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
if (queryResult.birthdate.disclose &&
|
|
492
|
+
queryResult.birthdate.disclose.result.getTime() !== birthdatePassport.getTime() &&
|
|
493
|
+
queryResult.birthdate.disclose.result.getTime() !== birthdateIDCard.getTime()) {
|
|
494
|
+
console.warn("Birthdate does not match the disclosed birthdate in query result");
|
|
495
|
+
isCorrect = false;
|
|
496
|
+
queryResultErrors.birthdate.disclose = {
|
|
497
|
+
expected: `${queryResult.birthdate.disclose.result.toISOString()}`,
|
|
498
|
+
received: `${birthdatePassport?.toISOString() ?? birthdateIDCard?.toISOString()}`,
|
|
499
|
+
message: "Birthdate does not match the disclosed birthdate in query result",
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
if (queryResult.expiry_date) {
|
|
504
|
+
const expiryDatePassport = disclosedDataPassport.dateOfExpiry;
|
|
505
|
+
const expiryDateIDCard = disclosedDataIDCard.dateOfExpiry;
|
|
506
|
+
if (queryResult.expiry_date.eq &&
|
|
507
|
+
queryResult.expiry_date.eq.result &&
|
|
508
|
+
queryResult.expiry_date.eq.expected.getTime() !== expiryDatePassport.getTime() &&
|
|
509
|
+
queryResult.expiry_date.eq.expected.getTime() !== expiryDateIDCard.getTime()) {
|
|
510
|
+
console.warn("Expiry date does not match the expected expiry date");
|
|
511
|
+
isCorrect = false;
|
|
512
|
+
queryResultErrors.expiry_date.eq = {
|
|
513
|
+
expected: `${queryResult.expiry_date.eq.expected.toISOString()}`,
|
|
514
|
+
received: `${expiryDatePassport?.toISOString() ?? expiryDateIDCard?.toISOString()}`,
|
|
515
|
+
message: "Expiry date does not match the expected expiry date",
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
if (queryResult.expiry_date.disclose &&
|
|
519
|
+
queryResult.expiry_date.disclose.result.getTime() !== expiryDatePassport.getTime() &&
|
|
520
|
+
queryResult.expiry_date.disclose.result.getTime() !== expiryDateIDCard.getTime()) {
|
|
521
|
+
console.warn("Expiry date does not match the disclosed expiry date in query result");
|
|
522
|
+
isCorrect = false;
|
|
523
|
+
queryResultErrors.expiry_date.disclose = {
|
|
524
|
+
expected: `${queryResult.expiry_date.disclose.result.toISOString()}`,
|
|
525
|
+
received: `${expiryDatePassport?.toISOString() ?? expiryDateIDCard?.toISOString()}`,
|
|
526
|
+
message: "Expiry date does not match the disclosed expiry date in query result",
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
if (queryResult.nationality) {
|
|
531
|
+
const nationalityPassport = disclosedDataPassport.nationality;
|
|
532
|
+
const nationalityIDCard = disclosedDataIDCard.nationality;
|
|
533
|
+
if (queryResult.nationality.eq &&
|
|
534
|
+
queryResult.nationality.eq.result &&
|
|
535
|
+
queryResult.nationality.eq.expected !== nationalityPassport &&
|
|
536
|
+
queryResult.nationality.eq.expected !== nationalityIDCard) {
|
|
537
|
+
console.warn("Nationality does not match the expected nationality");
|
|
538
|
+
isCorrect = false;
|
|
539
|
+
queryResultErrors.nationality.eq = {
|
|
540
|
+
expected: `${queryResult.nationality.eq.expected}`,
|
|
541
|
+
received: `${nationalityPassport ?? nationalityIDCard}`,
|
|
542
|
+
message: "Nationality does not match the expected nationality",
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
if (queryResult.nationality.disclose &&
|
|
546
|
+
queryResult.nationality.disclose.result !== nationalityPassport &&
|
|
547
|
+
queryResult.nationality.disclose.result !== nationalityIDCard) {
|
|
548
|
+
console.warn("Nationality does not match the disclosed nationality in query result");
|
|
549
|
+
isCorrect = false;
|
|
550
|
+
queryResultErrors.nationality.disclose = {
|
|
551
|
+
expected: `${queryResult.nationality.disclose.result}`,
|
|
552
|
+
received: `${nationalityPassport ?? nationalityIDCard}`,
|
|
553
|
+
message: "Nationality does not match the disclosed nationality in query result",
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
if (queryResult.document_number) {
|
|
558
|
+
const documentNumberPassport = disclosedDataPassport.documentNumber;
|
|
559
|
+
const documentNumberIDCard = disclosedDataIDCard.documentNumber;
|
|
560
|
+
if (queryResult.document_number.eq &&
|
|
561
|
+
queryResult.document_number.eq.result &&
|
|
562
|
+
queryResult.document_number.eq.expected !== documentNumberPassport &&
|
|
563
|
+
queryResult.document_number.eq.expected !== documentNumberIDCard) {
|
|
564
|
+
console.warn("Document number does not match the expected document number");
|
|
565
|
+
isCorrect = false;
|
|
566
|
+
queryResultErrors.document_number.eq = {
|
|
567
|
+
expected: `${queryResult.document_number.eq.expected}`,
|
|
568
|
+
received: `${documentNumberPassport ?? documentNumberIDCard}`,
|
|
569
|
+
message: "Document number does not match the expected document number",
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
if (queryResult.document_number.disclose &&
|
|
573
|
+
queryResult.document_number.disclose.result !== documentNumberPassport &&
|
|
574
|
+
queryResult.document_number.disclose.result !== documentNumberIDCard) {
|
|
575
|
+
console.warn("Document number does not match the disclosed document number in query result");
|
|
576
|
+
isCorrect = false;
|
|
577
|
+
queryResultErrors.document_number.disclose = {
|
|
578
|
+
expected: `${queryResult.document_number.disclose.result}`,
|
|
579
|
+
received: `${documentNumberPassport ?? documentNumberIDCard}`,
|
|
580
|
+
message: "Document number does not match the disclosed document number in query result",
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
if (queryResult.gender) {
|
|
585
|
+
const genderPassport = disclosedDataPassport.gender;
|
|
586
|
+
const genderIDCard = disclosedDataIDCard.gender;
|
|
587
|
+
if (queryResult.gender.eq &&
|
|
588
|
+
queryResult.gender.eq.result &&
|
|
589
|
+
queryResult.gender.eq.expected !== genderPassport &&
|
|
590
|
+
queryResult.gender.eq.expected !== genderIDCard) {
|
|
591
|
+
console.warn("Gender does not match the expected gender");
|
|
592
|
+
isCorrect = false;
|
|
593
|
+
queryResultErrors.gender.eq = {
|
|
594
|
+
expected: `${queryResult.gender.eq.expected}`,
|
|
595
|
+
received: `${genderPassport ?? genderIDCard}`,
|
|
596
|
+
message: "Gender does not match the expected gender",
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
if (queryResult.gender.disclose &&
|
|
600
|
+
queryResult.gender.disclose.result !== genderPassport &&
|
|
601
|
+
queryResult.gender.disclose.result !== genderIDCard) {
|
|
602
|
+
console.warn("Gender does not match the disclosed gender in query result");
|
|
603
|
+
isCorrect = false;
|
|
604
|
+
queryResultErrors.gender.disclose = {
|
|
605
|
+
expected: `${queryResult.gender.disclose.result}`,
|
|
606
|
+
received: `${genderPassport ?? genderIDCard}`,
|
|
607
|
+
message: "Gender does not match the disclosed gender in query result",
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
if (queryResult.issuing_country) {
|
|
612
|
+
const issuingCountryPassport = disclosedDataPassport.issuingCountry;
|
|
613
|
+
const issuingCountryIDCard = disclosedDataIDCard.issuingCountry;
|
|
614
|
+
if (queryResult.issuing_country.eq &&
|
|
615
|
+
queryResult.issuing_country.eq.result &&
|
|
616
|
+
queryResult.issuing_country.eq.expected !== issuingCountryPassport &&
|
|
617
|
+
queryResult.issuing_country.eq.expected !== issuingCountryIDCard) {
|
|
618
|
+
console.warn("Issuing country does not match the expected issuing country");
|
|
619
|
+
isCorrect = false;
|
|
620
|
+
queryResultErrors.issuing_country.eq = {
|
|
621
|
+
expected: `${queryResult.issuing_country.eq.expected}`,
|
|
622
|
+
received: `${issuingCountryPassport ?? issuingCountryIDCard}`,
|
|
623
|
+
message: "Issuing country does not match the expected issuing country",
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
if (queryResult.issuing_country.disclose &&
|
|
627
|
+
queryResult.issuing_country.disclose.result !== issuingCountryPassport &&
|
|
628
|
+
queryResult.issuing_country.disclose.result !== issuingCountryIDCard) {
|
|
629
|
+
console.warn("Issuing country does not match the disclosed issuing country in query result");
|
|
630
|
+
isCorrect = false;
|
|
631
|
+
queryResultErrors.issuing_country.disclose = {
|
|
632
|
+
expected: `${queryResult.issuing_country.disclose.result}`,
|
|
633
|
+
received: `${issuingCountryPassport ?? issuingCountryIDCard}`,
|
|
634
|
+
message: "Issuing country does not match the disclosed issuing country in query result",
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
if (queryResult.fullname) {
|
|
639
|
+
const fullnamePassport = disclosedDataPassport.name;
|
|
640
|
+
const fullnameIDCard = disclosedDataIDCard.name;
|
|
641
|
+
if (queryResult.fullname.eq &&
|
|
642
|
+
queryResult.fullname.eq.result &&
|
|
643
|
+
(0, utils_1.formatName)(queryResult.fullname.eq.expected).toLowerCase() !==
|
|
644
|
+
fullnamePassport.toLowerCase() &&
|
|
645
|
+
(0, utils_1.formatName)(queryResult.fullname.eq.expected).toLowerCase() !== fullnameIDCard.toLowerCase()) {
|
|
646
|
+
console.warn("Fullname does not match the expected fullname");
|
|
647
|
+
isCorrect = false;
|
|
648
|
+
queryResultErrors.fullname.eq = {
|
|
649
|
+
expected: `${queryResult.fullname.eq.expected}`,
|
|
650
|
+
received: `${fullnamePassport ?? fullnameIDCard}`,
|
|
651
|
+
message: "Fullname does not match the expected fullname",
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
if (queryResult.fullname.disclose &&
|
|
655
|
+
(0, utils_1.formatName)(queryResult.fullname.disclose.result).toLowerCase() !==
|
|
656
|
+
fullnamePassport.toLowerCase() &&
|
|
657
|
+
(0, utils_1.formatName)(queryResult.fullname.disclose.result).toLowerCase() !==
|
|
658
|
+
fullnameIDCard.toLowerCase()) {
|
|
659
|
+
console.warn("Fullname does not match the disclosed fullname in query result");
|
|
660
|
+
isCorrect = false;
|
|
661
|
+
queryResultErrors.fullname.disclose = {
|
|
662
|
+
expected: `${queryResult.fullname.disclose.result}`,
|
|
663
|
+
received: `${fullnamePassport ?? fullnameIDCard}`,
|
|
664
|
+
message: "Fullname does not match the disclosed fullname in query result",
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
if (queryResult.firstname) {
|
|
669
|
+
// If fullname was not revealed, then the name could be either the first name or last name
|
|
670
|
+
const firstnamePassport = disclosedDataPassport.firstName && disclosedDataPassport.firstName.length > 0
|
|
671
|
+
? disclosedDataPassport.firstName
|
|
672
|
+
: disclosedDataPassport.name;
|
|
673
|
+
const firstnameIDCard = disclosedDataIDCard.firstName && disclosedDataIDCard.firstName.length > 0
|
|
674
|
+
? disclosedDataIDCard.firstName
|
|
675
|
+
: disclosedDataIDCard.name;
|
|
676
|
+
if (queryResult.firstname.eq &&
|
|
677
|
+
queryResult.firstname.eq.result &&
|
|
678
|
+
(0, utils_1.formatName)(queryResult.firstname.eq.expected).toLowerCase() !==
|
|
679
|
+
firstnamePassport.toLowerCase() &&
|
|
680
|
+
(0, utils_1.formatName)(queryResult.firstname.eq.expected).toLowerCase() !==
|
|
681
|
+
firstnameIDCard.toLowerCase()) {
|
|
682
|
+
console.warn("Firstname does not match the expected firstname");
|
|
683
|
+
isCorrect = false;
|
|
684
|
+
queryResultErrors.firstname.eq = {
|
|
685
|
+
expected: `${queryResult.firstname.eq.expected}`,
|
|
686
|
+
received: `${firstnamePassport ?? firstnameIDCard}`,
|
|
687
|
+
message: "Firstname does not match the expected firstname",
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
if (queryResult.firstname.disclose &&
|
|
691
|
+
(0, utils_1.formatName)(queryResult.firstname.disclose.result).toLowerCase() !==
|
|
692
|
+
firstnamePassport.toLowerCase() &&
|
|
693
|
+
(0, utils_1.formatName)(queryResult.firstname.disclose.result).toLowerCase() !==
|
|
694
|
+
firstnameIDCard.toLowerCase()) {
|
|
695
|
+
console.warn("Firstname does not match the disclosed firstname in query result");
|
|
696
|
+
isCorrect = false;
|
|
697
|
+
queryResultErrors.firstname.disclose = {
|
|
698
|
+
expected: `${queryResult.firstname.disclose.result}`,
|
|
699
|
+
received: `${firstnamePassport ?? firstnameIDCard}`,
|
|
700
|
+
message: "Firstname does not match the disclosed firstname in query result",
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
if (queryResult.lastname) {
|
|
705
|
+
// If fullname was not revealed, then the name could be either the first name or last name
|
|
706
|
+
const lastnamePassport = disclosedDataPassport.lastName && disclosedDataPassport.lastName.length > 0
|
|
707
|
+
? disclosedDataPassport.lastName
|
|
708
|
+
: disclosedDataPassport.name;
|
|
709
|
+
const lastnameIDCard = disclosedDataIDCard.lastName && disclosedDataIDCard.lastName.length > 0
|
|
710
|
+
? disclosedDataIDCard.lastName
|
|
711
|
+
: disclosedDataIDCard.name;
|
|
712
|
+
if (queryResult.lastname.eq &&
|
|
713
|
+
queryResult.lastname.eq.result &&
|
|
714
|
+
(0, utils_1.formatName)(queryResult.lastname.eq.expected).toLowerCase() !==
|
|
715
|
+
lastnamePassport.toLowerCase() &&
|
|
716
|
+
(0, utils_1.formatName)(queryResult.lastname.eq.expected).toLowerCase() !== lastnameIDCard.toLowerCase()) {
|
|
717
|
+
console.warn("Lastname does not match the expected lastname");
|
|
718
|
+
isCorrect = false;
|
|
719
|
+
queryResultErrors.lastname.eq = {
|
|
720
|
+
expected: `${queryResult.lastname.eq.expected}`,
|
|
721
|
+
received: `${lastnamePassport ?? lastnameIDCard}`,
|
|
722
|
+
message: "Lastname does not match the expected lastname",
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
if (queryResult.lastname.disclose &&
|
|
726
|
+
(0, utils_1.formatName)(queryResult.lastname.disclose.result).toLowerCase() !==
|
|
727
|
+
lastnamePassport.toLowerCase() &&
|
|
728
|
+
(0, utils_1.formatName)(queryResult.lastname.disclose.result).toLowerCase() !==
|
|
729
|
+
lastnameIDCard.toLowerCase()) {
|
|
730
|
+
console.warn("Lastname does not match the disclosed lastname in query result");
|
|
731
|
+
isCorrect = false;
|
|
732
|
+
queryResultErrors.lastname.disclose = {
|
|
733
|
+
expected: `${queryResult.lastname.disclose.result}`,
|
|
734
|
+
received: `${lastnamePassport ?? lastnameIDCard}`,
|
|
735
|
+
message: "Lastname does not match the disclosed lastname in query result",
|
|
736
|
+
};
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
return { isCorrect, queryResultErrors };
|
|
740
|
+
}
|
|
741
|
+
checkAgePublicInputs(proof, queryResult) {
|
|
422
742
|
const queryResultErrors = {
|
|
423
743
|
sig_check_dsc: {},
|
|
424
744
|
sig_check_id_data: {},
|
|
@@ -435,388 +755,892 @@ class ZKPassport {
|
|
|
435
755
|
lastname: {},
|
|
436
756
|
fullname: {},
|
|
437
757
|
document_number: {},
|
|
758
|
+
outer: {},
|
|
438
759
|
};
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
const
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
"
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
const getIndex = (proof) => {
|
|
456
|
-
const name = proof.name || "";
|
|
457
|
-
return proofOrder.findIndex((p) => name.startsWith(p));
|
|
458
|
-
};
|
|
459
|
-
return getIndex(a) - getIndex(b);
|
|
460
|
-
});
|
|
461
|
-
for (const proof of sortedProofs) {
|
|
462
|
-
const proofData = (0, utils_1.getProofData)(proof.proof, true);
|
|
463
|
-
if (proof.name?.startsWith("sig_check_dsc")) {
|
|
464
|
-
commitmentOut = (0, utils_1.getCommitmentFromDSCProof)(proofData);
|
|
465
|
-
const merkleRoot = (0, utils_1.getMerkleRootFromDSCProof)(proofData);
|
|
466
|
-
if (!VALID_CERTIFICATE_REGISTRY_ROOT.includes(merkleRoot)) {
|
|
467
|
-
console.warn("The ID was signed by an unrecognized root certificate");
|
|
468
|
-
isCorrect = false;
|
|
469
|
-
queryResultErrors.sig_check_dsc.certificate = {
|
|
470
|
-
expected: `Certificate registry root: ${VALID_CERTIFICATE_REGISTRY_ROOT.join(", ")}`,
|
|
471
|
-
received: `Certificate registry root: ${merkleRoot.toString()}`,
|
|
472
|
-
message: "The ID was signed by an unrecognized root certificate",
|
|
473
|
-
};
|
|
474
|
-
}
|
|
760
|
+
let isCorrect = true;
|
|
761
|
+
const currentTime = new Date();
|
|
762
|
+
const today = new Date(currentTime.getFullYear(), currentTime.getMonth(), currentTime.getDate(), 0, 0, 0, 0);
|
|
763
|
+
const minAge = (0, utils_1.getMinAgeFromCommittedInputs)(proof.committedInputs?.compare_age);
|
|
764
|
+
const maxAge = (0, utils_1.getMaxAgeFromCommittedInputs)(proof.committedInputs?.compare_age);
|
|
765
|
+
if (queryResult.age) {
|
|
766
|
+
if (queryResult.age.gte &&
|
|
767
|
+
queryResult.age.gte.result &&
|
|
768
|
+
minAge < queryResult.age.gte.expected) {
|
|
769
|
+
console.warn("Age is not greater than or equal to the expected age");
|
|
770
|
+
isCorrect = false;
|
|
771
|
+
queryResultErrors.age.gte = {
|
|
772
|
+
expected: queryResult.age.gte.expected,
|
|
773
|
+
received: minAge,
|
|
774
|
+
message: "Age is not greater than or equal to the expected age",
|
|
775
|
+
};
|
|
475
776
|
}
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
}
|
|
487
|
-
commitmentOut = (0, utils_1.getCommitmentOutFromIDDataProof)(proofData);
|
|
777
|
+
if (queryResult.age.lt &&
|
|
778
|
+
queryResult.age.lt.result &&
|
|
779
|
+
maxAge >= queryResult.age.lt.expected) {
|
|
780
|
+
console.warn("Age is not less than the expected age");
|
|
781
|
+
isCorrect = false;
|
|
782
|
+
queryResultErrors.age.lt = {
|
|
783
|
+
expected: queryResult.age.lt.expected,
|
|
784
|
+
received: maxAge,
|
|
785
|
+
message: "Age is not less than the expected age",
|
|
786
|
+
};
|
|
488
787
|
}
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
788
|
+
if (queryResult.age.range) {
|
|
789
|
+
if (queryResult.age.range.result &&
|
|
790
|
+
(minAge < queryResult.age.range.expected[0] ||
|
|
791
|
+
maxAge >= queryResult.age.range.expected[1])) {
|
|
792
|
+
console.warn("Age is not in the expected range");
|
|
493
793
|
isCorrect = false;
|
|
494
|
-
queryResultErrors.
|
|
495
|
-
expected:
|
|
496
|
-
received:
|
|
497
|
-
message: "
|
|
794
|
+
queryResultErrors.age.range = {
|
|
795
|
+
expected: queryResult.age.range.expected,
|
|
796
|
+
received: [minAge, maxAge],
|
|
797
|
+
message: "Age is not in the expected range",
|
|
498
798
|
};
|
|
499
799
|
}
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
800
|
+
}
|
|
801
|
+
if (!queryResult.age.lt && !queryResult.age.range && maxAge != 0) {
|
|
802
|
+
console.warn("Maximum age should be equal to 0");
|
|
803
|
+
isCorrect = false;
|
|
804
|
+
queryResultErrors.age.disclose = {
|
|
805
|
+
expected: 0,
|
|
806
|
+
received: maxAge,
|
|
807
|
+
message: "Maximum age should be equal to 0",
|
|
808
|
+
};
|
|
809
|
+
}
|
|
810
|
+
if (!queryResult.age.gte && !queryResult.age.range && minAge != 0) {
|
|
811
|
+
console.warn("Minimum age should be equal to 0");
|
|
812
|
+
isCorrect = false;
|
|
813
|
+
queryResultErrors.age.disclose = {
|
|
814
|
+
expected: 0,
|
|
815
|
+
received: minAge,
|
|
816
|
+
message: "Minimum age should be equal to 0",
|
|
817
|
+
};
|
|
818
|
+
}
|
|
819
|
+
if (queryResult.age.disclose &&
|
|
820
|
+
(queryResult.age.disclose.result !== minAge || queryResult.age.disclose.result !== maxAge)) {
|
|
821
|
+
console.warn("Age does not match the disclosed age in query result");
|
|
822
|
+
isCorrect = false;
|
|
823
|
+
queryResultErrors.age.disclose = {
|
|
824
|
+
expected: `${minAge}`,
|
|
825
|
+
received: `${queryResult.age.disclose.result}`,
|
|
826
|
+
message: "Age does not match the disclosed age in query result",
|
|
827
|
+
};
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
else {
|
|
831
|
+
console.warn("Age is not set in the query result");
|
|
832
|
+
isCorrect = false;
|
|
833
|
+
queryResultErrors.age.disclose = {
|
|
834
|
+
message: "Age is not set in the query result",
|
|
835
|
+
};
|
|
836
|
+
}
|
|
837
|
+
const currentDate = (0, utils_1.getCurrentDateFromCommittedInputs)(proof.committedInputs?.compare_age);
|
|
838
|
+
if (currentDate.getTime() !== today.getTime() &&
|
|
839
|
+
currentDate.getTime() !== today.getTime() - 86400000) {
|
|
840
|
+
console.warn("Current date in the proof is too old");
|
|
841
|
+
isCorrect = false;
|
|
842
|
+
queryResultErrors.age.disclose = {
|
|
843
|
+
expected: `${today.toISOString()}`,
|
|
844
|
+
received: `${currentDate.toISOString()}`,
|
|
845
|
+
message: "Current date in the proof is too old",
|
|
846
|
+
};
|
|
847
|
+
}
|
|
848
|
+
return { isCorrect, queryResultErrors };
|
|
849
|
+
}
|
|
850
|
+
checkBirthdatePublicInputs(proof, queryResult) {
|
|
851
|
+
const queryResultErrors = {
|
|
852
|
+
sig_check_dsc: {},
|
|
853
|
+
sig_check_id_data: {},
|
|
854
|
+
data_check_integrity: {},
|
|
855
|
+
disclose: {},
|
|
856
|
+
age: {},
|
|
857
|
+
birthdate: {},
|
|
858
|
+
expiry_date: {},
|
|
859
|
+
document_type: {},
|
|
860
|
+
issuing_country: {},
|
|
861
|
+
gender: {},
|
|
862
|
+
nationality: {},
|
|
863
|
+
firstname: {},
|
|
864
|
+
lastname: {},
|
|
865
|
+
fullname: {},
|
|
866
|
+
document_number: {},
|
|
867
|
+
outer: {},
|
|
868
|
+
};
|
|
869
|
+
let isCorrect = true;
|
|
870
|
+
const currentTime = new Date();
|
|
871
|
+
const today = new Date(currentTime.getFullYear(), currentTime.getMonth(), currentTime.getDate(), 0, 0, 0);
|
|
872
|
+
const minDate = (0, utils_1.getMinDateFromCommittedInputs)(proof.committedInputs?.compare_birthdate);
|
|
873
|
+
const maxDate = (0, utils_1.getMaxDateFromCommittedInputs)(proof.committedInputs?.compare_birthdate);
|
|
874
|
+
const currentDate = (0, utils_1.getCurrentDateFromCommittedInputs)(proof.committedInputs?.compare_birthdate);
|
|
875
|
+
if (queryResult.birthdate) {
|
|
876
|
+
if (queryResult.birthdate.gte &&
|
|
877
|
+
queryResult.birthdate.gte.result &&
|
|
878
|
+
minDate < queryResult.birthdate.gte.expected) {
|
|
879
|
+
console.warn("Birthdate is not greater than or equal to the expected birthdate");
|
|
880
|
+
isCorrect = false;
|
|
881
|
+
queryResultErrors.birthdate.gte = {
|
|
882
|
+
expected: queryResult.birthdate.gte.expected,
|
|
883
|
+
received: minDate,
|
|
884
|
+
message: "Birthdate is not greater than or equal to the expected birthdate",
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
if (queryResult.birthdate.lte &&
|
|
888
|
+
queryResult.birthdate.lte.result &&
|
|
889
|
+
maxDate > queryResult.birthdate.lte.expected) {
|
|
890
|
+
console.warn("Birthdate is not less than the expected birthdate");
|
|
891
|
+
isCorrect = false;
|
|
892
|
+
queryResultErrors.birthdate.lte = {
|
|
893
|
+
expected: queryResult.birthdate.lte.expected,
|
|
894
|
+
received: maxDate,
|
|
895
|
+
message: "Birthdate is not less than the expected birthdate",
|
|
896
|
+
};
|
|
897
|
+
}
|
|
898
|
+
if (queryResult.birthdate.range) {
|
|
899
|
+
if (queryResult.birthdate.range.result &&
|
|
900
|
+
(minDate < queryResult.birthdate.range.expected[0] ||
|
|
901
|
+
maxDate > queryResult.birthdate.range.expected[1])) {
|
|
902
|
+
console.warn("Birthdate is not in the expected range");
|
|
509
903
|
isCorrect = false;
|
|
510
|
-
queryResultErrors.
|
|
511
|
-
expected:
|
|
512
|
-
received:
|
|
513
|
-
message: "
|
|
904
|
+
queryResultErrors.birthdate.range = {
|
|
905
|
+
expected: queryResult.birthdate.range.expected,
|
|
906
|
+
received: [minDate, maxDate],
|
|
907
|
+
message: "Birthdate is not in the expected range",
|
|
514
908
|
};
|
|
515
909
|
}
|
|
516
910
|
}
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
911
|
+
if (!queryResult.birthdate.lte &&
|
|
912
|
+
!queryResult.birthdate.range &&
|
|
913
|
+
maxDate.getTime() != DEFAULT_DATE_VALUE.getTime()) {
|
|
914
|
+
console.warn("Maximum birthdate should be equal to default date value");
|
|
915
|
+
isCorrect = false;
|
|
916
|
+
queryResultErrors.birthdate.disclose = {
|
|
917
|
+
expected: `${DEFAULT_DATE_VALUE.toISOString()}`,
|
|
918
|
+
received: `${maxDate.toISOString()}`,
|
|
919
|
+
message: "Maximum birthdate should be equal to default date value",
|
|
920
|
+
};
|
|
921
|
+
}
|
|
922
|
+
if (!queryResult.birthdate.gte &&
|
|
923
|
+
!queryResult.birthdate.range &&
|
|
924
|
+
minDate.getTime() != DEFAULT_DATE_VALUE.getTime()) {
|
|
925
|
+
console.warn("Minimum birthdate should be equal to default date value");
|
|
926
|
+
isCorrect = false;
|
|
927
|
+
queryResultErrors.birthdate.disclose = {
|
|
928
|
+
expected: `${DEFAULT_DATE_VALUE.toISOString()}`,
|
|
929
|
+
received: `${minDate.toISOString()}`,
|
|
930
|
+
message: "Minimum birthdate should be equal to default date value",
|
|
931
|
+
};
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
else {
|
|
935
|
+
console.warn("Birthdate is not set in the query result");
|
|
936
|
+
isCorrect = false;
|
|
937
|
+
queryResultErrors.birthdate.disclose = {
|
|
938
|
+
message: "Birthdate is not set in the query result",
|
|
939
|
+
};
|
|
940
|
+
}
|
|
941
|
+
if (currentDate.getTime() !== today.getTime() &&
|
|
942
|
+
currentDate.getTime() !== today.getTime() - 86400000) {
|
|
943
|
+
console.warn("Current date in the proof is too old");
|
|
944
|
+
isCorrect = false;
|
|
945
|
+
queryResultErrors.age.disclose = {
|
|
946
|
+
expected: `${today.toISOString()}`,
|
|
947
|
+
received: `${currentDate.toISOString()}`,
|
|
948
|
+
message: "Current date in the proof is too old",
|
|
949
|
+
};
|
|
950
|
+
}
|
|
951
|
+
return { isCorrect, queryResultErrors };
|
|
952
|
+
}
|
|
953
|
+
checkExpiryDatePublicInputs(proof, queryResult) {
|
|
954
|
+
const queryResultErrors = {
|
|
955
|
+
sig_check_dsc: {},
|
|
956
|
+
sig_check_id_data: {},
|
|
957
|
+
data_check_integrity: {},
|
|
958
|
+
disclose: {},
|
|
959
|
+
age: {},
|
|
960
|
+
birthdate: {},
|
|
961
|
+
expiry_date: {},
|
|
962
|
+
document_type: {},
|
|
963
|
+
issuing_country: {},
|
|
964
|
+
gender: {},
|
|
965
|
+
nationality: {},
|
|
966
|
+
firstname: {},
|
|
967
|
+
lastname: {},
|
|
968
|
+
fullname: {},
|
|
969
|
+
document_number: {},
|
|
970
|
+
outer: {},
|
|
971
|
+
};
|
|
972
|
+
let isCorrect = true;
|
|
973
|
+
const currentTime = new Date();
|
|
974
|
+
const today = new Date(currentTime.getFullYear(), currentTime.getMonth(), currentTime.getDate(), 0, 0, 0);
|
|
975
|
+
const minDate = (0, utils_1.getMinDateFromCommittedInputs)(proof.committedInputs?.compare_expiry);
|
|
976
|
+
const maxDate = (0, utils_1.getMaxDateFromCommittedInputs)(proof.committedInputs?.compare_expiry);
|
|
977
|
+
const currentDate = (0, utils_1.getCurrentDateFromCommittedInputs)(proof.committedInputs?.compare_expiry);
|
|
978
|
+
if (queryResult.expiry_date) {
|
|
979
|
+
if (queryResult.expiry_date.gte &&
|
|
980
|
+
queryResult.expiry_date.gte.result &&
|
|
981
|
+
minDate < queryResult.expiry_date.gte.expected) {
|
|
982
|
+
console.warn("Expiry date is not greater than or equal to the expected expiry date");
|
|
983
|
+
isCorrect = false;
|
|
984
|
+
queryResultErrors.expiry_date.gte = {
|
|
985
|
+
expected: queryResult.expiry_date.gte.expected,
|
|
986
|
+
received: minDate,
|
|
987
|
+
message: "Expiry date is not greater than or equal to the expected expiry date",
|
|
988
|
+
};
|
|
989
|
+
}
|
|
990
|
+
if (queryResult.expiry_date.lte &&
|
|
991
|
+
queryResult.expiry_date.lte.result &&
|
|
992
|
+
maxDate > queryResult.expiry_date.lte.expected) {
|
|
993
|
+
console.warn("Expiry date is not less than the expected expiry date");
|
|
994
|
+
isCorrect = false;
|
|
995
|
+
queryResultErrors.expiry_date.lte = {
|
|
996
|
+
expected: queryResult.expiry_date.lte.expected,
|
|
997
|
+
received: maxDate,
|
|
998
|
+
message: "Expiry date is not less than the expected expiry date",
|
|
999
|
+
};
|
|
1000
|
+
}
|
|
1001
|
+
if (queryResult.expiry_date.range) {
|
|
1002
|
+
if (queryResult.expiry_date.range.result &&
|
|
1003
|
+
(minDate < queryResult.expiry_date.range.expected[0] ||
|
|
1004
|
+
maxDate > queryResult.expiry_date.range.expected[1])) {
|
|
1005
|
+
console.warn("Expiry date is not in the expected range");
|
|
521
1006
|
isCorrect = false;
|
|
522
|
-
queryResultErrors.
|
|
523
|
-
expected:
|
|
524
|
-
received:
|
|
525
|
-
message: "
|
|
1007
|
+
queryResultErrors.expiry_date.range = {
|
|
1008
|
+
expected: queryResult.expiry_date.range.expected,
|
|
1009
|
+
received: [minDate, maxDate],
|
|
1010
|
+
message: "Expiry date is not in the expected range",
|
|
526
1011
|
};
|
|
527
1012
|
}
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
1013
|
+
}
|
|
1014
|
+
if (!queryResult.expiry_date.lte &&
|
|
1015
|
+
!queryResult.expiry_date.range &&
|
|
1016
|
+
maxDate.getTime() != DEFAULT_DATE_VALUE.getTime()) {
|
|
1017
|
+
console.warn("Maximum expiry date should be equal to default date value");
|
|
1018
|
+
isCorrect = false;
|
|
1019
|
+
queryResultErrors.expiry_date.disclose = {
|
|
1020
|
+
expected: `${DEFAULT_DATE_VALUE.toISOString()}`,
|
|
1021
|
+
received: `${maxDate.toISOString()}`,
|
|
1022
|
+
message: "Maximum expiry date should be equal to default date value",
|
|
1023
|
+
};
|
|
1024
|
+
}
|
|
1025
|
+
if (!queryResult.expiry_date.gte &&
|
|
1026
|
+
!queryResult.expiry_date.range &&
|
|
1027
|
+
minDate.getTime() != DEFAULT_DATE_VALUE.getTime()) {
|
|
1028
|
+
console.warn("Minimum expiry date should be equal to default date value");
|
|
1029
|
+
isCorrect = false;
|
|
1030
|
+
queryResultErrors.expiry_date.disclose = {
|
|
1031
|
+
expected: `${DEFAULT_DATE_VALUE.toISOString()}`,
|
|
1032
|
+
received: `${minDate.toISOString()}`,
|
|
1033
|
+
message: "Minimum expiry date should be equal to default date value",
|
|
1034
|
+
};
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
else {
|
|
1038
|
+
console.warn("Expiry date is not set in the query result");
|
|
1039
|
+
isCorrect = false;
|
|
1040
|
+
queryResultErrors.expiry_date.disclose = {
|
|
1041
|
+
message: "Expiry date is not set in the query result",
|
|
1042
|
+
};
|
|
1043
|
+
}
|
|
1044
|
+
if (currentDate.getTime() !== today.getTime() &&
|
|
1045
|
+
currentDate.getTime() !== today.getTime() - 86400000) {
|
|
1046
|
+
console.warn("Current date in the proof is too old");
|
|
1047
|
+
isCorrect = false;
|
|
1048
|
+
queryResultErrors.age.disclose = {
|
|
1049
|
+
expected: `${today.toISOString()}`,
|
|
1050
|
+
received: `${currentDate.toISOString()}`,
|
|
1051
|
+
message: "Current date in the proof is too old",
|
|
1052
|
+
};
|
|
1053
|
+
}
|
|
1054
|
+
return { isCorrect, queryResultErrors };
|
|
1055
|
+
}
|
|
1056
|
+
checkNationalityExclusionPublicInputs(queryResult, countryList) {
|
|
1057
|
+
const queryResultErrors = {
|
|
1058
|
+
sig_check_dsc: {},
|
|
1059
|
+
sig_check_id_data: {},
|
|
1060
|
+
data_check_integrity: {},
|
|
1061
|
+
disclose: {},
|
|
1062
|
+
age: {},
|
|
1063
|
+
birthdate: {},
|
|
1064
|
+
expiry_date: {},
|
|
1065
|
+
document_type: {},
|
|
1066
|
+
issuing_country: {},
|
|
1067
|
+
gender: {},
|
|
1068
|
+
nationality: {},
|
|
1069
|
+
firstname: {},
|
|
1070
|
+
lastname: {},
|
|
1071
|
+
fullname: {},
|
|
1072
|
+
document_number: {},
|
|
1073
|
+
outer: {},
|
|
1074
|
+
};
|
|
1075
|
+
let isCorrect = true;
|
|
1076
|
+
if (queryResult.nationality &&
|
|
1077
|
+
queryResult.nationality.out &&
|
|
1078
|
+
queryResult.nationality.out.result) {
|
|
1079
|
+
if (!queryResult.nationality.out.expected?.every((country) => countryList.includes(country))) {
|
|
1080
|
+
console.warn("Nationality exclusion list does not match the one from the query results");
|
|
1081
|
+
isCorrect = false;
|
|
1082
|
+
queryResultErrors.nationality.out = {
|
|
1083
|
+
expected: queryResult.nationality.out.expected,
|
|
1084
|
+
received: countryList,
|
|
1085
|
+
message: "Nationality exclusion list does not match the one from the query results",
|
|
1086
|
+
};
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
else if (!queryResult.nationality || !queryResult.nationality.out) {
|
|
1090
|
+
console.warn("Nationality exclusion is not set in the query result");
|
|
1091
|
+
isCorrect = false;
|
|
1092
|
+
queryResultErrors.nationality.out = {
|
|
1093
|
+
message: "Nationality exclusion is not set in the query result",
|
|
1094
|
+
};
|
|
1095
|
+
}
|
|
1096
|
+
// Check the countryList is in ascending order
|
|
1097
|
+
// If the prover doesn't use a sorted list then the proof cannot be trusted
|
|
1098
|
+
// as it is requirement in the circuit for the exclusion check to work
|
|
1099
|
+
for (let i = 1; i < countryList.length; i++) {
|
|
1100
|
+
if (countryList[i] < countryList[i - 1]) {
|
|
1101
|
+
console.warn("The nationality exclusion list has not been sorted, and thus the proof cannot be trusted");
|
|
1102
|
+
isCorrect = false;
|
|
1103
|
+
queryResultErrors.nationality.out = {
|
|
1104
|
+
message: "The nationality exclusion list has not been sorted, and thus the proof cannot be trusted",
|
|
1105
|
+
};
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
return { isCorrect, queryResultErrors };
|
|
1109
|
+
}
|
|
1110
|
+
checkIssuingCountryExclusionPublicInputs(queryResult, countryList) {
|
|
1111
|
+
const queryResultErrors = {
|
|
1112
|
+
sig_check_dsc: {},
|
|
1113
|
+
sig_check_id_data: {},
|
|
1114
|
+
data_check_integrity: {},
|
|
1115
|
+
disclose: {},
|
|
1116
|
+
age: {},
|
|
1117
|
+
birthdate: {},
|
|
1118
|
+
expiry_date: {},
|
|
1119
|
+
document_type: {},
|
|
1120
|
+
issuing_country: {},
|
|
1121
|
+
gender: {},
|
|
1122
|
+
nationality: {},
|
|
1123
|
+
firstname: {},
|
|
1124
|
+
lastname: {},
|
|
1125
|
+
fullname: {},
|
|
1126
|
+
document_number: {},
|
|
1127
|
+
outer: {},
|
|
1128
|
+
};
|
|
1129
|
+
let isCorrect = true;
|
|
1130
|
+
if (queryResult.issuing_country &&
|
|
1131
|
+
queryResult.issuing_country.out &&
|
|
1132
|
+
queryResult.issuing_country.out.result) {
|
|
1133
|
+
if (!queryResult.issuing_country.out.expected?.every((country) => countryList.includes(country))) {
|
|
1134
|
+
console.warn("Issuing country exclusion list does not match the one from the query results");
|
|
1135
|
+
isCorrect = false;
|
|
1136
|
+
queryResultErrors.issuing_country.out = {
|
|
1137
|
+
expected: queryResult.issuing_country.out.expected,
|
|
1138
|
+
received: countryList,
|
|
1139
|
+
message: "Issuing country exclusion list does not match the one from the query results",
|
|
1140
|
+
};
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
else if (!queryResult.issuing_country || !queryResult.issuing_country.out) {
|
|
1144
|
+
console.warn("Issuing country exclusion is not set in the query result");
|
|
1145
|
+
isCorrect = false;
|
|
1146
|
+
queryResultErrors.issuing_country.out = {
|
|
1147
|
+
message: "Issuing country exclusion is not set in the query result",
|
|
1148
|
+
};
|
|
1149
|
+
}
|
|
1150
|
+
// Check the countryList is in ascending order
|
|
1151
|
+
// If the prover doesn't use a sorted list then the proof cannot be trusted
|
|
1152
|
+
// as it is requirement in the circuit for the exclusion check to work
|
|
1153
|
+
for (let i = 1; i < countryList.length; i++) {
|
|
1154
|
+
if (countryList[i] < countryList[i - 1]) {
|
|
1155
|
+
console.warn("The issuing country exclusion list has not been sorted, and thus the proof cannot be trusted");
|
|
1156
|
+
isCorrect = false;
|
|
1157
|
+
queryResultErrors.issuing_country.out = {
|
|
1158
|
+
message: "The issuing country exclusion list has not been sorted, and thus the proof cannot be trusted",
|
|
1159
|
+
};
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
return { isCorrect, queryResultErrors };
|
|
1163
|
+
}
|
|
1164
|
+
checkNationalityInclusionPublicInputs(queryResult, countryList) {
|
|
1165
|
+
const queryResultErrors = {
|
|
1166
|
+
sig_check_dsc: {},
|
|
1167
|
+
sig_check_id_data: {},
|
|
1168
|
+
data_check_integrity: {},
|
|
1169
|
+
disclose: {},
|
|
1170
|
+
age: {},
|
|
1171
|
+
birthdate: {},
|
|
1172
|
+
expiry_date: {},
|
|
1173
|
+
document_type: {},
|
|
1174
|
+
issuing_country: {},
|
|
1175
|
+
gender: {},
|
|
1176
|
+
nationality: {},
|
|
1177
|
+
firstname: {},
|
|
1178
|
+
lastname: {},
|
|
1179
|
+
fullname: {},
|
|
1180
|
+
document_number: {},
|
|
1181
|
+
outer: {},
|
|
1182
|
+
};
|
|
1183
|
+
let isCorrect = true;
|
|
1184
|
+
if (queryResult.nationality &&
|
|
1185
|
+
queryResult.nationality.in &&
|
|
1186
|
+
queryResult.nationality.in.result) {
|
|
1187
|
+
if (!queryResult.nationality.in.expected?.every((country) => countryList.includes(country))) {
|
|
1188
|
+
console.warn("Nationality inclusion list does not match the one from the query results");
|
|
1189
|
+
isCorrect = false;
|
|
1190
|
+
queryResultErrors.nationality.in = {
|
|
1191
|
+
expected: queryResult.nationality.in.expected,
|
|
1192
|
+
received: countryList,
|
|
1193
|
+
message: "Nationality inclusion list does not match the one from the query results",
|
|
1194
|
+
};
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
else if (!queryResult.nationality || !queryResult.nationality.in) {
|
|
1198
|
+
console.warn("Nationality inclusion is not set in the query result");
|
|
1199
|
+
isCorrect = false;
|
|
1200
|
+
queryResultErrors.nationality.in = {
|
|
1201
|
+
message: "Nationality inclusion is not set in the query result",
|
|
1202
|
+
};
|
|
1203
|
+
}
|
|
1204
|
+
return { isCorrect, queryResultErrors };
|
|
1205
|
+
}
|
|
1206
|
+
checkIssuingCountryInclusionPublicInputs(queryResult, countryList) {
|
|
1207
|
+
const queryResultErrors = {
|
|
1208
|
+
sig_check_dsc: {},
|
|
1209
|
+
sig_check_id_data: {},
|
|
1210
|
+
data_check_integrity: {},
|
|
1211
|
+
disclose: {},
|
|
1212
|
+
age: {},
|
|
1213
|
+
birthdate: {},
|
|
1214
|
+
expiry_date: {},
|
|
1215
|
+
document_type: {},
|
|
1216
|
+
issuing_country: {},
|
|
1217
|
+
gender: {},
|
|
1218
|
+
nationality: {},
|
|
1219
|
+
firstname: {},
|
|
1220
|
+
lastname: {},
|
|
1221
|
+
fullname: {},
|
|
1222
|
+
document_number: {},
|
|
1223
|
+
outer: {},
|
|
1224
|
+
};
|
|
1225
|
+
let isCorrect = true;
|
|
1226
|
+
if (queryResult.issuing_country &&
|
|
1227
|
+
queryResult.issuing_country.in &&
|
|
1228
|
+
queryResult.issuing_country.in.result) {
|
|
1229
|
+
if (!queryResult.issuing_country.in.expected?.every((country) => countryList.includes(country))) {
|
|
1230
|
+
console.warn("Issuing country inclusion list does not match the one from the query results");
|
|
1231
|
+
isCorrect = false;
|
|
1232
|
+
queryResultErrors.issuing_country.in = {
|
|
1233
|
+
expected: queryResult.issuing_country.in.expected,
|
|
1234
|
+
received: countryList,
|
|
1235
|
+
message: "Issuing country inclusion list does not match the one from the query results",
|
|
1236
|
+
};
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
else if (!queryResult.issuing_country || !queryResult.issuing_country.in) {
|
|
1240
|
+
console.warn("Issuing country inclusion is not set in the query result");
|
|
1241
|
+
isCorrect = false;
|
|
1242
|
+
queryResultErrors.issuing_country.in = {
|
|
1243
|
+
message: "Issuing country inclusion is not set in the query result",
|
|
1244
|
+
};
|
|
1245
|
+
}
|
|
1246
|
+
return { isCorrect, queryResultErrors };
|
|
1247
|
+
}
|
|
1248
|
+
checkScopeFromDisclosureProof(proofData, queryResultErrors, key, scope) {
|
|
1249
|
+
let isCorrect = true;
|
|
1250
|
+
if (this.domain && (0, utils_1.getScopeHash)(this.domain) !== BigInt(proofData.publicInputs[1])) {
|
|
1251
|
+
console.warn("The proof comes from a different domain than the one expected");
|
|
1252
|
+
isCorrect = false;
|
|
1253
|
+
queryResultErrors[key].scope = {
|
|
1254
|
+
expected: `Scope: ${(0, utils_1.getScopeHash)(this.domain).toString()}`,
|
|
1255
|
+
received: `Scope: ${BigInt(proofData.publicInputs[1]).toString()}`,
|
|
1256
|
+
message: "The proof comes from a different domain than the one expected",
|
|
1257
|
+
};
|
|
1258
|
+
}
|
|
1259
|
+
if (scope && (0, utils_1.getScopeHash)(scope) !== BigInt(proofData.publicInputs[2])) {
|
|
1260
|
+
console.warn("The proof uses a different scope than the one expected");
|
|
1261
|
+
isCorrect = false;
|
|
1262
|
+
queryResultErrors[key].scope = {
|
|
1263
|
+
expected: `Scope: ${(0, utils_1.getScopeHash)(scope).toString()}`,
|
|
1264
|
+
received: `Scope: ${BigInt(proofData.publicInputs[2]).toString()}`,
|
|
1265
|
+
message: "The proof uses a different scope than the one expected",
|
|
1266
|
+
};
|
|
1267
|
+
}
|
|
1268
|
+
return { isCorrect, queryResultErrors };
|
|
1269
|
+
}
|
|
1270
|
+
async checkPublicInputs(proofs, queryResult, validity, scope) {
|
|
1271
|
+
let commitmentIn;
|
|
1272
|
+
let commitmentOut;
|
|
1273
|
+
let isCorrect = true;
|
|
1274
|
+
let uniqueIdentifier;
|
|
1275
|
+
const VALID_CERTIFICATE_REGISTRY_ROOT = [
|
|
1276
|
+
BigInt("20192042006788880778219739574377003123593792072535937278552252195461520776494"),
|
|
1277
|
+
BigInt("21301853597069384763054217328384418971999152625381818922211526730996340553696"),
|
|
1278
|
+
BigInt("10839898448097753834842514286432152806152415606387598803678317315409344029817"),
|
|
1279
|
+
];
|
|
1280
|
+
const currentTime = new Date();
|
|
1281
|
+
const today = new Date(currentTime.getFullYear(), currentTime.getMonth(), currentTime.getDate(), 0, 0, 0, 0);
|
|
1282
|
+
let queryResultErrors = {
|
|
1283
|
+
sig_check_dsc: {},
|
|
1284
|
+
sig_check_id_data: {},
|
|
1285
|
+
data_check_integrity: {},
|
|
1286
|
+
disclose: {},
|
|
1287
|
+
age: {},
|
|
1288
|
+
birthdate: {},
|
|
1289
|
+
expiry_date: {},
|
|
1290
|
+
document_type: {},
|
|
1291
|
+
issuing_country: {},
|
|
1292
|
+
gender: {},
|
|
1293
|
+
nationality: {},
|
|
1294
|
+
firstname: {},
|
|
1295
|
+
lastname: {},
|
|
1296
|
+
fullname: {},
|
|
1297
|
+
document_number: {},
|
|
1298
|
+
outer: {},
|
|
1299
|
+
};
|
|
1300
|
+
// Since the order is important for the commitments, we need to sort the proofs
|
|
1301
|
+
// by their expected order: root signature check -> ID signature check -> integrity check -> disclosure
|
|
1302
|
+
const sortedProofs = proofs.sort((a, b) => {
|
|
1303
|
+
const proofOrder = [
|
|
1304
|
+
"sig_check_dsc",
|
|
1305
|
+
"sig_check_id_data",
|
|
1306
|
+
"data_check_integrity",
|
|
1307
|
+
"disclose_bytes",
|
|
1308
|
+
"compare_age",
|
|
1309
|
+
"compare_birthdate",
|
|
1310
|
+
"compare_expiry",
|
|
1311
|
+
"exclusion_check_nationality",
|
|
1312
|
+
"inclusion_check_nationality",
|
|
1313
|
+
"exclusion_check_issuing_country",
|
|
1314
|
+
"inclusion_check_issuing_country",
|
|
1315
|
+
];
|
|
1316
|
+
const getIndex = (proof) => {
|
|
1317
|
+
const name = proof.name || "";
|
|
1318
|
+
return proofOrder.findIndex((p) => name.startsWith(p));
|
|
1319
|
+
};
|
|
1320
|
+
return getIndex(a) - getIndex(b);
|
|
1321
|
+
});
|
|
1322
|
+
for (const proof of sortedProofs) {
|
|
1323
|
+
const proofData = (0, utils_1.getProofData)(proof.proof, (0, utils_1.getNumberOfPublicInputs)(proof.name));
|
|
1324
|
+
if (proof.name?.startsWith("outer")) {
|
|
1325
|
+
const isForEVM = proof.name?.startsWith("outer_evm");
|
|
1326
|
+
const certificateRegistryRoot = (0, utils_1.getCertificateRegistryRootFromOuterProof)(proofData);
|
|
1327
|
+
if (!VALID_CERTIFICATE_REGISTRY_ROOT.includes(certificateRegistryRoot)) {
|
|
1328
|
+
console.warn("The ID was signed by an unrecognized root certificate");
|
|
1329
|
+
isCorrect = false;
|
|
1330
|
+
queryResultErrors.outer.certificate = {
|
|
1331
|
+
expected: `Certificate registry root: ${VALID_CERTIFICATE_REGISTRY_ROOT.join(", ")}`,
|
|
1332
|
+
received: `Certificate registry root: ${certificateRegistryRoot.toString()}`,
|
|
1333
|
+
message: "The ID was signed by an unrecognized root certificate",
|
|
1334
|
+
};
|
|
662
1335
|
}
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
}
|
|
1336
|
+
const currentDate = (0, utils_1.getCurrentDateFromOuterProof)(proofData);
|
|
1337
|
+
const todayToCurrentDate = today.getTime() - currentDate.getTime();
|
|
1338
|
+
const differenceInDays = validity ?? 180;
|
|
1339
|
+
const expectedDifference = differenceInDays * 86400000;
|
|
1340
|
+
const actualDifference = today.getTime() - (today.getTime() - expectedDifference);
|
|
1341
|
+
// The ID should not expire within the next 6 months (or whatever the custom value is)
|
|
1342
|
+
if (todayToCurrentDate >= actualDifference) {
|
|
1343
|
+
console.warn(`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`);
|
|
1344
|
+
isCorrect = false;
|
|
1345
|
+
queryResultErrors.outer.date = {
|
|
1346
|
+
expected: `Difference: ${differenceInDays} days`,
|
|
1347
|
+
received: `Difference: ${Math.round(todayToCurrentDate / 86400000)} days`,
|
|
1348
|
+
message: "The date used to check the validity of the ID is older than the validity period",
|
|
1349
|
+
};
|
|
1350
|
+
}
|
|
1351
|
+
const paramCommitments = (0, utils_1.getParamCommitmentsFromOuterProof)(proofData);
|
|
1352
|
+
const committedInputs = proof.committedInputs;
|
|
1353
|
+
const keysInCommittedInputs = Object.keys(committedInputs || {});
|
|
1354
|
+
if (keysInCommittedInputs.length !== paramCommitments.length) {
|
|
1355
|
+
console.warn("The proof does not verify all the requested conditions and information");
|
|
1356
|
+
isCorrect = false;
|
|
1357
|
+
queryResultErrors.outer.commitment = {
|
|
1358
|
+
expected: `Number of parameter commitments: ${paramCommitments.length}`,
|
|
1359
|
+
received: `Number of disclosure proofs provided: ${keysInCommittedInputs.length}`,
|
|
1360
|
+
message: "The proof does not verify all the requested conditions and information",
|
|
1361
|
+
};
|
|
1362
|
+
}
|
|
1363
|
+
if (this.domain && (0, utils_1.getScopeHash)(this.domain) !== (0, utils_1.getScopeFromOuterProof)(proofData)) {
|
|
1364
|
+
console.warn("The proof comes from a different domain than the one expected");
|
|
1365
|
+
isCorrect = false;
|
|
1366
|
+
queryResultErrors.outer.scope = {
|
|
1367
|
+
expected: `Scope: ${(0, utils_1.getScopeHash)(this.domain).toString()}`,
|
|
1368
|
+
received: `Scope: ${(0, utils_1.getScopeFromOuterProof)(proofData).toString()}`,
|
|
1369
|
+
message: "The proof comes from a different domain than the one expected",
|
|
1370
|
+
};
|
|
1371
|
+
}
|
|
1372
|
+
if (scope && (0, utils_1.getScopeHash)(scope) !== (0, utils_1.getSubscopeFromOuterProof)(proofData)) {
|
|
1373
|
+
console.warn("The proof uses a different scope than the one expected");
|
|
1374
|
+
isCorrect = false;
|
|
1375
|
+
queryResultErrors.outer.scope = {
|
|
1376
|
+
expected: `Scope: ${(0, utils_1.getScopeHash)(scope).toString()}`,
|
|
1377
|
+
received: `Scope: ${(0, utils_1.getSubscopeFromOuterProof)(proofData).toString()}`,
|
|
1378
|
+
message: "The proof uses a different scope than the one expected",
|
|
1379
|
+
};
|
|
689
1380
|
}
|
|
690
|
-
if (
|
|
691
|
-
const
|
|
692
|
-
const
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
console.warn("Issuing country does not match the expected issuing country");
|
|
1381
|
+
if (!!committedInputs?.compare_age) {
|
|
1382
|
+
const ageCommittedInputs = committedInputs?.compare_age;
|
|
1383
|
+
const ageParameterCommitment = isForEVM
|
|
1384
|
+
? await (0, utils_1.getAgeEVMParameterCommitment)(ageCommittedInputs.currentDate, ageCommittedInputs.minAge, ageCommittedInputs.maxAge)
|
|
1385
|
+
: await (0, utils_1.getAgeParameterCommitment)(ageCommittedInputs.currentDate, ageCommittedInputs.minAge, ageCommittedInputs.maxAge);
|
|
1386
|
+
if (!paramCommitments.includes(ageParameterCommitment)) {
|
|
1387
|
+
console.warn("This proof does not verify the age");
|
|
698
1388
|
isCorrect = false;
|
|
699
|
-
queryResultErrors.
|
|
700
|
-
expected:
|
|
701
|
-
received:
|
|
702
|
-
message: "
|
|
1389
|
+
queryResultErrors.age.commitment = {
|
|
1390
|
+
expected: `Age parameter commitment: ${ageParameterCommitment.toString()}`,
|
|
1391
|
+
received: `Parameter commitments included: ${paramCommitments.join(", ")}`,
|
|
1392
|
+
message: "This proof does not verify the age",
|
|
703
1393
|
};
|
|
704
1394
|
}
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
1395
|
+
const { isCorrect: isCorrectAge, queryResultErrors: queryResultErrorsAge } = this.checkAgePublicInputs(proof, queryResult);
|
|
1396
|
+
isCorrect = isCorrect && isCorrectAge;
|
|
1397
|
+
queryResultErrors = {
|
|
1398
|
+
...queryResultErrors,
|
|
1399
|
+
...queryResultErrorsAge,
|
|
1400
|
+
};
|
|
1401
|
+
}
|
|
1402
|
+
else if (!!committedInputs?.compare_birthdate) {
|
|
1403
|
+
const birthdateCommittedInputs = committedInputs?.compare_birthdate;
|
|
1404
|
+
const birthdateParameterCommitment = isForEVM
|
|
1405
|
+
? await (0, utils_1.getDateEVMParameterCommitment)(utils_1.ProofType.BIRTHDATE, birthdateCommittedInputs.currentDate, birthdateCommittedInputs.minDate, birthdateCommittedInputs.maxDate)
|
|
1406
|
+
: await (0, utils_1.getDateParameterCommitment)(utils_1.ProofType.BIRTHDATE, birthdateCommittedInputs.currentDate, birthdateCommittedInputs.minDate, birthdateCommittedInputs.maxDate);
|
|
1407
|
+
if (!paramCommitments.includes(birthdateParameterCommitment)) {
|
|
1408
|
+
console.warn("This proof does not verify the birthdate");
|
|
709
1409
|
isCorrect = false;
|
|
710
|
-
queryResultErrors.
|
|
711
|
-
expected:
|
|
712
|
-
received:
|
|
713
|
-
message: "
|
|
1410
|
+
queryResultErrors.birthdate.commitment = {
|
|
1411
|
+
expected: `Birthdate parameter commitment: ${birthdateParameterCommitment.toString()}`,
|
|
1412
|
+
received: `Parameter commitments included: ${paramCommitments.join(", ")}`,
|
|
1413
|
+
message: "This proof does not verify the birthdate",
|
|
714
1414
|
};
|
|
715
1415
|
}
|
|
1416
|
+
const { isCorrect: isCorrectBirthdate, queryResultErrors: queryResultErrorsBirthdate } = this.checkBirthdatePublicInputs(proof, queryResult);
|
|
1417
|
+
isCorrect = isCorrect && isCorrectBirthdate;
|
|
1418
|
+
queryResultErrors = {
|
|
1419
|
+
...queryResultErrors,
|
|
1420
|
+
...queryResultErrorsBirthdate,
|
|
1421
|
+
};
|
|
716
1422
|
}
|
|
717
|
-
if (
|
|
718
|
-
const
|
|
719
|
-
const
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
(0, utils_1.formatName)(queryResult.fullname.eq.expected).toLowerCase() !==
|
|
725
|
-
fullnameIDCard.toLowerCase()) {
|
|
726
|
-
console.warn("Fullname does not match the expected fullname");
|
|
1423
|
+
else if (!!committedInputs?.compare_expiry) {
|
|
1424
|
+
const expiryCommittedInputs = committedInputs?.compare_expiry;
|
|
1425
|
+
const expiryParameterCommitment = isForEVM
|
|
1426
|
+
? await (0, utils_1.getDateEVMParameterCommitment)(utils_1.ProofType.EXPIRY_DATE, expiryCommittedInputs.currentDate, expiryCommittedInputs.minDate, expiryCommittedInputs.maxDate)
|
|
1427
|
+
: await (0, utils_1.getDateParameterCommitment)(utils_1.ProofType.EXPIRY_DATE, expiryCommittedInputs.currentDate, expiryCommittedInputs.minDate, expiryCommittedInputs.maxDate);
|
|
1428
|
+
if (!paramCommitments.includes(expiryParameterCommitment)) {
|
|
1429
|
+
console.warn("This proof does not verify the expiry date");
|
|
727
1430
|
isCorrect = false;
|
|
728
|
-
queryResultErrors.
|
|
729
|
-
expected:
|
|
730
|
-
received:
|
|
731
|
-
message: "
|
|
1431
|
+
queryResultErrors.expiry_date.commitment = {
|
|
1432
|
+
expected: `Expiry date parameter commitment: ${expiryParameterCommitment.toString()}`,
|
|
1433
|
+
received: `Parameter commitments included: ${paramCommitments.join(", ")}`,
|
|
1434
|
+
message: "This proof does not verify the expiry date",
|
|
732
1435
|
};
|
|
733
1436
|
}
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
1437
|
+
const { isCorrect: isCorrectExpiryDate, queryResultErrors: queryResultErrorsExpiryDate } = this.checkExpiryDatePublicInputs(proof, queryResult);
|
|
1438
|
+
isCorrect = isCorrect && isCorrectExpiryDate;
|
|
1439
|
+
queryResultErrors = {
|
|
1440
|
+
...queryResultErrors,
|
|
1441
|
+
...queryResultErrorsExpiryDate,
|
|
1442
|
+
};
|
|
1443
|
+
}
|
|
1444
|
+
else if (!!committedInputs?.disclose_bytes) {
|
|
1445
|
+
const discloseCommittedInputs = committedInputs?.disclose_bytes;
|
|
1446
|
+
const discloseParameterCommitment = isForEVM
|
|
1447
|
+
? await (0, utils_1.getDiscloseEVMParameterCommitment)(discloseCommittedInputs.discloseMask, discloseCommittedInputs.disclosedBytes)
|
|
1448
|
+
: await (0, utils_1.getDiscloseParameterCommitment)(discloseCommittedInputs.discloseMask, discloseCommittedInputs.disclosedBytes);
|
|
1449
|
+
if (!paramCommitments.includes(discloseParameterCommitment)) {
|
|
1450
|
+
console.warn("This proof does not verify any of the data disclosed");
|
|
740
1451
|
isCorrect = false;
|
|
741
|
-
queryResultErrors.
|
|
742
|
-
expected:
|
|
743
|
-
received:
|
|
744
|
-
message: "
|
|
1452
|
+
queryResultErrors.disclose.commitment = {
|
|
1453
|
+
expected: `Disclosure parameter commitment: ${discloseParameterCommitment.toString()}`,
|
|
1454
|
+
received: `Parameter commitments included: ${paramCommitments.join(", ")}`,
|
|
1455
|
+
message: "This proof does not verify any of the data disclosed",
|
|
745
1456
|
};
|
|
746
1457
|
}
|
|
1458
|
+
const { isCorrect: isCorrectDisclose, queryResultErrors: queryResultErrorsDisclose } = this.checkDiscloseBytesPublicInputs(proof, queryResult);
|
|
1459
|
+
isCorrect = isCorrect && isCorrectDisclose;
|
|
1460
|
+
queryResultErrors = {
|
|
1461
|
+
...queryResultErrors,
|
|
1462
|
+
...queryResultErrorsDisclose,
|
|
1463
|
+
};
|
|
747
1464
|
}
|
|
748
|
-
if (
|
|
749
|
-
|
|
750
|
-
const
|
|
751
|
-
?
|
|
752
|
-
:
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
: disclosedDataIDCard.name;
|
|
756
|
-
if (queryResult.firstname.eq &&
|
|
757
|
-
queryResult.firstname.eq.result &&
|
|
758
|
-
(0, utils_1.formatName)(queryResult.firstname.eq.expected).toLowerCase() !==
|
|
759
|
-
firstnamePassport.toLowerCase() &&
|
|
760
|
-
(0, utils_1.formatName)(queryResult.firstname.eq.expected).toLowerCase() !==
|
|
761
|
-
firstnameIDCard.toLowerCase()) {
|
|
762
|
-
console.warn("Firstname does not match the expected firstname");
|
|
1465
|
+
else if (!!committedInputs?.inclusion_check_nationality) {
|
|
1466
|
+
const inclusionCheckNationalityCommittedInputs = committedInputs?.inclusion_check_nationality;
|
|
1467
|
+
const inclusionCheckNationalityParameterCommitment = isForEVM
|
|
1468
|
+
? await (0, utils_1.getCountryEVMParameterCommitment)(utils_1.ProofType.NATIONALITY_INCLUSION, inclusionCheckNationalityCommittedInputs.countries)
|
|
1469
|
+
: await (0, utils_1.getCountryParameterCommitment)(utils_1.ProofType.NATIONALITY_INCLUSION, inclusionCheckNationalityCommittedInputs.countries);
|
|
1470
|
+
if (!paramCommitments.includes(inclusionCheckNationalityParameterCommitment)) {
|
|
1471
|
+
console.warn("This proof does not verify the inclusion of the nationality");
|
|
763
1472
|
isCorrect = false;
|
|
764
|
-
queryResultErrors.
|
|
765
|
-
expected:
|
|
766
|
-
received:
|
|
767
|
-
message: "
|
|
1473
|
+
queryResultErrors.nationality.commitment = {
|
|
1474
|
+
expected: `Nationality parameter commitment: ${inclusionCheckNationalityParameterCommitment.toString()}`,
|
|
1475
|
+
received: `Parameter commitments included: ${paramCommitments.join(", ")}`,
|
|
1476
|
+
message: "This proof does not verify the inclusion of the nationality",
|
|
768
1477
|
};
|
|
769
1478
|
}
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
1479
|
+
const countryList = inclusionCheckNationalityCommittedInputs.countries;
|
|
1480
|
+
const { isCorrect: isCorrectNationalityInclusion, queryResultErrors: queryResultErrorsNationalityInclusion, } = this.checkNationalityInclusionPublicInputs(queryResult, countryList);
|
|
1481
|
+
isCorrect = isCorrect && isCorrectNationalityInclusion;
|
|
1482
|
+
queryResultErrors = {
|
|
1483
|
+
...queryResultErrors,
|
|
1484
|
+
...queryResultErrorsNationalityInclusion,
|
|
1485
|
+
};
|
|
1486
|
+
}
|
|
1487
|
+
else if (!!committedInputs?.inclusion_check_issuing_country) {
|
|
1488
|
+
const inclusionCheckIssuingCountryCommittedInputs = committedInputs?.inclusion_check_issuing_country;
|
|
1489
|
+
const inclusionCheckIssuingCountryParameterCommitment = isForEVM
|
|
1490
|
+
? await (0, utils_1.getCountryEVMParameterCommitment)(utils_1.ProofType.ISSUING_COUNTRY_INCLUSION, inclusionCheckIssuingCountryCommittedInputs.countries)
|
|
1491
|
+
: await (0, utils_1.getCountryParameterCommitment)(utils_1.ProofType.ISSUING_COUNTRY_INCLUSION, inclusionCheckIssuingCountryCommittedInputs.countries);
|
|
1492
|
+
if (!paramCommitments.includes(inclusionCheckIssuingCountryParameterCommitment)) {
|
|
1493
|
+
console.warn("This proof does not verify the inclusion of the issuing country");
|
|
776
1494
|
isCorrect = false;
|
|
777
|
-
queryResultErrors.
|
|
778
|
-
expected:
|
|
779
|
-
received:
|
|
780
|
-
message: "
|
|
1495
|
+
queryResultErrors.issuing_country.commitment = {
|
|
1496
|
+
expected: `Issuing country parameter commitment: ${inclusionCheckIssuingCountryParameterCommitment.toString()}`,
|
|
1497
|
+
received: `Parameter commitments included: ${paramCommitments.join(", ")}`,
|
|
1498
|
+
message: "This proof does not verify the inclusion of the issuing country",
|
|
781
1499
|
};
|
|
782
1500
|
}
|
|
1501
|
+
const countryList = inclusionCheckIssuingCountryCommittedInputs.countries;
|
|
1502
|
+
const { isCorrect: isCorrectIssuingCountryInclusion, queryResultErrors: queryResultErrorsIssuingCountryInclusion, } = this.checkIssuingCountryInclusionPublicInputs(queryResult, countryList);
|
|
1503
|
+
isCorrect = isCorrect && isCorrectIssuingCountryInclusion;
|
|
1504
|
+
queryResultErrors = {
|
|
1505
|
+
...queryResultErrors,
|
|
1506
|
+
...queryResultErrorsIssuingCountryInclusion,
|
|
1507
|
+
};
|
|
783
1508
|
}
|
|
784
|
-
if (
|
|
785
|
-
|
|
786
|
-
const
|
|
787
|
-
?
|
|
788
|
-
:
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
: disclosedDataIDCard.name;
|
|
792
|
-
if (queryResult.lastname.eq &&
|
|
793
|
-
queryResult.lastname.eq.result &&
|
|
794
|
-
(0, utils_1.formatName)(queryResult.lastname.eq.expected).toLowerCase() !==
|
|
795
|
-
lastnamePassport.toLowerCase() &&
|
|
796
|
-
(0, utils_1.formatName)(queryResult.lastname.eq.expected).toLowerCase() !==
|
|
797
|
-
lastnameIDCard.toLowerCase()) {
|
|
798
|
-
console.warn("Lastname does not match the expected lastname");
|
|
1509
|
+
else if (!!committedInputs?.exclusion_check_nationality) {
|
|
1510
|
+
const exclusionCheckNationalityCommittedInputs = committedInputs?.exclusion_check_nationality;
|
|
1511
|
+
const exclusionCheckNationalityParameterCommitment = isForEVM
|
|
1512
|
+
? await (0, utils_1.getCountryEVMParameterCommitment)(utils_1.ProofType.NATIONALITY_EXCLUSION, exclusionCheckNationalityCommittedInputs.countries)
|
|
1513
|
+
: await (0, utils_1.getCountryParameterCommitment)(utils_1.ProofType.NATIONALITY_EXCLUSION, exclusionCheckNationalityCommittedInputs.countries);
|
|
1514
|
+
if (!paramCommitments.includes(exclusionCheckNationalityParameterCommitment)) {
|
|
1515
|
+
console.warn("This proof does not verify the exclusion of the nationality");
|
|
799
1516
|
isCorrect = false;
|
|
800
|
-
queryResultErrors.
|
|
801
|
-
expected:
|
|
802
|
-
received:
|
|
803
|
-
message: "
|
|
1517
|
+
queryResultErrors.nationality.commitment = {
|
|
1518
|
+
expected: `Nationality parameter commitment: ${exclusionCheckNationalityParameterCommitment.toString()}`,
|
|
1519
|
+
received: `Parameter commitments included: ${paramCommitments.join(", ")}`,
|
|
1520
|
+
message: "This proof does not verify the exclusion of the nationality",
|
|
804
1521
|
};
|
|
805
1522
|
}
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
1523
|
+
const countryList = exclusionCheckNationalityCommittedInputs.countries;
|
|
1524
|
+
const { isCorrect: isCorrectNationalityExclusion, queryResultErrors: queryResultErrorsNationalityExclusion, } = this.checkNationalityExclusionPublicInputs(queryResult, countryList);
|
|
1525
|
+
isCorrect = isCorrect && isCorrectNationalityExclusion;
|
|
1526
|
+
queryResultErrors = {
|
|
1527
|
+
...queryResultErrors,
|
|
1528
|
+
...queryResultErrorsNationalityExclusion,
|
|
1529
|
+
};
|
|
1530
|
+
}
|
|
1531
|
+
else if (!!committedInputs?.exclusion_check_issuing_country) {
|
|
1532
|
+
const exclusionCheckIssuingCountryCommittedInputs = committedInputs?.exclusion_check_issuing_country;
|
|
1533
|
+
const exclusionCheckIssuingCountryParameterCommitment = isForEVM
|
|
1534
|
+
? await (0, utils_1.getCountryEVMParameterCommitment)(utils_1.ProofType.ISSUING_COUNTRY_EXCLUSION, exclusionCheckIssuingCountryCommittedInputs.countries)
|
|
1535
|
+
: await (0, utils_1.getCountryParameterCommitment)(utils_1.ProofType.ISSUING_COUNTRY_EXCLUSION, exclusionCheckIssuingCountryCommittedInputs.countries);
|
|
1536
|
+
if (!paramCommitments.includes(exclusionCheckIssuingCountryParameterCommitment)) {
|
|
1537
|
+
console.warn("This proof does not verify the exclusion of the issuing country");
|
|
812
1538
|
isCorrect = false;
|
|
813
|
-
queryResultErrors.
|
|
814
|
-
expected:
|
|
815
|
-
received:
|
|
816
|
-
message: "
|
|
1539
|
+
queryResultErrors.issuing_country.commitment = {
|
|
1540
|
+
expected: `Issuing country parameter commitment: ${exclusionCheckIssuingCountryParameterCommitment.toString()}`,
|
|
1541
|
+
received: `Parameter commitments included: ${paramCommitments.join(", ")}`,
|
|
1542
|
+
message: "This proof does not verify the exclusion of the issuing country",
|
|
817
1543
|
};
|
|
818
1544
|
}
|
|
1545
|
+
const countryList = exclusionCheckIssuingCountryCommittedInputs.countries;
|
|
1546
|
+
const { isCorrect: isCorrectIssuingCountryExclusion, queryResultErrors: queryResultErrorsIssuingCountryExclusion, } = this.checkIssuingCountryExclusionPublicInputs(queryResult, countryList);
|
|
1547
|
+
isCorrect = isCorrect && isCorrectIssuingCountryExclusion;
|
|
1548
|
+
queryResultErrors = {
|
|
1549
|
+
...queryResultErrors,
|
|
1550
|
+
...queryResultErrorsIssuingCountryExclusion,
|
|
1551
|
+
};
|
|
1552
|
+
}
|
|
1553
|
+
uniqueIdentifier = (0, utils_1.getNullifierFromOuterProof)(proofData).toString(10);
|
|
1554
|
+
}
|
|
1555
|
+
else if (proof.name?.startsWith("sig_check_dsc")) {
|
|
1556
|
+
commitmentOut = (0, utils_1.getCommitmentFromDSCProof)(proofData);
|
|
1557
|
+
const merkleRoot = (0, utils_1.getMerkleRootFromDSCProof)(proofData);
|
|
1558
|
+
if (!VALID_CERTIFICATE_REGISTRY_ROOT.includes(merkleRoot)) {
|
|
1559
|
+
console.warn("The ID was signed by an unrecognized root certificate");
|
|
1560
|
+
isCorrect = false;
|
|
1561
|
+
queryResultErrors.sig_check_dsc.certificate = {
|
|
1562
|
+
expected: `Certificate registry root: ${VALID_CERTIFICATE_REGISTRY_ROOT.join(", ")}`,
|
|
1563
|
+
received: `Certificate registry root: ${merkleRoot.toString()}`,
|
|
1564
|
+
message: "The ID was signed by an unrecognized root certificate",
|
|
1565
|
+
};
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
else if (proof.name?.startsWith("sig_check_id_data")) {
|
|
1569
|
+
commitmentIn = (0, utils_1.getCommitmentInFromIDDataProof)(proofData);
|
|
1570
|
+
if (commitmentIn !== commitmentOut) {
|
|
1571
|
+
console.warn("Failed to check the link between the certificate signature and ID signature");
|
|
1572
|
+
isCorrect = false;
|
|
1573
|
+
queryResultErrors.sig_check_id_data.commitment = {
|
|
1574
|
+
expected: `Commitment: ${commitmentOut?.toString() || "undefined"}`,
|
|
1575
|
+
received: `Commitment: ${commitmentIn?.toString() || "undefined"}`,
|
|
1576
|
+
message: "Failed to check the link between the certificate signature and ID signature",
|
|
1577
|
+
};
|
|
1578
|
+
}
|
|
1579
|
+
commitmentOut = (0, utils_1.getCommitmentOutFromIDDataProof)(proofData);
|
|
1580
|
+
}
|
|
1581
|
+
else if (proof.name?.startsWith("data_check_integrity")) {
|
|
1582
|
+
commitmentIn = (0, utils_1.getCommitmentInFromIntegrityProof)(proofData);
|
|
1583
|
+
if (commitmentIn !== commitmentOut) {
|
|
1584
|
+
console.warn("Failed to check the link between the ID signature and the data signed");
|
|
1585
|
+
isCorrect = false;
|
|
1586
|
+
queryResultErrors.data_check_integrity.commitment = {
|
|
1587
|
+
expected: `Commitment: ${commitmentOut?.toString() || "undefined"}`,
|
|
1588
|
+
received: `Commitment: ${commitmentIn?.toString() || "undefined"}`,
|
|
1589
|
+
message: "Failed to check the link between the ID signature and the data signed",
|
|
1590
|
+
};
|
|
819
1591
|
}
|
|
1592
|
+
commitmentOut = (0, utils_1.getCommitmentOutFromIntegrityProof)(proofData);
|
|
1593
|
+
const currentDate = (0, utils_1.getCurrentDateFromIntegrityProof)(proofData);
|
|
1594
|
+
const todayToCurrentDate = today.getTime() - currentDate.getTime();
|
|
1595
|
+
const differenceInDays = validity ?? 180;
|
|
1596
|
+
const expectedDifference = differenceInDays * 86400000;
|
|
1597
|
+
const actualDifference = today.getTime() - (today.getTime() - expectedDifference);
|
|
1598
|
+
// The ID should not expire within the next 6 months (or whatever the custom value is)
|
|
1599
|
+
if (todayToCurrentDate >= actualDifference) {
|
|
1600
|
+
console.warn(`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`);
|
|
1601
|
+
isCorrect = false;
|
|
1602
|
+
queryResultErrors.data_check_integrity.date = {
|
|
1603
|
+
expected: `Difference: ${differenceInDays} days`,
|
|
1604
|
+
received: `Difference: ${Math.round(todayToCurrentDate / 86400000)} days`,
|
|
1605
|
+
message: "The date used to check the validity of the ID is older than the validity period",
|
|
1606
|
+
};
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
else if (proof.name === "disclose_bytes") {
|
|
1610
|
+
commitmentIn = (0, utils_1.getCommitmentInFromDisclosureProof)(proofData);
|
|
1611
|
+
if (commitmentIn !== commitmentOut) {
|
|
1612
|
+
console.warn("Failed to check the link between the validity of the ID and the data to disclose");
|
|
1613
|
+
isCorrect = false;
|
|
1614
|
+
queryResultErrors.disclose.commitment = {
|
|
1615
|
+
expected: `Commitment: ${commitmentOut?.toString() || "undefined"}`,
|
|
1616
|
+
received: `Commitment: ${commitmentIn?.toString() || "undefined"}`,
|
|
1617
|
+
message: "Failed to check the link between the validity of the ID and the data to disclose",
|
|
1618
|
+
};
|
|
1619
|
+
}
|
|
1620
|
+
const paramCommitment = (0, utils_1.getParameterCommitmentFromDisclosureProof)(proofData);
|
|
1621
|
+
const calculatedParamCommitment = await (0, utils_1.getDiscloseParameterCommitment)((proof.committedInputs?.disclose_bytes).discloseMask, (proof.committedInputs?.disclose_bytes).disclosedBytes);
|
|
1622
|
+
if (paramCommitment !== calculatedParamCommitment) {
|
|
1623
|
+
console.warn("The disclosed data does not match the data committed by the proof");
|
|
1624
|
+
isCorrect = false;
|
|
1625
|
+
queryResultErrors.disclose.commitment = {
|
|
1626
|
+
expected: `Commitment: ${calculatedParamCommitment}`,
|
|
1627
|
+
received: `Commitment: ${paramCommitment}`,
|
|
1628
|
+
message: "The disclosed data does not match the data committed by the proof",
|
|
1629
|
+
};
|
|
1630
|
+
}
|
|
1631
|
+
const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "disclose", scope);
|
|
1632
|
+
isCorrect = isCorrect && isCorrectScope;
|
|
1633
|
+
queryResultErrors = {
|
|
1634
|
+
...queryResultErrors,
|
|
1635
|
+
...queryResultErrorsScope,
|
|
1636
|
+
};
|
|
1637
|
+
const { isCorrect: isCorrectDisclose, queryResultErrors: queryResultErrorsDisclose } = this.checkDiscloseBytesPublicInputs(proof, queryResult);
|
|
1638
|
+
isCorrect = isCorrect && isCorrectDisclose && isCorrectScope;
|
|
1639
|
+
queryResultErrors = {
|
|
1640
|
+
...queryResultErrors,
|
|
1641
|
+
...queryResultErrorsDisclose,
|
|
1642
|
+
...queryResultErrorsScope,
|
|
1643
|
+
};
|
|
820
1644
|
uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
|
|
821
1645
|
}
|
|
822
1646
|
else if (proof.name === "compare_age") {
|
|
@@ -830,92 +1654,26 @@ class ZKPassport {
|
|
|
830
1654
|
message: "Failed to check the link between the validity of the ID and the age derived from it",
|
|
831
1655
|
};
|
|
832
1656
|
}
|
|
833
|
-
const
|
|
834
|
-
const
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
minAge < queryResult.age.gte.expected) {
|
|
839
|
-
console.warn("Age is not greater than or equal to the expected age");
|
|
840
|
-
isCorrect = false;
|
|
841
|
-
queryResultErrors.age.gte = {
|
|
842
|
-
expected: queryResult.age.gte.expected,
|
|
843
|
-
received: minAge,
|
|
844
|
-
message: "Age is not greater than or equal to the expected age",
|
|
845
|
-
};
|
|
846
|
-
}
|
|
847
|
-
if (queryResult.age.lt &&
|
|
848
|
-
queryResult.age.lt.result &&
|
|
849
|
-
maxAge >= queryResult.age.lt.expected) {
|
|
850
|
-
console.warn("Age is not less than the expected age");
|
|
851
|
-
isCorrect = false;
|
|
852
|
-
queryResultErrors.age.lt = {
|
|
853
|
-
expected: queryResult.age.lt.expected,
|
|
854
|
-
received: maxAge,
|
|
855
|
-
message: "Age is not less than the expected age",
|
|
856
|
-
};
|
|
857
|
-
}
|
|
858
|
-
if (queryResult.age.range) {
|
|
859
|
-
if (queryResult.age.range.result &&
|
|
860
|
-
(minAge < queryResult.age.range.expected[0] ||
|
|
861
|
-
maxAge >= queryResult.age.range.expected[1])) {
|
|
862
|
-
console.warn("Age is not in the expected range");
|
|
863
|
-
isCorrect = false;
|
|
864
|
-
queryResultErrors.age.range = {
|
|
865
|
-
expected: queryResult.age.range.expected,
|
|
866
|
-
received: [minAge, maxAge],
|
|
867
|
-
message: "Age is not in the expected range",
|
|
868
|
-
};
|
|
869
|
-
}
|
|
870
|
-
}
|
|
871
|
-
if (!queryResult.age.lt && !queryResult.age.range && maxAge != 0) {
|
|
872
|
-
console.warn("Maximum age should be equal to 0");
|
|
873
|
-
isCorrect = false;
|
|
874
|
-
queryResultErrors.age.disclose = {
|
|
875
|
-
expected: 0,
|
|
876
|
-
received: maxAge,
|
|
877
|
-
message: "Maximum age should be equal to 0",
|
|
878
|
-
};
|
|
879
|
-
}
|
|
880
|
-
if (!queryResult.age.gte && !queryResult.age.range && minAge != 0) {
|
|
881
|
-
console.warn("Minimum age should be equal to 0");
|
|
882
|
-
isCorrect = false;
|
|
883
|
-
queryResultErrors.age.disclose = {
|
|
884
|
-
expected: 0,
|
|
885
|
-
received: minAge,
|
|
886
|
-
message: "Minimum age should be equal to 0",
|
|
887
|
-
};
|
|
888
|
-
}
|
|
889
|
-
if (queryResult.age.disclose &&
|
|
890
|
-
(queryResult.age.disclose.result !== minAge ||
|
|
891
|
-
queryResult.age.disclose.result !== maxAge)) {
|
|
892
|
-
console.warn("Age does not match the disclosed age in query result");
|
|
893
|
-
isCorrect = false;
|
|
894
|
-
queryResultErrors.age.disclose = {
|
|
895
|
-
expected: `${minAge}`,
|
|
896
|
-
received: `${queryResult.age.disclose.result}`,
|
|
897
|
-
message: "Age does not match the disclosed age in query result",
|
|
898
|
-
};
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
else {
|
|
902
|
-
console.warn("Age is not set in the query result");
|
|
903
|
-
isCorrect = false;
|
|
904
|
-
queryResultErrors.age.disclose = {
|
|
905
|
-
message: "Age is not set in the query result",
|
|
906
|
-
};
|
|
907
|
-
}
|
|
908
|
-
const currentDate = (0, utils_1.getCurrentDateFromAgeProof)(proofData);
|
|
909
|
-
if (currentDate.getTime() !== today.getTime() &&
|
|
910
|
-
currentDate.getTime() !== today.getTime() - 86400000) {
|
|
911
|
-
console.warn("Current date in the proof is too old");
|
|
1657
|
+
const paramCommitment = (0, utils_1.getParameterCommitmentFromDisclosureProof)(proofData);
|
|
1658
|
+
const committedInputs = proof.committedInputs?.compare_age;
|
|
1659
|
+
const calculatedParamCommitment = await (0, utils_1.getAgeParameterCommitment)(committedInputs.currentDate, committedInputs.minAge, committedInputs.maxAge);
|
|
1660
|
+
if (paramCommitment !== calculatedParamCommitment) {
|
|
1661
|
+
console.warn("The conditions for the age check do not match the conditions checked by the proof");
|
|
912
1662
|
isCorrect = false;
|
|
913
|
-
queryResultErrors.age.
|
|
914
|
-
expected:
|
|
915
|
-
received:
|
|
916
|
-
message: "
|
|
1663
|
+
queryResultErrors.age.commitment = {
|
|
1664
|
+
expected: `Commitment: ${calculatedParamCommitment}`,
|
|
1665
|
+
received: `Commitment: ${paramCommitment}`,
|
|
1666
|
+
message: "The conditions for the age check do not match the conditions checked by the proof",
|
|
917
1667
|
};
|
|
918
1668
|
}
|
|
1669
|
+
const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "age", scope);
|
|
1670
|
+
const { isCorrect: isCorrectAge, queryResultErrors: queryResultErrorsAge } = this.checkAgePublicInputs(proof, queryResult);
|
|
1671
|
+
isCorrect = isCorrect && isCorrectAge && isCorrectScope;
|
|
1672
|
+
queryResultErrors = {
|
|
1673
|
+
...queryResultErrors,
|
|
1674
|
+
...queryResultErrorsAge,
|
|
1675
|
+
...queryResultErrorsScope,
|
|
1676
|
+
};
|
|
919
1677
|
uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
|
|
920
1678
|
}
|
|
921
1679
|
else if (proof.name === "compare_birthdate") {
|
|
@@ -929,74 +1687,26 @@ class ZKPassport {
|
|
|
929
1687
|
message: "Failed to check the link between the validity of the ID and the birthdate derived from it",
|
|
930
1688
|
};
|
|
931
1689
|
}
|
|
932
|
-
const
|
|
933
|
-
const
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
minDate < queryResult.birthdate.gte.expected) {
|
|
938
|
-
console.warn("Birthdate is not greater than or equal to the expected birthdate");
|
|
939
|
-
isCorrect = false;
|
|
940
|
-
queryResultErrors.birthdate.gte = {
|
|
941
|
-
expected: queryResult.birthdate.gte.expected,
|
|
942
|
-
received: minDate,
|
|
943
|
-
message: "Birthdate is not greater than or equal to the expected birthdate",
|
|
944
|
-
};
|
|
945
|
-
}
|
|
946
|
-
if (queryResult.birthdate.lte &&
|
|
947
|
-
queryResult.birthdate.lte.result &&
|
|
948
|
-
maxDate > queryResult.birthdate.lte.expected) {
|
|
949
|
-
console.warn("Birthdate is not less than the expected birthdate");
|
|
950
|
-
isCorrect = false;
|
|
951
|
-
queryResultErrors.birthdate.lte = {
|
|
952
|
-
expected: queryResult.birthdate.lte.expected,
|
|
953
|
-
received: maxDate,
|
|
954
|
-
message: "Birthdate is not less than the expected birthdate",
|
|
955
|
-
};
|
|
956
|
-
}
|
|
957
|
-
if (queryResult.birthdate.range) {
|
|
958
|
-
if (queryResult.birthdate.range.result &&
|
|
959
|
-
(minDate < queryResult.birthdate.range.expected[0] ||
|
|
960
|
-
maxDate > queryResult.birthdate.range.expected[1])) {
|
|
961
|
-
console.warn("Birthdate is not in the expected range");
|
|
962
|
-
isCorrect = false;
|
|
963
|
-
queryResultErrors.birthdate.range = {
|
|
964
|
-
expected: queryResult.birthdate.range.expected,
|
|
965
|
-
received: [minDate, maxDate],
|
|
966
|
-
message: "Birthdate is not in the expected range",
|
|
967
|
-
};
|
|
968
|
-
}
|
|
969
|
-
}
|
|
970
|
-
if (!queryResult.birthdate.lte &&
|
|
971
|
-
!queryResult.birthdate.range &&
|
|
972
|
-
maxDate.getTime() != defaultDateValue.getTime()) {
|
|
973
|
-
console.warn("Maximum birthdate should be equal to default date value");
|
|
974
|
-
isCorrect = false;
|
|
975
|
-
queryResultErrors.birthdate.disclose = {
|
|
976
|
-
expected: `${defaultDateValue.toISOString()}`,
|
|
977
|
-
received: `${maxDate.toISOString()}`,
|
|
978
|
-
message: "Maximum birthdate should be equal to default date value",
|
|
979
|
-
};
|
|
980
|
-
}
|
|
981
|
-
if (!queryResult.birthdate.gte &&
|
|
982
|
-
!queryResult.birthdate.range &&
|
|
983
|
-
minDate.getTime() != defaultDateValue.getTime()) {
|
|
984
|
-
console.warn("Minimum birthdate should be equal to default date value");
|
|
985
|
-
isCorrect = false;
|
|
986
|
-
queryResultErrors.birthdate.disclose = {
|
|
987
|
-
expected: `${defaultDateValue.toISOString()}`,
|
|
988
|
-
received: `${minDate.toISOString()}`,
|
|
989
|
-
message: "Minimum birthdate should be equal to default date value",
|
|
990
|
-
};
|
|
991
|
-
}
|
|
992
|
-
}
|
|
993
|
-
else {
|
|
994
|
-
console.warn("Birthdate is not set in the query result");
|
|
1690
|
+
const paramCommitment = (0, utils_1.getParameterCommitmentFromDisclosureProof)(proofData);
|
|
1691
|
+
const committedInputs = proof.committedInputs?.compare_birthdate;
|
|
1692
|
+
const calculatedParamCommitment = await (0, utils_1.getDateParameterCommitment)(utils_1.ProofType.BIRTHDATE, committedInputs.currentDate, committedInputs.minDate, committedInputs.maxDate);
|
|
1693
|
+
if (paramCommitment !== calculatedParamCommitment) {
|
|
1694
|
+
console.warn("The conditions for the birthdate check do not match the conditions checked by the proof");
|
|
995
1695
|
isCorrect = false;
|
|
996
|
-
queryResultErrors.birthdate.
|
|
997
|
-
|
|
1696
|
+
queryResultErrors.birthdate.commitment = {
|
|
1697
|
+
expected: `Commitment: ${calculatedParamCommitment}`,
|
|
1698
|
+
received: `Commitment: ${paramCommitment}`,
|
|
1699
|
+
message: "The conditions for the birthdate check do not match the conditions checked by the proof",
|
|
998
1700
|
};
|
|
999
1701
|
}
|
|
1702
|
+
const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "birthdate", scope);
|
|
1703
|
+
const { isCorrect: isCorrectBirthdate, queryResultErrors: queryResultErrorsBirthdate } = this.checkBirthdatePublicInputs(proof, queryResult);
|
|
1704
|
+
isCorrect = isCorrect && isCorrectBirthdate && isCorrectScope;
|
|
1705
|
+
queryResultErrors = {
|
|
1706
|
+
...queryResultErrors,
|
|
1707
|
+
...queryResultErrorsBirthdate,
|
|
1708
|
+
...queryResultErrorsScope,
|
|
1709
|
+
};
|
|
1000
1710
|
uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
|
|
1001
1711
|
}
|
|
1002
1712
|
else if (proof.name === "compare_expiry") {
|
|
@@ -1010,74 +1720,26 @@ class ZKPassport {
|
|
|
1010
1720
|
message: "Failed to check the link between the validity of the ID and its expiry date",
|
|
1011
1721
|
};
|
|
1012
1722
|
}
|
|
1013
|
-
const
|
|
1014
|
-
const
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
minDate < queryResult.expiry_date.gte.expected) {
|
|
1019
|
-
console.warn("Expiry date is not greater than or equal to the expected expiry date");
|
|
1020
|
-
isCorrect = false;
|
|
1021
|
-
queryResultErrors.expiry_date.gte = {
|
|
1022
|
-
expected: queryResult.expiry_date.gte.expected,
|
|
1023
|
-
received: minDate,
|
|
1024
|
-
message: "Expiry date is not greater than or equal to the expected expiry date",
|
|
1025
|
-
};
|
|
1026
|
-
}
|
|
1027
|
-
if (queryResult.expiry_date.lte &&
|
|
1028
|
-
queryResult.expiry_date.lte.result &&
|
|
1029
|
-
maxDate > queryResult.expiry_date.lte.expected) {
|
|
1030
|
-
console.warn("Expiry date is not less than the expected expiry date");
|
|
1031
|
-
isCorrect = false;
|
|
1032
|
-
queryResultErrors.expiry_date.lte = {
|
|
1033
|
-
expected: queryResult.expiry_date.lte.expected,
|
|
1034
|
-
received: maxDate,
|
|
1035
|
-
message: "Expiry date is not less than the expected expiry date",
|
|
1036
|
-
};
|
|
1037
|
-
}
|
|
1038
|
-
if (queryResult.expiry_date.range) {
|
|
1039
|
-
if (queryResult.expiry_date.range.result &&
|
|
1040
|
-
(minDate < queryResult.expiry_date.range.expected[0] ||
|
|
1041
|
-
maxDate > queryResult.expiry_date.range.expected[1])) {
|
|
1042
|
-
console.warn("Expiry date is not in the expected range");
|
|
1043
|
-
isCorrect = false;
|
|
1044
|
-
queryResultErrors.expiry_date.range = {
|
|
1045
|
-
expected: queryResult.expiry_date.range.expected,
|
|
1046
|
-
received: [minDate, maxDate],
|
|
1047
|
-
message: "Expiry date is not in the expected range",
|
|
1048
|
-
};
|
|
1049
|
-
}
|
|
1050
|
-
}
|
|
1051
|
-
if (!queryResult.expiry_date.lte &&
|
|
1052
|
-
!queryResult.expiry_date.range &&
|
|
1053
|
-
maxDate.getTime() != defaultDateValue.getTime()) {
|
|
1054
|
-
console.warn("Maximum expiry date should be equal to default date value");
|
|
1055
|
-
isCorrect = false;
|
|
1056
|
-
queryResultErrors.expiry_date.disclose = {
|
|
1057
|
-
expected: `${defaultDateValue.toISOString()}`,
|
|
1058
|
-
received: `${maxDate.toISOString()}`,
|
|
1059
|
-
message: "Maximum expiry date should be equal to default date value",
|
|
1060
|
-
};
|
|
1061
|
-
}
|
|
1062
|
-
if (!queryResult.expiry_date.gte &&
|
|
1063
|
-
!queryResult.expiry_date.range &&
|
|
1064
|
-
minDate.getTime() != defaultDateValue.getTime()) {
|
|
1065
|
-
console.warn("Minimum expiry date should be equal to default date value");
|
|
1066
|
-
isCorrect = false;
|
|
1067
|
-
queryResultErrors.expiry_date.disclose = {
|
|
1068
|
-
expected: `${defaultDateValue.toISOString()}`,
|
|
1069
|
-
received: `${minDate.toISOString()}`,
|
|
1070
|
-
message: "Minimum expiry date should be equal to default date value",
|
|
1071
|
-
};
|
|
1072
|
-
}
|
|
1073
|
-
}
|
|
1074
|
-
else {
|
|
1075
|
-
console.warn("Expiry date is not set in the query result");
|
|
1723
|
+
const paramCommitment = (0, utils_1.getParameterCommitmentFromDisclosureProof)(proofData);
|
|
1724
|
+
const committedInputs = proof.committedInputs?.compare_expiry;
|
|
1725
|
+
const calculatedParamCommitment = await (0, utils_1.getDateParameterCommitment)(utils_1.ProofType.EXPIRY_DATE, committedInputs.currentDate, committedInputs.minDate, committedInputs.maxDate);
|
|
1726
|
+
if (paramCommitment !== calculatedParamCommitment) {
|
|
1727
|
+
console.warn("The conditions for the expiry date check do not match the conditions checked by the proof");
|
|
1076
1728
|
isCorrect = false;
|
|
1077
|
-
queryResultErrors.expiry_date.
|
|
1078
|
-
|
|
1729
|
+
queryResultErrors.expiry_date.commitment = {
|
|
1730
|
+
expected: `Commitment: ${calculatedParamCommitment}`,
|
|
1731
|
+
received: `Commitment: ${paramCommitment}`,
|
|
1732
|
+
message: "The conditions for the expiry date check do not match the conditions checked by the proof",
|
|
1079
1733
|
};
|
|
1080
1734
|
}
|
|
1735
|
+
const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "expiry_date", scope);
|
|
1736
|
+
const { isCorrect: isCorrectExpiryDate, queryResultErrors: queryResultErrorsExpiryDate } = this.checkExpiryDatePublicInputs(proof, queryResult);
|
|
1737
|
+
isCorrect = isCorrect && isCorrectExpiryDate && isCorrectScope;
|
|
1738
|
+
queryResultErrors = {
|
|
1739
|
+
...queryResultErrors,
|
|
1740
|
+
...queryResultErrorsExpiryDate,
|
|
1741
|
+
...queryResultErrorsScope,
|
|
1742
|
+
};
|
|
1081
1743
|
uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
|
|
1082
1744
|
}
|
|
1083
1745
|
else if (proof.name === "exclusion_check_nationality") {
|
|
@@ -1091,39 +1753,26 @@ class ZKPassport {
|
|
|
1091
1753
|
message: "Failed to check the link between the validity of the ID and the nationality exclusion check",
|
|
1092
1754
|
};
|
|
1093
1755
|
}
|
|
1094
|
-
const countryList = (
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
console.warn("Nationality exclusion list does not match the one from the query results");
|
|
1100
|
-
isCorrect = false;
|
|
1101
|
-
queryResultErrors.nationality.out = {
|
|
1102
|
-
expected: queryResult.nationality.out.expected,
|
|
1103
|
-
received: countryList,
|
|
1104
|
-
message: "Nationality exclusion list does not match the one from the query results",
|
|
1105
|
-
};
|
|
1106
|
-
}
|
|
1107
|
-
}
|
|
1108
|
-
else if (!queryResult.nationality || !queryResult.nationality.out) {
|
|
1109
|
-
console.warn("Nationality exclusion is not set in the query result");
|
|
1756
|
+
const countryList = (proof.committedInputs?.exclusion_check_nationality).countries;
|
|
1757
|
+
const paramCommittment = (0, utils_1.getParameterCommitmentFromDisclosureProof)(proofData);
|
|
1758
|
+
const calculatedParamCommitment = await (0, utils_1.getCountryParameterCommitment)(utils_1.ProofType.NATIONALITY_EXCLUSION, countryList, true);
|
|
1759
|
+
if (paramCommittment !== calculatedParamCommitment) {
|
|
1760
|
+
console.warn("The committed country list for the exclusion check does not match the one from the proof");
|
|
1110
1761
|
isCorrect = false;
|
|
1111
|
-
queryResultErrors.nationality.
|
|
1112
|
-
|
|
1762
|
+
queryResultErrors.nationality.commitment = {
|
|
1763
|
+
expected: `Commitment: ${calculatedParamCommitment}`,
|
|
1764
|
+
received: `Commitment: ${paramCommittment}`,
|
|
1765
|
+
message: "The committed country list for the exclusion check does not match the one from the proof",
|
|
1113
1766
|
};
|
|
1114
1767
|
}
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
message: "The nationality exclusion list has not been sorted, and thus the proof cannot be trusted",
|
|
1124
|
-
};
|
|
1125
|
-
}
|
|
1126
|
-
}
|
|
1768
|
+
const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "nationality", scope);
|
|
1769
|
+
const { isCorrect: isCorrectNationalityExclusion, queryResultErrors: queryResultErrorsNationalityExclusion, } = this.checkNationalityExclusionPublicInputs(queryResult, countryList);
|
|
1770
|
+
isCorrect = isCorrect && isCorrectNationalityExclusion && isCorrectScope;
|
|
1771
|
+
queryResultErrors = {
|
|
1772
|
+
...queryResultErrors,
|
|
1773
|
+
...queryResultErrorsNationalityExclusion,
|
|
1774
|
+
...queryResultErrorsScope,
|
|
1775
|
+
};
|
|
1127
1776
|
uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
|
|
1128
1777
|
}
|
|
1129
1778
|
else if (proof.name === "exclusion_check_issuing_country") {
|
|
@@ -1137,39 +1786,26 @@ class ZKPassport {
|
|
|
1137
1786
|
message: "Failed to check the link between the validity of the ID and the issuing country exclusion check",
|
|
1138
1787
|
};
|
|
1139
1788
|
}
|
|
1140
|
-
const countryList = (
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
console.warn("Issuing country exclusion list does not match the one from the query results");
|
|
1146
|
-
isCorrect = false;
|
|
1147
|
-
queryResultErrors.issuing_country.out = {
|
|
1148
|
-
expected: queryResult.issuing_country.out.expected,
|
|
1149
|
-
received: countryList,
|
|
1150
|
-
message: "Issuing country exclusion list does not match the one from the query results",
|
|
1151
|
-
};
|
|
1152
|
-
}
|
|
1153
|
-
}
|
|
1154
|
-
else if (!queryResult.issuing_country || !queryResult.issuing_country.out) {
|
|
1155
|
-
console.warn("Issuing country exclusion is not set in the query result");
|
|
1789
|
+
const countryList = (proof.committedInputs?.exclusion_check_issuing_country).countries;
|
|
1790
|
+
const paramCommittment = (0, utils_1.getParameterCommitmentFromDisclosureProof)(proofData);
|
|
1791
|
+
const calculatedParamCommitment = await (0, utils_1.getCountryParameterCommitment)(utils_1.ProofType.ISSUING_COUNTRY_EXCLUSION, countryList, true);
|
|
1792
|
+
if (paramCommittment !== calculatedParamCommitment) {
|
|
1793
|
+
console.warn("The committed country list for the issuing country exclusion check does not match the one from the proof");
|
|
1156
1794
|
isCorrect = false;
|
|
1157
|
-
queryResultErrors.issuing_country.
|
|
1158
|
-
|
|
1795
|
+
queryResultErrors.issuing_country.commitment = {
|
|
1796
|
+
expected: `Commitment: ${calculatedParamCommitment}`,
|
|
1797
|
+
received: `Commitment: ${paramCommittment}`,
|
|
1798
|
+
message: "The committed country list for the issuing country exclusion check does not match the one from the proof",
|
|
1159
1799
|
};
|
|
1160
1800
|
}
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
message: "The issuing country exclusion list has not been sorted, and thus the proof cannot be trusted",
|
|
1170
|
-
};
|
|
1171
|
-
}
|
|
1172
|
-
}
|
|
1801
|
+
const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "nationality", scope);
|
|
1802
|
+
const { isCorrect: isCorrectIssuingCountryExclusion, queryResultErrors: queryResultErrorsIssuingCountryExclusion, } = this.checkIssuingCountryExclusionPublicInputs(queryResult, countryList);
|
|
1803
|
+
isCorrect = isCorrect && isCorrectIssuingCountryExclusion && isCorrectScope;
|
|
1804
|
+
queryResultErrors = {
|
|
1805
|
+
...queryResultErrors,
|
|
1806
|
+
...queryResultErrorsIssuingCountryExclusion,
|
|
1807
|
+
...queryResultErrorsScope,
|
|
1808
|
+
};
|
|
1173
1809
|
uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
|
|
1174
1810
|
}
|
|
1175
1811
|
else if (proof.name === "inclusion_check_nationality") {
|
|
@@ -1183,27 +1819,26 @@ class ZKPassport {
|
|
|
1183
1819
|
message: "Failed to check the link between the validity of the ID and the nationality inclusion check",
|
|
1184
1820
|
};
|
|
1185
1821
|
}
|
|
1186
|
-
const countryList = (
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
console.warn("Nationality inclusion list does not match the one from the query results");
|
|
1192
|
-
isCorrect = false;
|
|
1193
|
-
queryResultErrors.nationality.in = {
|
|
1194
|
-
expected: queryResult.nationality.in.expected,
|
|
1195
|
-
received: countryList,
|
|
1196
|
-
message: "Nationality inclusion list does not match the one from the query results",
|
|
1197
|
-
};
|
|
1198
|
-
}
|
|
1199
|
-
}
|
|
1200
|
-
else if (!queryResult.nationality || !queryResult.nationality.in) {
|
|
1201
|
-
console.warn("Nationality inclusion is not set in the query result");
|
|
1822
|
+
const countryList = (proof.committedInputs?.inclusion_check_nationality).countries;
|
|
1823
|
+
const paramCommittment = (0, utils_1.getParameterCommitmentFromDisclosureProof)(proofData);
|
|
1824
|
+
const calculatedParamCommitment = await (0, utils_1.getCountryParameterCommitment)(utils_1.ProofType.NATIONALITY_INCLUSION, countryList, false);
|
|
1825
|
+
if (paramCommittment !== calculatedParamCommitment) {
|
|
1826
|
+
console.warn("The committed country list for the nationality inclusion check does not match the one from the proof");
|
|
1202
1827
|
isCorrect = false;
|
|
1203
|
-
queryResultErrors.nationality.
|
|
1204
|
-
|
|
1828
|
+
queryResultErrors.nationality.commitment = {
|
|
1829
|
+
expected: `Commitment: ${calculatedParamCommitment}`,
|
|
1830
|
+
received: `Commitment: ${paramCommittment}`,
|
|
1831
|
+
message: "The committed country list for the nationality inclusion check does not match the one from the proof",
|
|
1205
1832
|
};
|
|
1206
1833
|
}
|
|
1834
|
+
const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "nationality", scope);
|
|
1835
|
+
const { isCorrect: isCorrectNationalityInclusion, queryResultErrors: queryResultErrorsNationalityInclusion, } = this.checkNationalityInclusionPublicInputs(queryResult, countryList);
|
|
1836
|
+
isCorrect = isCorrect && isCorrectNationalityInclusion && isCorrectScope;
|
|
1837
|
+
queryResultErrors = {
|
|
1838
|
+
...queryResultErrors,
|
|
1839
|
+
...queryResultErrorsNationalityInclusion,
|
|
1840
|
+
...queryResultErrorsScope,
|
|
1841
|
+
};
|
|
1207
1842
|
uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
|
|
1208
1843
|
}
|
|
1209
1844
|
else if (proof.name === "inclusion_check_issuing_country") {
|
|
@@ -1217,27 +1852,26 @@ class ZKPassport {
|
|
|
1217
1852
|
message: "Failed to check the link between the validity of the ID and the issuing country inclusion check",
|
|
1218
1853
|
};
|
|
1219
1854
|
}
|
|
1220
|
-
const countryList = (
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
console.warn("Issuing country inclusion list does not match the one from the query results");
|
|
1226
|
-
isCorrect = false;
|
|
1227
|
-
queryResultErrors.issuing_country.in = {
|
|
1228
|
-
expected: queryResult.issuing_country.in.expected,
|
|
1229
|
-
received: countryList,
|
|
1230
|
-
message: "Issuing country inclusion list does not match the one from the query results",
|
|
1231
|
-
};
|
|
1232
|
-
}
|
|
1233
|
-
}
|
|
1234
|
-
else if (!queryResult.issuing_country || !queryResult.issuing_country.in) {
|
|
1235
|
-
console.warn("Issuing country inclusion is not set in the query result");
|
|
1855
|
+
const countryList = (proof.committedInputs?.inclusion_check_issuing_country).countries;
|
|
1856
|
+
const paramCommittment = (0, utils_1.getParameterCommitmentFromDisclosureProof)(proofData);
|
|
1857
|
+
const calculatedParamCommitment = await (0, utils_1.getCountryParameterCommitment)(utils_1.ProofType.ISSUING_COUNTRY_INCLUSION, countryList, false);
|
|
1858
|
+
if (paramCommittment !== calculatedParamCommitment) {
|
|
1859
|
+
console.warn("The committed country list for the issuing country inclusion check does not match the one from the proof");
|
|
1236
1860
|
isCorrect = false;
|
|
1237
|
-
queryResultErrors.issuing_country.
|
|
1238
|
-
|
|
1861
|
+
queryResultErrors.issuing_country.commitment = {
|
|
1862
|
+
expected: `Commitment: ${calculatedParamCommitment}`,
|
|
1863
|
+
received: `Commitment: ${paramCommittment}`,
|
|
1864
|
+
message: "The committed country list for the issuing country inclusion check does not match the one from the proof",
|
|
1239
1865
|
};
|
|
1240
1866
|
}
|
|
1867
|
+
const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(proofData, queryResultErrors, "nationality", scope);
|
|
1868
|
+
const { isCorrect: isCorrectIssuingCountryInclusion, queryResultErrors: queryResultErrorsIssuingCountryInclusion, } = this.checkIssuingCountryInclusionPublicInputs(queryResult, countryList);
|
|
1869
|
+
isCorrect = isCorrect && isCorrectIssuingCountryInclusion && isCorrectScope;
|
|
1870
|
+
queryResultErrors = {
|
|
1871
|
+
...queryResultErrors,
|
|
1872
|
+
...queryResultErrorsIssuingCountryInclusion,
|
|
1873
|
+
...queryResultErrorsScope,
|
|
1874
|
+
};
|
|
1241
1875
|
uniqueIdentifier = (0, utils_1.getNullifierFromDisclosureProof)(proofData).toString(10);
|
|
1242
1876
|
}
|
|
1243
1877
|
}
|
|
@@ -1251,7 +1885,7 @@ class ZKPassport {
|
|
|
1251
1885
|
* @returns An object containing the unique identifier associated to the user
|
|
1252
1886
|
* and a boolean indicating whether the proofs were successfully verified.
|
|
1253
1887
|
*/
|
|
1254
|
-
async verify({ proofs, queryResult, validity, }) {
|
|
1888
|
+
async verify({ proofs, queryResult, validity, scope, }) {
|
|
1255
1889
|
const formattedResult = queryResult;
|
|
1256
1890
|
// Make sure to reconvert the dates to Date objects
|
|
1257
1891
|
if (formattedResult.birthdate && formattedResult.birthdate.disclose) {
|
|
@@ -1265,22 +1899,56 @@ class ZKPassport {
|
|
|
1265
1899
|
let verified = true;
|
|
1266
1900
|
let uniqueIdentifier;
|
|
1267
1901
|
let queryResultErrors;
|
|
1268
|
-
const { isCorrect, uniqueIdentifier: uniqueIdentifierFromPublicInputs, queryResultErrors: queryResultErrorsFromPublicInputs, } = await this.checkPublicInputs(proofs, formattedResult, validity);
|
|
1902
|
+
const { isCorrect, uniqueIdentifier: uniqueIdentifierFromPublicInputs, queryResultErrors: queryResultErrorsFromPublicInputs, } = await this.checkPublicInputs(proofs, formattedResult, validity, scope);
|
|
1269
1903
|
uniqueIdentifier = uniqueIdentifierFromPublicInputs;
|
|
1270
1904
|
verified = isCorrect;
|
|
1271
1905
|
queryResultErrors = isCorrect ? undefined : queryResultErrorsFromPublicInputs;
|
|
1272
1906
|
// Only proceed with the proof verification if the public inputs are correct
|
|
1273
1907
|
if (verified) {
|
|
1274
1908
|
for (const proof of proofs) {
|
|
1275
|
-
const proofData = (0, utils_1.getProofData)(proof.proof,
|
|
1909
|
+
const proofData = (0, utils_1.getProofData)(proof.proof, (0, utils_1.getNumberOfPublicInputs)(proof.name));
|
|
1276
1910
|
const hostedPackagedCircuit = await (0, utils_1.getHostedPackagedCircuitByName)(proof.version, proof.name);
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1911
|
+
if (proof.name?.startsWith("outer_evm")) {
|
|
1912
|
+
try {
|
|
1913
|
+
const { createPublicClient, http } = await Promise.resolve().then(() => tslib_1.__importStar(require("viem")));
|
|
1914
|
+
const { sepolia } = await Promise.resolve().then(() => tslib_1.__importStar(require("viem/chains")));
|
|
1915
|
+
const { address, abi, functionName } = this.getSolidityVerifierDetails("ethereum_sepolia");
|
|
1916
|
+
const client = createPublicClient({
|
|
1917
|
+
chain: sepolia,
|
|
1918
|
+
transport: http("https://ethereum-sepolia-rpc.publicnode.com"),
|
|
1919
|
+
});
|
|
1920
|
+
const params = this.getSolidityVerifierParameters({
|
|
1921
|
+
proof,
|
|
1922
|
+
validityPeriodInDays: validity,
|
|
1923
|
+
domain: this.domain,
|
|
1924
|
+
scope,
|
|
1925
|
+
});
|
|
1926
|
+
const result = await client.readContract({
|
|
1927
|
+
address,
|
|
1928
|
+
abi,
|
|
1929
|
+
functionName,
|
|
1930
|
+
args: [params],
|
|
1931
|
+
});
|
|
1932
|
+
const isVerified = Array.isArray(result) ? Boolean(result[0]) : false;
|
|
1933
|
+
verified = isVerified;
|
|
1934
|
+
}
|
|
1935
|
+
catch (error) {
|
|
1936
|
+
console.warn("Error verifying proof", error);
|
|
1937
|
+
verified = false;
|
|
1938
|
+
}
|
|
1280
1939
|
}
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1940
|
+
else {
|
|
1941
|
+
const vkeyBytes = buffer_1.Buffer.from(hostedPackagedCircuit.vkey, "base64");
|
|
1942
|
+
try {
|
|
1943
|
+
verified = await verifier.verifyUltraHonkProof({
|
|
1944
|
+
proof: buffer_1.Buffer.from(proofData.proof.join(""), "hex"),
|
|
1945
|
+
publicInputs: proofData.publicInputs,
|
|
1946
|
+
}, new Uint8Array(vkeyBytes));
|
|
1947
|
+
}
|
|
1948
|
+
catch (e) {
|
|
1949
|
+
console.warn("Error verifying proof", e);
|
|
1950
|
+
verified = false;
|
|
1951
|
+
}
|
|
1284
1952
|
}
|
|
1285
1953
|
if (!verified) {
|
|
1286
1954
|
// Break the loop if the proof is not valid
|
|
@@ -1293,6 +1961,156 @@ class ZKPassport {
|
|
|
1293
1961
|
uniqueIdentifier = verified ? uniqueIdentifier : undefined;
|
|
1294
1962
|
return { uniqueIdentifier, verified, queryResultErrors };
|
|
1295
1963
|
}
|
|
1964
|
+
getSolidityVerifierDetails(network) {
|
|
1965
|
+
const baseConfig = {
|
|
1966
|
+
functionName: "verifyProof",
|
|
1967
|
+
abi: ZKPassportVerifier_json_1.default.abi,
|
|
1968
|
+
};
|
|
1969
|
+
if (network === "ethereum_sepolia") {
|
|
1970
|
+
return {
|
|
1971
|
+
...baseConfig,
|
|
1972
|
+
address: "0x21E12Fa30a1F98699F242ac062Db4a8e7b344B5d",
|
|
1973
|
+
};
|
|
1974
|
+
}
|
|
1975
|
+
else if (network === "local_anvil") {
|
|
1976
|
+
return {
|
|
1977
|
+
...baseConfig,
|
|
1978
|
+
address: "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6",
|
|
1979
|
+
};
|
|
1980
|
+
}
|
|
1981
|
+
throw new Error(`Unsupported network: ${network}`);
|
|
1982
|
+
}
|
|
1983
|
+
getSolidityVerifierParameters({ proof, validityPeriodInDays = 7, domain, scope, }) {
|
|
1984
|
+
if (!proof.name?.startsWith("outer_evm")) {
|
|
1985
|
+
throw new Error("This proof cannot be verified on an EVM chain. Please make sure to use the `compressed-evm` mode.");
|
|
1986
|
+
}
|
|
1987
|
+
const proofData = (0, utils_1.getProofData)(proof.proof, (0, utils_1.getNumberOfPublicInputs)(proof.name));
|
|
1988
|
+
// For EVM optimised proofs, the first 16 bytes of the proof are the aggregation object
|
|
1989
|
+
// and should be moved at the end of the public inputs
|
|
1990
|
+
const actualProof = proofData.proof.slice(16);
|
|
1991
|
+
const actualPublicInputs = proofData.publicInputs.concat(proofData.proof.slice(0, 16).map((x) => `0x${x}`));
|
|
1992
|
+
let committedInputCounts = [];
|
|
1993
|
+
let committedInputs = [];
|
|
1994
|
+
for (const key in proof.committedInputs) {
|
|
1995
|
+
const committedInputCount = (0, utils_1.getCommittedInputCount)(key);
|
|
1996
|
+
const circuitName = key;
|
|
1997
|
+
committedInputCounts.push({ circuitName, count: committedInputCount });
|
|
1998
|
+
let compressedCommittedInputs = "";
|
|
1999
|
+
if (circuitName === "inclusion_check_issuing_country_evm" ||
|
|
2000
|
+
circuitName === "inclusion_check_nationality_evm" ||
|
|
2001
|
+
circuitName === "exclusion_check_issuing_country_evm" ||
|
|
2002
|
+
circuitName === "exclusion_check_nationality_evm") {
|
|
2003
|
+
const value = proof.committedInputs[circuitName];
|
|
2004
|
+
const formattedCountries = value.countries;
|
|
2005
|
+
if (circuitName === "exclusion_check_issuing_country_evm" ||
|
|
2006
|
+
circuitName === "exclusion_check_nationality_evm") {
|
|
2007
|
+
formattedCountries.sort((a, b) => a.localeCompare(b));
|
|
2008
|
+
}
|
|
2009
|
+
const proofType = (() => {
|
|
2010
|
+
switch (circuitName) {
|
|
2011
|
+
case "exclusion_check_issuing_country_evm":
|
|
2012
|
+
return utils_1.ProofType.ISSUING_COUNTRY_EXCLUSION;
|
|
2013
|
+
case "exclusion_check_nationality_evm":
|
|
2014
|
+
return utils_1.ProofType.NATIONALITY_EXCLUSION;
|
|
2015
|
+
case "inclusion_check_issuing_country_evm":
|
|
2016
|
+
return utils_1.ProofType.ISSUING_COUNTRY_INCLUSION;
|
|
2017
|
+
case "inclusion_check_nationality_evm":
|
|
2018
|
+
return utils_1.ProofType.NATIONALITY_INCLUSION;
|
|
2019
|
+
}
|
|
2020
|
+
})();
|
|
2021
|
+
compressedCommittedInputs =
|
|
2022
|
+
proofType.toString(16).padStart(2, "0") +
|
|
2023
|
+
(0, utils_1.rightPadArrayWithZeros)(formattedCountries.map((c) => Array.from(new TextEncoder().encode(c))).flat(), 600)
|
|
2024
|
+
.map((x) => x.toString(16).padStart(2, "0"))
|
|
2025
|
+
.join("");
|
|
2026
|
+
}
|
|
2027
|
+
else if (circuitName === "compare_age_evm") {
|
|
2028
|
+
const value = proof.committedInputs[circuitName];
|
|
2029
|
+
const currentDateBytes = Array.from(new TextEncoder().encode(value.currentDate));
|
|
2030
|
+
compressedCommittedInputs =
|
|
2031
|
+
utils_1.ProofType.AGE.toString(16).padStart(2, "0") +
|
|
2032
|
+
currentDateBytes.map((x) => x.toString(16).padStart(2, "0")).join("") +
|
|
2033
|
+
value.minAge.toString(16).padStart(2, "0") +
|
|
2034
|
+
value.maxAge.toString(16).padStart(2, "0");
|
|
2035
|
+
}
|
|
2036
|
+
else if (circuitName === "compare_birthdate_evm") {
|
|
2037
|
+
const value = proof.committedInputs[circuitName];
|
|
2038
|
+
const currentDateBytes = Array.from(new TextEncoder().encode(value.currentDate));
|
|
2039
|
+
const minDateBytes = Array.from(new TextEncoder().encode(value.minDate));
|
|
2040
|
+
const maxDateBytes = Array.from(new TextEncoder().encode(value.maxDate));
|
|
2041
|
+
compressedCommittedInputs =
|
|
2042
|
+
utils_1.ProofType.BIRTHDATE.toString(16).padStart(2, "0") +
|
|
2043
|
+
currentDateBytes.map((x) => x.toString(16).padStart(2, "0")).join("") +
|
|
2044
|
+
minDateBytes.map((x) => x.toString(16).padStart(2, "0")).join("") +
|
|
2045
|
+
maxDateBytes.map((x) => x.toString(16).padStart(2, "0")).join("");
|
|
2046
|
+
}
|
|
2047
|
+
else if (circuitName === "compare_expiry_evm") {
|
|
2048
|
+
const value = proof.committedInputs[circuitName];
|
|
2049
|
+
const currentDateBytes = Array.from(new TextEncoder().encode(value.currentDate));
|
|
2050
|
+
const minDateBytes = Array.from(new TextEncoder().encode(value.minDate));
|
|
2051
|
+
const maxDateBytes = Array.from(new TextEncoder().encode(value.maxDate));
|
|
2052
|
+
compressedCommittedInputs =
|
|
2053
|
+
utils_1.ProofType.EXPIRY_DATE.toString(16).padStart(2, "0") +
|
|
2054
|
+
currentDateBytes.map((x) => x.toString(16).padStart(2, "0")).join("") +
|
|
2055
|
+
minDateBytes.map((x) => x.toString(16).padStart(2, "0")).join("") +
|
|
2056
|
+
maxDateBytes.map((x) => x.toString(16).padStart(2, "0")).join("");
|
|
2057
|
+
}
|
|
2058
|
+
else if (circuitName === "disclose_bytes_evm") {
|
|
2059
|
+
const value = proof.committedInputs[circuitName];
|
|
2060
|
+
compressedCommittedInputs =
|
|
2061
|
+
utils_1.ProofType.DISCLOSE.toString(16).padStart(2, "0") +
|
|
2062
|
+
value.discloseMask.map((x) => x.toString(16).padStart(2, "0")).join("") +
|
|
2063
|
+
value.disclosedBytes.map((x) => x.toString(16).padStart(2, "0")).join("");
|
|
2064
|
+
}
|
|
2065
|
+
else {
|
|
2066
|
+
throw new Error(`Unsupported circuit for EVM verification: ${circuitName}`);
|
|
2067
|
+
}
|
|
2068
|
+
committedInputs.push({ circuitName, inputs: compressedCommittedInputs });
|
|
2069
|
+
}
|
|
2070
|
+
const parameterCommitments = proofData.publicInputs.slice(11, proofData.publicInputs.length - 1);
|
|
2071
|
+
let compressedCommittedInputs = "";
|
|
2072
|
+
let committedInputCountsArray = [];
|
|
2073
|
+
for (const commitment of parameterCommitments) {
|
|
2074
|
+
const committedInput = committedInputs.find((x) => {
|
|
2075
|
+
const rawHashedInputs = (0, sha256_1.sha256)((0, utils_3.hexToBytes)(x.inputs));
|
|
2076
|
+
// Shift the hash 8 bits to the right (1 byte)
|
|
2077
|
+
// as one byte is dropped in the circuit to fit in the 254-bit field size
|
|
2078
|
+
const hashedInputs = new Uint8Array(rawHashedInputs.length);
|
|
2079
|
+
// Move each byte 1 position to the right (shifting 8 bits)
|
|
2080
|
+
for (let i = 0; i < rawHashedInputs.length - 1; i++) {
|
|
2081
|
+
hashedInputs[i + 1] = rawHashedInputs[i];
|
|
2082
|
+
}
|
|
2083
|
+
// First byte becomes 0 (since we're shifting right)
|
|
2084
|
+
hashedInputs[0] = 0;
|
|
2085
|
+
return (0, utils_2.bytesToHex)(hashedInputs) === commitment.replace("0x", "");
|
|
2086
|
+
});
|
|
2087
|
+
if (committedInput) {
|
|
2088
|
+
const count = committedInputCounts.find((x) => x.circuitName === committedInput.circuitName)?.count;
|
|
2089
|
+
if (count) {
|
|
2090
|
+
committedInputCountsArray.push(count);
|
|
2091
|
+
compressedCommittedInputs += committedInput.inputs;
|
|
2092
|
+
}
|
|
2093
|
+
else {
|
|
2094
|
+
throw new Error(`Unknown circuit name: ${committedInput.circuitName}`);
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
else {
|
|
2098
|
+
throw new Error(`Invalid commitment: ${commitment}`);
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
const params = {
|
|
2102
|
+
// Make sure the vkeyHash is 32 bytes
|
|
2103
|
+
vkeyHash: `0x${proof.vkeyHash.replace("0x", "").padStart(64, "0")}`,
|
|
2104
|
+
proof: `0x${actualProof.join("")}`,
|
|
2105
|
+
publicInputs: actualPublicInputs,
|
|
2106
|
+
committedInputs: `0x${compressedCommittedInputs}`,
|
|
2107
|
+
committedInputCounts: committedInputCountsArray,
|
|
2108
|
+
validityPeriodInDays,
|
|
2109
|
+
scope: domain ?? this.domain,
|
|
2110
|
+
subscope: scope ?? "",
|
|
2111
|
+
};
|
|
2112
|
+
return params;
|
|
2113
|
+
}
|
|
1296
2114
|
/**
|
|
1297
2115
|
* @notice Returns the URL of the request.
|
|
1298
2116
|
* @param requestId The request ID.
|
|
@@ -1302,7 +2120,7 @@ class ZKPassport {
|
|
|
1302
2120
|
const pubkey = (0, utils_2.bytesToHex)(this.topicToKeyPair[requestId].publicKey);
|
|
1303
2121
|
const base64Config = buffer_1.Buffer.from(JSON.stringify(this.topicToConfig[requestId])).toString("base64");
|
|
1304
2122
|
const base64Service = buffer_1.Buffer.from(JSON.stringify(this.topicToService[requestId])).toString("base64");
|
|
1305
|
-
return `https://zkpassport.id/r?d=${this.domain}&t=${requestId}&c=${base64Config}&s=${base64Service}&p=${pubkey}`;
|
|
2123
|
+
return `https://zkpassport.id/r?d=${this.domain}&t=${requestId}&c=${base64Config}&s=${base64Service}&p=${pubkey}&m=${this.topicToLocalConfig[requestId].mode}`;
|
|
1306
2124
|
}
|
|
1307
2125
|
/**
|
|
1308
2126
|
* @notice Cancels a request by closing the WebSocket connection and deleting the associated data.
|