From 08230ba3eb512237eb50becd60bb12678ee13d21 Mon Sep 17 00:00:00 2001 From: Michael Elliot Date: Mon, 19 Jan 2026 16:20:15 +1100 Subject: [PATCH 01/30] chore(explorer): Use custom IPFS URL (#148) --- packages/registry-explorer/components/CertificateRootCard.tsx | 2 +- packages/registry-explorer/components/CircuitRootCard.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/registry-explorer/components/CertificateRootCard.tsx b/packages/registry-explorer/components/CertificateRootCard.tsx index d5546ad4e..464575ae8 100644 --- a/packages/registry-explorer/components/CertificateRootCard.tsx +++ b/packages/registry-explorer/components/CertificateRootCard.tsx @@ -107,7 +107,7 @@ export function CertificateRootCard({ rootDetails, previousRoot }: CertificateRo
IPFS CID:
- + {formatCid(cid)}
diff --git a/packages/registry-explorer/components/CircuitRootCard.tsx b/packages/registry-explorer/components/CircuitRootCard.tsx index d0936e594..41f819310 100644 --- a/packages/registry-explorer/components/CircuitRootCard.tsx +++ b/packages/registry-explorer/components/CircuitRootCard.tsx @@ -98,7 +98,7 @@ export function CircuitRootCard({ rootDetails }: CircuitRootCardProps) {
IPFS CID:
- + {formatCid(cid)}
From e425b960784ab7cfe8c917dc17093477f7117a51 Mon Sep 17 00:00:00 2001 From: Michael Elliot Date: Thu, 5 Feb 2026 00:06:16 +1100 Subject: [PATCH 02/30] chore(registry-sdk): Update IPFS links to use Pinata gateway (#151) Replace all ipfs.infura.io links with ipfs.zkpassport.id Co-authored-by: Michael Elliot --- packages/registry-sdk/src/constants.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/registry-sdk/src/constants.ts b/packages/registry-sdk/src/constants.ts index 6c1ea468b..cb8424b32 100644 --- a/packages/registry-sdk/src/constants.ts +++ b/packages/registry-sdk/src/constants.ts @@ -26,7 +26,7 @@ export const PACKAGED_CERTIFICATES_URL_DEV = "http://localhost:3000/certificates */ export const PACKAGED_CERTIFICATES_URL_TEMPLATE = (chainId: number, root: string, cid?: string) => { if (cid) { - return `https://ipfs.infura.io/ipfs/${cid}` + return `https://ipfs.zkpassport.id/ipfs/${cid}` } root = normaliseHash(root) if (chainId === 1) { @@ -74,7 +74,7 @@ export const CIRCUIT_MANIFEST_URL_TEMPLATE = ( return `${CIRCUIT_URL_DEV}/by-version/${version}/manifest.json` } } else if (cid) { - return `https://ipfs.infura.io/ipfs/${cid}` + return `https://ipfs.zkpassport.id/ipfs/${cid}` } else { throw new Error("No root, version or cid provided") } @@ -88,7 +88,7 @@ export const CIRCUIT_MANIFEST_URL_TEMPLATE = ( */ export const PACKAGED_CIRCUIT_URL_TEMPLATE = (chainId: number, hash: string, cid?: string) => { if (cid) { - return `https://ipfs.infura.io/ipfs/${cid}` + return `https://ipfs.zkpassport.id/ipfs/${cid}` } hash = normaliseHash(hash) if (chainId === 1) { From e0bfd8d74e9d5f8e179536e6ed75c9f481a2049f Mon Sep 17 00:00:00 2001 From: Michael Elliot Date: Sat, 7 Feb 2026 02:27:10 +1100 Subject: [PATCH 03/30] ci(workspace): Improve linting for better code quality (#149) * improve linting for better code quality * remove build:types and tsc-alias and simplify * ci: run validate-packages * update validate-package.sh script to run bins directly --- .eslintrc.cjs | 30 ++++ .eslintrc.json | 29 ---- .github/workflows/ci.yml | 3 + bun.lock | 154 +++++++++++++----- package.json | 9 +- packages/registry-sdk/.eslintrc.json | 2 +- packages/registry-sdk/package.json | 3 +- packages/registry-sdk/src/client.ts | 6 +- packages/registry-sdk/src/index.ts | 3 +- packages/registry-sdk/src/types.ts | 7 - .../tests/registry-client.test.ts | 5 +- packages/registry-sdk/tests/retry.test.ts | 37 +++-- packages/registry-sdk/tests/utils/helpers.ts | 34 ++-- packages/registry-sdk/tsconfig.json | 10 +- packages/zkpassport-sdk/.eslintrc.json | 2 +- packages/zkpassport-sdk/package.json | 3 +- packages/zkpassport-sdk/src/index.ts | 7 +- packages/zkpassport-sdk/src/logger.ts | 2 + .../src/public-input-checker.ts | 2 + .../zkpassport-sdk/src/solidity-verifier.ts | 2 + .../zkpassport-sdk/tests/helpers/index.ts | 2 + .../tests/helpers/mock-websocket.ts | 35 +++- packages/zkpassport-sdk/tsconfig.json | 11 +- packages/zkpassport-utils/.eslintrc.json | 2 +- packages/zkpassport-utils/package.json | 3 +- .../zkpassport-utils/src/circuit-matcher.ts | 2 + packages/zkpassport-utils/src/cms/utils.ts | 2 + .../src/merkle-tree/async-imt.ts | 2 + .../src/merkle-tree/async-ordered-mt.test.ts | 2 + .../zkpassport-utils/src/merkle-tree/index.ts | 2 + .../zkpassport-utils/src/passport/common.ts | 2 + packages/zkpassport-utils/src/promise-pool.ts | 2 + packages/zkpassport-utils/src/types/index.ts | 3 + .../zkpassport-utils/src/types/registry.ts | 16 ++ packages/zkpassport-utils/src/utils.ts | 2 + .../tests/fixtures/passports.ts | 19 +-- packages/zkpassport-utils/tsconfig.json | 6 +- scripts/validate-package.sh | 5 +- tsconfig.json | 4 +- turbo.json | 7 +- 40 files changed, 310 insertions(+), 169 deletions(-) create mode 100644 .eslintrc.cjs delete mode 100644 .eslintrc.json diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 000000000..2359ebaca --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,30 @@ +module.exports = { + root: true, + extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"], + plugins: ["@typescript-eslint", "prettier"], + parser: "@typescript-eslint/parser", + parserOptions: { + project: true, + }, + env: { + browser: true, + node: true, + }, + rules: { + "prettier/prettier": "error", + "semi": ["error", "never"], + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": [ + "error", + { + args: "all", + argsIgnorePattern: "^_", + caughtErrors: "all", + caughtErrorsIgnorePattern: "^_", + destructuredArrayIgnorePattern: "^_", + varsIgnorePattern: "^_", + ignoreRestSiblings: true, + }, + ], + }, +} diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 47fc4963e..000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "root": true, - "parser": "@typescript-eslint/parser", - "plugins": ["@typescript-eslint", "prettier"], - "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"], - "env": { - "browser": true, - "node": true - }, - "rules": { - "prettier/prettier": "error", - "semi": ["error", "never"], - "no-unused-vars": "off", - "@typescript-eslint/no-unused-vars": [ - "error", - { - "args": "all", - "argsIgnorePattern": "^_", - "caughtErrors": "all", - "caughtErrorsIgnorePattern": "^_", - "destructuredArrayIgnorePattern": "^_", - "varsIgnorePattern": "^_", - "ignoreRestSiblings": true - } - ], - "@typescript-eslint/no-explicit-any": "off" - } -} - diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 269486618..a99c60fa0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -59,6 +59,9 @@ jobs: - name: Test run: bun run test + - name: Validate packages + run: bun run validate-packages + dependency-sync-check: name: Dependency Sync Check runs-on: ubuntu-latest diff --git a/bun.lock b/bun.lock index e27d6c5fe..c5c08c31b 100644 --- a/bun.lock +++ b/bun.lock @@ -4,18 +4,20 @@ "": { "name": "zkpassport-packages", "devDependencies": { + "@arethetypeswrong/cli": "^0.18.2", "@types/bun": "^1.3.1", "@types/debug": "^4.1.12", "@types/jest": "^30.0.0", "@types/node": "^24.0.13", + "@types/sinonjs__fake-timers": "^15.0.1", "@typescript-eslint/eslint-plugin": "^8.36.0", "@typescript-eslint/parser": "^8.36.0", "eslint": "^8.57.1", "eslint-config-prettier": "^10.1.2", "eslint-plugin-prettier": "^5.2.6", "prettier": "^3.6.2", + "publint": "^0.3.17", "rimraf": "^6.0.1", - "tsc-alias": "^1.8.16", "tsup": "^8.5.0", "turbo": "^2.6.0", "typescript": "^5.0.0", @@ -136,12 +138,22 @@ "@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="], + "@andrewbranch/untar.js": ["@andrewbranch/untar.js@1.0.3", "", {}, "sha512-Jh15/qVmrLGhkKJBdXlK1+9tY4lZruYjsgkDFj08ZmDiWVBLJcqkok7Z0/R0In+i1rScBpJlSvrTS2Lm41Pbnw=="], + + "@arethetypeswrong/cli": ["@arethetypeswrong/cli@0.18.2", "", { "dependencies": { "@arethetypeswrong/core": "0.18.2", "chalk": "^4.1.2", "cli-table3": "^0.6.3", "commander": "^10.0.1", "marked": "^9.1.2", "marked-terminal": "^7.1.0", "semver": "^7.5.4" }, "bin": { "attw": "dist/index.js" } }, "sha512-PcFM20JNlevEDKBg4Re29Rtv2xvjvQZzg7ENnrWFSS0PHgdP2njibVFw+dRUhNkPgNfac9iUqO0ohAXqQL4hbw=="], + + "@arethetypeswrong/core": ["@arethetypeswrong/core@0.18.2", "", { "dependencies": { "@andrewbranch/untar.js": "^1.0.3", "@loaderkit/resolve": "^1.0.2", "cjs-module-lexer": "^1.2.3", "fflate": "^0.8.2", "lru-cache": "^11.0.1", "semver": "^7.5.4", "typescript": "5.6.1-rc", "validate-npm-package-name": "^5.0.0" } }, "sha512-GiwTmBFOU1/+UVNqqCGzFJYfBXEytUkiI+iRZ6Qx7KmUVtLm00sYySkfe203C9QtPG11yOz1ZaMek8dT/xnlgg=="], + "@aztec/bb.js": ["@aztec/bb.js@2.0.3", "", { "dependencies": { "comlink": "^4.4.1", "commander": "^12.1.0", "idb-keyval": "^6.2.1", "msgpackr": "^1.11.2", "pako": "^2.1.0", "pino": "^9.5.0", "tslib": "^2.4.0" }, "bin": { "bb.js": "dest/node/main.js" } }, "sha512-sI8lA2L8RMACsi6iBtcuKgGLx4crMzoAaTNtfP3VAaOpjoIwB3O/AMETz5IDGdkOA6tOqM2R0nWh1J+wDYPlVQ=="], "@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="], + "@braidai/lang": ["@braidai/lang@1.1.2", "", {}, "sha512-qBcknbBufNHlui137Hft8xauQMTZDKdophmLFv05r2eNmdIv/MlPuP4TdUknHG68UdWLgVZwgxVe735HzJNIwA=="], + + "@colors/colors": ["@colors/colors@1.5.0", "", {}, "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ=="], + "@emnapi/core": ["@emnapi/core@1.5.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg=="], "@emnapi/runtime": ["@emnapi/runtime@1.5.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ=="], @@ -250,6 +262,8 @@ "@lapo/asn1js": ["@lapo/asn1js@2.1.0", "", { "bin": { "dumpASN1": "dumpASN1.js" } }, "sha512-SIRsS9jhhpsRxr1d5leFfdI6sEOQciQXShN7sIwoze+iEevvoKmLGG66PyLDgIEYeONq80sx48xs86eK4MItEw=="], + "@loaderkit/resolve": ["@loaderkit/resolve@1.0.4", "", { "dependencies": { "@braidai/lang": "^1.0.0" } }, "sha512-rJzYKVcV4dxJv+vW6jlvagF8zvGxHJ2+HTr1e2qOejfmGhAApgJHl8Aog4mMszxceTRiKTTbnpgmTO1bEZHV/A=="], + "@msgpackr-extract/msgpackr-extract-darwin-arm64": ["@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw=="], "@msgpackr-extract/msgpackr-extract-darwin-x64": ["@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw=="], @@ -330,6 +344,8 @@ "@pkgr/core": ["@pkgr/core@0.2.9", "", {}, "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA=="], + "@publint/pack": ["@publint/pack@0.1.4", "", {}, "sha512-HDVTWq3H0uTXiU0eeSQntcVUTPP3GamzeXI41+x7uU9J65JgWQh3qWZHblR1i0npXfFtF+mxBiU2nJH8znxWnQ=="], + "@radix-ui/number": ["@radix-ui/number@1.1.1", "", {}, "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g=="], "@radix-ui/primitive": ["@radix-ui/primitive@1.1.3", "", {}, "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg=="], @@ -442,6 +458,8 @@ "@sinclair/typebox": ["@sinclair/typebox@0.34.41", "", {}, "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g=="], + "@sindresorhus/is": ["@sindresorhus/is@4.6.0", "", {}, "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw=="], + "@sinonjs/commons": ["@sinonjs/commons@3.0.1", "", { "dependencies": { "type-detect": "4.0.8" } }, "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ=="], "@sinonjs/fake-timers": ["@sinonjs/fake-timers@15.0.0", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-dlUB2oL+hDIYkIq/OWFBDhQAuU6kDey3eeMiYpVb7UXHhkMq/r1HloKXAbJwJZpYWkFWsydLjMqDpueMUEOjXQ=="], @@ -494,6 +512,8 @@ "@types/react-simple-maps": ["@types/react-simple-maps@3.0.6", "", { "dependencies": { "@types/d3-geo": "^2", "@types/d3-zoom": "^2", "@types/geojson": "*", "@types/react": "*" } }, "sha512-hR01RXt6VvsE41FxDd+Bqm1PPGdKbYjCYVtCgh38YeBPt46z3SwmWPWu2L3EdCAP6bd6VYEgztucihRw1C0Klg=="], + "@types/sinonjs__fake-timers": ["@types/sinonjs__fake-timers@15.0.1", "", {}, "sha512-Ko2tjWJq8oozHzHV+reuvS5KYIRAokHnGbDwGh/J64LntgpbuylF74ipEL24HCyRjf9FOlBiBHWBR1RlVKsI1w=="], + "@types/stack-utils": ["@types/stack-utils@2.0.3", "", {}, "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw=="], "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], @@ -582,9 +602,11 @@ "ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], - "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "ansi-escapes": ["ansi-escapes@7.3.0", "", { "dependencies": { "environment": "^1.0.0" } }, "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg=="], - "ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], + "ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + + "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], "any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="], @@ -602,8 +624,6 @@ "array-includes": ["array-includes@3.1.9", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-abstract": "^1.24.0", "es-object-atoms": "^1.1.1", "get-intrinsic": "^1.3.0", "is-string": "^1.1.1", "math-intrinsics": "^1.1.0" } }, "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ=="], - "array-union": ["array-union@2.1.0", "", {}, "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw=="], - "array.prototype.findlast": ["array.prototype.findlast@1.2.5", "", { "dependencies": { "call-bind": "^1.0.7", "define-properties": "^1.2.1", "es-abstract": "^1.23.2", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "es-shim-unscopables": "^1.0.2" } }, "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ=="], "array.prototype.findlastindex": ["array.prototype.findlastindex@1.2.6", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "es-shim-unscopables": "^1.1.0" } }, "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ=="], @@ -668,14 +688,24 @@ "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], - "chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], + "char-regex": ["char-regex@1.0.2", "", {}, "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw=="], + + "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], "ci-info": ["ci-info@4.3.1", "", {}, "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA=="], + "cjs-module-lexer": ["cjs-module-lexer@1.4.3", "", {}, "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q=="], + "class-variance-authority": ["class-variance-authority@0.7.1", "", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="], + "cli-highlight": ["cli-highlight@2.1.11", "", { "dependencies": { "chalk": "^4.0.0", "highlight.js": "^10.7.1", "mz": "^2.4.0", "parse5": "^5.1.1", "parse5-htmlparser2-tree-adapter": "^6.0.0", "yargs": "^16.0.0" }, "bin": { "highlight": "bin/highlight" } }, "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg=="], + + "cli-table3": ["cli-table3@0.6.5", "", { "dependencies": { "string-width": "^4.2.0" }, "optionalDependencies": { "@colors/colors": "1.5.0" } }, "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ=="], + "client-only": ["client-only@0.0.1", "", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="], + "cliui": ["cliui@7.0.4", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^7.0.0" } }, "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ=="], + "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], @@ -684,7 +714,7 @@ "comlink": ["comlink@4.4.2", "", {}, "sha512-OxGdvBmJuNKSCMO4NTl1L47VRp6xn2wG4F/2hYzB6tiCb709otOxtEYCSvK80PtjODfXXZu8ds+Nw5kVCjqd2g=="], - "commander": ["commander@9.5.0", "", {}, "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ=="], + "commander": ["commander@10.0.1", "", {}, "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug=="], "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], @@ -754,8 +784,6 @@ "didyoumean": ["didyoumean@1.2.2", "", {}, "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="], - "dir-glob": ["dir-glob@3.0.1", "", { "dependencies": { "path-type": "^4.0.0" } }, "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA=="], - "dlv": ["dlv@1.1.3", "", {}, "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="], "doctrine": ["doctrine@3.0.0", "", { "dependencies": { "esutils": "^2.0.2" } }, "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w=="], @@ -774,8 +802,12 @@ "emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + "emojilib": ["emojilib@2.4.0", "", {}, "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw=="], + "entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], + "environment": ["environment@1.1.0", "", {}, "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q=="], + "es-abstract": ["es-abstract@1.24.0", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.3.0", "get-proto": "^1.0.1", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-negative-zero": "^2.0.3", "is-regex": "^1.2.1", "is-set": "^2.0.3", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.1", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.4", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.4", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "stop-iteration-iterator": "^1.1.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.19" } }, "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg=="], "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], @@ -794,6 +826,8 @@ "esbuild": ["esbuild@0.25.10", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.10", "@esbuild/android-arm": "0.25.10", "@esbuild/android-arm64": "0.25.10", "@esbuild/android-x64": "0.25.10", "@esbuild/darwin-arm64": "0.25.10", "@esbuild/darwin-x64": "0.25.10", "@esbuild/freebsd-arm64": "0.25.10", "@esbuild/freebsd-x64": "0.25.10", "@esbuild/linux-arm": "0.25.10", "@esbuild/linux-arm64": "0.25.10", "@esbuild/linux-ia32": "0.25.10", "@esbuild/linux-loong64": "0.25.10", "@esbuild/linux-mips64el": "0.25.10", "@esbuild/linux-ppc64": "0.25.10", "@esbuild/linux-riscv64": "0.25.10", "@esbuild/linux-s390x": "0.25.10", "@esbuild/linux-x64": "0.25.10", "@esbuild/netbsd-arm64": "0.25.10", "@esbuild/netbsd-x64": "0.25.10", "@esbuild/openbsd-arm64": "0.25.10", "@esbuild/openbsd-x64": "0.25.10", "@esbuild/openharmony-arm64": "0.25.10", "@esbuild/sunos-x64": "0.25.10", "@esbuild/win32-arm64": "0.25.10", "@esbuild/win32-ia32": "0.25.10", "@esbuild/win32-x64": "0.25.10" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ=="], + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], "eslint": ["eslint@8.57.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", "@eslint/js": "8.57.1", "@humanwhocodes/config-array": "^0.13.0", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.2.2", "eslint-visitor-keys": "^3.4.3", "espree": "^9.6.1", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "globals": "^13.19.0", "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.3", "strip-ansi": "^6.0.1", "text-table": "^0.2.0" }, "bin": { "eslint": "bin/eslint.js" } }, "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA=="], @@ -852,6 +886,8 @@ "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + "fflate": ["fflate@0.8.2", "", {}, "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="], + "file-entry-cache": ["file-entry-cache@6.0.1", "", { "dependencies": { "flat-cache": "^3.0.4" } }, "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg=="], "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], @@ -882,6 +918,8 @@ "generator-function": ["generator-function@2.0.1", "", {}, "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g=="], + "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], + "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], "get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="], @@ -900,8 +938,6 @@ "globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="], - "globby": ["globby@11.1.0", "", { "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", "fast-glob": "^3.2.9", "ignore": "^5.2.0", "merge2": "^1.4.1", "slash": "^3.0.0" } }, "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g=="], - "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], @@ -922,6 +958,8 @@ "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], + "highlight.js": ["highlight.js@10.7.3", "", {}, "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A=="], + "i18n-iso-countries": ["i18n-iso-countries@7.14.0", "", { "dependencies": { "diacritics": "1.3.0" } }, "sha512-nXHJZYtNrfsi1UQbyRqm3Gou431elgLjKl//CYlnBGt5aTWdRPH1PiS2T/p/n8Q8LnqYqzQJik3Q7mkwvLokeg=="], "idb-keyval": ["idb-keyval@6.2.2", "", {}, "sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg=="], @@ -1072,6 +1110,10 @@ "magic-string": ["magic-string@0.30.19", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw=="], + "marked": ["marked@9.1.6", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-jcByLnIFkd5gSXZmjNvS1TlmRhCXZjIzHYlaGkPlLIekG55JDR2Z4va9tZwCiP+/RDERiNhMOFu01xd6O5ct1Q=="], + + "marked-terminal": ["marked-terminal@7.3.0", "", { "dependencies": { "ansi-escapes": "^7.0.0", "ansi-regex": "^6.1.0", "chalk": "^5.4.1", "cli-highlight": "^2.1.11", "cli-table3": "^0.6.5", "node-emoji": "^2.2.0", "supports-hyperlinks": "^3.1.0" }, "peerDependencies": { "marked": ">=1 <16" } }, "sha512-t4rBvPsHc57uE/2nJOLmMbZCQ4tgAccAED3ngXQqW6g+TxA488JzJ+FK3lQkzBQOI1mRV/r/Kq+1ZlJ4D0owQw=="], + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], "mdn-data": ["mdn-data@2.0.30", "", {}, "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA=="], @@ -1092,14 +1134,14 @@ "motion-utils": ["motion-utils@11.18.1", "", {}, "sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA=="], + "mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="], + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], "msgpackr": ["msgpackr@1.11.5", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.2" } }, "sha512-UjkUHN0yqp9RWKy0Lplhh+wlpdt9oQBYgULZOiFhV3VclSF1JnSQWZ5r9gORQlNYaUKQoR8itv7g7z1xDDuACA=="], "msgpackr-extract": ["msgpackr-extract@3.0.3", "", { "dependencies": { "node-gyp-build-optional-packages": "5.2.2" }, "optionalDependencies": { "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3", "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3", "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" } }, "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA=="], - "mylas": ["mylas@2.1.14", "", {}, "sha512-BzQguy9W9NJgoVn2mRWzbFrFWWztGCcng2QI9+41frfk+Athwgx3qhqhvStz7ExeUUu7Kzw427sNzHpEZNINog=="], - "mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="], "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], @@ -1112,6 +1154,8 @@ "node-addon-api": ["node-addon-api@2.0.2", "", {}, "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA=="], + "node-emoji": ["node-emoji@2.2.0", "", { "dependencies": { "@sindresorhus/is": "^4.6.0", "char-regex": "^1.0.2", "emojilib": "^2.4.0", "skin-tone": "^2.0.0" } }, "sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw=="], + "node-gyp-build": ["node-gyp-build@4.8.4", "", { "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ=="], "node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.2.2", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", "node-gyp-build-optional-packages-test": "build-test.js" } }, "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw=="], @@ -1154,10 +1198,16 @@ "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], + "package-manager-detector": ["package-manager-detector@1.6.0", "", {}, "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA=="], + "pako": ["pako@2.1.0", "", {}, "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug=="], "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "^3.0.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], + "parse5": ["parse5@5.1.1", "", {}, "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug=="], + + "parse5-htmlparser2-tree-adapter": ["parse5-htmlparser2-tree-adapter@6.0.1", "", { "dependencies": { "parse5": "^6.0.1" } }, "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA=="], + "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], "path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="], @@ -1168,8 +1218,6 @@ "path-scurry": ["path-scurry@2.0.0", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg=="], - "path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="], - "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], @@ -1188,8 +1236,6 @@ "pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], - "plimit-lit": ["plimit-lit@1.6.1", "", { "dependencies": { "queue-lit": "^1.5.1" } }, "sha512-B7+VDyb8Tl6oMJT9oSO2CW8XC/T4UcJGrwOVoNGwOQsQYhlpfajmrMj5xeejqaASq3V/EqThyOeATEOMuSEXiA=="], - "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], @@ -1218,14 +1264,14 @@ "prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], + "publint": ["publint@0.3.17", "", { "dependencies": { "@publint/pack": "^0.1.3", "package-manager-detector": "^1.6.0", "picocolors": "^1.1.1", "sade": "^1.8.1" }, "bin": { "publint": "src/cli.js" } }, "sha512-Q3NLegA9XM6usW+dYQRG1g9uEHiYUzcCVBJDJ7yMcWRqVU9LYZUWdqbwMZfmTCFC5PZLQpLAmhvRcQRl3exqkw=="], + "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], "pvtsutils": ["pvtsutils@1.3.6", "", { "dependencies": { "tslib": "^2.8.1" } }, "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg=="], "pvutils": ["pvutils@1.1.3", "", {}, "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ=="], - "queue-lit": ["queue-lit@1.5.2", "", {}, "sha512-tLc36IOPeMAubu8BkW8YDBV+WyIgKlYU7zUNs0J5Vk9skSZ4JfGlPOqplP0aHdfv7HL0B2Pg6nwiq60Qc6M2Hw=="], - "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], "quick-format-unescaped": ["quick-format-unescaped@4.0.4", "", {}, "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="], @@ -1250,7 +1296,7 @@ "readable-stream": ["readable-stream@3.6.2", "", { "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", "util-deprecate": "^1.0.1" } }, "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA=="], - "readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], + "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], "real-require": ["real-require@0.2.0", "", {}, "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg=="], @@ -1264,6 +1310,8 @@ "registry-explorer": ["registry-explorer@workspace:packages/registry-explorer"], + "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], + "resolve": ["resolve@1.22.10", "", { "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w=="], "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], @@ -1278,6 +1326,8 @@ "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], + "sade": ["sade@1.8.1", "", { "dependencies": { "mri": "^1.1.0" } }, "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A=="], + "safe-array-concat": ["safe-array-concat@1.1.3", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.2", "get-intrinsic": "^1.2.6", "has-symbols": "^1.1.0", "isarray": "^2.0.5" } }, "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q=="], "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], @@ -1312,6 +1362,8 @@ "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], + "skin-tone": ["skin-tone@2.0.0", "", { "dependencies": { "unicode-emoji-modifier-base": "^1.0.0" } }, "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA=="], + "slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], "slow-redact": ["slow-redact@0.3.2", "", {}, "sha512-MseHyi2+E/hBRqdOi5COy6wZ7j7DxXRz9NkseavNYSvvWC06D8a5cidVZX3tcG5eCW3NIyVU4zT63hw0Q486jw=="], @@ -1332,7 +1384,7 @@ "streamsearch": ["streamsearch@1.1.0", "", {}, "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg=="], - "string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], + "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], "string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], @@ -1364,6 +1416,8 @@ "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + "supports-hyperlinks": ["supports-hyperlinks@3.2.0", "", { "dependencies": { "has-flag": "^4.0.0", "supports-color": "^7.0.0" } }, "sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig=="], + "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], "svg-country-flags": ["svg-country-flags@1.2.10", "", {}, "sha512-xrqwo0TYf/h2cfPvGpjdSuSguUbri4vNNizBnwzoZnX0xGo3O5nGJMlbYEp7NOYcnPGBm6LE2axqDWSB847bLw=="], @@ -1402,8 +1456,6 @@ "ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="], - "tsc-alias": ["tsc-alias@1.8.16", "", { "dependencies": { "chokidar": "^3.5.3", "commander": "^9.0.0", "get-tsconfig": "^4.10.0", "globby": "^11.0.4", "mylas": "^2.1.9", "normalize-path": "^3.0.0", "plimit-lit": "^1.2.6" }, "bin": { "tsc-alias": "dist/bin/index.js" } }, "sha512-QjCyu55NFyRSBAl6+MTFwplpFcnm2Pq01rR/uxfqJoLMm6X3O14KEGtaSDZpJYaE1bJBGDjD0eSuiIWPe2T58g=="], - "tsconfig-paths": ["tsconfig-paths@3.15.0", "", { "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg=="], "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], @@ -1448,6 +1500,8 @@ "undici-types": ["undici-types@7.14.0", "", {}, "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA=="], + "unicode-emoji-modifier-base": ["unicode-emoji-modifier-base@1.0.0", "", {}, "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g=="], + "unrs-resolver": ["unrs-resolver@1.11.1", "", { "dependencies": { "napi-postinstall": "^0.3.0" }, "optionalDependencies": { "@unrs/resolver-binding-android-arm-eabi": "1.11.1", "@unrs/resolver-binding-android-arm64": "1.11.1", "@unrs/resolver-binding-darwin-arm64": "1.11.1", "@unrs/resolver-binding-darwin-x64": "1.11.1", "@unrs/resolver-binding-freebsd-x64": "1.11.1", "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", "@unrs/resolver-binding-linux-x64-musl": "1.11.1", "@unrs/resolver-binding-wasm32-wasi": "1.11.1", "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" } }, "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg=="], "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], @@ -1458,6 +1512,8 @@ "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + "validate-npm-package-name": ["validate-npm-package-name@5.0.1", "", {}, "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ=="], + "viem": ["viem@2.38.2", "", { "dependencies": { "@noble/curves": "1.9.1", "@noble/hashes": "1.8.0", "@scure/bip32": "1.7.0", "@scure/bip39": "1.6.0", "abitype": "1.1.0", "isows": "1.0.7", "ox": "0.9.6", "ws": "8.18.3" }, "peerDependencies": { "typescript": ">=5.0.4" }, "optionalPeers": ["typescript"] }, "sha512-MJDiTDD9gfOT7lPQRimdmw+g46hU/aWJ3loqb+tN6UBOO00XEd0O4LJx+Kp5/uCRnMlJr8zJ1bNzCK7eG6gMjg=="], "webidl-conversions": ["webidl-conversions@4.0.2", "", {}, "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg=="], @@ -1486,12 +1542,22 @@ "ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="], + "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], + + "yargs": ["yargs@16.2.0", "", { "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.0", "y18n": "^5.0.5", "yargs-parser": "^20.2.2" } }, "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw=="], + + "yargs-parser": ["yargs-parser@20.2.9", "", {}, "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="], + "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], + "@arethetypeswrong/core/typescript": ["typescript@5.6.1-rc", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-E3b2+1zEFu84jB0YQi9BORDjz9+jGbwwy1Zi3G0LUNw7a7cePUrHMRNy8aPh53nXpkFGVHSxIZo5vKTfYaFiBQ=="], + "@aztec/bb.js/commander": ["commander@12.1.0", "", {}, "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA=="], "@eslint/eslintrc/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], + "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], + "@isaacs/cliui/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], "@next/eslint-plugin-next/glob": ["glob@10.3.10", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^2.3.5", "minimatch": "^9.0.1", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", "path-scurry": "^1.10.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g=="], @@ -1504,9 +1570,7 @@ "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - - "chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + "cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], "csso/css-tree": ["css-tree@2.2.1", "", { "dependencies": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" } }, "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA=="], @@ -1546,37 +1610,43 @@ "glob/minimatch": ["minimatch@10.0.3", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw=="], - "globby/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], - "import-fresh/resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], + "marked-terminal/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], + "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], "next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="], "ox/@noble/curves": ["@noble/curves@1.9.1", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA=="], + "parse5-htmlparser2-tree-adapter/parse5": ["parse5@6.0.1", "", {}, "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw=="], + + "pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], + "prop-types/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], "react-simple-maps/d3-geo": ["d3-geo@2.0.2", "", { "dependencies": { "d3-array": "^2.5.0" } }, "sha512-8pM1WGMLGFuhq9S+FpPURxic+gKzjluCD/CHTuUF3mXMeiCo0i6R0tO1s4+GArRFde96SLcW/kOFRjoAosPsFA=="], - "readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "stack-utils/escape-string-regexp": ["escape-string-regexp@2.0.0", "", {}, "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w=="], - "string-width/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], + "string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], "string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + "strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "sucrase/commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], "sucrase/glob": ["glob@10.3.10", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^2.3.5", "minimatch": "^9.0.1", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", "path-scurry": "^1.10.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g=="], "svgo/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="], - "topojson-client/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], + "tailwindcss/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], - "tsup/chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], + "topojson-client/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], "tsyringe/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], @@ -1584,13 +1654,9 @@ "wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], - "wrap-ansi/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], - - "wrap-ansi-cjs/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], - - "wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + "wrap-ansi/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], - "@isaacs/cliui/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + "wrap-ansi/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], "@next/eslint-plugin-next/glob/jackspeak": ["jackspeak@2.3.6", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ=="], @@ -1608,19 +1674,15 @@ "react-simple-maps/d3-geo/d3-array": ["d3-array@2.12.1", "", { "dependencies": { "internmap": "^1.0.0" } }, "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ=="], - "string-width/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], - "sucrase/glob/jackspeak": ["jackspeak@2.3.6", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ=="], "sucrase/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], "sucrase/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], - "tsup/chokidar/readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], + "tailwindcss/chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], - "wrap-ansi-cjs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], - - "wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + "tailwindcss/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], "@next/eslint-plugin-next/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], @@ -1631,5 +1693,7 @@ "sucrase/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], "sucrase/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + + "tailwindcss/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], } } diff --git a/package.json b/package.json index 18ba863b5..fd6570ed0 100644 --- a/package.json +++ b/package.json @@ -4,29 +4,32 @@ "private": true, "scripts": { "build": "turbo run build", - "build:types": "turbo run build:types", "dev:build": "turbo run dev:build", + "validate-packages": "turbo run validate-package", "test": "turbo run test", "check": "turbo run check", "format": "turbo run format", - "clean": "turbo run clean && rimraf node_modules/.cache" + "clean": "turbo run clean && rimraf .turbo node_modules/.cache", + "clean:deep": "turbo run clean && rimraf .turbo **/node_modules && bun i" }, "workspaces": [ "packages/*" ], "devDependencies": { + "@arethetypeswrong/cli": "^0.18.2", "@types/bun": "^1.3.1", "@types/debug": "^4.1.12", "@types/jest": "^30.0.0", "@types/node": "^24.0.13", + "@types/sinonjs__fake-timers": "^15.0.1", "@typescript-eslint/eslint-plugin": "^8.36.0", "@typescript-eslint/parser": "^8.36.0", "eslint": "^8.57.1", "eslint-config-prettier": "^10.1.2", "eslint-plugin-prettier": "^5.2.6", "prettier": "^3.6.2", + "publint": "^0.3.17", "rimraf": "^6.0.1", - "tsc-alias": "^1.8.16", "tsup": "^8.5.0", "turbo": "^2.6.0", "typescript": "^5.0.0" diff --git a/packages/registry-sdk/.eslintrc.json b/packages/registry-sdk/.eslintrc.json index be97c53fb..b38ecf3d7 100644 --- a/packages/registry-sdk/.eslintrc.json +++ b/packages/registry-sdk/.eslintrc.json @@ -1,3 +1,3 @@ { - "extends": "../../.eslintrc.json" + "extends": "../../.eslintrc.cjs" } diff --git a/packages/registry-sdk/package.json b/packages/registry-sdk/package.json index a05dbad41..cd2e8a33d 100644 --- a/packages/registry-sdk/package.json +++ b/packages/registry-sdk/package.json @@ -15,8 +15,7 @@ } }, "scripts": { - "build": "bun run build:types && tsup --config tsup.config.ts", - "build:types": "tsc -b && tsc-alias -v -p tsconfig.json -f", + "build": "tsup --config tsup.config.ts", "dev:build": "DEV_BUILD=true bun run build", "clean": "rimraf dist tsconfig.tsbuildinfo", "test": "bun test tests/*.test.ts", diff --git a/packages/registry-sdk/src/client.ts b/packages/registry-sdk/src/client.ts index c315f6094..337bea100 100644 --- a/packages/registry-sdk/src/client.ts +++ b/packages/registry-sdk/src/client.ts @@ -1,5 +1,6 @@ import { poseidon2HashAsync } from "@zkpassport/poseidon2" import { Binary } from "@zkpassport/utils" +import { PackagedCertificatesFile } from "@zkpassport/utils/types" import { ultraVkToFields } from "@zkpassport/utils/circuits" import { buildMerkleTreeFromCerts, @@ -32,9 +33,8 @@ import { import { DocumentSupport, DocumentSupportRule, - PackagedCertificatesFile, RegistryClientOptions, - RootDetails, + type RootDetails, } from "./types" import { normaliseHash, strip0x } from "./utils" import { withRetry } from "@zkpassport/utils" @@ -781,7 +781,7 @@ export class RegistryClient { return this.packagedCircuitUrlGenerator(this.chainId, hash, cid) } - private async rpcRequest(to: string, data: any): Promise { + private async rpcRequest(to: string, data: string): Promise { return withRetry( () => fetch(this.rpcUrl, { diff --git a/packages/registry-sdk/src/index.ts b/packages/registry-sdk/src/index.ts index 66021f9d6..5549a776d 100644 --- a/packages/registry-sdk/src/index.ts +++ b/packages/registry-sdk/src/index.ts @@ -1,2 +1,3 @@ export { RegistryClient } from "./client" -export type { RootDetails, PackagedCertificatesFile } from "./types" +export type { RootDetails } from "./types" +export type { PackagedCertificatesFile } from "@zkpassport/utils/types" diff --git a/packages/registry-sdk/src/types.ts b/packages/registry-sdk/src/types.ts index 75663b065..145579bdc 100644 --- a/packages/registry-sdk/src/types.ts +++ b/packages/registry-sdk/src/types.ts @@ -1,5 +1,3 @@ -import type { PackagedCertificate } from "@zkpassport/utils/types" - /** * Registry client configuration options */ @@ -93,11 +91,6 @@ export interface RootDetails { index?: number } -export interface PackagedCertificatesFile { - certificates: PackagedCertificate[] - serialised: any[] -} - export enum DocumentSupport { NOT_SUPPORTED = 0, TENTATIVE_SUPPORT = 0.25, diff --git a/packages/registry-sdk/tests/registry-client.test.ts b/packages/registry-sdk/tests/registry-client.test.ts index 193a42b11..78a8160db 100644 --- a/packages/registry-sdk/tests/registry-client.test.ts +++ b/packages/registry-sdk/tests/registry-client.test.ts @@ -1,8 +1,9 @@ import { describe, beforeAll, afterAll, it, expect, setDefaultTimeout } from "bun:test" -import { CircuitManifest, PackagedCircuit, strip0x } from "@zkpassport/utils" +import { strip0x } from "@zkpassport/utils" +import { CircuitManifest, PackagedCircuit, PackagedCertificatesFile } from "@zkpassport/utils/types" import path from "path" import { RegistryClient } from "../src/client" -import { DocumentSupport, PackagedCertificatesFile } from "../src/types" +import { DocumentSupport } from "../src/types" import { CERTIFICATE_FIXTURES_CID, CERTIFICATE_FIXTURES_ROOT, diff --git a/packages/registry-sdk/tests/retry.test.ts b/packages/registry-sdk/tests/retry.test.ts index 8a4698d91..594f5fba0 100644 --- a/packages/registry-sdk/tests/retry.test.ts +++ b/packages/registry-sdk/tests/retry.test.ts @@ -1,5 +1,5 @@ import { RegistryClient } from "../src/client" -import type { PackagedCertificatesFile } from "../src/types" +import { PackagedCertificatesFile } from "@zkpassport/utils/types" import FakeTimers from "@sinonjs/fake-timers" import type { InstalledClock } from "@sinonjs/fake-timers" @@ -12,6 +12,8 @@ describe("Retry Logic", () => { const MOCK_RPC_URL = "https://mock-rpc.example.com" const mockPackagedCerts: PackagedCertificatesFile = { + version: 1, + timestamp: 1768823285, certificates: [ { country: "USA", @@ -59,7 +61,7 @@ describe("Retry Logic", () => { it("should retry on TypeError (network error) and succeed", async () => { clock = FakeTimers.install() - globalThis.fetch = async (input: RequestInfo | URL) => { + globalThis.fetch = (async (input: RequestInfo | URL): Promise => { const url = input.toString() attemptCount++ @@ -83,7 +85,7 @@ describe("Retry Logic", () => { ) } return new Response("Not found", { status: 404 }) - } + }) as typeof fetch const certPromise = registry.getCertificates(MOCK_ROOT, { validate: false }) await clock.runAllAsync() @@ -96,10 +98,10 @@ describe("Retry Logic", () => { it("should fail after exhausting all retries", async () => { clock = FakeTimers.install() - globalThis.fetch = async () => { + globalThis.fetch = (async (_: RequestInfo | URL): Promise => { attemptCount++ throw new TypeError("Network request failed") - } + }) as typeof fetch const certPromise = registry.getCertificates(MOCK_ROOT, { validate: false }) @@ -119,14 +121,15 @@ describe("Retry Logic", () => { // Track setTimeout calls to verify exponential backoff const originalSetTimeout = globalThis.setTimeout - globalThis.setTimeout = ((callback: any, delay?: number) => { + // @ts-expect-error - setTimeout is mocked + globalThis.setTimeout = (callback: TimerHandler, delay?: number) => { if (delay !== undefined) { timerDelays.push(delay) } return originalSetTimeout(callback, delay) - }) as any + } - globalThis.fetch = async (input: RequestInfo | URL) => { + globalThis.fetch = (async (input: RequestInfo | URL) => { const url = input.toString() attemptCount++ @@ -138,7 +141,7 @@ describe("Retry Logic", () => { return new Response(JSON.stringify(mockPackagedCerts), { status: 200 }) } return new Response("OK", { status: 200 }) - } + }) as typeof fetch const certPromise = registry.getCertificates(MOCK_ROOT, { validate: false }) await clock.runAllAsync() @@ -165,10 +168,10 @@ describe("Retry Logic", () => { retryCount: 1, }) - globalThis.fetch = async () => { + globalThis.fetch = (async (_: RequestInfo | URL): Promise => { attemptCount++ throw new TypeError("Network error") - } + }) as typeof fetch const certPromise = registrySingleRetry.getCertificates(MOCK_ROOT, { validate: false }) @@ -190,10 +193,10 @@ describe("Retry Logic", () => { retryCount: 5, }) - globalThis.fetch = async () => { + globalThis.fetch = (async (_: RequestInfo | URL): Promise => { attemptCount++ throw new TypeError("Network error") - } + }) as typeof fetch const certPromise = registryManyRetries.getCertificates(MOCK_ROOT, { validate: false }) @@ -208,7 +211,7 @@ describe("Retry Logic", () => { it("should retry RPC requests on network errors", async () => { clock = FakeTimers.install() - globalThis.fetch = async (input: RequestInfo | URL) => { + globalThis.fetch = (async (input: RequestInfo | URL) => { const url = input.toString() attemptCount++ @@ -226,7 +229,7 @@ describe("Retry Logic", () => { ) } return new Response("OK", { status: 200 }) - } + }) as typeof fetch const rootPromise = registry.getLatestCertificateRoot() await clock.runAllAsync() @@ -252,7 +255,7 @@ describe("Retry Logic", () => { }, } - globalThis.fetch = async (input: RequestInfo | URL) => { + globalThis.fetch = (async (input: RequestInfo | URL) => { const url = input.toString() attemptCount++ @@ -277,7 +280,7 @@ describe("Retry Logic", () => { } return new Response("Not Found", { status: 404 }) - } + }) as typeof fetch const manifestPromise = registry.getCircuitManifest(MOCK_ROOT, { validate: false }) await clock.runAllAsync() diff --git a/packages/registry-sdk/tests/utils/helpers.ts b/packages/registry-sdk/tests/utils/helpers.ts index fbd7c51ff..f8f989b75 100644 --- a/packages/registry-sdk/tests/utils/helpers.ts +++ b/packages/registry-sdk/tests/utils/helpers.ts @@ -1,9 +1,8 @@ -import { CircuitManifest, PackagedCircuit } from "@zkpassport/utils" +import { CircuitManifest, PackagedCircuit, PackagedCertificatesFile } from "@zkpassport/utils/types" import { ChildProcess, execSync, spawn } from "child_process" import fs from "fs" import keccak256 from "keccak256" import path from "path" -import { PackagedCertificatesFile } from "../../src/types" // Configuration export const CHAIN_ID = 31337 @@ -12,6 +11,15 @@ export const RPC_URL = `http://localhost:${PORT}` export const ORACLE_ADDRESS = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" export const CONTRACTS_DIR = path.resolve(__dirname, "../../../registry-contracts") +interface ExecException extends Error { + cmd?: string + killed?: boolean + code?: number + signal?: NodeJS.Signals + stdout?: string + stderr?: string +} + /** * Utility to log only if verbose mode is enabled */ @@ -219,10 +227,10 @@ export async function startAnvil({ stdio: ["ignore", verbose ? "inherit" : "ignore", "pipe"], cwd: CONTRACTS_DIR, }) - } catch (error: any) { + } catch (error) { console.error("Error building contracts") - if (error.stderr) { - console.error(error.stderr.toString()) + if ((error as ExecException).stderr) { + console.error((error as ExecException)?.stderr?.toString()) } throw error } @@ -237,14 +245,14 @@ export async function startAnvil({ cwd: CONTRACTS_DIR, }) verboseLog(deployOutput) - } catch (error: any) { + } catch (error) { // Show the error output from the command console.error("Error deploying contracts") - if (error.stderr) { - console.error(error.stderr.toString()) + if ((error as ExecException)?.stderr) { + console.error((error as ExecException)?.stderr?.toString()) } - if (error.stdout) { - console.error(error.stdout.toString()) + if ((error as ExecException)?.stdout) { + console.error((error as ExecException)?.stdout?.toString()) } throw error } @@ -267,10 +275,10 @@ export async function startAnvil({ cwd: CONTRACTS_DIR, }) verboseLog(seedOutput) - } catch (error: any) { + } catch (error) { console.error("Error seeding registries") - if (error.stdout) { - console.error(error.stdout.toString()) + if ((error as ExecException)?.stdout) { + console.error((error as ExecException)?.stdout?.toString()) } throw error } diff --git a/packages/registry-sdk/tsconfig.json b/packages/registry-sdk/tsconfig.json index cfb11a8b4..cf57fd31b 100644 --- a/packages/registry-sdk/tsconfig.json +++ b/packages/registry-sdk/tsconfig.json @@ -1,16 +1,18 @@ { "extends": "../../tsconfig.packages.json", "compilerOptions": { - "rootDir": "./src", + "rootDir": "./", "outDir": "./dist", "declarationDir": "./dist/esm", "tsBuildInfoFile": "./tsconfig.tsbuildinfo", "baseUrl": "./src", "paths": { - "@/*": ["./*"] + "@/*": ["./*"], + "@zkpassport/utils": ["../zkpassport-utils/src/index.ts"], + "@zkpassport/utils/*": ["../zkpassport-utils/src/*"] } }, - "include": ["src/**/*.ts", "src/**/*.json"], - "exclude": ["**/*.test.ts"], + // "include" controls type-checking only; build output is controlled by tsup.config.ts entry points + "include": ["src/**/*.ts", "src/**/*.json", "tests/**/*.ts", "tsup.config.ts"], "references": [{ "path": "../zkpassport-utils" }] } diff --git a/packages/zkpassport-sdk/.eslintrc.json b/packages/zkpassport-sdk/.eslintrc.json index be97c53fb..b38ecf3d7 100644 --- a/packages/zkpassport-sdk/.eslintrc.json +++ b/packages/zkpassport-sdk/.eslintrc.json @@ -1,3 +1,3 @@ { - "extends": "../../.eslintrc.json" + "extends": "../../.eslintrc.cjs" } diff --git a/packages/zkpassport-sdk/package.json b/packages/zkpassport-sdk/package.json index 3a96de466..8c17896a9 100644 --- a/packages/zkpassport-sdk/package.json +++ b/packages/zkpassport-sdk/package.json @@ -14,8 +14,7 @@ } }, "scripts": { - "build": "bun run build:types && tsup --config tsup.config.ts", - "build:types": "tsc -b && tsc-alias -v -p tsconfig.json -f", + "build": "tsup --config tsup.config.ts", "dev:build": "DEV_BUILD=true bun run build", "clean": "rimraf dist tsconfig.tsbuildinfo", "test": "bun test", diff --git a/packages/zkpassport-sdk/src/index.ts b/packages/zkpassport-sdk/src/index.ts index a0103e78b..6ca9b90c5 100644 --- a/packages/zkpassport-sdk/src/index.ts +++ b/packages/zkpassport-sdk/src/index.ts @@ -33,9 +33,9 @@ import { DEFAULT_VALIDITY, VERSION } from "./constants" // If Buffer is not defined, then we use the Buffer from the buffer package if (typeof globalThis.Buffer === "undefined") { - globalThis.Buffer = Buffer as any + globalThis.Buffer = Buffer as any // eslint-disable-line if (typeof window !== "undefined") { - window.Buffer = Buffer as any + window.Buffer = Buffer as any // eslint-disable-line } } @@ -79,7 +79,7 @@ function rangeCompare( function generalCompare( fnName: "in" | "out" | "eq", key: IDCredential, - value: any, + value: any, // eslint-disable-line requestId: string, requestIdToConfig: Record, ) { @@ -496,6 +496,7 @@ export class ZKPassport { logger.debug("Secure channel established") await Promise.all(this.onRequestReceivedCallbacks[topic].map((callback) => callback())) }) + // eslint-disable-next-line bridge.onSecureMessage(async (message: any) => { logger.debug("Received message:", message) this.handleEncryptedMessage(topic, message) diff --git a/packages/zkpassport-sdk/src/logger.ts b/packages/zkpassport-sdk/src/logger.ts index 214e2b3ca..1a3e0f774 100644 --- a/packages/zkpassport-sdk/src/logger.ts +++ b/packages/zkpassport-sdk/src/logger.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + export const customLogger = { debug: (message: string, ...args: any[]) => console.debug(message, ...args), info: (message: string, ...args: any[]) => console.info(message, ...args), diff --git a/packages/zkpassport-sdk/src/public-input-checker.ts b/packages/zkpassport-sdk/src/public-input-checker.ts index 1bcb1234b..794e2dd15 100644 --- a/packages/zkpassport-sdk/src/public-input-checker.ts +++ b/packages/zkpassport-sdk/src/public-input-checker.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + import { type ProofResult, type QueryResult, diff --git a/packages/zkpassport-sdk/src/solidity-verifier.ts b/packages/zkpassport-sdk/src/solidity-verifier.ts index 6f76f194b..af05f13bf 100644 --- a/packages/zkpassport-sdk/src/solidity-verifier.ts +++ b/packages/zkpassport-sdk/src/solidity-verifier.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + import { AgeCommittedInputs, BindCommittedInputs, diff --git a/packages/zkpassport-sdk/tests/helpers/index.ts b/packages/zkpassport-sdk/tests/helpers/index.ts index 63398a4c7..461ab8f2d 100644 --- a/packages/zkpassport-sdk/tests/helpers/index.ts +++ b/packages/zkpassport-sdk/tests/helpers/index.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + export { mockWebSocket, MockWebSocket } from "./mock-websocket" export const waitForCallback = ( diff --git a/packages/zkpassport-sdk/tests/helpers/mock-websocket.ts b/packages/zkpassport-sdk/tests/helpers/mock-websocket.ts index 3e4f0d324..6f8f2efd6 100644 --- a/packages/zkpassport-sdk/tests/helpers/mock-websocket.ts +++ b/packages/zkpassport-sdk/tests/helpers/mock-websocket.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + export class MockWebSocket { static readonly CONNECTING = 0 static readonly OPEN = 1 @@ -221,7 +223,15 @@ export class MockWebSocket { } // This is a mock function that mimics the behavior of the bridge server on client connect -const mockBridgeServerClientConnect = function () { +const mockBridgeServerClientConnect = function (this: { + url: string + headers: { Origin: string } + hubChannel: string + onConnectInterceptor: () => void + onSendInterceptor: (data: string) => string | undefined + send: (data: string) => void + origin: string | null +}) { // If the WebSocket URI used to connect contains a pubkey param, the server will automatically // broadcast a handshake message to all connected clients if (this.url) { @@ -242,16 +252,33 @@ const mockBridgeServerClientConnect = function () { } // This is a mock function that mimics the behavior of the bridge server on message relay -const mockBridgeServerMessageRelay = function (data: string): string | undefined { +const mockBridgeServerMessageRelay = function ( + this: { + origin: any + headers: { Origin: string } + hubChannel: string // Use topic from URL + onConnectInterceptor: (this: { + url: string + headers: { Origin: string } + hubChannel: string + onConnectInterceptor: () => void + onSendInterceptor: (data: string) => string | undefined + send: (data: string) => void + origin: string | null + }) => void + onSendInterceptor: (data: string) => string | undefined + }, + data: string, +): string | undefined { // The WebSocket server will parse the data as JSON and throw error if invalid let parsedData: any try { parsedData = JSON.parse(data) } catch (error) { - throw new Error("Invalid JSON: " + error.message) + throw new Error("Invalid JSON: " + (error as Error).message) } // The WebSocket server will set the origin property on every message relayed if the origin is set - if (this.origin) parsedData.origin = this.origin + if (this.origin) parsedData.origin = this.origin as string return JSON.stringify(parsedData) } diff --git a/packages/zkpassport-sdk/tsconfig.json b/packages/zkpassport-sdk/tsconfig.json index a5cbe3db6..43db66904 100644 --- a/packages/zkpassport-sdk/tsconfig.json +++ b/packages/zkpassport-sdk/tsconfig.json @@ -1,16 +1,19 @@ { "extends": "../../tsconfig.packages.json", "compilerOptions": { - "rootDir": "./src", + "rootDir": "./", "outDir": "./dist", "declarationDir": "./dist/esm", "tsBuildInfoFile": "./tsconfig.tsbuildinfo", "baseUrl": "./src", "paths": { - "@/*": ["./*"] + "@/*": ["./*"], + "@zkpassport/utils": ["../zkpassport-utils/src/index.ts"], + "@zkpassport/utils/*": ["../zkpassport-utils/src/*"], + "@zkpassport/registry": ["../registry-sdk/src/index.ts"] } }, - "include": ["src/**/*.ts", "src/**/*.json"], - "exclude": ["**/*.test.ts"], + // "include" controls type-checking only; build output is controlled by tsup.config.ts entry points + "include": ["src/**/*.ts", "src/**/*.json", "tests/**/*.ts", "tsup.config.ts"], "references": [{ "path": "../zkpassport-utils" }, { "path": "../registry-sdk" }] } diff --git a/packages/zkpassport-utils/.eslintrc.json b/packages/zkpassport-utils/.eslintrc.json index be97c53fb..b38ecf3d7 100644 --- a/packages/zkpassport-utils/.eslintrc.json +++ b/packages/zkpassport-utils/.eslintrc.json @@ -1,3 +1,3 @@ { - "extends": "../../.eslintrc.json" + "extends": "../../.eslintrc.cjs" } diff --git a/packages/zkpassport-utils/package.json b/packages/zkpassport-utils/package.json index 375c42972..dedaa18f5 100644 --- a/packages/zkpassport-utils/package.json +++ b/packages/zkpassport-utils/package.json @@ -75,8 +75,7 @@ } }, "scripts": { - "build": "bun run build:types && tsup --config tsup.config.ts", - "build:types": "tsc -b && tsc-alias -v -p tsconfig.json -f", + "build": "tsup --config tsup.config.ts", "dev:build": "DEV_BUILD=true bun run build", "clean": "rimraf dist tsconfig.tsbuildinfo", "test": "bun test src tests", diff --git a/packages/zkpassport-utils/src/circuit-matcher.ts b/packages/zkpassport-utils/src/circuit-matcher.ts index 926a4d317..52c2fdc9a 100644 --- a/packages/zkpassport-utils/src/circuit-matcher.ts +++ b/packages/zkpassport-utils/src/circuit-matcher.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + import { sha256 } from "@noble/hashes/sha2" import { AsnParser } from "@peculiar/asn1-schema" import { AuthorityKeyIdentifier } from "@peculiar/asn1-x509" diff --git a/packages/zkpassport-utils/src/cms/utils.ts b/packages/zkpassport-utils/src/cms/utils.ts index ec48f65a4..fc71ca463 100644 --- a/packages/zkpassport-utils/src/cms/utils.ts +++ b/packages/zkpassport-utils/src/cms/utils.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + import { ECParameters } from "@peculiar/asn1-ecc" import { RSAPublicKey, RsaSaPssParams } from "@peculiar/asn1-rsa" import { AsnParser } from "@peculiar/asn1-schema" diff --git a/packages/zkpassport-utils/src/merkle-tree/async-imt.ts b/packages/zkpassport-utils/src/merkle-tree/async-imt.ts index 6c6fa906f..10ab6c1da 100644 --- a/packages/zkpassport-utils/src/merkle-tree/async-imt.ts +++ b/packages/zkpassport-utils/src/merkle-tree/async-imt.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + // c.f. https://github.com/zkpassport/zk-kit/blob/main/packages/imt/src/async-imt.ts import { requireArray, diff --git a/packages/zkpassport-utils/src/merkle-tree/async-ordered-mt.test.ts b/packages/zkpassport-utils/src/merkle-tree/async-ordered-mt.test.ts index 919d4c6fb..e1eeb4377 100644 --- a/packages/zkpassport-utils/src/merkle-tree/async-ordered-mt.test.ts +++ b/packages/zkpassport-utils/src/merkle-tree/async-ordered-mt.test.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + import AsyncOrderedMT, { MembershipProof, SortedNonMembershipProof, diff --git a/packages/zkpassport-utils/src/merkle-tree/index.ts b/packages/zkpassport-utils/src/merkle-tree/index.ts index 3010755cf..16247c364 100644 --- a/packages/zkpassport-utils/src/merkle-tree/index.ts +++ b/packages/zkpassport-utils/src/merkle-tree/index.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + import { poseidon2HashAsync } from "@zkpassport/poseidon2" import { normaliseHex } from "../utils" import { AsyncIMT } from "./async-imt" diff --git a/packages/zkpassport-utils/src/passport/common.ts b/packages/zkpassport-utils/src/passport/common.ts index 881ee698d..3bbbeed86 100644 --- a/packages/zkpassport-utils/src/passport/common.ts +++ b/packages/zkpassport-utils/src/passport/common.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + import { getOIDName } from ".." export function formatDN(issuer: any[]): string { diff --git a/packages/zkpassport-utils/src/promise-pool.ts b/packages/zkpassport-utils/src/promise-pool.ts index 06de3fb80..03ab020f3 100644 --- a/packages/zkpassport-utils/src/promise-pool.ts +++ b/packages/zkpassport-utils/src/promise-pool.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + // Promise pool for controlled concurrency export class PromisePool { private queue: (() => Promise)[] = [] diff --git a/packages/zkpassport-utils/src/types/index.ts b/packages/zkpassport-utils/src/types/index.ts index 46aaf6dd6..29a9da263 100644 --- a/packages/zkpassport-utils/src/types/index.ts +++ b/packages/zkpassport-utils/src/types/index.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + import type { Alpha2Code, Alpha3Code } from "i18n-iso-countries" import type { SOD } from "../passport" import type { CountryName } from "./countries" @@ -640,6 +642,7 @@ export type { CurveName, SignatureAlgorithmType, PackagedCertificate, + PackagedCertificatesFile, CircuitManifest, CircuitManifestEntry, } from "./registry" diff --git a/packages/zkpassport-utils/src/types/registry.ts b/packages/zkpassport-utils/src/types/registry.ts index 30f064993..a2732a9be 100644 --- a/packages/zkpassport-utils/src/types/registry.ts +++ b/packages/zkpassport-utils/src/types/registry.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + import { TwoLetterCode } from ".." type NISTCurve = @@ -81,6 +83,20 @@ export type PackagedCertificate = { type?: string } +/** + * Structure of the packaged certificates file output + */ +export type PackagedCertificatesFile = { + /** Version of the packaged certificates file format */ + version: number + /** Unix timestamp of when the certificates were packaged (used for certificate expiry checks) */ + timestamp: number + /** Array of packaged certificates */ + certificates: PackagedCertificate[] + /** Serialized merkle tree data */ + serialised: Record +} + export type CircuitManifestEntry = { hash: string; size: number } export type CircuitManifest = { diff --git a/packages/zkpassport-utils/src/utils.ts b/packages/zkpassport-utils/src/utils.ts index 9d103fe47..eeeb8490e 100644 --- a/packages/zkpassport-utils/src/utils.ts +++ b/packages/zkpassport-utils/src/utils.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + import { bigIntToBuffer } from "@zk-kit/utils" import { HashAlgorithm, QueryResult, SupportedChain } from "./types" import { hexToBytes } from "@noble/hashes/utils" diff --git a/packages/zkpassport-utils/tests/fixtures/passports.ts b/packages/zkpassport-utils/tests/fixtures/passports.ts index 51ce67a7e..55ae31b18 100644 --- a/packages/zkpassport-utils/tests/fixtures/passports.ts +++ b/packages/zkpassport-utils/tests/fixtures/passports.ts @@ -1,23 +1,10 @@ -import { DigestAlgorithm, PassportViewModel } from "../../src/types" +import { PassportViewModel } from "../../src/types" import { Binary } from "../../src/binary" import johnSODJson from "./john-miller-smith-rsa-2048-sha256.json" import marySODJson from "./mary-miller-smith-ecdsa-p256-sha256.json" import { SOD } from "../../src" -import { sha256, sha384, sha512 } from "@noble/hashes/sha2" - -const hash = (hashAlgorithm: DigestAlgorithm, msg: Uint8Array) => { - switch (hashAlgorithm) { - case "SHA256": - return sha256(msg) - case "SHA384": - return sha384(msg) - case "SHA512": - return sha512(msg) - default: - throw new Error(`Unsupported hash algorithm: ${hashAlgorithm}`) - } -} +import { sha256 } from "@noble/hashes/sha2" const johnSOD = SOD.fromDER(Binary.fromBase64(johnSODJson.encoded)) // John Miller Smith's MRZ @@ -35,6 +22,7 @@ export const PASSPORTS: { [key: string]: PassportViewModel } = { john: { + dateOfIssue: "941112", appVersion: "", mrz: johnMRZ, name: "John Smith", @@ -73,6 +61,7 @@ export const PASSPORTS: { sod: johnSOD, }, mary: { + dateOfIssue: "730302", appVersion: "", mrz: maryMRZ, name: "Mary Smith", diff --git a/packages/zkpassport-utils/tsconfig.json b/packages/zkpassport-utils/tsconfig.json index 044076c76..5c0f2ef91 100644 --- a/packages/zkpassport-utils/tsconfig.json +++ b/packages/zkpassport-utils/tsconfig.json @@ -1,7 +1,7 @@ { "extends": "../../tsconfig.packages.json", "compilerOptions": { - "rootDir": "./src", + "rootDir": "./", "outDir": "./dist", "declarationDir": "./dist/esm", "tsBuildInfoFile": "./tsconfig.tsbuildinfo", @@ -10,6 +10,6 @@ "@/*": ["./*"] } }, - "include": ["src/**/*.ts"], - "exclude": ["**/*.test.ts"] + // "include" controls type-checking only; build output is controlled by tsup.config.ts entry points + "include": ["src/**/*.ts", "tests/**/*.json", "tests/**/*.ts", "tsup.config.ts"] } diff --git a/scripts/validate-package.sh b/scripts/validate-package.sh index 0691293c1..cc282a6cd 100755 --- a/scripts/validate-package.sh +++ b/scripts/validate-package.sh @@ -6,6 +6,7 @@ set -e +REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" echo "🔍 Validating package..." # Pack the package @@ -15,10 +16,10 @@ trap 'rm "$PKG"' EXIT # Run publint validation echo "🔍 Running publint..." -bunx publint "$PKG" +"$REPO_ROOT/node_modules/.bin/publint" "$PKG" # Run @arethetypeswrong/cli validation echo "🔍 Running @arethetypeswrong/cli..." -bunx @arethetypeswrong/cli "$PKG" --profile node16 -f table-flipped +"$REPO_ROOT/node_modules/.bin/attw" "$PKG" --profile node16 -f table-flipped echo "✅ Package validation complete: $PKG" diff --git a/tsconfig.json b/tsconfig.json index c734f7efb..d32a11d9d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,6 +5,6 @@ { "path": "./packages/registry-sdk" }, { "path": "./packages/zkpassport-sdk" }, { "path": "./packages/registry-explorer" } - ] + ], + "include": [".eslintrc.cjs"] } - diff --git a/turbo.json b/turbo.json index af4273158..16d4ea793 100644 --- a/turbo.json +++ b/turbo.json @@ -6,13 +6,14 @@ "dependsOn": ["^build"], "outputs": ["dist/**", ".next/**", "out/**"] }, - "build:types": { - "outputs": ["dist/**"] - }, "dev:build": { "dependsOn": ["^dev:build"], "cache": false }, + "validate-package": { + "dependsOn": ["build"], + "cache": false + }, "test": { "dependsOn": ["build"], "cache": false From 4c4023954b5e2d6b43bfbeef42b6d971448faef6 Mon Sep 17 00:00:00 2001 From: Michael Elliot Date: Sat, 7 Feb 2026 02:37:38 +1100 Subject: [PATCH 04/30] ci: Add npm auto publishing using OIDC (#154) * add auto publishing with oidc * update publish process to use bun to pack tarball and npm to publish it * update prepublish script * simplify readme --- .github/workflows/publish-registry-sdk.yml | 31 +++++++++++-------- .github/workflows/publish-zkpassport-sdk.yml | 31 +++++++++++-------- .../workflows/publish-zkpassport-utils.yml | 31 +++++++++++-------- README.md | 14 ++++++--- packages/registry-sdk/package.json | 5 +++ packages/zkpassport-sdk/package.json | 5 +++ packages/zkpassport-utils/package.json | 5 +++ scripts/prepublish.sh | 9 ++++-- 8 files changed, 85 insertions(+), 46 deletions(-) diff --git a/.github/workflows/publish-registry-sdk.yml b/.github/workflows/publish-registry-sdk.yml index 5a8028fef..05599561a 100644 --- a/.github/workflows/publish-registry-sdk.yml +++ b/.github/workflows/publish-registry-sdk.yml @@ -10,6 +10,11 @@ jobs: publish: name: Publish Registry SDK runs-on: ubuntu-latest + environment: npm-publish + permissions: + id-token: write # Required for OIDC + contents: read + steps: - name: Checkout repository uses: actions/checkout@v4 @@ -34,22 +39,18 @@ jobs: run: bash scripts/sync-workspace-deps.sh check - name: Install system dependencies - if: github.ref == 'refs/heads/main' run: sudo apt-get install -y lsof jq zsh - name: Install Foundry - if: github.ref == 'refs/heads/main' uses: foundry-rs/foundry-toolchain@v1 with: version: v1.4.4 - name: Install Foundry dependencies - if: github.ref == 'refs/heads/main' run: forge install working-directory: packages/registry-contracts - name: Setup Turbo cache - if: github.ref == 'refs/heads/main' uses: actions/cache@v4 with: path: .turbo @@ -58,27 +59,31 @@ jobs: ${{ runner.os }}-turbo- - name: Build package - if: github.ref == 'refs/heads/main' run: bun run build --filter=@zkpassport/registry + - name: Setup Node.js for npm publish + uses: actions/setup-node@v4 + with: + node-version: '24' + registry-url: 'https://registry.npmjs.org' + - name: Check if version is published to npm - if: github.ref == 'refs/heads/main' id: version_check run: | - VERSION=$(bun -p "require('./packages/registry-sdk/package.json').version") - if ! bun pm view @zkpassport/registry@$VERSION version 2>/dev/null; then + VERSION=$(node -p "require('./packages/registry-sdk/package.json').version") + if ! npm view @zkpassport/registry@$VERSION version 2>/dev/null; then echo "publish=true" >> $GITHUB_OUTPUT echo "version=$VERSION" >> $GITHUB_OUTPUT fi - name: Publish new version to npm - if: steps.version_check.outputs.publish == 'true' && github.ref == 'refs/heads/main' + if: steps.version_check.outputs.publish == 'true' run: | + ../../scripts/prepublish.sh + PKG=$(bun pm pack --quiet | xargs) if [[ "${{ steps.version_check.outputs.version }}" =~ [0-9]+\.[0-9]+\.[0-9]+\- ]]; then - bun publish --tag beta + npm publish "$PKG" --ignore-scripts --provenance --access public --tag beta else - bun publish + npm publish "$PKG" --ignore-scripts --provenance --access public fi working-directory: packages/registry-sdk - env: - NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/publish-zkpassport-sdk.yml b/.github/workflows/publish-zkpassport-sdk.yml index 852c59393..cee3177eb 100644 --- a/.github/workflows/publish-zkpassport-sdk.yml +++ b/.github/workflows/publish-zkpassport-sdk.yml @@ -10,6 +10,11 @@ jobs: publish: name: Publish SDK runs-on: ubuntu-latest + environment: npm-publish + permissions: + id-token: write # Required for OIDC + contents: read + steps: - name: Checkout repository uses: actions/checkout@v4 @@ -34,22 +39,18 @@ jobs: run: bash scripts/sync-workspace-deps.sh check - name: Install system dependencies - if: github.ref == 'refs/heads/main' run: sudo apt-get install -y lsof jq zsh - name: Install Foundry - if: github.ref == 'refs/heads/main' uses: foundry-rs/foundry-toolchain@v1 with: version: v1.4.4 - name: Install Foundry dependencies - if: github.ref == 'refs/heads/main' run: forge install working-directory: packages/registry-contracts - name: Setup Turbo cache - if: github.ref == 'refs/heads/main' uses: actions/cache@v4 with: path: .turbo @@ -58,27 +59,31 @@ jobs: ${{ runner.os }}-turbo- - name: Build package - if: github.ref == 'refs/heads/main' run: bun run build --filter=@zkpassport/sdk + - name: Setup Node.js for npm publish + uses: actions/setup-node@v4 + with: + node-version: '24' + registry-url: 'https://registry.npmjs.org' + - name: Check if version is published to npm - if: github.ref == 'refs/heads/main' id: version_check run: | - VERSION=$(bun -p "require('./packages/zkpassport-sdk/package.json').version") - if ! bun pm view @zkpassport/sdk@$VERSION version 2>/dev/null; then + VERSION=$(node -p "require('./packages/zkpassport-sdk/package.json').version") + if ! npm view @zkpassport/sdk@$VERSION version 2>/dev/null; then echo "publish=true" >> $GITHUB_OUTPUT echo "version=$VERSION" >> $GITHUB_OUTPUT fi - name: Publish new version to npm - if: steps.version_check.outputs.publish == 'true' && github.ref == 'refs/heads/main' + if: steps.version_check.outputs.publish == 'true' run: | + ../../scripts/prepublish.sh + PKG=$(bun pm pack --quiet | xargs) if [[ "${{ steps.version_check.outputs.version }}" =~ [0-9]+\.[0-9]+\.[0-9]+\- ]]; then - bun publish --tag beta + npm publish "$PKG" --ignore-scripts --provenance --access public --tag beta else - bun publish + npm publish "$PKG" --ignore-scripts --provenance --access public fi working-directory: packages/zkpassport-sdk - env: - NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/publish-zkpassport-utils.yml b/.github/workflows/publish-zkpassport-utils.yml index c52270330..cb45ddbcb 100644 --- a/.github/workflows/publish-zkpassport-utils.yml +++ b/.github/workflows/publish-zkpassport-utils.yml @@ -10,6 +10,11 @@ jobs: publish: name: Publish Utils runs-on: ubuntu-latest + environment: npm-publish + permissions: + id-token: write # Required for OIDC + contents: read + steps: - name: Checkout repository uses: actions/checkout@v4 @@ -34,22 +39,18 @@ jobs: run: bash scripts/sync-workspace-deps.sh check - name: Install system dependencies - if: github.ref == 'refs/heads/main' run: sudo apt-get install -y lsof jq zsh - name: Install Foundry - if: github.ref == 'refs/heads/main' uses: foundry-rs/foundry-toolchain@v1 with: version: v1.4.4 - name: Install Foundry dependencies - if: github.ref == 'refs/heads/main' run: forge install working-directory: packages/registry-contracts - name: Setup Turbo cache - if: github.ref == 'refs/heads/main' uses: actions/cache@v4 with: path: .turbo @@ -58,27 +59,31 @@ jobs: ${{ runner.os }}-turbo- - name: Build package - if: github.ref == 'refs/heads/main' run: bun run build --filter=@zkpassport/utils + - name: Setup Node.js for npm publish + uses: actions/setup-node@v4 + with: + node-version: '24' + registry-url: 'https://registry.npmjs.org' + - name: Check if version is published to npm - if: github.ref == 'refs/heads/main' id: version_check run: | - VERSION=$(bun -p "require('./packages/zkpassport-utils/package.json').version") - if ! bun pm view @zkpassport/utils@$VERSION version 2>/dev/null; then + VERSION=$(node -p "require('./packages/zkpassport-utils/package.json').version") + if ! npm view @zkpassport/utils@$VERSION version 2>/dev/null; then echo "publish=true" >> $GITHUB_OUTPUT echo "version=$VERSION" >> $GITHUB_OUTPUT fi - name: Publish new version to npm - if: steps.version_check.outputs.publish == 'true' && github.ref == 'refs/heads/main' + if: steps.version_check.outputs.publish == 'true' run: | + ../../scripts/prepublish.sh + PKG=$(bun pm pack --quiet | xargs) if [[ "${{ steps.version_check.outputs.version }}" =~ [0-9]+\.[0-9]+\.[0-9]+\- ]]; then - bun publish --tag beta + npm publish "$PKG" --ignore-scripts --provenance --access public --tag beta else - bun publish + npm publish "$PKG" --ignore-scripts --provenance --access public fi working-directory: packages/zkpassport-utils - env: - NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/README.md b/README.md index 39daf0437..aab27ff07 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,21 @@ # ZKPassport Monorepo -This monorepo contains the components of the ZKPassport Registry: +This monorepo contains the components of the ZKPassport project: - - **Registry Contracts**: Smart contracts for the on-chain registry + - **Registry Contracts**: Smart contracts for the onchain registry - **Registry SDK**: JavaScript SDK for interacting with the registry - **Registry Explorer**: Web app for exploring and verifying registry certificates + - **ZKPassport SDK**: SDK for integrating with ZKPassport + - **ZKPassport Utils**: Shared utilities used across ZKPassport packages ## Project Structure ``` zkpassport-packages/ ├── packages/ -│ ├── registry-contracts/ # Registry smart contracts -│ ├── registry-sdk/ # Registry JS SDK for querying the registry -│ ├── registry-explorer/ # Registry Explorer web app for exploring the registry +│ ├── registry-contracts/ # Registry Contracts +│ ├── registry-sdk/ # Registry SDK +│ ├── registry-explorer/ # Registry Explorer +│ ├── zkpassport-sdk/ # ZKPassport SDK +│ └── zkpassport-utils/ # ZKPassport Utils ``` diff --git a/packages/registry-sdk/package.json b/packages/registry-sdk/package.json index cd2e8a33d..29dec95ee 100644 --- a/packages/registry-sdk/package.json +++ b/packages/registry-sdk/package.json @@ -4,6 +4,11 @@ "description": "Registry SDK for interacting with the ZKPassport Registry", "author": "ZKPassport", "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "https://github.com/zkpassport/zkpassport-packages", + "directory": "packages/registry-sdk" + }, "type": "module", "main": "./dist/esm/index.js", "types": "./dist/esm/index.d.ts", diff --git a/packages/zkpassport-sdk/package.json b/packages/zkpassport-sdk/package.json index 8c17896a9..950271381 100644 --- a/packages/zkpassport-sdk/package.json +++ b/packages/zkpassport-sdk/package.json @@ -4,6 +4,11 @@ "description": "Privacy-preserving identity verification using passports and ID cards", "author": "ZKPassport", "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "https://github.com/zkpassport/zkpassport-packages", + "directory": "packages/zkpassport-sdk" + }, "type": "module", "main": "./dist/esm/index.js", "types": "./dist/esm/index.d.ts", diff --git a/packages/zkpassport-utils/package.json b/packages/zkpassport-utils/package.json index dedaa18f5..63c2161ae 100644 --- a/packages/zkpassport-utils/package.json +++ b/packages/zkpassport-utils/package.json @@ -1,6 +1,11 @@ { "name": "@zkpassport/utils", "version": "0.32.1", + "repository": { + "type": "git", + "url": "https://github.com/zkpassport/zkpassport-packages", + "directory": "packages/zkpassport-utils" + }, "type": "module", "main": "./dist/esm/index.js", "types": "./dist/esm/index.d.ts", diff --git a/scripts/prepublish.sh b/scripts/prepublish.sh index 0a6a470d7..13ebe5b32 100755 --- a/scripts/prepublish.sh +++ b/scripts/prepublish.sh @@ -6,10 +6,15 @@ set -e # Ensure script is being run with `bun publish` (not `npm publish`) -bun -e "process.env.npm_config_user_agent?.startsWith('bun/') || (console.error('ERROR: Must use bun publish'), process.exit(1))" +# This is because bun publish resolves workspace:* refs, whereas npm publish does not +if [ -z "$CI" ]; then + bun -e "process.env.npm_config_user_agent?.startsWith('bun/') || (console.error('ERROR: Must use bun publish'), process.exit(1))" +fi # Check for prerelease version accidentally being published to 'latest' tag -../../scripts/check-prerelease-tag.sh +if [ -z "$CI" ]; then + ../../scripts/check-prerelease-tag.sh +fi # Sync workspace dependencies (cd $(git rev-parse --show-toplevel) && scripts/sync-workspace-deps.sh) From bea49db524c3937d4cb2a4934f74c54614ad3886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Madzou?= <17496111+madztheo@users.noreply.github.com> Date: Fri, 6 Feb 2026 16:50:12 +0000 Subject: [PATCH 05/30] feat(utils): Brute force signature verification for CSC <> DSC matching (#153) * implement brute force signature verification fallback retrieval for csc * simplify signature verification logic * remove console log * simplify bytes conversion for rsa pub key * bump utils version to 0.33.0 * sync deps * sync deps 2 * format * run forge fmt * run scripts/sync-workspace-deps.sh * remove crypto lib import * bump utils version to 0.33.1 * fix bun.lock * bump utils version to 0.33.2 * update ci to use bun 1.3.8 * sync deps * fix linting error --------- Co-authored-by: Michael Elliot --- .github/workflows/ci.yml | 4 +- .github/workflows/publish-registry-sdk.yml | 2 +- .github/workflows/publish-zkpassport-sdk.yml | 2 +- .../workflows/publish-zkpassport-utils.yml | 2 +- bun.lock | 355 ++++---- .../registry-explorer/components/ui/badge.tsx | 3 +- .../components/ui/button.tsx | 3 +- .../registry-explorer/components/ui/input.tsx | 3 +- packages/zkpassport-sdk/package.json | 2 +- .../zkpassport-sdk/src/solidity-verifier.ts | 4 +- packages/zkpassport-utils/package.json | 6 +- .../zkpassport-utils/src/circuit-matcher.ts | 152 ++-- packages/zkpassport-utils/src/circuits/age.ts | 2 +- .../zkpassport-utils/src/circuits/bind.ts | 2 +- .../zkpassport-utils/src/circuits/country.ts | 2 +- .../zkpassport-utils/src/circuits/date.ts | 2 +- .../zkpassport-utils/src/circuits/disclose.ts | 2 +- .../src/circuits/facematch.ts | 2 +- .../src/circuits/sanctions/sanctions.ts | 2 +- .../zkpassport-utils/src/cms/constants.ts | 28 +- packages/zkpassport-utils/src/index.ts | 1 + .../src/signature-verification.ts | 835 ++++++++++++++++++ packages/zkpassport-utils/src/utils.ts | 2 +- .../tests/circuit-matcher.test.ts | 175 ++-- .../tests/fixtures/passports.ts | 2 +- 25 files changed, 1245 insertions(+), 350 deletions(-) create mode 100644 packages/zkpassport-utils/src/signature-verification.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a99c60fa0..21722387b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,7 @@ jobs: - name: Install Bun uses: oven-sh/setup-bun@v2 with: - bun-version: 1.3.1 + bun-version: 1.3.8 - name: Cache Bun dependencies uses: actions/cache@v4 @@ -72,7 +72,7 @@ jobs: - name: Install Bun uses: oven-sh/setup-bun@v2 with: - bun-version: 1.3.1 + bun-version: 1.3.8 - name: Cache Bun dependencies uses: actions/cache@v4 diff --git a/.github/workflows/publish-registry-sdk.yml b/.github/workflows/publish-registry-sdk.yml index 05599561a..197ff192f 100644 --- a/.github/workflows/publish-registry-sdk.yml +++ b/.github/workflows/publish-registry-sdk.yml @@ -22,7 +22,7 @@ jobs: - name: Install Bun uses: oven-sh/setup-bun@v2 with: - bun-version: 1.3.1 + bun-version: 1.3.8 - name: Cache Bun dependencies uses: actions/cache@v4 diff --git a/.github/workflows/publish-zkpassport-sdk.yml b/.github/workflows/publish-zkpassport-sdk.yml index cee3177eb..fa3110561 100644 --- a/.github/workflows/publish-zkpassport-sdk.yml +++ b/.github/workflows/publish-zkpassport-sdk.yml @@ -22,7 +22,7 @@ jobs: - name: Install Bun uses: oven-sh/setup-bun@v2 with: - bun-version: 1.3.1 + bun-version: 1.3.8 - name: Cache Bun dependencies uses: actions/cache@v4 diff --git a/.github/workflows/publish-zkpassport-utils.yml b/.github/workflows/publish-zkpassport-utils.yml index cb45ddbcb..407d38052 100644 --- a/.github/workflows/publish-zkpassport-utils.yml +++ b/.github/workflows/publish-zkpassport-utils.yml @@ -22,7 +22,7 @@ jobs: - name: Install Bun uses: oven-sh/setup-bun@v2 with: - bun-version: 1.3.1 + bun-version: 1.3.8 - name: Cache Bun dependencies uses: actions/cache@v4 diff --git a/bun.lock b/bun.lock index c5c08c31b..3e2973809 100644 --- a/bun.lock +++ b/bun.lock @@ -1,5 +1,6 @@ { "lockfileVersion": 1, + "configVersion": 0, "workspaces": { "": { "name": "zkpassport-packages", @@ -87,7 +88,7 @@ "dependencies": { "@aztec/bb.js": "2.0.3", "@noble/ciphers": "^1.2.1", - "@noble/hashes": "^1.7.2", + "@noble/hashes": "^2.0.1", "@noble/secp256k1": "^2.2.3", "@obsidion/bridge": "^0.11.2", "@zkpassport/registry": "workspace:*", @@ -109,12 +110,12 @@ }, "packages/zkpassport-utils": { "name": "@zkpassport/utils", - "version": "0.32.1", + "version": "0.33.2", "dependencies": { "@lapo/asn1js": "^2.0.4", "@noble/ciphers": "^1.0.0", - "@noble/curves": "^1.6.0", - "@noble/hashes": "^1.5.0", + "@noble/curves": "^2.0.1", + "@noble/hashes": "^2.0.1", "@noble/secp256k1": "^2.1.0", "@peculiar/asn1-cms": "^2.3.15", "@peculiar/asn1-ecc": "^2.3.15", @@ -146,85 +147,85 @@ "@aztec/bb.js": ["@aztec/bb.js@2.0.3", "", { "dependencies": { "comlink": "^4.4.1", "commander": "^12.1.0", "idb-keyval": "^6.2.1", "msgpackr": "^1.11.2", "pako": "^2.1.0", "pino": "^9.5.0", "tslib": "^2.4.0" }, "bin": { "bb.js": "dest/node/main.js" } }, "sha512-sI8lA2L8RMACsi6iBtcuKgGLx4crMzoAaTNtfP3VAaOpjoIwB3O/AMETz5IDGdkOA6tOqM2R0nWh1J+wDYPlVQ=="], - "@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="], + "@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], - "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="], + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], "@braidai/lang": ["@braidai/lang@1.1.2", "", {}, "sha512-qBcknbBufNHlui137Hft8xauQMTZDKdophmLFv05r2eNmdIv/MlPuP4TdUknHG68UdWLgVZwgxVe735HzJNIwA=="], "@colors/colors": ["@colors/colors@1.5.0", "", {}, "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ=="], - "@emnapi/core": ["@emnapi/core@1.5.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg=="], + "@emnapi/core": ["@emnapi/core@1.8.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg=="], - "@emnapi/runtime": ["@emnapi/runtime@1.5.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ=="], + "@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="], "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="], - "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.10", "", { "os": "aix", "cpu": "ppc64" }, "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw=="], + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.3", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg=="], - "@esbuild/android-arm": ["@esbuild/android-arm@0.25.10", "", { "os": "android", "cpu": "arm" }, "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w=="], + "@esbuild/android-arm": ["@esbuild/android-arm@0.27.3", "", { "os": "android", "cpu": "arm" }, "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA=="], - "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.10", "", { "os": "android", "cpu": "arm64" }, "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg=="], + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.3", "", { "os": "android", "cpu": "arm64" }, "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg=="], - "@esbuild/android-x64": ["@esbuild/android-x64@0.25.10", "", { "os": "android", "cpu": "x64" }, "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg=="], + "@esbuild/android-x64": ["@esbuild/android-x64@0.27.3", "", { "os": "android", "cpu": "x64" }, "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ=="], - "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.10", "", { "os": "darwin", "cpu": "arm64" }, "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA=="], + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg=="], - "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.10", "", { "os": "darwin", "cpu": "x64" }, "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg=="], + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg=="], - "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.10", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg=="], + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w=="], - "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.10", "", { "os": "freebsd", "cpu": "x64" }, "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA=="], + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA=="], - "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.10", "", { "os": "linux", "cpu": "arm" }, "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg=="], + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.3", "", { "os": "linux", "cpu": "arm" }, "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw=="], - "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ=="], + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg=="], - "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.10", "", { "os": "linux", "cpu": "ia32" }, "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ=="], + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.3", "", { "os": "linux", "cpu": "ia32" }, "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg=="], - "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.10", "", { "os": "linux", "cpu": "none" }, "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg=="], + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA=="], - "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.10", "", { "os": "linux", "cpu": "none" }, "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA=="], + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw=="], - "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.10", "", { "os": "linux", "cpu": "ppc64" }, "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA=="], + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA=="], - "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.10", "", { "os": "linux", "cpu": "none" }, "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA=="], + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.3", "", { "os": "linux", "cpu": "none" }, "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ=="], - "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.10", "", { "os": "linux", "cpu": "s390x" }, "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew=="], + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw=="], - "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.10", "", { "os": "linux", "cpu": "x64" }, "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA=="], + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.3", "", { "os": "linux", "cpu": "x64" }, "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA=="], - "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.10", "", { "os": "none", "cpu": "arm64" }, "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A=="], + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA=="], - "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.10", "", { "os": "none", "cpu": "x64" }, "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig=="], + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.3", "", { "os": "none", "cpu": "x64" }, "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA=="], - "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.10", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw=="], + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.3", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw=="], - "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.10", "", { "os": "openbsd", "cpu": "x64" }, "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw=="], + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.3", "", { "os": "openbsd", "cpu": "x64" }, "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ=="], - "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.10", "", { "os": "none", "cpu": "arm64" }, "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag=="], + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.3", "", { "os": "none", "cpu": "arm64" }, "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g=="], - "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.10", "", { "os": "sunos", "cpu": "x64" }, "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ=="], + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.3", "", { "os": "sunos", "cpu": "x64" }, "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA=="], - "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.10", "", { "os": "win32", "cpu": "arm64" }, "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw=="], + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA=="], - "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.10", "", { "os": "win32", "cpu": "ia32" }, "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw=="], + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q=="], - "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.10", "", { "os": "win32", "cpu": "x64" }, "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw=="], + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.3", "", { "os": "win32", "cpu": "x64" }, "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA=="], - "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g=="], + "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.1", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ=="], - "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.1", "", {}, "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ=="], + "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="], "@eslint/eslintrc": ["@eslint/eslintrc@2.1.4", "", { "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^9.6.0", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ=="], "@eslint/js": ["@eslint/js@8.57.1", "", {}, "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q=="], - "@floating-ui/core": ["@floating-ui/core@1.7.3", "", { "dependencies": { "@floating-ui/utils": "^0.2.10" } }, "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w=="], + "@floating-ui/core": ["@floating-ui/core@1.7.4", "", { "dependencies": { "@floating-ui/utils": "^0.2.10" } }, "sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg=="], - "@floating-ui/dom": ["@floating-ui/dom@1.7.4", "", { "dependencies": { "@floating-ui/core": "^1.7.3", "@floating-ui/utils": "^0.2.10" } }, "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA=="], + "@floating-ui/dom": ["@floating-ui/dom@1.7.5", "", { "dependencies": { "@floating-ui/core": "^1.7.4", "@floating-ui/utils": "^0.2.10" } }, "sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg=="], - "@floating-ui/react-dom": ["@floating-ui/react-dom@2.1.6", "", { "dependencies": { "@floating-ui/dom": "^1.7.4" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw=="], + "@floating-ui/react-dom": ["@floating-ui/react-dom@2.1.7", "", { "dependencies": { "@floating-ui/dom": "^1.7.5" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-0tLRojf/1Go2JgEVm+3Frg9A3IW8bJgKgdO0BN5RkF//ufuz2joZM63Npau2ff3J6lUVYgDSNzNkR+aH3IVfjg=="], "@floating-ui/utils": ["@floating-ui/utils@0.2.10", "", {}, "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ=="], @@ -236,7 +237,7 @@ "@isaacs/balanced-match": ["@isaacs/balanced-match@4.0.1", "", {}, "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ=="], - "@isaacs/brace-expansion": ["@isaacs/brace-expansion@5.0.0", "", { "dependencies": { "@isaacs/balanced-match": "^4.0.1" } }, "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA=="], + "@isaacs/brace-expansion": ["@isaacs/brace-expansion@5.0.1", "", { "dependencies": { "@isaacs/balanced-match": "^4.0.1" } }, "sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ=="], "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], @@ -260,7 +261,7 @@ "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], - "@lapo/asn1js": ["@lapo/asn1js@2.1.0", "", { "bin": { "dumpASN1": "dumpASN1.js" } }, "sha512-SIRsS9jhhpsRxr1d5leFfdI6sEOQciQXShN7sIwoze+iEevvoKmLGG66PyLDgIEYeONq80sx48xs86eK4MItEw=="], + "@lapo/asn1js": ["@lapo/asn1js@2.1.1", "", { "bin": { "dumpASN1": "dumpASN1.js" } }, "sha512-a4wOBae3D8EfOEcGjLyQIFIgNh+5I80a804jM7oMnH8WcMKdOZoa1xGc92wDo4k6EzKovkNwaUbnmkOr5CuAWQ=="], "@loaderkit/resolve": ["@loaderkit/resolve@1.0.4", "", { "dependencies": { "@braidai/lang": "^1.0.0" } }, "sha512-rJzYKVcV4dxJv+vW6jlvagF8zvGxHJ2+HTr1e2qOejfmGhAApgJHl8Aog4mMszxceTRiKTTbnpgmTO1bEZHV/A=="], @@ -302,9 +303,9 @@ "@noble/ciphers": ["@noble/ciphers@1.3.0", "", {}, "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw=="], - "@noble/curves": ["@noble/curves@1.9.7", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw=="], + "@noble/curves": ["@noble/curves@2.0.1", "", { "dependencies": { "@noble/hashes": "2.0.1" } }, "sha512-vs1Az2OOTBiP4q0pwjW5aF0xp9n4MxVrmkFBxc6EKZc6ddYx5gaZiAsZoq0uRRXWbi3AT/sBqn05eRPtn1JCPw=="], - "@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="], + "@noble/hashes": ["@noble/hashes@2.0.1", "", {}, "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw=="], "@noble/secp256k1": ["@noble/secp256k1@2.3.0", "", {}, "sha512-0TQed2gcBbIrh7Ccyw+y/uZQvbJwm7Ao4scBUxqpBCcsOlZG0O4KGfjtNAy/li4W8n1xt3dxrwJ0beZ2h2G6Kw=="], @@ -318,27 +319,29 @@ "@obsidion/bridge": ["@obsidion/bridge@0.11.2", "", { "dependencies": { "@noble/ciphers": "^1.2.1", "@noble/hashes": "^1.8.0", "@noble/secp256k1": "^2.2.3", "@types/pako": "^2.0.3", "debug": "^4.3.4", "pako": "^2.1.0", "ws": "^8.16.0" }, "peerDependencies": { "typescript": "^5.0.0" } }, "sha512-IX5g2c6TF9xKGFgnQBAq4TJLns+W2SfDgndE1orsLIQCRJ8UKsu5Mt+RwbI6sDu7PxVveZvmLEaiXhJl7NhJaQ=="], - "@peculiar/asn1-cms": ["@peculiar/asn1-cms@2.5.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.5.0", "@peculiar/asn1-x509": "^2.5.0", "@peculiar/asn1-x509-attr": "^2.5.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-p0SjJ3TuuleIvjPM4aYfvYw8Fk1Hn/zAVyPJZTtZ2eE9/MIer6/18ROxX6N/e6edVSfvuZBqhxAj3YgsmSjQ/A=="], + "@peculiar/asn1-cms": ["@peculiar/asn1-cms@2.6.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.6.0", "@peculiar/asn1-x509": "^2.6.0", "@peculiar/asn1-x509-attr": "^2.6.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-2uZqP+ggSncESeUF/9Su8rWqGclEfEiz1SyU02WX5fUONFfkjzS2Z/F1Li0ofSmf4JqYXIOdCAZqIXAIBAT1OA=="], - "@peculiar/asn1-csr": ["@peculiar/asn1-csr@2.5.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.5.0", "@peculiar/asn1-x509": "^2.5.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-ioigvA6WSYN9h/YssMmmoIwgl3RvZlAYx4A/9jD2qaqXZwGcNlAxaw54eSx2QG1Yu7YyBC5Rku3nNoHrQ16YsQ=="], + "@peculiar/asn1-csr": ["@peculiar/asn1-csr@2.6.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.6.0", "@peculiar/asn1-x509": "^2.6.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-BeWIu5VpTIhfRysfEp73SGbwjjoLL/JWXhJ/9mo4vXnz3tRGm+NGm3KNcRzQ9VMVqwYS2RHlolz21svzRXIHPQ=="], - "@peculiar/asn1-ecc": ["@peculiar/asn1-ecc@2.5.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.5.0", "@peculiar/asn1-x509": "^2.5.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-t4eYGNhXtLRxaP50h3sfO6aJebUCDGQACoeexcelL4roMFRRVgB20yBIu2LxsPh/tdW9I282gNgMOyg3ywg/mg=="], + "@peculiar/asn1-ecc": ["@peculiar/asn1-ecc@2.6.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.6.0", "@peculiar/asn1-x509": "^2.6.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-FF3LMGq6SfAOwUG2sKpPXblibn6XnEIKa+SryvUl5Pik+WR9rmRA3OCiwz8R3lVXnYnyRkSZsSLdml8H3UiOcw=="], - "@peculiar/asn1-pfx": ["@peculiar/asn1-pfx@2.5.0", "", { "dependencies": { "@peculiar/asn1-cms": "^2.5.0", "@peculiar/asn1-pkcs8": "^2.5.0", "@peculiar/asn1-rsa": "^2.5.0", "@peculiar/asn1-schema": "^2.5.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-Vj0d0wxJZA+Ztqfb7W+/iu8Uasw6hhKtCdLKXLG/P3kEPIQpqGI4P4YXlROfl7gOCqFIbgsj1HzFIFwQ5s20ug=="], + "@peculiar/asn1-pfx": ["@peculiar/asn1-pfx@2.6.0", "", { "dependencies": { "@peculiar/asn1-cms": "^2.6.0", "@peculiar/asn1-pkcs8": "^2.6.0", "@peculiar/asn1-rsa": "^2.6.0", "@peculiar/asn1-schema": "^2.6.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-rtUvtf+tyKGgokHHmZzeUojRZJYPxoD/jaN1+VAB4kKR7tXrnDCA/RAWXAIhMJJC+7W27IIRGe9djvxKgsldCQ=="], - "@peculiar/asn1-pkcs8": ["@peculiar/asn1-pkcs8@2.5.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.5.0", "@peculiar/asn1-x509": "^2.5.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-L7599HTI2SLlitlpEP8oAPaJgYssByI4eCwQq2C9eC90otFpm8MRn66PpbKviweAlhinWQ3ZjDD2KIVtx7PaVw=="], + "@peculiar/asn1-pkcs8": ["@peculiar/asn1-pkcs8@2.6.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.6.0", "@peculiar/asn1-x509": "^2.6.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-KyQ4D8G/NrS7Fw3XCJrngxmjwO/3htnA0lL9gDICvEQ+GJ+EPFqldcJQTwPIdvx98Tua+WjkdKHSC0/Km7T+lA=="], - "@peculiar/asn1-pkcs9": ["@peculiar/asn1-pkcs9@2.5.0", "", { "dependencies": { "@peculiar/asn1-cms": "^2.5.0", "@peculiar/asn1-pfx": "^2.5.0", "@peculiar/asn1-pkcs8": "^2.5.0", "@peculiar/asn1-schema": "^2.5.0", "@peculiar/asn1-x509": "^2.5.0", "@peculiar/asn1-x509-attr": "^2.5.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-UgqSMBLNLR5TzEZ5ZzxR45Nk6VJrammxd60WMSkofyNzd3DQLSNycGWSK5Xg3UTYbXcDFyG8pA/7/y/ztVCa6A=="], + "@peculiar/asn1-pkcs9": ["@peculiar/asn1-pkcs9@2.6.0", "", { "dependencies": { "@peculiar/asn1-cms": "^2.6.0", "@peculiar/asn1-pfx": "^2.6.0", "@peculiar/asn1-pkcs8": "^2.6.0", "@peculiar/asn1-schema": "^2.6.0", "@peculiar/asn1-x509": "^2.6.0", "@peculiar/asn1-x509-attr": "^2.6.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-b78OQ6OciW0aqZxdzliXGYHASeCvvw5caqidbpQRYW2mBtXIX2WhofNXTEe7NyxTb0P6J62kAAWLwn0HuMF1Fw=="], - "@peculiar/asn1-rsa": ["@peculiar/asn1-rsa@2.5.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.5.0", "@peculiar/asn1-x509": "^2.5.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-qMZ/vweiTHy9syrkkqWFvbT3eLoedvamcUdnnvwyyUNv5FgFXA3KP8td+ATibnlZ0EANW5PYRm8E6MJzEB/72Q=="], + "@peculiar/asn1-rsa": ["@peculiar/asn1-rsa@2.6.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.6.0", "@peculiar/asn1-x509": "^2.6.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-Nu4C19tsrTsCp9fDrH+sdcOKoVfdfoQQ7S3VqjJU6vedR7tY3RLkQ5oguOIB3zFW33USDUuYZnPEQYySlgha4w=="], - "@peculiar/asn1-schema": ["@peculiar/asn1-schema@2.5.0", "", { "dependencies": { "asn1js": "^3.0.6", "pvtsutils": "^1.3.6", "tslib": "^2.8.1" } }, "sha512-YM/nFfskFJSlHqv59ed6dZlLZqtZQwjRVJ4bBAiWV08Oc+1rSd5lDZcBEx0lGDHfSoH3UziI2pXt2UM33KerPQ=="], + "@peculiar/asn1-schema": ["@peculiar/asn1-schema@2.6.0", "", { "dependencies": { "asn1js": "^3.0.6", "pvtsutils": "^1.3.6", "tslib": "^2.8.1" } }, "sha512-xNLYLBFTBKkCzEZIw842BxytQQATQv+lDTCEMZ8C196iJcJJMBUZxrhSTxLaohMyKK8QlzRNTRkUmanucnDSqg=="], - "@peculiar/asn1-x509": ["@peculiar/asn1-x509@2.5.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.5.0", "asn1js": "^3.0.6", "pvtsutils": "^1.3.6", "tslib": "^2.8.1" } }, "sha512-CpwtMCTJvfvYTFMuiME5IH+8qmDe3yEWzKHe7OOADbGfq7ohxeLaXwQo0q4du3qs0AII3UbLCvb9NF/6q0oTKQ=="], + "@peculiar/asn1-x509": ["@peculiar/asn1-x509@2.6.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.6.0", "asn1js": "^3.0.6", "pvtsutils": "^1.3.6", "tslib": "^2.8.1" } }, "sha512-uzYbPEpoQiBoTq0/+jZtpM6Gq6zADBx+JNFP3yqRgziWBxQ/Dt/HcuvRfm9zJTPdRcBqPNdaRHTVwpyiq6iNMA=="], - "@peculiar/asn1-x509-attr": ["@peculiar/asn1-x509-attr@2.5.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.5.0", "@peculiar/asn1-x509": "^2.5.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-9f0hPOxiJDoG/bfNLAFven+Bd4gwz/VzrCIIWc1025LEI4BXO0U5fOCTNDPbbp2ll+UzqKsZ3g61mpBp74gk9A=="], + "@peculiar/asn1-x509-attr": ["@peculiar/asn1-x509-attr@2.6.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.6.0", "@peculiar/asn1-x509": "^2.6.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-MuIAXFX3/dc8gmoZBkwJWxUWOSvG4MMDntXhrOZpJVMkYX+MYc/rUAU2uJOved9iJEoiUx7//3D8oG83a78UJA=="], - "@peculiar/x509": ["@peculiar/x509@1.14.0", "", { "dependencies": { "@peculiar/asn1-cms": "^2.5.0", "@peculiar/asn1-csr": "^2.5.0", "@peculiar/asn1-ecc": "^2.5.0", "@peculiar/asn1-pkcs9": "^2.5.0", "@peculiar/asn1-rsa": "^2.5.0", "@peculiar/asn1-schema": "^2.5.0", "@peculiar/asn1-x509": "^2.5.0", "pvtsutils": "^1.3.6", "reflect-metadata": "^0.2.2", "tslib": "^2.8.1", "tsyringe": "^4.10.0" } }, "sha512-Yc4PDxN3OrxUPiXgU63c+ZRXKGE8YKF2McTciYhUHFtHVB0KMnjeFSU0qpztGhsp4P0uKix4+J2xEpIEDu8oXg=="], + "@peculiar/x509": ["@peculiar/x509@1.14.3", "", { "dependencies": { "@peculiar/asn1-cms": "^2.6.0", "@peculiar/asn1-csr": "^2.6.0", "@peculiar/asn1-ecc": "^2.6.0", "@peculiar/asn1-pkcs9": "^2.6.0", "@peculiar/asn1-rsa": "^2.6.0", "@peculiar/asn1-schema": "^2.6.0", "@peculiar/asn1-x509": "^2.6.0", "pvtsutils": "^1.3.6", "reflect-metadata": "^0.2.2", "tslib": "^2.8.1", "tsyringe": "^4.10.0" } }, "sha512-C2Xj8FZ0uHWeCXXqX5B4/gVFQmtSkiuOolzAgutjTfseNOHT3pUjljDZsTSxXFGgio54bCzVFqmEOUrIVk8RDA=="], + + "@pinojs/redact": ["@pinojs/redact@0.4.0", "", {}, "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg=="], "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], @@ -378,7 +381,7 @@ "@radix-ui/react-select": ["@radix-ui/react-select@2.2.6", "", { "dependencies": { "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-layout-effect": "1.1.1", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-visually-hidden": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ=="], - "@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], + "@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.4", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA=="], "@radix-ui/react-tooltip": ["@radix-ui/react-tooltip@1.2.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-visually-hidden": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg=="], @@ -402,53 +405,59 @@ "@radix-ui/rect": ["@radix-ui/rect@1.1.1", "", {}, "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw=="], - "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.52.4", "", { "os": "android", "cpu": "arm" }, "sha512-BTm2qKNnWIQ5auf4deoetINJm2JzvihvGb9R6K/ETwKLql/Bb3Eg2H1FBp1gUb4YGbydMA3jcmQTR73q7J+GAA=="], + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.57.1", "", { "os": "android", "cpu": "arm" }, "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg=="], + + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.57.1", "", { "os": "android", "cpu": "arm64" }, "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w=="], + + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.57.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg=="], + + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.57.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w=="], - "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.52.4", "", { "os": "android", "cpu": "arm64" }, "sha512-P9LDQiC5vpgGFgz7GSM6dKPCiqR3XYN1WwJKA4/BUVDjHpYsf3iBEmVz62uyq20NGYbiGPR5cNHI7T1HqxNs2w=="], + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.57.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug=="], - "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.52.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-QRWSW+bVccAvZF6cbNZBJwAehmvG9NwfWHwMy4GbWi/BQIA/laTIktebT2ipVjNncqE6GLPxOok5hsECgAxGZg=="], + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.57.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q=="], - "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.52.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-hZgP05pResAkRJxL1b+7yxCnXPGsXU0fG9Yfd6dUaoGk+FhdPKCJ5L1Sumyxn8kvw8Qi5PvQ8ulenUbRjzeCTw=="], + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.57.1", "", { "os": "linux", "cpu": "arm" }, "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw=="], - "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.52.4", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-xmc30VshuBNUd58Xk4TKAEcRZHaXlV+tCxIXELiE9sQuK3kG8ZFgSPi57UBJt8/ogfhAF5Oz4ZSUBN77weM+mQ=="], + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.57.1", "", { "os": "linux", "cpu": "arm" }, "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw=="], - "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.52.4", "", { "os": "freebsd", "cpu": "x64" }, "sha512-WdSLpZFjOEqNZGmHflxyifolwAiZmDQzuOzIq9L27ButpCVpD7KzTRtEG1I0wMPFyiyUdOO+4t8GvrnBLQSwpw=="], + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.57.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g=="], - "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.52.4", "", { "os": "linux", "cpu": "arm" }, "sha512-xRiOu9Of1FZ4SxVbB0iEDXc4ddIcjCv2aj03dmW8UrZIW7aIQ9jVJdLBIhxBI+MaTnGAKyvMwPwQnoOEvP7FgQ=="], + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.57.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q=="], - "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.52.4", "", { "os": "linux", "cpu": "arm" }, "sha512-FbhM2p9TJAmEIEhIgzR4soUcsW49e9veAQCziwbR+XWB2zqJ12b4i/+hel9yLiD8pLncDH4fKIPIbt5238341Q=="], + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA=="], - "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.52.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-4n4gVwhPHR9q/g8lKCyz0yuaD0MvDf7dV4f9tHt0C73Mp8h38UCtSCSE6R9iBlTbXlmA8CjpsZoujhszefqueg=="], + "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw=="], - "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.52.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-u0n17nGA0nvi/11gcZKsjkLj1QIpAuPFQbR48Subo7SmZJnGxDpspyw2kbpuoQnyK+9pwf3pAoEXerJs/8Mi9g=="], + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.57.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w=="], - "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.52.4", "", { "os": "linux", "cpu": "none" }, "sha512-0G2c2lpYtbTuXo8KEJkDkClE/+/2AFPdPAbmaHoE870foRFs4pBrDehilMcrSScrN/fB/1HTaWO4bqw+ewBzMQ=="], + "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.57.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw=="], - "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.52.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-teSACug1GyZHmPDv14VNbvZFX779UqWTsd7KtTM9JIZRDI5NUwYSIS30kzI8m06gOPB//jtpqlhmraQ68b5X2g=="], + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A=="], - "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.52.4", "", { "os": "linux", "cpu": "none" }, "sha512-/MOEW3aHjjs1p4Pw1Xk4+3egRevx8Ji9N6HUIA1Ifh8Q+cg9dremvFCUbOX2Zebz80BwJIgCBUemjqhU5XI5Eg=="], + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw=="], - "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.52.4", "", { "os": "linux", "cpu": "none" }, "sha512-1HHmsRyh845QDpEWzOFtMCph5Ts+9+yllCrREuBR/vg2RogAQGGBRC8lDPrPOMnrdOJ+mt1WLMOC2Kao/UwcvA=="], + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.57.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg=="], - "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.52.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-seoeZp4L/6D1MUyjWkOMRU6/iLmCU2EjbMTyAG4oIOs1/I82Y5lTeaxW0KBfkUdHAWN7j25bpkt0rjnOgAcQcA=="], + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.57.1", "", { "os": "linux", "cpu": "x64" }, "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg=="], - "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.52.4", "", { "os": "linux", "cpu": "x64" }, "sha512-Wi6AXf0k0L7E2gteNsNHUs7UMwCIhsCTs6+tqQ5GPwVRWMaflqGec4Sd8n6+FNFDw9vGcReqk2KzBDhCa1DLYg=="], + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.57.1", "", { "os": "linux", "cpu": "x64" }, "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw=="], - "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.52.4", "", { "os": "linux", "cpu": "x64" }, "sha512-dtBZYjDmCQ9hW+WgEkaffvRRCKm767wWhxsFW3Lw86VXz/uJRuD438/XvbZT//B96Vs8oTA8Q4A0AfHbrxP9zw=="], + "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.57.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw=="], - "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.52.4", "", { "os": "none", "cpu": "arm64" }, "sha512-1ox+GqgRWqaB1RnyZXL8PD6E5f7YyRUJYnCqKpNzxzP0TkaUh112NDrR9Tt+C8rJ4x5G9Mk8PQR3o7Ku2RKqKA=="], + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.57.1", "", { "os": "none", "cpu": "arm64" }, "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ=="], - "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.52.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-8GKr640PdFNXwzIE0IrkMWUNUomILLkfeHjXBi/nUvFlpZP+FA8BKGKpacjW6OUUHaNI6sUURxR2U2g78FOHWQ=="], + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.57.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ=="], - "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.52.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-AIy/jdJ7WtJ/F6EcfOb2GjR9UweO0n43jNObQMb6oGxkYTfLcnN7vYYpG+CN3lLxrQkzWnMOoNSHTW54pgbVxw=="], + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.57.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew=="], - "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.52.4", "", { "os": "win32", "cpu": "x64" }, "sha512-UF9KfsH9yEam0UjTwAgdK0anlQ7c8/pWPU2yVjyWcF1I1thABt6WXE47cI71pGiZ8wGvxohBoLnxM04L/wj8mQ=="], + "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.57.1", "", { "os": "win32", "cpu": "x64" }, "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ=="], - "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.52.4", "", { "os": "win32", "cpu": "x64" }, "sha512-bf9PtUa0u8IXDVxzRToFQKsNCRz9qLYfR/MpECxl4mRoWYjAeFjgxj1XdZr2M/GNVpT05p+LgQOHopYDlUu6/w=="], + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.57.1", "", { "os": "win32", "cpu": "x64" }, "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA=="], "@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="], - "@rushstack/eslint-patch": ["@rushstack/eslint-patch@1.14.0", "", {}, "sha512-WJFej426qe4RWOm9MMtP4V3CV4AucXolQty+GRgAWLgQXmpCuwzs7hEpxxhSc/znXUSxum9d/P/32MW0FlAAlA=="], + "@rushstack/eslint-patch": ["@rushstack/eslint-patch@1.15.0", "", {}, "sha512-ojSshQPKwVvSMR8yT2L/QtUkV5SXi/IfDiJ4/8d6UbTPjiHVmxZzUAzGD8Tzks1b9+qQkZa0isUOvYObedITaw=="], "@scure/base": ["@scure/base@1.2.6", "", {}, "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg=="], @@ -456,13 +465,13 @@ "@scure/bip39": ["@scure/bip39@1.6.0", "", { "dependencies": { "@noble/hashes": "~1.8.0", "@scure/base": "~1.2.5" } }, "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A=="], - "@sinclair/typebox": ["@sinclair/typebox@0.34.41", "", {}, "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g=="], + "@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], "@sindresorhus/is": ["@sindresorhus/is@4.6.0", "", {}, "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw=="], "@sinonjs/commons": ["@sinonjs/commons@3.0.1", "", { "dependencies": { "type-detect": "4.0.8" } }, "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ=="], - "@sinonjs/fake-timers": ["@sinonjs/fake-timers@15.0.0", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-dlUB2oL+hDIYkIq/OWFBDhQAuU6kDey3eeMiYpVb7UXHhkMq/r1HloKXAbJwJZpYWkFWsydLjMqDpueMUEOjXQ=="], + "@sinonjs/fake-timers": ["@sinonjs/fake-timers@15.1.0", "", { "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "sha512-cqfapCxwTGsrR80FEgOoPsTonoefMBY7dnUEbQ+GRcved0jvkJLzvX6F4WtN+HBqbPX/SiFsIRUp+IrCW/2I2w=="], "@swc/counter": ["@swc/counter@0.1.3", "", {}, "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ=="], @@ -472,7 +481,7 @@ "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], - "@types/bun": ["@types/bun@1.3.1", "", { "dependencies": { "bun-types": "1.3.1" } }, "sha512-4jNMk2/K9YJtfqwoAa28c8wK+T7nvJFOjxI4h/7sORWcypRNxBpr+TPNaCfVWq70tLCJsqoFwcf0oI0JU/fvMQ=="], + "@types/bun": ["@types/bun@1.3.8", "", { "dependencies": { "bun-types": "1.3.8" } }, "sha512-3LvWJ2q5GerAXYxO2mffLTqOzEu5qnhEAlh48Vnu8WQfnmSwbgagjGZV6BoHKJztENYEDn6QmVd949W4uESRJA=="], "@types/d3-color": ["@types/d3-color@2.0.6", "", {}, "sha512-tbaFGDmJWHqnenvk3QGSvD3RVwr631BjKRD7Sc7VLRgrdX5mk5hTyoeBL6rXZaeoXzmZwIl1D2HPogEdt1rHBg=="], @@ -502,13 +511,13 @@ "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="], - "@types/node": ["@types/node@24.7.2", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-/NbVmcGTP+lj5oa4yiYxxeBjRivKQ5Ns1eSZeB99ExsEQ6rX5XYU1Zy/gGxY/ilqtD4Etx9mKyrPxZRetiahhA=="], + "@types/node": ["@types/node@24.10.11", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-/Af7O8r1frCVgOz0I62jWUtMohJ0/ZQU/ZoketltOJPZpnb17yoNc9BSoVuV9qlaIXJiPNOpsfq4ByFajSArNQ=="], "@types/pako": ["@types/pako@2.0.4", "", {}, "sha512-VWDCbrLeVXJM9fihYodcLiIv0ku+AlOa/TQ1SvYOaBuyrSKgEcro95LJyIsJ4vSo6BXIxOKxiJAat04CmST9Fw=="], "@types/prop-types": ["@types/prop-types@15.7.15", "", {}, "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw=="], - "@types/react": ["@types/react@18.3.26", "", { "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" } }, "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA=="], + "@types/react": ["@types/react@18.3.28", "", { "dependencies": { "@types/prop-types": "*", "csstype": "^3.2.2" } }, "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw=="], "@types/react-simple-maps": ["@types/react-simple-maps@3.0.6", "", { "dependencies": { "@types/d3-geo": "^2", "@types/d3-zoom": "^2", "@types/geojson": "*", "@types/react": "*" } }, "sha512-hR01RXt6VvsE41FxDd+Bqm1PPGdKbYjCYVtCgh38YeBPt46z3SwmWPWu2L3EdCAP6bd6VYEgztucihRw1C0Klg=="], @@ -518,29 +527,29 @@ "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], - "@types/yargs": ["@types/yargs@17.0.33", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA=="], + "@types/yargs": ["@types/yargs@17.0.35", "", { "dependencies": { "@types/yargs-parser": "*" } }, "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg=="], "@types/yargs-parser": ["@types/yargs-parser@21.0.3", "", {}, "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ=="], - "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.46.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.46.1", "@typescript-eslint/type-utils": "8.46.1", "@typescript-eslint/utils": "8.46.1", "@typescript-eslint/visitor-keys": "8.46.1", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.46.1", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-rUsLh8PXmBjdiPY+Emjz9NX2yHvhS11v0SR6xNJkm5GM1MO9ea/1GoDKlHHZGrOJclL/cZ2i/vRUYVtjRhrHVQ=="], + "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.54.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.54.0", "@typescript-eslint/type-utils": "8.54.0", "@typescript-eslint/utils": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.54.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ=="], - "@typescript-eslint/parser": ["@typescript-eslint/parser@8.46.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.46.1", "@typescript-eslint/types": "8.46.1", "@typescript-eslint/typescript-estree": "8.46.1", "@typescript-eslint/visitor-keys": "8.46.1", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-6JSSaBZmsKvEkbRUkf7Zj7dru/8ZCrJxAqArcLaVMee5907JdtEbKGsZ7zNiIm/UAkpGUkaSMZEXShnN2D1HZA=="], + "@typescript-eslint/parser": ["@typescript-eslint/parser@8.54.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.54.0", "@typescript-eslint/types": "8.54.0", "@typescript-eslint/typescript-estree": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA=="], - "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.46.1", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.46.1", "@typescript-eslint/types": "^8.46.1", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-FOIaFVMHzRskXr5J4Jp8lFVV0gz5ngv3RHmn+E4HYxSJ3DgDzU7fVI1/M7Ijh1zf6S7HIoaIOtln1H5y8V+9Zg=="], + "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.54.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.54.0", "@typescript-eslint/types": "^8.54.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g=="], - "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.46.1", "", { "dependencies": { "@typescript-eslint/types": "8.46.1", "@typescript-eslint/visitor-keys": "8.46.1" } }, "sha512-weL9Gg3/5F0pVQKiF8eOXFZp8emqWzZsOJuWRUNtHT+UNV2xSJegmpCNQHy37aEQIbToTq7RHKhWvOsmbM680A=="], + "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.54.0", "", { "dependencies": { "@typescript-eslint/types": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0" } }, "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg=="], - "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.46.1", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-X88+J/CwFvlJB+mK09VFqx5FE4H5cXD+H/Bdza2aEWkSb8hnWIQorNcscRl4IEo1Cz9VI/+/r/jnGWkbWPx54g=="], + "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.54.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw=="], - "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.46.1", "", { "dependencies": { "@typescript-eslint/types": "8.46.1", "@typescript-eslint/typescript-estree": "8.46.1", "@typescript-eslint/utils": "8.46.1", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-+BlmiHIiqufBxkVnOtFwjah/vrkF4MtKKvpXrKSPLCkCtAp8H01/VV43sfqA98Od7nJpDcFnkwgyfQbOG0AMvw=="], + "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.54.0", "", { "dependencies": { "@typescript-eslint/types": "8.54.0", "@typescript-eslint/typescript-estree": "8.54.0", "@typescript-eslint/utils": "8.54.0", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA=="], - "@typescript-eslint/types": ["@typescript-eslint/types@8.46.1", "", {}, "sha512-C+soprGBHwWBdkDpbaRC4paGBrkIXxVlNohadL5o0kfhsXqOC6GYH2S/Obmig+I0HTDl8wMaRySwrfrXVP8/pQ=="], + "@typescript-eslint/types": ["@typescript-eslint/types@8.54.0", "", {}, "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA=="], - "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.46.1", "", { "dependencies": { "@typescript-eslint/project-service": "8.46.1", "@typescript-eslint/tsconfig-utils": "8.46.1", "@typescript-eslint/types": "8.46.1", "@typescript-eslint/visitor-keys": "8.46.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-uIifjT4s8cQKFQ8ZBXXyoUODtRoAd7F7+G8MKmtzj17+1UbdzFl52AzRyZRyKqPHhgzvXunnSckVu36flGy8cg=="], + "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.54.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.54.0", "@typescript-eslint/tsconfig-utils": "8.54.0", "@typescript-eslint/types": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0", "debug": "^4.4.3", "minimatch": "^9.0.5", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA=="], - "@typescript-eslint/utils": ["@typescript-eslint/utils@8.46.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.46.1", "@typescript-eslint/types": "8.46.1", "@typescript-eslint/typescript-estree": "8.46.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-vkYUy6LdZS7q1v/Gxb2Zs7zziuXN0wxqsetJdeZdRe/f5dwJFglmuvZBfTUivCtjH725C1jWCDfpadadD95EDQ=="], + "@typescript-eslint/utils": ["@typescript-eslint/utils@8.54.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.54.0", "@typescript-eslint/types": "8.54.0", "@typescript-eslint/typescript-estree": "8.54.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA=="], - "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.46.1", "", { "dependencies": { "@typescript-eslint/types": "8.46.1", "eslint-visitor-keys": "^4.2.1" } }, "sha512-ptkmIf2iDkNUjdeu2bQqhFPV1m6qTnFFjg7PPDjxKWaMaP0Z6I9l30Jr3g5QqbZGdw8YdYvLp+XnqnWWZOg/NA=="], + "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.54.0", "", { "dependencies": { "@typescript-eslint/types": "8.54.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA=="], "@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="], @@ -592,7 +601,7 @@ "@zkpassport/utils": ["@zkpassport/utils@workspace:packages/zkpassport-utils"], - "abitype": ["abitype@1.1.0", "", { "peerDependencies": { "typescript": ">=5.0.4", "zod": "^3.22.0 || ^4.0.0" }, "optionalPeers": ["typescript", "zod"] }, "sha512-6Vh4HcRxNMLA0puzPjM5GBgT4aAcFGKZzSgAXvuZ27shJP6NEpielTuqbBmZILR5/xd0PizkBGy5hReKz9jl5A=="], + "abitype": ["abitype@1.2.3", "", { "peerDependencies": { "typescript": ">=5.0.4", "zod": "^3.22.0 || ^4.0.0" }, "optionalPeers": ["typescript", "zod"] }, "sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg=="], "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], @@ -636,7 +645,7 @@ "arraybuffer.prototype.slice": ["arraybuffer.prototype.slice@1.0.4", "", { "dependencies": { "array-buffer-byte-length": "^1.0.1", "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.5", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "is-array-buffer": "^3.0.4" } }, "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ=="], - "asn1js": ["asn1js@3.0.6", "", { "dependencies": { "pvtsutils": "^1.3.6", "pvutils": "^1.1.3", "tslib": "^2.8.1" } }, "sha512-UOCGPYbl0tv8+006qks/dTgV9ajs97X2p0FAbyS2iyCRrmLSRolDaHdp+v/CLgnzHc3fVB+CwYiUmei7ndFcgA=="], + "asn1js": ["asn1js@3.0.7", "", { "dependencies": { "pvtsutils": "^1.3.6", "pvutils": "^1.1.3", "tslib": "^2.8.1" } }, "sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ=="], "ast-types-flow": ["ast-types-flow@0.0.8", "", {}, "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ=="], @@ -646,7 +655,7 @@ "available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="], - "axe-core": ["axe-core@4.11.0", "", {}, "sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ=="], + "axe-core": ["axe-core@4.11.1", "", {}, "sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A=="], "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], @@ -666,7 +675,7 @@ "buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], - "bun-types": ["bun-types@1.3.1", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-NMrcy7smratanWJ2mMXdpatalovtxVggkj11bScuWuiOoXTiKIu2eVS1/7qbyI/4yHedtsn175n4Sm4JcdHLXw=="], + "bun-types": ["bun-types@1.3.8", "", { "dependencies": { "@types/node": "*" } }, "sha512-fL99nxdOWvV4LqjmC+8Q9kW3M4QTtTR1eePs94v5ctGqU8OeceWrSUaRw3JYb7tU3FkMIAjkueehrHPPPGKi5Q=="], "bundle-require": ["bundle-require@5.1.0", "", { "dependencies": { "load-tsconfig": "^0.2.3" }, "peerDependencies": { "esbuild": ">=0.18" } }, "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA=="], @@ -684,7 +693,7 @@ "camelcase-css": ["camelcase-css@2.0.1", "", {}, "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA=="], - "caniuse-lite": ["caniuse-lite@1.0.30001750", "", {}, "sha512-cuom0g5sdX6rw00qOoLNSFCJ9/mYIsuSOA+yzpDw8eopiFqcVwQvZHqov0vmEighRxX++cfC0Vg1G+1Iy/mSpQ=="], + "caniuse-lite": ["caniuse-lite@1.0.30001769", "", {}, "sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg=="], "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], @@ -692,7 +701,7 @@ "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], - "ci-info": ["ci-info@4.3.1", "", {}, "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA=="], + "ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], "cjs-module-lexer": ["cjs-module-lexer@1.4.3", "", {}, "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q=="], @@ -734,7 +743,7 @@ "csso": ["csso@5.0.5", "", { "dependencies": { "css-tree": "~2.2.0" } }, "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ=="], - "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], + "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], "d3-array": ["d3-array@3.2.4", "", { "dependencies": { "internmap": "1 - 2" } }, "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg=="], @@ -808,13 +817,13 @@ "environment": ["environment@1.1.0", "", {}, "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q=="], - "es-abstract": ["es-abstract@1.24.0", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.3.0", "get-proto": "^1.0.1", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-negative-zero": "^2.0.3", "is-regex": "^1.2.1", "is-set": "^2.0.3", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.1", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.4", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.4", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "stop-iteration-iterator": "^1.1.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.19" } }, "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg=="], + "es-abstract": ["es-abstract@1.24.1", "", { "dependencies": { "array-buffer-byte-length": "^1.0.2", "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "data-view-buffer": "^1.0.2", "data-view-byte-length": "^1.0.2", "data-view-byte-offset": "^1.0.1", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "es-set-tostringtag": "^2.1.0", "es-to-primitive": "^1.3.0", "function.prototype.name": "^1.1.8", "get-intrinsic": "^1.3.0", "get-proto": "^1.0.1", "get-symbol-description": "^1.1.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "internal-slot": "^1.1.0", "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", "is-data-view": "^1.0.2", "is-negative-zero": "^2.0.3", "is-regex": "^1.2.1", "is-set": "^2.0.3", "is-shared-array-buffer": "^1.0.4", "is-string": "^1.1.1", "is-typed-array": "^1.1.15", "is-weakref": "^1.1.1", "math-intrinsics": "^1.1.0", "object-inspect": "^1.13.4", "object-keys": "^1.1.1", "object.assign": "^4.1.7", "own-keys": "^1.0.1", "regexp.prototype.flags": "^1.5.4", "safe-array-concat": "^1.1.3", "safe-push-apply": "^1.0.0", "safe-regex-test": "^1.1.0", "set-proto": "^1.0.0", "stop-iteration-iterator": "^1.1.0", "string.prototype.trim": "^1.2.10", "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", "typed-array-buffer": "^1.0.3", "typed-array-byte-length": "^1.0.3", "typed-array-byte-offset": "^1.0.4", "typed-array-length": "^1.0.7", "unbox-primitive": "^1.1.0", "which-typed-array": "^1.1.19" } }, "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw=="], "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], - "es-iterator-helpers": ["es-iterator-helpers@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-abstract": "^1.23.6", "es-errors": "^1.3.0", "es-set-tostringtag": "^2.0.3", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.6", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", "iterator.prototype": "^1.1.4", "safe-array-concat": "^1.1.3" } }, "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w=="], + "es-iterator-helpers": ["es-iterator-helpers@1.2.2", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.4", "define-properties": "^1.2.1", "es-abstract": "^1.24.1", "es-errors": "^1.3.0", "es-set-tostringtag": "^2.1.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.3.0", "globalthis": "^1.0.4", "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", "has-proto": "^1.2.0", "has-symbols": "^1.1.0", "internal-slot": "^1.1.0", "iterator.prototype": "^1.1.5", "safe-array-concat": "^1.1.3" } }, "sha512-BrUQ0cPTB/IwXj23HtwHjS9n7O4h9FX94b4xc5zlTHxeLgTAdzYUDyy6KdExAl9lbN5rtfe44xpjpmj9grxs5w=="], "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], @@ -824,7 +833,7 @@ "es-to-primitive": ["es-to-primitive@1.3.0", "", { "dependencies": { "is-callable": "^1.2.7", "is-date-object": "^1.0.5", "is-symbol": "^1.0.4" } }, "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g=="], - "esbuild": ["esbuild@0.25.10", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.10", "@esbuild/android-arm": "0.25.10", "@esbuild/android-arm64": "0.25.10", "@esbuild/android-x64": "0.25.10", "@esbuild/darwin-arm64": "0.25.10", "@esbuild/darwin-x64": "0.25.10", "@esbuild/freebsd-arm64": "0.25.10", "@esbuild/freebsd-x64": "0.25.10", "@esbuild/linux-arm": "0.25.10", "@esbuild/linux-arm64": "0.25.10", "@esbuild/linux-ia32": "0.25.10", "@esbuild/linux-loong64": "0.25.10", "@esbuild/linux-mips64el": "0.25.10", "@esbuild/linux-ppc64": "0.25.10", "@esbuild/linux-riscv64": "0.25.10", "@esbuild/linux-s390x": "0.25.10", "@esbuild/linux-x64": "0.25.10", "@esbuild/netbsd-arm64": "0.25.10", "@esbuild/netbsd-x64": "0.25.10", "@esbuild/openbsd-arm64": "0.25.10", "@esbuild/openbsd-x64": "0.25.10", "@esbuild/openharmony-arm64": "0.25.10", "@esbuild/sunos-x64": "0.25.10", "@esbuild/win32-arm64": "0.25.10", "@esbuild/win32-ia32": "0.25.10", "@esbuild/win32-x64": "0.25.10" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ=="], + "esbuild": ["esbuild@0.27.3", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.3", "@esbuild/android-arm": "0.27.3", "@esbuild/android-arm64": "0.27.3", "@esbuild/android-x64": "0.27.3", "@esbuild/darwin-arm64": "0.27.3", "@esbuild/darwin-x64": "0.27.3", "@esbuild/freebsd-arm64": "0.27.3", "@esbuild/freebsd-x64": "0.27.3", "@esbuild/linux-arm": "0.27.3", "@esbuild/linux-arm64": "0.27.3", "@esbuild/linux-ia32": "0.27.3", "@esbuild/linux-loong64": "0.27.3", "@esbuild/linux-mips64el": "0.27.3", "@esbuild/linux-ppc64": "0.27.3", "@esbuild/linux-riscv64": "0.27.3", "@esbuild/linux-s390x": "0.27.3", "@esbuild/linux-x64": "0.27.3", "@esbuild/netbsd-arm64": "0.27.3", "@esbuild/netbsd-x64": "0.27.3", "@esbuild/openbsd-arm64": "0.27.3", "@esbuild/openbsd-x64": "0.27.3", "@esbuild/openharmony-arm64": "0.27.3", "@esbuild/sunos-x64": "0.27.3", "@esbuild/win32-arm64": "0.27.3", "@esbuild/win32-ia32": "0.27.3", "@esbuild/win32-x64": "0.27.3" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg=="], "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], @@ -846,7 +855,7 @@ "eslint-plugin-jsx-a11y": ["eslint-plugin-jsx-a11y@6.10.2", "", { "dependencies": { "aria-query": "^5.3.2", "array-includes": "^3.1.8", "array.prototype.flatmap": "^1.3.2", "ast-types-flow": "^0.0.8", "axe-core": "^4.10.0", "axobject-query": "^4.1.0", "damerau-levenshtein": "^1.0.8", "emoji-regex": "^9.2.2", "hasown": "^2.0.2", "jsx-ast-utils": "^3.3.5", "language-tags": "^1.0.9", "minimatch": "^3.1.2", "object.fromentries": "^2.0.8", "safe-regex-test": "^1.0.3", "string.prototype.includes": "^2.0.1" }, "peerDependencies": { "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" } }, "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q=="], - "eslint-plugin-prettier": ["eslint-plugin-prettier@5.5.4", "", { "dependencies": { "prettier-linter-helpers": "^1.0.0", "synckit": "^0.11.7" }, "peerDependencies": { "@types/eslint": ">=8.0.0", "eslint": ">=8.0.0", "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", "prettier": ">=3.0.0" }, "optionalPeers": ["@types/eslint", "eslint-config-prettier"] }, "sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg=="], + "eslint-plugin-prettier": ["eslint-plugin-prettier@5.5.5", "", { "dependencies": { "prettier-linter-helpers": "^1.0.1", "synckit": "^0.11.12" }, "peerDependencies": { "@types/eslint": ">=8.0.0", "eslint": ">=8.0.0", "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", "prettier": ">=3.0.0" }, "optionalPeers": ["@types/eslint", "eslint-config-prettier"] }, "sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw=="], "eslint-plugin-react": ["eslint-plugin-react@7.37.5", "", { "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", "array.prototype.flatmap": "^1.3.3", "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", "es-iterator-helpers": "^1.2.1", "estraverse": "^5.3.0", "hasown": "^2.0.2", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", "object.entries": "^1.1.9", "object.fromentries": "^2.0.8", "object.values": "^1.2.1", "prop-types": "^15.8.1", "resolve": "^2.0.0-next.5", "semver": "^6.3.1", "string.prototype.matchall": "^4.0.12", "string.prototype.repeat": "^1.0.0" }, "peerDependencies": { "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA=="], @@ -858,7 +867,7 @@ "espree": ["espree@9.6.1", "", { "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.4.1" } }, "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ=="], - "esquery": ["esquery@1.6.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg=="], + "esquery": ["esquery@1.7.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g=="], "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], @@ -882,7 +891,7 @@ "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="], - "fastq": ["fastq@1.19.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ=="], + "fastq": ["fastq@1.20.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="], "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], @@ -928,9 +937,9 @@ "get-symbol-description": ["get-symbol-description@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6" } }, "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg=="], - "get-tsconfig": ["get-tsconfig@4.12.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-LScr2aNr2FbjAjZh2C6X6BxRx1/x+aTDExct/xyq2XKbYOiG5c0aK7pMsSuyc0brz3ibr/lbQiHD9jzt4lccJw=="], + "get-tsconfig": ["get-tsconfig@4.13.6", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw=="], - "glob": ["glob@11.0.3", "", { "dependencies": { "foreground-child": "^3.3.1", "jackspeak": "^4.1.1", "minimatch": "^10.0.3", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^2.0.0" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA=="], + "glob": ["glob@13.0.1", "", { "dependencies": { "minimatch": "^10.1.2", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-B7U/vJpE3DkJ5WXTgTpTRN63uV42DseiXXKMwG14LQBXmsdeIoHAPbU/MEo6II0k5ED74uc2ZGTC6MwHFQhF6w=="], "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], @@ -1046,7 +1055,7 @@ "iterator.prototype": ["iterator.prototype@1.1.5", "", { "dependencies": { "define-data-property": "^1.1.4", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.6", "get-proto": "^1.0.0", "has-symbols": "^1.1.0", "set-function-name": "^2.0.2" } }, "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g=="], - "jackspeak": ["jackspeak@4.1.1", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" } }, "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ=="], + "jackspeak": ["jackspeak@2.3.6", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ=="], "jest-diff": ["jest-diff@30.2.0", "", { "dependencies": { "@jest/diff-sequences": "30.0.1", "@jest/get-type": "30.1.0", "chalk": "^4.1.2", "pretty-format": "30.2.0" } }, "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A=="], @@ -1066,7 +1075,7 @@ "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], - "js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="], + "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], @@ -1100,15 +1109,13 @@ "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], - "lodash.sortby": ["lodash.sortby@4.7.0", "", {}, "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA=="], - "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], - "lru-cache": ["lru-cache@11.2.2", "", {}, "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg=="], + "lru-cache": ["lru-cache@11.2.5", "", {}, "sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw=="], "lucide-react": ["lucide-react@0.468.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" } }, "sha512-6koYRhnM2N0GGZIdXzSeiNwguv1gt/FAjZOiPl76roBi3xKEXa4WmfpxgQwTTL4KipXjefrnf3oV4IsYhi4JFA=="], - "magic-string": ["magic-string@0.30.19", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw=="], + "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], "marked": ["marked@9.1.6", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-jcByLnIFkd5gSXZmjNvS1TlmRhCXZjIzHYlaGkPlLIekG55JDR2Z4va9tZwCiP+/RDERiNhMOFu01xd6O5ct1Q=="], @@ -1138,7 +1145,7 @@ "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], - "msgpackr": ["msgpackr@1.11.5", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.2" } }, "sha512-UjkUHN0yqp9RWKy0Lplhh+wlpdt9oQBYgULZOiFhV3VclSF1JnSQWZ5r9gORQlNYaUKQoR8itv7g7z1xDDuACA=="], + "msgpackr": ["msgpackr@1.11.8", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.2" } }, "sha512-bC4UGzHhVvgDNS7kn9tV8fAucIYUBuGojcaLiz7v+P63Lmtm0Xeji8B/8tYKddALXxJLpwIeBmUN3u64C4YkRA=="], "msgpackr-extract": ["msgpackr-extract@3.0.3", "", { "dependencies": { "node-gyp-build-optional-packages": "5.2.2" }, "optionalDependencies": { "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3", "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3", "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3", "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" } }, "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA=="], @@ -1190,7 +1197,7 @@ "own-keys": ["own-keys@1.0.1", "", { "dependencies": { "get-intrinsic": "^1.2.6", "object-keys": "^1.1.1", "safe-push-apply": "^1.0.0" } }, "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg=="], - "ox": ["ox@0.9.6", "", { "dependencies": { "@adraffy/ens-normalize": "^1.11.0", "@noble/ciphers": "^1.3.0", "@noble/curves": "1.9.1", "@noble/hashes": "^1.8.0", "@scure/bip32": "^1.7.0", "@scure/bip39": "^1.6.0", "abitype": "^1.0.9", "eventemitter3": "5.0.1" }, "peerDependencies": { "typescript": ">=5.4.0" }, "optionalPeers": ["typescript"] }, "sha512-8SuCbHPvv2eZLYXrNmC0EC12rdzXQLdhnOMlHDW2wiCPLxBrOOJwX5L5E61by+UjTPOryqQiRSnjIKCI+GykKg=="], + "ox": ["ox@0.11.3", "", { "dependencies": { "@adraffy/ens-normalize": "^1.11.0", "@noble/ciphers": "^1.3.0", "@noble/curves": "1.9.1", "@noble/hashes": "^1.8.0", "@scure/bip32": "^1.7.0", "@scure/bip39": "^1.6.0", "abitype": "^1.2.3", "eventemitter3": "5.0.1" }, "peerDependencies": { "typescript": ">=5.4.0" }, "optionalPeers": ["typescript"] }, "sha512-1bWYGk/xZel3xro3l8WGg6eq4YEKlaqvyMtVhfMFpbJzK2F6rj4EDRtqDCWVEJMkzcmEi9uW2QxsqELokOlarw=="], "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], @@ -1216,7 +1223,7 @@ "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], - "path-scurry": ["path-scurry@2.0.0", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg=="], + "path-scurry": ["path-scurry@2.0.1", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA=="], "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], @@ -1226,11 +1233,11 @@ "pify": ["pify@2.3.0", "", {}, "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog=="], - "pino": ["pino@9.13.1", "", { "dependencies": { "atomic-sleep": "^1.0.0", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^5.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "slow-redact": "^0.3.0", "sonic-boom": "^4.0.1", "thread-stream": "^3.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-Szuj+ViDTjKPQYiKumGmEn3frdl+ZPSdosHyt9SnUevFosOkMY2b7ipxlEctNKPmMD/VibeBI+ZcZCJK+4DPuw=="], + "pino": ["pino@9.14.0", "", { "dependencies": { "@pinojs/redact": "^0.4.0", "atomic-sleep": "^1.0.0", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^5.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "sonic-boom": "^4.0.1", "thread-stream": "^3.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-8OEwKp5juEvb/MjpIc4hjqfgCNysrS94RIOMXYvpYCdm/jglrKEiAYmiumbmGhCvs+IcInsphYDFwqrjr7398w=="], "pino-abstract-transport": ["pino-abstract-transport@2.0.0", "", { "dependencies": { "split2": "^4.0.0" } }, "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw=="], - "pino-std-serializers": ["pino-std-serializers@7.0.0", "", {}, "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA=="], + "pino-std-serializers": ["pino-std-serializers@7.1.0", "", {}, "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw=="], "pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], @@ -1254,9 +1261,9 @@ "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], - "prettier": ["prettier@3.6.2", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ=="], + "prettier": ["prettier@3.8.1", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg=="], - "prettier-linter-helpers": ["prettier-linter-helpers@1.0.0", "", { "dependencies": { "fast-diff": "^1.1.2" } }, "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w=="], + "prettier-linter-helpers": ["prettier-linter-helpers@1.0.1", "", { "dependencies": { "fast-diff": "^1.1.2" } }, "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg=="], "pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="], @@ -1270,7 +1277,7 @@ "pvtsutils": ["pvtsutils@1.3.6", "", { "dependencies": { "tslib": "^2.8.1" } }, "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg=="], - "pvutils": ["pvutils@1.1.3", "", {}, "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ=="], + "pvutils": ["pvutils@1.1.5", "", {}, "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA=="], "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], @@ -1282,7 +1289,7 @@ "react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], - "react-remove-scroll": ["react-remove-scroll@2.7.1", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA=="], + "react-remove-scroll": ["react-remove-scroll@2.7.2", "", { "dependencies": { "react-remove-scroll-bar": "^2.3.7", "react-style-singleton": "^2.2.3", "tslib": "^2.1.0", "use-callback-ref": "^1.3.3", "use-sidecar": "^1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q=="], "react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="], @@ -1312,7 +1319,7 @@ "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], - "resolve": ["resolve@1.22.10", "", { "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w=="], + "resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="], "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], @@ -1320,9 +1327,9 @@ "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], - "rimraf": ["rimraf@6.0.1", "", { "dependencies": { "glob": "^11.0.0", "package-json-from-dist": "^1.0.0" }, "bin": { "rimraf": "dist/esm/bin.mjs" } }, "sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A=="], + "rimraf": ["rimraf@6.1.2", "", { "dependencies": { "glob": "^13.0.0", "package-json-from-dist": "^1.0.1" }, "bin": { "rimraf": "dist/esm/bin.mjs" } }, "sha512-cFCkPslJv7BAXJsYlK1dZsbP8/ZNLkCAQ0bi1hf5EKX2QHegmDFEFA6QhuYJlk7UDdc+02JjO80YSOrWPpw06g=="], - "rollup": ["rollup@4.52.4", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.52.4", "@rollup/rollup-android-arm64": "4.52.4", "@rollup/rollup-darwin-arm64": "4.52.4", "@rollup/rollup-darwin-x64": "4.52.4", "@rollup/rollup-freebsd-arm64": "4.52.4", "@rollup/rollup-freebsd-x64": "4.52.4", "@rollup/rollup-linux-arm-gnueabihf": "4.52.4", "@rollup/rollup-linux-arm-musleabihf": "4.52.4", "@rollup/rollup-linux-arm64-gnu": "4.52.4", "@rollup/rollup-linux-arm64-musl": "4.52.4", "@rollup/rollup-linux-loong64-gnu": "4.52.4", "@rollup/rollup-linux-ppc64-gnu": "4.52.4", "@rollup/rollup-linux-riscv64-gnu": "4.52.4", "@rollup/rollup-linux-riscv64-musl": "4.52.4", "@rollup/rollup-linux-s390x-gnu": "4.52.4", "@rollup/rollup-linux-x64-gnu": "4.52.4", "@rollup/rollup-linux-x64-musl": "4.52.4", "@rollup/rollup-openharmony-arm64": "4.52.4", "@rollup/rollup-win32-arm64-msvc": "4.52.4", "@rollup/rollup-win32-ia32-msvc": "4.52.4", "@rollup/rollup-win32-x64-gnu": "4.52.4", "@rollup/rollup-win32-x64-msvc": "4.52.4", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-CLEVl+MnPAiKh5pl4dEWSyMTpuflgNQiLGhMv8ezD5W/qP8AKvmYpCOKRRNOh7oRKnauBZ4SyeYkMS+1VSyKwQ=="], + "rollup": ["rollup@4.57.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.57.1", "@rollup/rollup-android-arm64": "4.57.1", "@rollup/rollup-darwin-arm64": "4.57.1", "@rollup/rollup-darwin-x64": "4.57.1", "@rollup/rollup-freebsd-arm64": "4.57.1", "@rollup/rollup-freebsd-x64": "4.57.1", "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", "@rollup/rollup-linux-arm-musleabihf": "4.57.1", "@rollup/rollup-linux-arm64-gnu": "4.57.1", "@rollup/rollup-linux-arm64-musl": "4.57.1", "@rollup/rollup-linux-loong64-gnu": "4.57.1", "@rollup/rollup-linux-loong64-musl": "4.57.1", "@rollup/rollup-linux-ppc64-gnu": "4.57.1", "@rollup/rollup-linux-ppc64-musl": "4.57.1", "@rollup/rollup-linux-riscv64-gnu": "4.57.1", "@rollup/rollup-linux-riscv64-musl": "4.57.1", "@rollup/rollup-linux-s390x-gnu": "4.57.1", "@rollup/rollup-linux-x64-gnu": "4.57.1", "@rollup/rollup-linux-x64-musl": "4.57.1", "@rollup/rollup-openbsd-x64": "4.57.1", "@rollup/rollup-openharmony-arm64": "4.57.1", "@rollup/rollup-win32-arm64-msvc": "4.57.1", "@rollup/rollup-win32-ia32-msvc": "4.57.1", "@rollup/rollup-win32-x64-gnu": "4.57.1", "@rollup/rollup-win32-x64-msvc": "4.57.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A=="], "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], @@ -1340,7 +1347,7 @@ "scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="], - "semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + "semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], "set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="], @@ -1366,11 +1373,9 @@ "slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], - "slow-redact": ["slow-redact@0.3.2", "", {}, "sha512-MseHyi2+E/hBRqdOi5COy6wZ7j7DxXRz9NkseavNYSvvWC06D8a5cidVZX3tcG5eCW3NIyVU4zT63hw0Q486jw=="], - "sonic-boom": ["sonic-boom@4.2.0", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww=="], - "source-map": ["source-map@0.8.0-beta.0", "", { "dependencies": { "whatwg-url": "^7.0.0" } }, "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA=="], + "source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], @@ -1412,7 +1417,7 @@ "styled-jsx": ["styled-jsx@5.1.1", "", { "dependencies": { "client-only": "0.0.1" }, "peerDependencies": { "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" } }, "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw=="], - "sucrase": ["sucrase@3.35.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", "glob": "^10.3.10", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", "ts-interface-checker": "^0.1.9" }, "bin": { "sucrase": "bin/sucrase", "sucrase-node": "bin/sucrase-node" } }, "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA=="], + "sucrase": ["sucrase@3.35.1", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", "tinyglobby": "^0.2.11", "ts-interface-checker": "^0.1.9" }, "bin": { "sucrase": "bin/sucrase", "sucrase-node": "bin/sucrase-node" } }, "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw=="], "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], @@ -1424,11 +1429,11 @@ "svgo": ["svgo@3.3.2", "", { "dependencies": { "@trysound/sax": "0.2.0", "commander": "^7.2.0", "css-select": "^5.1.0", "css-tree": "^2.3.1", "css-what": "^6.1.0", "csso": "^5.0.5", "picocolors": "^1.0.0" }, "bin": "./bin/svgo" }, "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw=="], - "synckit": ["synckit@0.11.11", "", { "dependencies": { "@pkgr/core": "^0.2.9" } }, "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw=="], + "synckit": ["synckit@0.11.12", "", { "dependencies": { "@pkgr/core": "^0.2.9" } }, "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ=="], - "tailwind-merge": ["tailwind-merge@2.6.0", "", {}, "sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA=="], + "tailwind-merge": ["tailwind-merge@2.6.1", "", {}, "sha512-Oo6tHdpZsGpkKG88HJ8RR1rg/RdnEkQEfMoEk2x1XRI3F1AxeU+ijRXpiVUF4UbLfcxxRGw6TbUINKYdWVsQTQ=="], - "tailwindcss": ["tailwindcss@3.4.18", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", "chokidar": "^3.6.0", "didyoumean": "^1.2.2", "dlv": "^1.1.3", "fast-glob": "^3.3.2", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "jiti": "^1.21.7", "lilconfig": "^3.1.3", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.1.1", "postcss": "^8.4.47", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", "postcss-nested": "^6.2.0", "postcss-selector-parser": "^6.1.2", "resolve": "^1.22.8", "sucrase": "^3.35.0" }, "bin": { "tailwind": "lib/cli.js", "tailwindcss": "lib/cli.js" } }, "sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ=="], + "tailwindcss": ["tailwindcss@3.4.19", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", "chokidar": "^3.6.0", "didyoumean": "^1.2.2", "dlv": "^1.1.3", "fast-glob": "^3.3.2", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "jiti": "^1.21.7", "lilconfig": "^3.1.3", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.1.1", "postcss": "^8.4.47", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", "postcss-nested": "^6.2.0", "postcss-selector-parser": "^6.1.2", "resolve": "^1.22.8", "sucrase": "^3.35.0" }, "bin": { "tailwind": "lib/cli.js", "tailwindcss": "lib/cli.js" } }, "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ=="], "tailwindcss-animate": ["tailwindcss-animate@1.0.7", "", { "peerDependencies": { "tailwindcss": ">=3.0.0 || insiders" } }, "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA=="], @@ -1448,11 +1453,9 @@ "topojson-client": ["topojson-client@3.1.0", "", { "dependencies": { "commander": "2" }, "bin": { "topo2geo": "bin/topo2geo", "topomerge": "bin/topomerge", "topoquantize": "bin/topoquantize" } }, "sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw=="], - "tr46": ["tr46@1.0.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA=="], - "tree-kill": ["tree-kill@1.2.2", "", { "bin": { "tree-kill": "cli.js" } }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="], - "ts-api-utils": ["ts-api-utils@2.1.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ=="], + "ts-api-utils": ["ts-api-utils@2.4.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA=="], "ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="], @@ -1460,23 +1463,23 @@ "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - "tsup": ["tsup@8.5.0", "", { "dependencies": { "bundle-require": "^5.1.0", "cac": "^6.7.14", "chokidar": "^4.0.3", "consola": "^3.4.0", "debug": "^4.4.0", "esbuild": "^0.25.0", "fix-dts-default-cjs-exports": "^1.0.0", "joycon": "^3.1.1", "picocolors": "^1.1.1", "postcss-load-config": "^6.0.1", "resolve-from": "^5.0.0", "rollup": "^4.34.8", "source-map": "0.8.0-beta.0", "sucrase": "^3.35.0", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.11", "tree-kill": "^1.2.2" }, "peerDependencies": { "@microsoft/api-extractor": "^7.36.0", "@swc/core": "^1", "postcss": "^8.4.12", "typescript": ">=4.5.0" }, "optionalPeers": ["@microsoft/api-extractor", "@swc/core", "postcss", "typescript"], "bin": { "tsup": "dist/cli-default.js", "tsup-node": "dist/cli-node.js" } }, "sha512-VmBp77lWNQq6PfuMqCHD3xWl22vEoWsKajkF8t+yMBawlUS8JzEI+vOVMeuNZIuMML8qXRizFKi9oD5glKQVcQ=="], + "tsup": ["tsup@8.5.1", "", { "dependencies": { "bundle-require": "^5.1.0", "cac": "^6.7.14", "chokidar": "^4.0.3", "consola": "^3.4.0", "debug": "^4.4.0", "esbuild": "^0.27.0", "fix-dts-default-cjs-exports": "^1.0.0", "joycon": "^3.1.1", "picocolors": "^1.1.1", "postcss-load-config": "^6.0.1", "resolve-from": "^5.0.0", "rollup": "^4.34.8", "source-map": "^0.7.6", "sucrase": "^3.35.0", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.11", "tree-kill": "^1.2.2" }, "peerDependencies": { "@microsoft/api-extractor": "^7.36.0", "@swc/core": "^1", "postcss": "^8.4.12", "typescript": ">=4.5.0" }, "optionalPeers": ["@microsoft/api-extractor", "@swc/core", "postcss", "typescript"], "bin": { "tsup": "dist/cli-default.js", "tsup-node": "dist/cli-node.js" } }, "sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing=="], "tsyringe": ["tsyringe@4.10.0", "", { "dependencies": { "tslib": "^1.9.3" } }, "sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw=="], - "turbo": ["turbo@2.6.0", "", { "optionalDependencies": { "turbo-darwin-64": "2.6.0", "turbo-darwin-arm64": "2.6.0", "turbo-linux-64": "2.6.0", "turbo-linux-arm64": "2.6.0", "turbo-windows-64": "2.6.0", "turbo-windows-arm64": "2.6.0" }, "bin": { "turbo": "bin/turbo" } }, "sha512-kC5VJqOXo50k0/0jnJDDjibLAXalqT9j7PQ56so0pN+81VR4Fwb2QgIE9dTzT3phqOTQuEXkPh3sCpnv5Isz2g=="], + "turbo": ["turbo@2.8.3", "", { "optionalDependencies": { "turbo-darwin-64": "2.8.3", "turbo-darwin-arm64": "2.8.3", "turbo-linux-64": "2.8.3", "turbo-linux-arm64": "2.8.3", "turbo-windows-64": "2.8.3", "turbo-windows-arm64": "2.8.3" }, "bin": { "turbo": "bin/turbo" } }, "sha512-8Osxz5Tu/Dw2kb31EAY+nhq/YZ3wzmQSmYa1nIArqxgCAldxv9TPlrAiaBUDVnKA4aiPn0OFBD1ACcpc5VFOAQ=="], - "turbo-darwin-64": ["turbo-darwin-64@2.6.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-6vHnLAubHj8Ib45Knu+oY0ZVCLO7WcibzAvt5b1E72YHqAs4y8meMAGMZM0jLqWPh/9maHDc16/qBCMxtW4pXg=="], + "turbo-darwin-64": ["turbo-darwin-64@2.8.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-4kXRLfcygLOeNcP6JquqRLmGB/ATjjfehiojL2dJkL7GFm3SPSXbq7oNj8UbD8XriYQ5hPaSuz59iF1ijPHkTw=="], - "turbo-darwin-arm64": ["turbo-darwin-arm64@2.6.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-IU+gWMEXNBw8H0pxvE7nPEa5p6yahxbN8g/Q4Bf0AHymsAFqsScgV0peeNbWybdmY9jk1LPbALOsF2kY1I7ZiQ=="], + "turbo-darwin-arm64": ["turbo-darwin-arm64@2.8.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-xF7uCeC0UY0Hrv/tqax0BMbFlVP1J/aRyeGQPZT4NjvIPj8gSPDgFhfkfz06DhUwDg5NgMo04uiSkAWE8WB/QQ=="], - "turbo-linux-64": ["turbo-linux-64@2.6.0", "", { "os": "linux", "cpu": "x64" }, "sha512-CKoiJ2ZFJLCDsWdRlZg+ew1BkGn8iCEGdePhISVpjsGwkJwSVhVu49z2zKdBeL1IhcSKS2YALwp9ellNZANJxw=="], + "turbo-linux-64": ["turbo-linux-64@2.8.3", "", { "os": "linux", "cpu": "x64" }, "sha512-vxMDXwaOjweW/4etY7BxrXCSkvtwh0PbwVafyfT1Ww659SedUxd5rM3V2ZCmbwG8NiCfY7d6VtxyHx3Wh1GoZA=="], - "turbo-linux-arm64": ["turbo-linux-arm64@2.6.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-WroVCdCvJbrhNxNdw7XB7wHAfPPJPV+IXY+ZKNed+9VdfBu/2mQNfKnvqTuFTH7n+Pdpv8to9qwhXRTJe26upg=="], + "turbo-linux-arm64": ["turbo-linux-arm64@2.8.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-mQX7uYBZFkuPLLlKaNe9IjR1JIef4YvY8f21xFocvttXvdPebnq3PK1Zjzl9A1zun2BEuWNUwQIL8lgvN9Pm3Q=="], - "turbo-windows-64": ["turbo-windows-64@2.6.0", "", { "os": "win32", "cpu": "x64" }, "sha512-7pZo5aGQPR+A7RMtWCZHusarJ6y15LQ+o3jOmpMxTic/W6Bad+jSeqo07TWNIseIWjCVzrSv27+0odiYRYtQdA=="], + "turbo-windows-64": ["turbo-windows-64@2.8.3", "", { "os": "win32", "cpu": "x64" }, "sha512-YLGEfppGxZj3VWcNOVa08h6ISsVKiG85aCAWosOKNUjb6yErWEuydv6/qImRJUI+tDLvDvW7BxopAkujRnWCrw=="], - "turbo-windows-arm64": ["turbo-windows-arm64@2.6.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-1Ty+NwIksQY7AtFUCPrTpcKQE7zmd/f7aRjdT+qkqGFQjIjFYctEtN7qo4vpQPBgCfS1U3ka83A2u/9CfJQ3wQ=="], + "turbo-windows-arm64": ["turbo-windows-arm64@2.8.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-afTUGKBRmOJU1smQSBnFGcbq0iabAPwh1uXu2BVk7BREg30/1gMnJh9DFEQTah+UD3n3ru8V55J83RQNFfqoyw=="], "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], @@ -1494,11 +1497,11 @@ "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], - "ufo": ["ufo@1.6.1", "", {}, "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA=="], + "ufo": ["ufo@1.6.3", "", {}, "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="], "unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="], - "undici-types": ["undici-types@7.14.0", "", {}, "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA=="], + "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], "unicode-emoji-modifier-base": ["unicode-emoji-modifier-base@1.0.0", "", {}, "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g=="], @@ -1514,11 +1517,7 @@ "validate-npm-package-name": ["validate-npm-package-name@5.0.1", "", {}, "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ=="], - "viem": ["viem@2.38.2", "", { "dependencies": { "@noble/curves": "1.9.1", "@noble/hashes": "1.8.0", "@scure/bip32": "1.7.0", "@scure/bip39": "1.6.0", "abitype": "1.1.0", "isows": "1.0.7", "ox": "0.9.6", "ws": "8.18.3" }, "peerDependencies": { "typescript": ">=5.0.4" }, "optionalPeers": ["typescript"] }, "sha512-MJDiTDD9gfOT7lPQRimdmw+g46hU/aWJ3loqb+tN6UBOO00XEd0O4LJx+Kp5/uCRnMlJr8zJ1bNzCK7eG6gMjg=="], - - "webidl-conversions": ["webidl-conversions@4.0.2", "", {}, "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg=="], - - "whatwg-url": ["whatwg-url@7.1.0", "", { "dependencies": { "lodash.sortby": "^4.7.0", "tr46": "^1.0.1", "webidl-conversions": "^4.0.2" } }, "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg=="], + "viem": ["viem@2.45.1", "", { "dependencies": { "@noble/curves": "1.9.1", "@noble/hashes": "1.8.0", "@scure/bip32": "1.7.0", "@scure/bip39": "1.6.0", "abitype": "1.2.3", "isows": "1.0.7", "ox": "0.11.3", "ws": "8.18.3" }, "peerDependencies": { "typescript": ">=5.0.4" }, "optionalPeers": ["typescript"] }, "sha512-LN6Pp7vSfv50LgwhkfSbIXftAM5J89lP9x8TeDa8QM7o41IxlHrDh0F9X+FfnCWtsz11pEVV5sn+yBUoOHNqYA=="], "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], @@ -1528,19 +1527,19 @@ "which-collection": ["which-collection@1.0.2", "", { "dependencies": { "is-map": "^2.0.3", "is-set": "^2.0.3", "is-weakmap": "^2.0.2", "is-weakset": "^2.0.3" } }, "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw=="], - "which-typed-array": ["which-typed-array@1.1.19", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" } }, "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw=="], + "which-typed-array": ["which-typed-array@1.1.20", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" } }, "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg=="], "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], "world-countries": ["world-countries@5.1.0", "", {}, "sha512-CXR6EBvTbArDlDDIWU3gfKb7Qk0ck2WNZ234b/A0vuecPzIfzzxH+O6Ejnvg1sT8XuiZjVlzOH0h08ZtaO7g0w=="], - "wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], + "wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], - "ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="], + "ws": ["ws@8.19.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="], "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], @@ -1560,8 +1559,26 @@ "@isaacs/cliui/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], + "@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], + "@next/eslint-plugin-next/glob": ["glob@10.3.10", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^2.3.5", "minimatch": "^9.0.1", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", "path-scurry": "^1.10.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g=="], + "@obsidion/bridge/@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="], + + "@radix-ui/react-collection/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], + + "@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], + + "@radix-ui/react-select/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], + + "@radix-ui/react-tooltip/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="], + + "@scure/bip32/@noble/curves": ["@noble/curves@1.9.1", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA=="], + + "@scure/bip32/@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="], + + "@scure/bip39/@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="], + "@types/react-simple-maps/@types/d3-geo": ["@types/d3-geo@2.0.7", "", { "dependencies": { "@types/geojson": "*" } }, "sha512-RIXlxPdxvX+LAZFv+t78CuYpxYag4zuw9mZc+AwfB8tZpKU90rMEn2il2ADncmeZlb7nER9dDsJpRisA3lRvjA=="], "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], @@ -1570,8 +1587,6 @@ "anymatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], - "cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], - "csso/css-tree": ["css-tree@2.2.1", "", { "dependencies": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" } }, "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA=="], "eslint/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], @@ -1608,7 +1623,7 @@ "flat-cache/rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="], - "glob/minimatch": ["minimatch@10.0.3", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.0" } }, "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw=="], + "glob/minimatch": ["minimatch@10.1.2", "", { "dependencies": { "@isaacs/brace-expansion": "^5.0.1" } }, "sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw=="], "import-fresh/resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], @@ -1620,6 +1635,8 @@ "ox/@noble/curves": ["@noble/curves@1.9.1", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA=="], + "ox/@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="], + "parse5-htmlparser2-tree-adapter/parse5": ["parse5@6.0.1", "", {}, "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw=="], "pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], @@ -1640,8 +1657,6 @@ "sucrase/commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], - "sucrase/glob": ["glob@10.3.10", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^2.3.5", "minimatch": "^9.0.1", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", "path-scurry": "^1.10.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g=="], - "svgo/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="], "tailwindcss/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], @@ -1652,13 +1667,11 @@ "viem/@noble/curves": ["@noble/curves@1.9.1", "", { "dependencies": { "@noble/hashes": "1.8.0" } }, "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA=="], - "wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + "viem/@noble/hashes": ["@noble/hashes@1.8.0", "", {}, "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A=="], - "wrap-ansi/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], + "viem/ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="], - "wrap-ansi/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], - - "@next/eslint-plugin-next/glob/jackspeak": ["jackspeak@2.3.6", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ=="], + "@isaacs/cliui/wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], "@next/eslint-plugin-next/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], @@ -1674,12 +1687,6 @@ "react-simple-maps/d3-geo/d3-array": ["d3-array@2.12.1", "", { "dependencies": { "internmap": "^1.0.0" } }, "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ=="], - "sucrase/glob/jackspeak": ["jackspeak@2.3.6", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ=="], - - "sucrase/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - - "sucrase/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], - "tailwindcss/chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], "tailwindcss/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], @@ -1690,10 +1697,6 @@ "react-simple-maps/d3-geo/d3-array/internmap": ["internmap@1.0.1", "", {}, "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw=="], - "sucrase/glob/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], - - "sucrase/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], - "tailwindcss/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], } } diff --git a/packages/registry-explorer/components/ui/badge.tsx b/packages/registry-explorer/components/ui/badge.tsx index d5debacdd..781e5694f 100644 --- a/packages/registry-explorer/components/ui/badge.tsx +++ b/packages/registry-explorer/components/ui/badge.tsx @@ -23,8 +23,7 @@ const badgeVariants = cva( ) export interface BadgeProps - extends React.HTMLAttributes, - VariantProps {} + extends React.HTMLAttributes, VariantProps {} function Badge({ className, variant, ...props }: BadgeProps) { return
diff --git a/packages/registry-explorer/components/ui/button.tsx b/packages/registry-explorer/components/ui/button.tsx index dbe9d4b6e..f31c311b4 100644 --- a/packages/registry-explorer/components/ui/button.tsx +++ b/packages/registry-explorer/components/ui/button.tsx @@ -30,8 +30,7 @@ const buttonVariants = cva( ) export interface ButtonProps - extends React.ButtonHTMLAttributes, - VariantProps { + extends React.ButtonHTMLAttributes, VariantProps { asChild?: boolean } diff --git a/packages/registry-explorer/components/ui/input.tsx b/packages/registry-explorer/components/ui/input.tsx index 2dafa1997..1dc6f1af3 100644 --- a/packages/registry-explorer/components/ui/input.tsx +++ b/packages/registry-explorer/components/ui/input.tsx @@ -7,8 +7,7 @@ const inputVariants = cva( ) export interface InputProps - extends React.InputHTMLAttributes, - VariantProps {} + extends React.InputHTMLAttributes, VariantProps {} const Input = React.forwardRef( ({ className, type, ...props }, ref) => { diff --git a/packages/zkpassport-sdk/package.json b/packages/zkpassport-sdk/package.json index 950271381..d17fdb969 100644 --- a/packages/zkpassport-sdk/package.json +++ b/packages/zkpassport-sdk/package.json @@ -42,7 +42,7 @@ "dependencies": { "@aztec/bb.js": "2.0.3", "@noble/ciphers": "^1.2.1", - "@noble/hashes": "^1.7.2", + "@noble/hashes": "^2.0.1", "@noble/secp256k1": "^2.2.3", "@obsidion/bridge": "^0.11.2", "@zkpassport/registry": "workspace:*", diff --git a/packages/zkpassport-sdk/src/solidity-verifier.ts b/packages/zkpassport-sdk/src/solidity-verifier.ts index af05f13bf..c4698ca0a 100644 --- a/packages/zkpassport-sdk/src/solidity-verifier.ts +++ b/packages/zkpassport-sdk/src/solidity-verifier.ts @@ -22,8 +22,8 @@ import { } from "@zkpassport/utils" import { SolidityVerifierParameters } from "./types" import { DEFAULT_VALIDITY } from "./constants" -import { sha256 } from "@noble/hashes/sha2" -import { bytesToHex, hexToBytes } from "@noble/hashes/utils" +import { sha256 } from "@noble/hashes/sha2.js" +import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js" import ZKPassportVerifierAbi from "./assets/abi/ZKPassportVerifier.json" export class SolidityVerifier { diff --git a/packages/zkpassport-utils/package.json b/packages/zkpassport-utils/package.json index 63c2161ae..ccb2b4ba6 100644 --- a/packages/zkpassport-utils/package.json +++ b/packages/zkpassport-utils/package.json @@ -1,6 +1,6 @@ { "name": "@zkpassport/utils", - "version": "0.32.1", + "version": "0.33.2", "repository": { "type": "git", "url": "https://github.com/zkpassport/zkpassport-packages", @@ -101,8 +101,8 @@ "dependencies": { "@lapo/asn1js": "^2.0.4", "@noble/ciphers": "^1.0.0", - "@noble/curves": "^1.6.0", - "@noble/hashes": "^1.5.0", + "@noble/curves": "^2.0.1", + "@noble/hashes": "^2.0.1", "@noble/secp256k1": "^2.1.0", "@peculiar/asn1-cms": "^2.3.15", "@peculiar/asn1-ecc": "^2.3.15", diff --git a/packages/zkpassport-utils/src/circuit-matcher.ts b/packages/zkpassport-utils/src/circuit-matcher.ts index 52c2fdc9a..a06ad7051 100644 --- a/packages/zkpassport-utils/src/circuit-matcher.ts +++ b/packages/zkpassport-utils/src/circuit-matcher.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { sha256 } from "@noble/hashes/sha2" +import { sha256 } from "@noble/hashes/sha2.js" import { AsnParser } from "@peculiar/asn1-schema" import { AuthorityKeyIdentifier } from "@peculiar/asn1-x509" import { Alpha3Code } from "i18n-iso-countries" @@ -159,20 +159,32 @@ export function getTBSMaxLen(passport: PassportViewModel): number { } } +/** + * @deprecated Use getCscaForPassportAsync instead for more reliable certificate matching. + * This synchronous version uses only AKI/SKI matching without signature verification. + */ export function getCscaForPassport( dsc: DSC, certificates: PackagedCertificate[], ): PackagedCertificate | null { - const extensions = dsc.tbs.extensions + const { akiMatchedCert } = getCscaCandidates(dsc, certificates) + return akiMatchedCert +} - /*let notBefore: number | undefined - let notAfter: number | undefined - const pkupBuffer = extensions.get("privateKeyUsagePeriod")?.value.toBuffer() - if (pkupBuffer) { - const pkup = AsnParser.parse(pkupBuffer, PrivateKeyUsagePeriod) - notBefore = (pkup.notBefore?.getTime() ?? 0) / 1000 - notAfter = (pkup.notAfter?.getTime() ?? 0) / 1000 - }*/ +/** + * Find CSC candidates for a DSC using AKI/SKI matching + * Returns both the best AKI match and all certificates from the same country + */ +function getCscaCandidates( + dsc: DSC, + certificates: PackagedCertificate[], + skipAKIMatching: boolean = false, +): { + akiMatchedCert: PackagedCertificate | null + countryCerts: PackagedCertificate[] + formattedCountry: string +} { + const extensions = dsc.tbs.extensions let authorityKeyIdentifier: string | undefined const akiBuffer = extensions.get("authorityKeyIdentifier")?.value.toBuffer() @@ -192,44 +204,22 @@ export function getCscaForPassport( ) } - /*const checkAgainstPrivateKeyUsagePeriod = (cert: PackagedCertificate) => { - return ( - cert.private_key_usage_period && - cert.private_key_usage_period?.not_before && - cert.private_key_usage_period?.not_after && - notBefore && - notAfter && - notBefore >= (cert.private_key_usage_period?.not_before || 0) && - notAfter <= (cert.private_key_usage_period?.not_after || 0) - ) - }*/ + // Get all certificates from the same country + const countryCerts = certificates.filter((cert) => { + return cert.country.toLowerCase() === formattedCountry.toLowerCase() + }) // First try to find the CSC by looking at the authority key identifier // which should uniquely identify the CSC that signed the DSC - const validCertificates = certificates.filter((cert) => { - return ( - cert.country.toLowerCase() === formattedCountry.toLowerCase() && - checkAgainstAuthorityKeyIdentifier(cert) - ) - }) + const validCertificates = skipAKIMatching + ? [] + : countryCerts.filter(checkAgainstAuthorityKeyIdentifier) - // Using the private key usage period is not really reliable, so we don't use it - /*if (validCertificates.length === 0) { - // If no certificate was found in the previous step, we use find the CSCs which - // could have signed the DSCs according to their private key usage period - validCertificates = certificates.filter((cert) => { - return ( - cert.country.toLowerCase() === formattedCountry.toLowerCase() && - checkAgainstPrivateKeyUsagePeriod(cert) - ) - }) - }*/ - - if (validCertificates.length === 0) { - return null - } else if (validCertificates.length === 1) { - return validCertificates[0] - } else { + let akiMatchedCert: PackagedCertificate | null = null + + if (validCertificates.length === 1) { + akiMatchedCert = validCertificates[0] + } else if (validCertificates.length > 1) { // Support edge cases where multiple CSCs with the same characteristics are found const checkSignatureAlgorithm = (cert: PackagedCertificate) => { if (cert.signature_algorithm === "RSA-PSS") { @@ -241,15 +231,77 @@ export function getCscaForPassport( } return false } - return ( + akiMatchedCert = validCertificates.find((cert) => { return ( cert.hash_algorithm.replace("-", "").toLowerCase() === getDSCSignatureHashAlgorithm(dsc)?.toLowerCase() && checkSignatureAlgorithm(cert) ) - }) ?? null - ) + }) ?? validCertificates[0] + } + + return { akiMatchedCert, countryCerts, formattedCountry } +} + +/** + * Find the CSC (Country Signing Certificate) that signed the given DSC (Document Signer Certificate). + * + * This function uses a three-tier fallback mechanism: + * 1. AKI/SKI matching: First tries to match the DSC's Authority Key Identifier with + * a CSC's Subject Key Identifier, then verifies the signature. + * 2. Country-wide search: If AKI/SKI match fails signature verification, searches all + * CSCs from the same country and verifies signatures. + * 3. Fallback: If all signature verifications fail, returns the original AKI/SKI match + * (which may still be correct despite verification failure due to algorithm mismatches). + * + * @param dsc - The Document Signer Certificate to find the parent CSC for + * @param certificates - Array of all available CSC certificates + * @param skipAKIMatching - Whether to skip AKI/SKI matching and only use country-wide search + * @returns The matching CSC certificate, or null if none found + */ +export async function getCscaForPassportAsync( + dsc: DSC, + certificates: PackagedCertificate[], + skipAKIMatching: boolean = false, +): Promise { + const { verifyDscSignature } = await import("./signature-verification") + + const { akiMatchedCert, countryCerts } = getCscaCandidates(dsc, certificates, skipAKIMatching) + + // Step 1: If we found a certificate via AKI/SKI matching, verify the signature + if (akiMatchedCert) { + try { + const isValid = await verifyDscSignature(dsc, akiMatchedCert) + if (isValid) { + return akiMatchedCert + } + } catch { + // Signature verification failed, continue to fallback + } + } + + // Step 2: If AKI/SKI match failed or no match found, try all certificates from the same country + // This handles cases where the AKI/SKI might be wrong or missing + for (const cert of countryCerts) { + // Skip the one we already tried + if (cert === akiMatchedCert) continue + + try { + const isValid = await verifyDscSignature(dsc, cert) + if (isValid) { + return cert + } + } catch { + // Continue to next certificate + } } + + // Step 3: If all signature verifications failed, return the original AKI/SKI match + // This is a fallback for edge cases where: + // - The signature algorithm parameters might be incorrectly declared + // - Our verification implementation might not support some edge cases + // - The certificate data might be malformed but still valid + return akiMatchedCert } function getDSCDataInputs( @@ -395,7 +447,7 @@ export function getScopeHash(value?: string): bigint { return 0n } // Hash the value using SHA256 and truncate to 31 bytes (248 bits) - const sha2Hash = sha256(value).slice(0, 31) + const sha2Hash = sha256(new TextEncoder().encode(value)).slice(0, 31) // Convert the hash to a bigint const bytes = fromBytesToBigInt(Array.from(sha2Hash)) return bytes @@ -451,8 +503,8 @@ export async function getDSCCircuitInputs( path: (string | HexString)[] }, ) { - // Get the CSCA for this passport's DSC - const csca = getCscaForPassport(passport.sod.certificate, certificates) + // Get the CSCA for this passport's DSC using the async version with signature verification fallback + const csca = await getCscaForPassportAsync(passport.sod.certificate, certificates) if (!csca) throw new Error("Could not find CSCA for DSC") // Generate the certificate registry merkle proof const cscaLeaf = await getCertificateLeafHash(csca) diff --git a/packages/zkpassport-utils/src/circuits/age.ts b/packages/zkpassport-utils/src/circuits/age.ts index 0b49f7a12..74f51acfe 100644 --- a/packages/zkpassport-utils/src/circuits/age.ts +++ b/packages/zkpassport-utils/src/circuits/age.ts @@ -1,7 +1,7 @@ import { packBeBytesIntoField, numberToBytesBE } from "../utils" import { AgeCommittedInputs } from "../types" import { poseidon2HashAsync } from "@zkpassport/poseidon2" -import { sha256 } from "@noble/hashes/sha2" +import { sha256 } from "@noble/hashes/sha2.js" import { ProofType, ProofTypeLength } from "." export function getMinAgeFromCommittedInputs(committedInputs: AgeCommittedInputs): number { diff --git a/packages/zkpassport-utils/src/circuits/bind.ts b/packages/zkpassport-utils/src/circuits/bind.ts index c4f64e811..01bdc6427 100644 --- a/packages/zkpassport-utils/src/circuits/bind.ts +++ b/packages/zkpassport-utils/src/circuits/bind.ts @@ -8,7 +8,7 @@ import { } from "../utils" import { BindCommittedInputs, BoundData } from "../types" import { poseidon2HashAsync } from "@zkpassport/poseidon2" -import { sha256 } from "@noble/hashes/sha2" +import { sha256 } from "@noble/hashes/sha2.js" import { ProofType, ProofTypeLength } from "." import { Binary } from "../binary" diff --git a/packages/zkpassport-utils/src/circuits/country.ts b/packages/zkpassport-utils/src/circuits/country.ts index c8a2c4660..a3874c01e 100644 --- a/packages/zkpassport-utils/src/circuits/country.ts +++ b/packages/zkpassport-utils/src/circuits/country.ts @@ -2,7 +2,7 @@ import { Alpha3Code } from "i18n-iso-countries" import { poseidon2HashAsync } from "@zkpassport/poseidon2" import { numberToBytesBE, packBeBytesIntoField, rightPadArrayWithZeros } from "../utils" import { CountryCommittedInputs } from "../types" -import { sha256 } from "@noble/hashes/sha2" +import { sha256 } from "@noble/hashes/sha2.js" import { ProofType, ProofTypeLength } from "." export function getCountryWeightedSum(country: Alpha3Code): number { diff --git a/packages/zkpassport-utils/src/circuits/date.ts b/packages/zkpassport-utils/src/circuits/date.ts index 4cde1120f..1c01fb7df 100644 --- a/packages/zkpassport-utils/src/circuits/date.ts +++ b/packages/zkpassport-utils/src/circuits/date.ts @@ -1,4 +1,4 @@ -import { sha256 } from "@noble/hashes/sha2" +import { sha256 } from "@noble/hashes/sha2.js" import { DateCommittedInputs } from "../types" import { poseidon2HashAsync } from "@zkpassport/poseidon2" import { packBeBytesIntoField, numberToBytesBE } from "../utils" diff --git a/packages/zkpassport-utils/src/circuits/disclose.ts b/packages/zkpassport-utils/src/circuits/disclose.ts index 27909bda5..cc33eece7 100644 --- a/packages/zkpassport-utils/src/circuits/disclose.ts +++ b/packages/zkpassport-utils/src/circuits/disclose.ts @@ -7,7 +7,7 @@ import { } from "../utils" import { ProofData, ProofType, ProofTypeLength } from "." import { poseidon2HashAsync } from "@zkpassport/poseidon2" -import { sha256 } from "@noble/hashes/sha2" +import { sha256 } from "@noble/hashes/sha2.js" interface DisclosedDataRaw { issuingCountry: Uint8Array // 3 bytes diff --git a/packages/zkpassport-utils/src/circuits/facematch.ts b/packages/zkpassport-utils/src/circuits/facematch.ts index d9088122c..8de763a89 100644 --- a/packages/zkpassport-utils/src/circuits/facematch.ts +++ b/packages/zkpassport-utils/src/circuits/facematch.ts @@ -1,4 +1,4 @@ -import { sha256 } from "@noble/hashes/sha2" +import { sha256 } from "@noble/hashes/sha2.js" import { ProofType, ProofTypeLength } from "." import { numberToBytesBE, packBeBytesIntoField } from "../utils" import { poseidon2HashAsync } from "@zkpassport/poseidon2" diff --git a/packages/zkpassport-utils/src/circuits/sanctions/sanctions.ts b/packages/zkpassport-utils/src/circuits/sanctions/sanctions.ts index b8ba2f06d..c41f06d1c 100644 --- a/packages/zkpassport-utils/src/circuits/sanctions/sanctions.ts +++ b/packages/zkpassport-utils/src/circuits/sanctions/sanctions.ts @@ -7,7 +7,7 @@ import { stringToAsciiStringArray, withRetry, } from "@/utils" -import { sha256 } from "@noble/hashes/sha2" +import { sha256 } from "@noble/hashes/sha2.js" import { poseidon2, AsyncOrderedMT } from "@/merkle-tree" import { SortedNonMembershipProof } from "@/merkle-tree/async-ordered-mt" import { diff --git a/packages/zkpassport-utils/src/cms/constants.ts b/packages/zkpassport-utils/src/cms/constants.ts index c0fe9bd7c..9ae35b73d 100644 --- a/packages/zkpassport-utils/src/cms/constants.ts +++ b/packages/zkpassport-utils/src/cms/constants.ts @@ -1,7 +1,5 @@ import type { HashAlgorithm } from "../types" -import { p256 } from "@noble/curves/p256" -import { p384 } from "@noble/curves/p384" -import { p521 } from "@noble/curves/p521" +import { p256, p384, p521 } from "@noble/curves/nist.js" export const HASH_OIDS = { "1.3.14.3.2.26": "SHA-1", @@ -95,22 +93,22 @@ export const NIST_CURVES = { p: 0xffffffffffffffffffffffffffffffff000000000000000000000001n, }, "P-256": { - a: p256.CURVE.a, - b: p256.CURVE.b, - n: p256.CURVE.n, - p: p256.CURVE.Fp.ORDER, + a: p256.Point.CURVE().a, + b: p256.Point.CURVE().b, + n: p256.Point.CURVE().n, + p: p256.Point.CURVE().p, }, "P-384": { - a: p384.CURVE.a, - b: p384.CURVE.b, - n: p384.CURVE.n, - p: p384.CURVE.Fp.ORDER, + a: p384.Point.CURVE().a, + b: p384.Point.CURVE().b, + n: p384.Point.CURVE().n, + p: p384.Point.CURVE().p, }, "P-521": { - a: p521.CURVE.a, - b: p521.CURVE.b, - n: p521.CURVE.n, - p: p521.CURVE.Fp.ORDER, + a: p521.Point.CURVE().a, + b: p521.Point.CURVE().b, + n: p521.Point.CURVE().n, + p: p521.Point.CURVE().p, }, } diff --git a/packages/zkpassport-utils/src/index.ts b/packages/zkpassport-utils/src/index.ts index 0355209ed..64c82b248 100644 --- a/packages/zkpassport-utils/src/index.ts +++ b/packages/zkpassport-utils/src/index.ts @@ -9,6 +9,7 @@ export * from "./passport" export * from "./proof-parser" export * from "./recursion" export * from "./rsa" +export * from "./signature-verification" export * from "./types" export * from "./utils" export * from "./registry" diff --git a/packages/zkpassport-utils/src/signature-verification.ts b/packages/zkpassport-utils/src/signature-verification.ts new file mode 100644 index 000000000..4532da652 --- /dev/null +++ b/packages/zkpassport-utils/src/signature-verification.ts @@ -0,0 +1,835 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +/** + * DSC Signature Verification Utilities + * + * This module provides cross-platform (browser, Node.js, React Native) signature + * verification for DSC certificates signed by CSC certificates. + * + * Supports: + * - ECDSA with NIST curves (P-192, P-224, P-256, P-384, P-521) + * - ECDSA with Brainpool curves (r1 variants) + * - RSA with PKCS#1 v1.5 padding + * - RSA-PSS + * + * Hash algorithms: SHA-1, SHA-224, SHA-256, SHA-384, SHA-512 + */ + +import { sha1 } from "@noble/hashes/legacy.js" +import { sha224, sha256, sha384, sha512 } from "@noble/hashes/sha2.js" +import { p256, p384, p521 } from "@noble/curves/nist.js" +import { brainpoolP256r1, brainpoolP384r1, brainpoolP512r1 } from "@noble/curves/misc.js" +import { ecdsa, weierstrass } from "@noble/curves/abstract/weierstrass.js" +import type { ECDSA, WeierstrassOpts } from "@noble/curves/abstract/weierstrass.js" +import type { HashAlgorithm, PackagedCertificate, ECPublicKey, RSAPublicKey } from "./types" +import type { DSC } from "./passport/dsc" +import { BRAINPOOL_CURVES, NIST_CURVES } from "./cms/constants" + +type HashFunction = (data: Uint8Array) => Uint8Array + +const HASH_FUNCTIONS: Record = { + "SHA-1": sha1, + "SHA-224": sha224, + "SHA-256": sha256, + "SHA-384": sha384, + "SHA-512": sha512, +} + +// Define brainpool curves that are not in @noble/curves/misc +// Using the constants already defined in cms/constants.ts + +// brainpoolP224r1 +const brainpoolP224r1_CURVE: WeierstrassOpts = { + p: BRAINPOOL_CURVES.brainpoolP224r1.p, + a: BRAINPOOL_CURVES.brainpoolP224r1.a, + b: BRAINPOOL_CURVES.brainpoolP224r1.b, + n: BRAINPOOL_CURVES.brainpoolP224r1.n, + h: BigInt(1), + Gx: BigInt("0xd9029ad2c7e5cf4340823b2a87dc68c9e4ce3174c1e6efdee12c07d"), + Gy: BigInt("0x58aa56f772c0726f24c6b89e4ecdac24354b9e99caa3f6d3761402cd"), +} +const brainpoolP224r1Custom: ECDSA = ecdsa(weierstrass(brainpoolP224r1_CURVE), sha224) + +// P-192 custom curve (not in @noble/curves) +const p192_CURVE: WeierstrassOpts = { + p: NIST_CURVES["P-192"].p, + a: NIST_CURVES["P-192"].a, + b: NIST_CURVES["P-192"].b, + n: NIST_CURVES["P-192"].n, + h: BigInt(1), + Gx: BigInt("0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012"), + Gy: BigInt("0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811"), +} +const p192Custom: ECDSA = ecdsa(weierstrass(p192_CURVE), sha1) + +// P-224 custom curve (not in @noble/curves) +const p224_CURVE: WeierstrassOpts = { + p: NIST_CURVES["P-224"].p, + a: NIST_CURVES["P-224"].a, + b: NIST_CURVES["P-224"].b, + n: NIST_CURVES["P-224"].n, + h: BigInt(1), + Gx: BigInt("0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21"), + Gy: BigInt("0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34"), +} +const p224Custom: ECDSA = ecdsa(weierstrass(p224_CURVE), sha224) + +// Map curve names to their ECDSA implementations +const ECDSA_CURVES: Record = { + "P-192": p192Custom, + "P-224": p224Custom, + "P-256": p256, + "P-384": p384, + "P-521": p521, + "brainpoolP224r1": brainpoolP224r1Custom, + "brainpoolP256r1": brainpoolP256r1, + "brainpoolP384r1": brainpoolP384r1, + "brainpoolP512r1": brainpoolP512r1, +} + +/** + * Get reasonable hash algorithms to try based on public key size + * Returns algorithms in order of likelihood + */ +function getHashAlgorithmsForKeySize(keySizeBits: number): HashAlgorithm[] { + if (keySizeBits <= 192) { + return ["SHA-1", "SHA-224", "SHA-256", "SHA-384", "SHA-512"] + } else if (keySizeBits <= 256) { + return ["SHA-256", "SHA-1", "SHA-224", "SHA-384", "SHA-512"] + } else if (keySizeBits <= 384) { + return ["SHA-384", "SHA-256", "SHA-512", "SHA-1", "SHA-224"] + } else { + return ["SHA-512", "SHA-384", "SHA-256", "SHA-1", "SHA-224"] + } +} + +/** + * Parse an ECDSA signature from DER format to raw r||s format + */ +function parseECDSASignature(signature: Uint8Array, byteSize: number): Uint8Array { + // Check if already in raw format + if (signature.length === byteSize * 2) { + return signature + } + + // Parse DER format + if (signature[0] !== 0x30) { + // Not a valid ASN.1 sequence, return as-is + return signature + } + + const innerLengthIndex = signature[1] === signature.length - 2 ? 1 : 2 + const innerLength = signature[innerLengthIndex] + + if ( + signature[innerLengthIndex + 1] !== 0x02 || + innerLength !== signature.length - innerLengthIndex - 1 + ) { + return signature + } + + const rLength = signature[innerLengthIndex + 2] + let r = signature.slice(innerLengthIndex + 3, innerLengthIndex + 3 + rLength) + + if (signature[innerLengthIndex + 3 + rLength] !== 0x02) { + return signature + } + + const sLength = signature[innerLengthIndex + 3 + rLength + 1] + let s = signature.slice( + innerLengthIndex + 3 + rLength + 2, + innerLengthIndex + 3 + rLength + 2 + sLength, + ) + + // Remove leading zeros + while (r.length > 0 && r[0] === 0x00) { + r = r.slice(1) + } + while (s.length > 0 && s[0] === 0x00) { + s = s.slice(1) + } + + // Pad to expected byte size + const rPadded = new Uint8Array(byteSize) + const sPadded = new Uint8Array(byteSize) + rPadded.set(r, byteSize - r.length) + sPadded.set(s, byteSize - s.length) + + const result = new Uint8Array(byteSize * 2) + result.set(rPadded, 0) + result.set(sPadded, byteSize) + return result +} + +/** + * Verify an ECDSA signature + */ +export function verifyECDSASignature( + digest: Uint8Array, + signature: Uint8Array, + publicKey: ECPublicKey, +): boolean { + const curve = ECDSA_CURVES[publicKey.curve] + if (!curve) { + return false + } + + try { + const byteSize = Math.ceil(publicKey.key_size / 8) + const parsedSignature = parseECDSASignature(signature, byteSize) + + // Create uncompressed public key (0x04 || x || y) + const pubKeyX = Buffer.from(publicKey.public_key_x.replace("0x", ""), "hex") + const pubKeyY = Buffer.from(publicKey.public_key_y.replace("0x", ""), "hex") + + // Pad to expected byte size + const xPadded = new Uint8Array(byteSize) + const yPadded = new Uint8Array(byteSize) + xPadded.set(pubKeyX, byteSize - pubKeyX.length) + yPadded.set(pubKeyY, byteSize - pubKeyY.length) + + const uncompressedPubKey = new Uint8Array(1 + byteSize * 2) + uncompressedPubKey[0] = 0x04 + uncompressedPubKey.set(xPadded, 1) + uncompressedPubKey.set(yPadded, 1 + byteSize) + + return curve.verify(parsedSignature, digest, uncompressedPubKey, { + prehash: false, + lowS: false, + }) + } catch { + return false + } +} + +// Hash algorithms supported by Web Crypto for RSA signatures +// Note: SHA-1 and SHA-224 are NOT supported by Web Crypto +const WEB_CRYPTO_SUPPORTED_HASH_ALGORITHMS: HashAlgorithm[] = ["SHA-256", "SHA-384", "SHA-512"] + +/** + * Verify an RSA signature using Web Crypto API (works in browser, Node.js, and React Native with polyfill) + * Falls back to manual verification if Web Crypto is not available or if the hash algorithm is not supported + * + * @param message - The original message bytes (unhashed) + * @param digest - The pre-computed hash of the message (used for manual verification) + * @param signature - The signature to verify + * @param publicKey - The RSA public key + * @param hashAlgorithm - The hash algorithm to use + * @param isPSS - Whether to use RSA-PSS padding + */ +export async function verifyRSASignature( + message: Uint8Array, + digest: Uint8Array, + signature: Uint8Array, + publicKey: RSAPublicKey, + hashAlgorithm: HashAlgorithm, + isPSS: boolean, +): Promise { + try { + // Check if the hash algorithm is supported by Web Crypto + // SHA-1 and SHA-224 are NOT supported, so use manual verification directly + const isWebCryptoSupported = WEB_CRYPTO_SUPPORTED_HASH_ALGORITHMS.includes(hashAlgorithm) + + if (isWebCryptoSupported) { + // Try Web Crypto API first (available in browsers, Node.js 15+, and React Native with polyfill) + const crypto = getCryptoSubtle() + if (crypto) { + // Web Crypto expects the original data (not the hash) and will hash it internally + return await verifyRSAWithWebCrypto( + message, + signature, + publicKey, + hashAlgorithm, + isPSS, + crypto, + ) + } + } + + // Fallback to manual RSA verification for: + // - Environments without Web Crypto + // - Unsupported hash algorithms (SHA-1, SHA-224) + // Manual verification uses the pre-computed hash + return verifyRSAManual(digest, signature, publicKey, hashAlgorithm, isPSS) + } catch { + return false + } +} + +/** + * Convert a number to big-endian bytes (minimal representation, no leading zeros) + */ +function numberToBytesBE(num: number): Uint8Array { + if (num === 0) return new Uint8Array([0]) + const bytes: number[] = [] + while (num > 0) { + bytes.unshift(num & 0xff) + num = num >>> 8 + } + return new Uint8Array(bytes) +} + +/** + * Get the SubtleCrypto interface from various environments + */ +function getCryptoSubtle(): SubtleCrypto | null { + // Browser + if (typeof globalThis !== "undefined" && globalThis.crypto?.subtle) { + return globalThis.crypto.subtle + } + // Node.js + if (typeof globalThis !== "undefined" && (globalThis as any).crypto?.webcrypto?.subtle) { + return (globalThis as any).crypto.webcrypto.subtle + } + return null +} + +/** + * Verify RSA signature using Web Crypto API + * Web Crypto expects the original data (not the hash) and will hash it internally + * + * @param message - The original message bytes (unhashed) + * @param signature - The signature to verify + * @param publicKey - The RSA public key + * @param hashAlgorithm - The hash algorithm that Web Crypto will use internally + * @param isPSS - Whether to use RSA-PSS padding + * @param crypto - The SubtleCrypto instance + */ +async function verifyRSAWithWebCrypto( + message: Uint8Array, + signature: Uint8Array, + publicKey: RSAPublicKey, + hashAlgorithm: HashAlgorithm, + isPSS: boolean, + crypto: SubtleCrypto, +): Promise { + // Convert modulus to ArrayBuffer + const modulusBytes = new Uint8Array(Buffer.from(publicKey.modulus.replace("0x", ""), "hex")) + + // Convert exponent to big-endian bytes + const exponentBytes = numberToBytesBE(publicKey.exponent) + + // Create JWK for the public key + const jwk: JsonWebKey = { + kty: "RSA", + n: base64UrlEncode(modulusBytes), + e: base64UrlEncode(exponentBytes), + alg: isPSS + ? `PS${hashAlgorithm.replace("SHA-", "")}` + : `RS${hashAlgorithm.replace("SHA-", "")}`, + ext: true, + } + + const algorithm: RsaHashedImportParams = isPSS + ? { + name: "RSA-PSS", + hash: { name: hashAlgorithm }, + } + : { + name: "RSASSA-PKCS1-v1_5", + hash: { name: hashAlgorithm }, + } + + const verifyAlgorithm: RsaPssParams | Algorithm = isPSS + ? { + name: "RSA-PSS", + saltLength: getHashLength(hashAlgorithm), + } + : { + name: "RSASSA-PKCS1-v1_5", + } + + try { + const key = await crypto.importKey("jwk", jwk, algorithm, false, ["verify"]) + // Web Crypto will internally hash the message using the specified hashAlgorithm + // and then verify the signature against that hash + const signatureBuffer = new Uint8Array(signature).buffer + const dataBuffer = new Uint8Array(message).buffer + const result = await crypto.verify(verifyAlgorithm, key, signatureBuffer, dataBuffer) + return result + } catch { + // This can fail for unsupported algorithms (e.g., SHA-224 is not supported by Web Crypto for RSA) + // or for invalid keys/signatures - continue to next algorithm in the brute force loop + return false + } +} + +function base64UrlEncode(bytes: Uint8Array): string { + const base64 = Buffer.from(bytes).toString("base64") + return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "") +} + +function getHashLength(hashAlgorithm: HashAlgorithm): number { + switch (hashAlgorithm) { + case "SHA-1": + return 20 + case "SHA-224": + return 28 + case "SHA-256": + return 32 + case "SHA-384": + return 48 + case "SHA-512": + return 64 + default: + return 32 + } +} + +/** + * Manual RSA signature verification (fallback when Web Crypto is not available) + * This implements RSA PKCS#1 v1.5 and PSS verification using bigint arithmetic + * Based on RFC 8017 and RustCrypto/RSA implementation patterns + */ +function verifyRSAManual( + digest: Uint8Array, + signature: Uint8Array, + publicKey: RSAPublicKey, + hashAlgorithm: HashAlgorithm, + isPSS: boolean, +): boolean { + try { + const modulus = BigInt(publicKey.modulus) + const exponent = BigInt(publicKey.exponent) + const modulusBytes = Math.ceil(publicKey.key_size / 8) + + // Step 1: Signature length check (RFC 8017 Section 8.2.2 Step 1) + // The signature must be exactly k octets, where k is the length of the modulus in bytes + if (signature.length !== modulusBytes) { + // Try to handle signatures that are shorter (missing leading zeros) + if (signature.length < modulusBytes) { + const paddedSig = new Uint8Array(modulusBytes) + paddedSig.set(signature, modulusBytes - signature.length) + signature = paddedSig + } else { + return false + } + } + + // Convert signature to bigint + let sigInt = BigInt(0) + for (const byte of signature) { + sigInt = (sigInt << BigInt(8)) | BigInt(byte) + } + + // Step 2: Check signature is in valid range [0, n-1] + if (sigInt >= modulus) { + return false + } + + // Step 3: RSA verification primitive RSAVP1: m = s^e mod n + const message = modPow(sigInt, exponent, modulus) + + // Convert message back to bytes (I2OSP - Integer to Octet String Primitive) + const messageBytes = new Uint8Array(modulusBytes) + let temp = message + for (let i = modulusBytes - 1; i >= 0; i--) { + messageBytes[i] = Number(temp & BigInt(0xff)) + temp = temp >> BigInt(8) + } + + if (isPSS) { + // PSS verification with auto salt length detection + return verifyPSSPadding(messageBytes, digest, hashAlgorithm, publicKey.key_size) + } else { + return verifyPKCS1Padding(messageBytes, digest, hashAlgorithm) + } + } catch { + return false + } +} + +/** + * Modular exponentiation using square-and-multiply + */ +function modPow(base: bigint, exponent: bigint, modulus: bigint): bigint { + if (modulus === BigInt(1)) return BigInt(0) + let result = BigInt(1) + base = base % modulus + while (exponent > BigInt(0)) { + if (exponent % BigInt(2) === BigInt(1)) { + result = (result * base) % modulus + } + exponent = exponent >> BigInt(1) + base = (base * base) % modulus + } + return result +} + +// DigestInfo prefixes for PKCS#1 v1.5 (DER encoded) +const DIGEST_INFO_PREFIXES: Record = { + "SHA-1": new Uint8Array([ + 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14, + ]), + "SHA-224": new Uint8Array([ + 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, + 0x00, 0x04, 0x1c, + ]), + "SHA-256": new Uint8Array([ + 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, + 0x00, 0x04, 0x20, + ]), + "SHA-384": new Uint8Array([ + 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, + 0x00, 0x04, 0x30, + ]), + "SHA-512": new Uint8Array([ + 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, + 0x00, 0x04, 0x40, + ]), +} + +// Minimum padding length for PKCS#1 v1.5 (RFC 8017 Section 9.2) +// The padding string PS must be at least 8 bytes +const MIN_PKCS1_PADDING_LENGTH = 8 + +// DigestInfo prefixes WITHOUT NULL parameter (some implementations omit it) +// This is for compatibility - some signers produce signatures without the NULL +const DIGEST_INFO_PREFIXES_NO_NULL: Record = { + "SHA-1": new Uint8Array([ + 0x30, 0x1f, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14, + ]), + "SHA-224": new Uint8Array([ + 0x30, 0x2b, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x04, + 0x1c, + ]), + "SHA-256": new Uint8Array([ + 0x30, 0x2f, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x04, + 0x20, + ]), + "SHA-384": new Uint8Array([ + 0x30, 0x3f, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x04, + 0x30, + ]), + "SHA-512": new Uint8Array([ + 0x30, 0x4f, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x04, + 0x40, + ]), +} + +/** + * Verify PKCS#1 v1.5 padding according to RFC 8017 Section 8.2.2 + * EMSA-PKCS1-v1_5 verification + */ +function verifyPKCS1Padding( + decryptedMessage: Uint8Array, + expectedHash: Uint8Array, + hashAlgorithm: HashAlgorithm, +): boolean { + // PKCS#1 v1.5 format: 0x00 0x01 [0xFF padding] 0x00 [DigestInfo] [Hash] + // Step 1: Check the first two bytes + if (decryptedMessage[0] !== 0x00 || decryptedMessage[1] !== 0x01) { + return false + } + + // Step 2: Find the 0x00 separator after the padding + let separatorIndex = 2 + while (separatorIndex < decryptedMessage.length && decryptedMessage[separatorIndex] === 0xff) { + separatorIndex++ + } + + // Step 3: Check minimum padding length (RFC 8017 requires at least 8 bytes of 0xFF) + const paddingLength = separatorIndex - 2 + if (paddingLength < MIN_PKCS1_PADDING_LENGTH) { + return false + } + + // Step 4: Check the 0x00 separator exists + if (separatorIndex >= decryptedMessage.length || decryptedMessage[separatorIndex] !== 0x00) { + return false + } + + separatorIndex++ // Move past the 0x00 separator + + // Step 5: Extract and verify DigestInfo + Hash + const digestInfo = decryptedMessage.slice(separatorIndex) + + // Try with standard DigestInfo prefix (with NULL parameter) + const prefixWithNull = DIGEST_INFO_PREFIXES[hashAlgorithm] + if (verifyDigestInfo(digestInfo, expectedHash, prefixWithNull)) { + return true + } + + // Try with DigestInfo prefix without NULL parameter (for compatibility) + const prefixNoNull = DIGEST_INFO_PREFIXES_NO_NULL[hashAlgorithm] + if (verifyDigestInfo(digestInfo, expectedHash, prefixNoNull)) { + return true + } + + return false +} + +/** + * Verify DigestInfo structure matches the expected prefix and hash + */ +function verifyDigestInfo( + digestInfo: Uint8Array, + expectedHash: Uint8Array, + prefix: Uint8Array, +): boolean { + if (digestInfo.length !== prefix.length + expectedHash.length) { + return false + } + + let result = 0 + + // Check prefix + for (let i = 0; i < prefix.length; i++) { + result |= digestInfo[i] ^ prefix[i] + } + + // Check hash + for (let i = 0; i < expectedHash.length; i++) { + result |= digestInfo[prefix.length + i] ^ expectedHash[i] + } + + return result === 0 +} + +/** + * Verify PSS padding according to RFC 8017 Section 9.1.2 + * EMSA-PSS-VERIFY operation with auto salt length detection + */ +function verifyPSSPadding( + em: Uint8Array, + mHash: Uint8Array, + hashAlgorithm: HashAlgorithm, + modBits: number, +): boolean { + const hashFunc = HASH_FUNCTIONS[hashAlgorithm] + const hLen = getHashLength(hashAlgorithm) + + // emBits = modBits - 1 (RFC 8017 Section 8.1.2) + const emBits = modBits - 1 + const emLen = Math.ceil(emBits / 8) + + // Step 3: Check minimum length + // emLen must be at least hLen + sLen + 2, but we don't know sLen yet + // Minimum is when sLen = 0: emLen >= hLen + 2 + if (emLen < hLen + 2) { + return false + } + + // Adjust EM if it's longer than emLen (can happen with certain key sizes) + const emToUse = em.length > emLen ? em.slice(em.length - emLen) : em + if (emToUse.length < emLen) { + return false + } + + // Step 4: Check trailing byte (rightmost octet must be 0xbc) + if (emToUse[emLen - 1] !== 0xbc) { + return false + } + + // Step 5: Split EM into maskedDB and H + const dbLen = emLen - hLen - 1 + const maskedDB = emToUse.slice(0, dbLen) + const H = emToUse.slice(dbLen, dbLen + hLen) + + // Step 6: Check leading bits of maskedDB + // The leftmost 8*emLen - emBits bits must be zero + const leadingBits = 8 * emLen - emBits + const topMask = 0xff >> leadingBits + if ((maskedDB[0] & ~topMask) !== 0) { + return false + } + + // Step 7: Generate dbMask using MGF1 + const dbMask = mgf1(H, dbLen, hashFunc) + + // Step 8: Recover DB = maskedDB XOR dbMask + const DB = new Uint8Array(dbLen) + for (let i = 0; i < dbLen; i++) { + DB[i] = maskedDB[i] ^ dbMask[i] + } + + // Step 9: Clear the leftmost 8*emLen - emBits bits + DB[0] &= topMask + + // Step 10: Find the 0x01 separator and auto-detect salt length + // DB format: [0x00...] 0x01 [salt] + // Find the position of 0x01 separator + let separatorPos = -1 + for (let i = 0; i < dbLen; i++) { + if (DB[i] === 0x01) { + separatorPos = i + break + } else if (DB[i] !== 0x00) { + // All bytes before 0x01 must be 0x00 + return false + } + } + + if (separatorPos === -1) { + return false + } + + // Auto-detected salt length + const sLen = dbLen - separatorPos - 1 + + // Sanity check: salt length should not be negative + if (sLen < 0) { + return false + } + + // Step 11: Extract salt + const salt = DB.slice(separatorPos + 1) + + // Step 12: Compute M' = (0x00 * 8) || mHash || salt + const mPrime = new Uint8Array(8 + hLen + sLen) + // First 8 bytes are 0x00 (already initialized to zero) + mPrime.set(mHash, 8) + if (sLen > 0) { + mPrime.set(salt, 8 + hLen) + } + + // Step 13: Compute H' = Hash(M') + const HPrime = hashFunc(mPrime) + + // Step 14: Compare H and H' using constant-time comparison + if (H.length !== HPrime.length) { + return false + } + + let result = 0 + for (let i = 0; i < H.length; i++) { + result |= H[i] ^ HPrime[i] + } + + return result === 0 +} + +/** + * MGF1 (Mask Generation Function 1) + */ +function mgf1(seed: Uint8Array, maskLen: number, hashFunc: HashFunction): Uint8Array { + const hLen = hashFunc(new Uint8Array(0)).length + const mask = new Uint8Array(maskLen) + let offset = 0 + + for (let counter = 0; offset < maskLen; counter++) { + const C = new Uint8Array(4) + C[0] = (counter >> 24) & 0xff + C[1] = (counter >> 16) & 0xff + C[2] = (counter >> 8) & 0xff + C[3] = counter & 0xff + + const input = new Uint8Array(seed.length + 4) + input.set(seed) + input.set(C, seed.length) + + const hash = hashFunc(input) + const copyLen = Math.min(hLen, maskLen - offset) + mask.set(hash.slice(0, copyLen), offset) + offset += copyLen + } + + return mask +} + +/** + * Verify a DSC signature against a CSC certificate's public key + * Tries all hash algorithms if the specific one fails + */ +export async function verifyDscSignature(dsc: DSC, csc: PackagedCertificate): Promise { + const tbsBytes = dsc.tbs.bytes.toUInt8Array() + const signature = dsc.signature.toUInt8Array() + + // Determine signature type from CSC + const isECDSA = csc.public_key.type === "EC" + const isPSS = csc.signature_algorithm === "RSA-PSS" + + // Get the hash algorithms to try, ordered by likelihood based on key size + const keySizeBits = csc.public_key.key_size + const hashAlgorithmsToTry = getHashAlgorithmsForKeySize(keySizeBits) + + // Try the declared hash algorithm first if available + const declaredHashAlg = csc.hash_algorithm + if (declaredHashAlg && !hashAlgorithmsToTry.includes(declaredHashAlg)) { + hashAlgorithmsToTry.unshift(declaredHashAlg) + } else if (declaredHashAlg) { + // Move declared algorithm to front + const index = hashAlgorithmsToTry.indexOf(declaredHashAlg) + if (index > 0) { + hashAlgorithmsToTry.splice(index, 1) + hashAlgorithmsToTry.unshift(declaredHashAlg) + } + } + + // Try each hash algorithm + for (const hashAlgorithm of hashAlgorithmsToTry) { + const hashFunc = HASH_FUNCTIONS[hashAlgorithm] + if (!hashFunc) continue + + const tbsHash = hashFunc(tbsBytes) + + if (isECDSA) { + const ecPublicKey = csc.public_key as ECPublicKey + if (verifyECDSASignature(tbsHash, signature, ecPublicKey)) { + return true + } + } else { + const rsaPublicKey = csc.public_key as RSAPublicKey + // Pass both tbsBytes (for Web Crypto) and tbsHash (for manual verification) + if ( + await verifyRSASignature(tbsBytes, tbsHash, signature, rsaPublicKey, hashAlgorithm, isPSS) + ) { + return true + } + } + } + + return false +} + +/** + * Verify a DSC signature using the original TBS bytes (for Web Crypto API) + * This is more reliable than using pre-hashed data + */ +export async function verifyDscSignatureWithTbs( + tbsBytes: Uint8Array, + signature: Uint8Array, + csc: PackagedCertificate, +): Promise { + const isECDSA = csc.public_key.type === "EC" + const isPSS = csc.signature_algorithm === "RSA-PSS" + + const keySizeBits = csc.public_key.key_size + const hashAlgorithmsToTry = getHashAlgorithmsForKeySize(keySizeBits) + + // Try the declared hash algorithm first + const declaredHashAlg = csc.hash_algorithm + if (declaredHashAlg) { + const index = hashAlgorithmsToTry.indexOf(declaredHashAlg) + if (index > 0) { + hashAlgorithmsToTry.splice(index, 1) + hashAlgorithmsToTry.unshift(declaredHashAlg) + } else if (index === -1) { + hashAlgorithmsToTry.unshift(declaredHashAlg) + } + } + + for (const hashAlgorithm of hashAlgorithmsToTry) { + const hashFunc = HASH_FUNCTIONS[hashAlgorithm] + if (!hashFunc) continue + + const tbsHash = hashFunc(tbsBytes) + + if (isECDSA) { + const ecPublicKey = csc.public_key as ECPublicKey + if (verifyECDSASignature(tbsHash, signature, ecPublicKey)) { + return true + } + } else { + const rsaPublicKey = csc.public_key as RSAPublicKey + // Pass both tbsBytes (for Web Crypto) and tbsHash (for manual verification) + if ( + await verifyRSASignature(tbsBytes, tbsHash, signature, rsaPublicKey, hashAlgorithm, isPSS) + ) { + return true + } + } + } + + return false +} diff --git a/packages/zkpassport-utils/src/utils.ts b/packages/zkpassport-utils/src/utils.ts index eeeb8490e..7432a773d 100644 --- a/packages/zkpassport-utils/src/utils.ts +++ b/packages/zkpassport-utils/src/utils.ts @@ -2,7 +2,7 @@ import { bigIntToBuffer } from "@zk-kit/utils" import { HashAlgorithm, QueryResult, SupportedChain } from "./types" -import { hexToBytes } from "@noble/hashes/utils" +import { hexToBytes } from "@noble/hashes/utils.js" import { HASH_ALGORITHM_SHA1, HASH_ALGORITHM_SHA224, diff --git a/packages/zkpassport-utils/tests/circuit-matcher.test.ts b/packages/zkpassport-utils/tests/circuit-matcher.test.ts index 51315d4ba..08187a603 100644 --- a/packages/zkpassport-utils/tests/circuit-matcher.test.ts +++ b/packages/zkpassport-utils/tests/circuit-matcher.test.ts @@ -3,7 +3,7 @@ import { calculateAge, getAgeCircuitInputs, getBirthdateCircuitInputs, - getCscaForPassport, + getCscaForPassportAsync, getDSCCircuitInputs, getDSCCountry, getDiscloseCircuitInputs, @@ -41,6 +41,7 @@ import { SanctionsBuilder, SECONDS_BETWEEN_1900_AND_1970, HASH_ALGORITHM_SHA256, + SOD, } from "../src" import { DSC } from "../src/passport/dsc" import { AsnParser } from "@peculiar/asn1-schema" @@ -104,89 +105,97 @@ describe("Circuit Matcher - General", () => { }) // Skipped because it requires the DSC list which is not commited to the repo - it.skip("should find the CSCs of all the DSCs", () => { - const dscs = getDSCs() - const expectedUnknownCSCSubjectKeyIdentifiers = [ - "45728821c8fbff1153455807ad09ed5e868035e8", - "0654b2b864ec78aa4675f9110634ecdac2a5b4af", - "a775af64b440e8dd386f2f002280ecedd19d1b97", - ] - const unknownCSCSubjectKeyIdentifiers: string[] = [] - const unknownCSCsCountries: string[] = [] - const supportedDSCs: DSC[] = [] - for (const dsc of dscs) { - if (dsc.tbs.validity.notAfter.getTime() < Date.now()) { - continue - } - const isSupported = isDSCSupported(dsc) - if (isSupported) { - supportedDSCs.push(dsc) - } - const result = getCscaForPassport(dsc, rootCerts.certificates as PackagedCertificate[]) - if (!result) { - const akiBuffer = dsc.tbs.extensions.get("authorityKeyIdentifier")?.value.toBuffer() - if (akiBuffer) { - const parsed = AsnParser.parse(akiBuffer, AuthorityKeyIdentifier) - if (parsed?.keyIdentifier?.buffer) { - const authorityKeyIdentifier = Binary.from(parsed.keyIdentifier.buffer) - .toHex() - .replace("0x", "") - unknownCSCSubjectKeyIdentifiers.push(authorityKeyIdentifier) - } + it.skip( + "should find the CSCs of all the DSCs", + async () => { + const dscs = getDSCs() + const expectedUnknownCSCSubjectKeyIdentifiers = [ + "45728821c8fbff1153455807ad09ed5e868035e8", + "0654b2b864ec78aa4675f9110634ecdac2a5b4af", + "a775af64b440e8dd386f2f002280ecedd19d1b97", + ] + const unknownCSCSubjectKeyIdentifiers: string[] = [] + const unknownCSCsCountries: string[] = [] + const supportedDSCs: DSC[] = [] + for (const dsc of dscs) { + if (dsc.tbs.validity.notAfter.getTime() < Date.now()) { + continue + } + const isSupported = isDSCSupported(dsc) + if (isSupported) { + supportedDSCs.push(dsc) } - const country = getDSCCountry(dsc) - if (country) { - unknownCSCsCountries.push(country) + const result = await getCscaForPassportAsync( + dsc, + rootCerts.certificates as PackagedCertificate[], + false, + ) + if (!result) { + const akiBuffer = dsc.tbs.extensions.get("authorityKeyIdentifier")?.value.toBuffer() + if (akiBuffer) { + const parsed = AsnParser.parse(akiBuffer, AuthorityKeyIdentifier) + if (parsed?.keyIdentifier?.buffer) { + const authorityKeyIdentifier = Binary.from(parsed.keyIdentifier.buffer) + .toHex() + .replace("0x", "") + unknownCSCSubjectKeyIdentifiers.push(authorityKeyIdentifier) + } + } + const country = getDSCCountry(dsc) + if (country) { + unknownCSCsCountries.push(country) + } } } - } - console.log( - `Total DSCs without known CSCs: ${unknownCSCSubjectKeyIdentifiers.length} out of ${dscs.length}`, - ) - const uniqueUnknownCSCSubjectKeyIdentifiers = Array.from( - new Set(unknownCSCSubjectKeyIdentifiers), - ) - const uniqueUnknownCSCsCountries = Array.from(new Set(unknownCSCsCountries)) - console.log( - `Total unique unknown CSC subject key identifiers: ${uniqueUnknownCSCSubjectKeyIdentifiers.length}`, - ) - console.log(JSON.stringify(uniqueUnknownCSCSubjectKeyIdentifiers)) - console.log(`Total unique unknown CSC countries: ${uniqueUnknownCSCsCountries.length}`) - console.log(JSON.stringify(uniqueUnknownCSCsCountries)) - console.log( - `Hash algorithms: ${JSON.stringify(Array.from(new Set(supportedDSCs.map((x) => getDSCSignatureHashAlgorithm(x)))))}`, - ) - console.log( - `Signature algorithms: ${JSON.stringify( - Array.from(new Set(supportedDSCs.map((x) => x.signatureAlgorithm.name))), - )}`, - ) - console.log( - `Curves: ${JSON.stringify( - Array.from( - new Set( - supportedDSCs.map((x) => - x.tbs.subjectPublicKeyInfo.signatureAlgorithm.name.toLowerCase().includes("ec") && - x.tbs.subjectPublicKeyInfo.signatureAlgorithm.parameters && - x.tbs.subjectPublicKeyInfo.signatureAlgorithm.parameters.toBuffer().length > 0 - ? getCurveName( - AsnParser.parse( - x.tbs.subjectPublicKeyInfo.signatureAlgorithm.parameters.toBuffer(), - ECParameters, - ), - ) - : "", + console.log( + `Total DSCs without known CSCs: ${unknownCSCSubjectKeyIdentifiers.length} out of ${dscs.length}`, + ) + const uniqueUnknownCSCSubjectKeyIdentifiers = Array.from( + new Set(unknownCSCSubjectKeyIdentifiers), + ) + const uniqueUnknownCSCsCountries = Array.from(new Set(unknownCSCsCountries)) + console.log( + `Total unique unknown CSC subject key identifiers: ${uniqueUnknownCSCSubjectKeyIdentifiers.length}`, + ) + console.log(JSON.stringify(uniqueUnknownCSCSubjectKeyIdentifiers)) + console.log(`Total unique unknown CSC countries: ${uniqueUnknownCSCsCountries.length}`) + console.log(JSON.stringify(uniqueUnknownCSCsCountries)) + console.log( + `Hash algorithms: ${JSON.stringify(Array.from(new Set(supportedDSCs.map((x) => getDSCSignatureHashAlgorithm(x)))))}`, + ) + console.log( + `Signature algorithms: ${JSON.stringify( + Array.from(new Set(supportedDSCs.map((x) => x.signatureAlgorithm.name))), + )}`, + ) + console.log( + `Curves: ${JSON.stringify( + Array.from( + new Set( + supportedDSCs.map((x) => + x.tbs.subjectPublicKeyInfo.signatureAlgorithm.name.toLowerCase().includes("ec") && + x.tbs.subjectPublicKeyInfo.signatureAlgorithm.parameters && + x.tbs.subjectPublicKeyInfo.signatureAlgorithm.parameters.toBuffer().length > 0 + ? getCurveName( + AsnParser.parse( + x.tbs.subjectPublicKeyInfo.signatureAlgorithm.parameters.toBuffer(), + ECParameters, + ), + ) + : "", + ), ), ), - ), - )}`, - ) - console.log(`Total supported DSCs: ${supportedDSCs.length}`) - console.log( - JSON.stringify(Array.from(new Set(supportedDSCs.map((x) => getDSCCountry(x)))).sort()), - ) - expect(uniqueUnknownCSCSubjectKeyIdentifiers).toEqual(expectedUnknownCSCSubjectKeyIdentifiers) - }) + )}`, + ) + console.log(`Total supported DSCs: ${supportedDSCs.length}`) + console.log( + JSON.stringify(Array.from(new Set(supportedDSCs.map((x) => getDSCCountry(x)))).sort()), + ) + expect(uniqueUnknownCSCSubjectKeyIdentifiers).toEqual(expectedUnknownCSCSubjectKeyIdentifiers) + }, + 10 * 60000, + ) }) describe("Circuit Matcher - RSA", () => { @@ -195,8 +204,8 @@ describe("Circuit Matcher - RSA", () => { expect(result).toBe(true) }) - it("should get the correct CSCA for the passport", () => { - const result = getCscaForPassport( + it("should get the correct CSCA for the passport", async () => { + const result = await getCscaForPassportAsync( PASSPORTS.john.sod.certificate, rootCerts.certificates as PackagedCertificate[], ) @@ -709,8 +718,8 @@ describe("Circuit Matcher - ECDSA", () => { expect(result).toBe(true) }) - it("should get the correct CSCA for the passport", () => { - const result = getCscaForPassport( + it("should get the correct CSCA for the passport", async () => { + const result = await getCscaForPassportAsync( PASSPORTS.mary.sod.certificate, rootCerts.certificates as PackagedCertificate[], ) diff --git a/packages/zkpassport-utils/tests/fixtures/passports.ts b/packages/zkpassport-utils/tests/fixtures/passports.ts index 55ae31b18..a10c753f7 100644 --- a/packages/zkpassport-utils/tests/fixtures/passports.ts +++ b/packages/zkpassport-utils/tests/fixtures/passports.ts @@ -4,7 +4,7 @@ import { Binary } from "../../src/binary" import johnSODJson from "./john-miller-smith-rsa-2048-sha256.json" import marySODJson from "./mary-miller-smith-ecdsa-p256-sha256.json" import { SOD } from "../../src" -import { sha256 } from "@noble/hashes/sha2" +import { sha256 } from "@noble/hashes/sha2.js" const johnSOD = SOD.fromDER(Binary.fromBase64(johnSODJson.encoded)) // John Miller Smith's MRZ From d1036732c9886077c8a97109b34cc92743a34d41 Mon Sep 17 00:00:00 2001 From: Michael Elliot Date: Sat, 7 Feb 2026 04:08:54 +1100 Subject: [PATCH 06/30] feat(registry)!: Add cert fingerprint and expiry to leaf hash calc (#152) - Added version, timestamp, and root to PackagedCertificatesFile interface - Introduced fingerprint property in PackagedCertificate type for better identification - Updated getCertificateLeafHash function to use fingerprint and expiry for leaf hash calculation - Bumped @zkpassport/utils and @zkpassport/registry versions BREAKING CHANGE: Leaf hash calculation now includes certificate fingerprint and expiry. Any existing leaf hashes / Merkle roots are incompatible --- bun.lock | 4 +- .../script/test/SeedRegistries.s.sol | 2 +- .../script/test/seed-registries.sh | 2 +- .../app/certificates/diff/page.tsx | 2 +- .../components/Map/RegistryDiff.tsx | 2 +- packages/registry-sdk/package.json | 2 +- packages/registry-sdk/src/client.ts | 13 +- .../tests/fixtures/certificates.json | 7069 +---------------- .../tests/registry-client.test.ts | 7 +- packages/registry-sdk/tests/retry.test.ts | 2 +- .../registry-sdk/tests/utils/constants.ts | 2 +- packages/registry-sdk/tests/utils/helpers.ts | 1 + packages/zkpassport-utils/package.json | 2 +- .../zkpassport-utils/src/circuit-matcher.ts | 15 +- .../zkpassport-utils/src/registry/index.ts | 102 +- .../zkpassport-utils/src/types/registry.ts | 29 +- .../tests/circuit-matcher.test.ts | 16 +- .../tests/fixtures/root-certs-v1.json | 605 ++ .../zkpassport-utils/tests/registry.test.ts | 63 +- 19 files changed, 1178 insertions(+), 6762 deletions(-) create mode 100644 packages/zkpassport-utils/tests/fixtures/root-certs-v1.json diff --git a/bun.lock b/bun.lock index 3e2973809..71c1fbd1c 100644 --- a/bun.lock +++ b/bun.lock @@ -67,7 +67,7 @@ }, "packages/registry-sdk": { "name": "@zkpassport/registry", - "version": "0.12.0", + "version": "0.13.0", "dependencies": { "@zkpassport/poseidon2": "^0.6.2", "@zkpassport/utils": "workspace:*", @@ -110,7 +110,7 @@ }, "packages/zkpassport-utils": { "name": "@zkpassport/utils", - "version": "0.33.2", + "version": "0.33.3", "dependencies": { "@lapo/asn1js": "^2.0.4", "@noble/ciphers": "^1.0.0", diff --git a/packages/registry-contracts/script/test/SeedRegistries.s.sol b/packages/registry-contracts/script/test/SeedRegistries.s.sol index 9390ea9a2..ce695f905 100644 --- a/packages/registry-contracts/script/test/SeedRegistries.s.sol +++ b/packages/registry-contracts/script/test/SeedRegistries.s.sol @@ -32,7 +32,7 @@ import {RegistryInstance} from "../../src/RegistryInstance.sol"; contract SeedRegistriesScript is Script { // These are the test fixture roots and CIDs from registry-sdk bytes32 constant DEFAULT_CERTIFICATE_REGISTRY_ROOT = - 0x03c239fdfafd89a568efac9175c32b998e208c4ab453d3615a31c83e65c90686; + 0x2b49d7ddaec2fa540efec3311af6223cfd19d3a9e9314e10039f9fae0747f062; bytes32 constant DEFAULT_CIRCUIT_REGISTRY_ROOT = 0x068f6e356f993bd2afaf3d3466efff1dd4bc06f61952ac336085b832b93289a7; bytes32 constant DEFAULT_SANCTIONS_REGISTRY_ROOT = 0x099699583ea7729a4a05821667645e927b74feb4e6e5382c6e4370e35ed2b23c; diff --git a/packages/registry-contracts/script/test/seed-registries.sh b/packages/registry-contracts/script/test/seed-registries.sh index 5bd957f33..07a87f6a1 100755 --- a/packages/registry-contracts/script/test/seed-registries.sh +++ b/packages/registry-contracts/script/test/seed-registries.sh @@ -13,7 +13,7 @@ export ETHERSCAN_API_KEY=${ETHERSCAN_API_KEY:-dummy} export ORACLE_ADDRESS=${ORACLE_ADDRESS:-0x70997970C51812dc3A010C7d01b50e0d17dc79C8} export ORACLE_PRIVATE_KEY=${ORACLE_PRIVATE_KEY:-0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d} -export CERTIFICATE_REGISTRY_ROOT=${CERTIFICATE_REGISTRY_ROOT:-0x03c239fdfafd89a568efac9175c32b998e208c4ab453d3615a31c83e65c90686} +export CERTIFICATE_REGISTRY_ROOT=${CERTIFICATE_REGISTRY_ROOT:-0x2b49d7ddaec2fa540efec3311af6223cfd19d3a9e9314e10039f9fae0747f062} export CIRCUIT_REGISTRY_ROOT=${CIRCUIT_REGISTRY_ROOT:-0x068f6e356f993bd2afaf3d3466efff1dd4bc06f61952ac336085b832b93289a7} export SANCTIONS_REGISTRY_ROOT=${SANCTIONS_REGISTRY_ROOT:-0x099699583ea7729a4a05821667645e927b74feb4e6e5382c6e4370e35ed2b23c} diff --git a/packages/registry-explorer/app/certificates/diff/page.tsx b/packages/registry-explorer/app/certificates/diff/page.tsx index a8c295447..64ff7bc99 100644 --- a/packages/registry-explorer/app/certificates/diff/page.tsx +++ b/packages/registry-explorer/app/certificates/diff/page.tsx @@ -8,7 +8,7 @@ import { ArrowLeft, AlertCircle, GitCompare, ArrowUpDown } from "lucide-react" import Link from "next/link" import { useSearchParams, useRouter } from "next/navigation" import { useEffect, useState, Suspense } from "react" -import { PackagedCertificatesFile } from "@zkpassport/registry" +import { PackagedCertificatesFile } from "@zkpassport/utils/types" import { countryCodeAlpha3ToName, PackagedCertificate } from "@zkpassport/utils" import { getCertificateUrl, getChainId } from "@/lib/certificate-url" diff --git a/packages/registry-explorer/components/Map/RegistryDiff.tsx b/packages/registry-explorer/components/Map/RegistryDiff.tsx index 6a850240c..c20af68d3 100644 --- a/packages/registry-explorer/components/Map/RegistryDiff.tsx +++ b/packages/registry-explorer/components/Map/RegistryDiff.tsx @@ -1,7 +1,7 @@ "use client" import React, { useCallback, useEffect, useMemo, useState } from "react" -import { PackagedCertificatesFile } from "@zkpassport/registry" +import { PackagedCertificatesFile } from "@zkpassport/utils/types" import { countryCodeAlpha3ToName, PackagedCertificate } from "@zkpassport/utils" import { getCertificateUrl, getChainId } from "@/lib/certificate-url" import { GitCompare, Plus, Minus, ExternalLink } from "lucide-react" diff --git a/packages/registry-sdk/package.json b/packages/registry-sdk/package.json index 29dec95ee..6165ea343 100644 --- a/packages/registry-sdk/package.json +++ b/packages/registry-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@zkpassport/registry", - "version": "0.12.0", + "version": "0.13.0", "description": "Registry SDK for interacting with the ZKPassport Registry", "author": "ZKPassport", "license": "Apache-2.0", diff --git a/packages/registry-sdk/src/client.ts b/packages/registry-sdk/src/client.ts index 337bea100..f543a2f9a 100644 --- a/packages/registry-sdk/src/client.ts +++ b/packages/registry-sdk/src/client.ts @@ -12,7 +12,6 @@ import { import type { CircuitManifest, CircuitManifestEntry, - PackagedCertificate, PackagedCircuit, } from "@zkpassport/utils/types" import debug from "debug" @@ -216,7 +215,7 @@ export class RegistryClient { throw new Error("Invalid serialised certificates tree returned") if (validate) { - const valid = await this.validateCertificates(data.certificates, root) + const valid = await this.validateCertificates(data, root) if (!valid) throw new Error(`Validation failed for packaged certificates: ${root}`) } return data @@ -225,9 +224,15 @@ export class RegistryClient { /** * Validate certificates against a root hash */ - async validateCertificates(certificates: PackagedCertificate[], root: string): Promise { + async validateCertificates( + packagedCerts: PackagedCertificatesFile, + root: string, + ): Promise { try { - const { root: calculatedRoot } = await buildMerkleTreeFromCerts(certificates) + const { root: calculatedRoot } = await buildMerkleTreeFromCerts( + packagedCerts.certificates, + packagedCerts.version, + ) const expectedRootHash = root.startsWith("0x") ? root : `0x${root}` const valid = calculatedRoot.toLowerCase() === expectedRootHash.toLowerCase() if (valid) { diff --git a/packages/registry-sdk/tests/fixtures/certificates.json b/packages/registry-sdk/tests/fixtures/certificates.json index 40be5c1cc..f83a24c9c 100644 --- a/packages/registry-sdk/tests/fixtures/certificates.json +++ b/packages/registry-sdk/tests/fixtures/certificates.json @@ -1,54 +1,24 @@ { + "version": 1, + "timestamp": 1768823285, + "root": "0x2b49d7ddaec2fa540efec3311af6223cfd19d3a9e9314e10039f9fae0747f062", "certificates": [ { - "country": "ALB", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xc84e0ffc3df9bd995c6ab6e8abb30751a8ff3b659c9cebbc9f38ad82b89271070aef6d42ffe9052ad60507946d772d1c83f3a525e24f5ad1cd859f49cffadda27c1b164b7d304ff7d68dc86891c41beb96b0064edc1fbe91895ba0142ecbf5f65a1cd1344b75809d4c9caf72a2ba379fba632351d6f2ff0a8bdc369ed5182e08db70cf8ad2c152a7485ba154c836488ceb22a97803555011dcf8d944983863aa9e977134e07e595de4163995658a17405173aefd90f1a04f442c400963573b3ca6faf6a23dba7c5d07fdfdc88885475af6908e0aad52143c1703f54501e51a256ee3e9eeb57a4dc8525b08f540b96500f61aba0d3307829530ea744c067300beefde05928b1273098f9a9f4b4f9798bea099ee2e3d8f32a6805ff9b45e088ca725b92ee554e304619ab2404d4a740a081dbfd75a6a9d7342116a134464a2792efdc5971ebf4f28cb802e4e4ff23d9b9dfd50baa736553c72411432f7bcd78da57f550d69202ed7959a8c39b8ffac45da09686352b548fb9238f2bbe83615bdac3ad5a6b55c8dc51c1c1fb20f892a5f2c88d99486f64737b95c967180a5455b6b859a0ca0053d57131659fd8aa606a647a1bf49f2e3bf01502256299596b8ede3997bcf8102bf41bf30215d740b4a732b06a7a37b39729e0e77862f1a3422145648f5fd7c92e94f09009ba72f0661a5f9d63d1fc51667525f3c349dd180f59d3f", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1392854400, - "not_after": 1874275200 - }, - "subject_key_identifier": "0x382f55bb2a3f84b250b0ad6a27d5e4221db3e7551e0cee4e5b2724971c13f94c", - "tags": ["UN"] - }, - { - "country": "ALB", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x92f9716150705b50fd94e5fadb4dcd4ac47c4a4f6a4cc0a83d163c808b201ce8f796a50b95a7db26e2149f10e9cbe0793b9c2e8d1732d90112c96c6e6c57356ecca8321516abd81f86384133352ff67b7774fafaf90b6ddf97cc6404e09bee167ef170347f1470f724ab4971202fe3684736041fb087b691e076b5c3a93ea5a9788a4f3601660a8dacf72725c819da8946f0aa7f18e78feca4d6bc4a7ad88631be1b9a770158f03e56ec905ae08cd074ecdf2652b1ac1eefebee4f6f753e496e07c1679d37ddd17c81ea5ae33d0d3b19aefcb8982bb586fa704b4e0d5f846100bbce48030571496f424edc545874192fa507951c9752f4fb249da10c3cba36da16a13dd8d4f95f501aeccc2da373cf87f9277c5edf785aca735550af3cf9dbf842e2e8393aeb4b968fab01f49895bb2823280c36652d195274f9f9008f94ca0f1d7333f70b2a5fe72b606868bde0732f40a88c7802d6b49bc8e981c188d3cb29af2659f1890cc05d6c323f7313f86d032ae791ce83d36f14f1de7617ba4794562c8ec1bdbb90b5dd19f1b2131f3f4d5004caf8a24a1d6839fc2016036595d7301cafbee010c79f2ef2ecee9319eea95b6cbc12862f413949b7cde10085672dc8e89a9c35568f7f8587a4977068e2ecd7045312c240f5c6bf07fecf42e6a177ea5b9bb06121026a5a09f458ba5957bc84ad9ee2261f0d40d1e8e1519669ec475d", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1415664000, - "not_after": 1897084800 - }, - "subject_key_identifier": "0xa5f84582490da0f9c6dfdeb2c46b309acb0b61d8aa5f7f20257bdef73a7e937e", - "tags": ["UN"] - }, - { - "country": "ALB", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", + "country": "AGO", + "signature_algorithm": "ECDSA", + "hash_algorithm": "SHA-384", "public_key": { - "type": "RSA", - "modulus": "0xb349787a23e783dfc88d4140fb6ff40ebf58fc1ea788f5b0ac697bbb49127b0d18d186583e57279682eee34f235abe1330d2afc4fb238248b42456c969b956afcfde86f7c672925ab6f05efba14e145d1e6d537585797f1927a8d48ec7c3c35791bce57edefc834b637b984d5e57737486656f9ce05cc1e08227e75861b4998d362e06d13c87d4e1f2f0d842bf5751415b5b9f07f30baf6132a523dc8b2a3bd50c0344559df9e974693c3fac84e55064bfa1e67316612d67a128a8c5f8ddb583a46a155adf042aefd53c116d97d8ad68c6e6c19dd4067c1374b5d82aaced782e340539310596c127a7be139d3181773f161953857f8d7354c557c5b3c0f3568ac3b86ed0da4a81663d8e37fbecd8e951a977fd7bb559978a9b4e5be421239a1eb84b4c2c467f76144f8d689f448f85cc9feaa25e964ea7666833eb929a81798b8e3c8210ba98a79ee3278e6b0313e588cc5fd89cbd65dc79e1758219d064101709cba121fc2b5f572c7c228e1d6f10dd43dacbbc8e87466f6b7ec01c5d8b33cab07111ab7c7771007c9e041f98a7e4f9a28095d0e995465b78ba14ec5bd816773904265c653b761b7fd58b4d7a1d34d3df19741ff29df9cbdd062cac0db4b2e6986218085c9245266f4a91ab92a4069e4ca74e96770194d5b68e8967e67745eadc9daad729eba5dc1a0d3f7d8ceacf4d74b5809ac9bf6a9d92810f32d4bf344d", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1573516800, - "not_after": 2054937600 + "type": "EC", + "curve": "brainpoolP384r1", + "key_size": 384, + "public_key_x": "0x5bb488bbd2774ce7ced40dc8034ec3048f3782f4018bd59e7f30b2ed588c57611ab7483965b8456f45b8167a2d41ab21", + "public_key_y": "0x59ad32299013af2a01f5515dd77de5abafab16f24bd9ea3415d5447ec863e1705a67bff2aa773ee38bfdfe12e16db90f" }, - "subject_key_identifier": "0x8ae51a9b5d98146ec458736dbbd46c3d1116f71cb267e9a0b87d5a7d0c860a6a", + "validity": { "not_before": 1760537584, "not_after": 2241871984 }, + "private_key_usage_period": { "not_before": 1760537578, "not_after": 1918303978 }, + "authority_key_identifier": "0xaf444982ebf06fb9ff67caf451aa4515e9e23fa9", + "subject_key_identifier": "0xaf444982ebf06fb9ff67caf451aa4515e9e23fa9", + "fingerprint": "0x111a08ff123a169cf2a0830649262c875eaa9544d707a9bd0ba2a92e9dfe1eba", "tags": ["UN"] }, { @@ -57,21 +27,14 @@ "hash_algorithm": "SHA-256", "public_key": { "type": "RSA", - "modulus": "0xc877069eb89ad56a920bfdd7b4d566daf63a51970ae9582833b1a4ae6a16fa0979aa79881bbab4653f56731afbf16397d86276414f49d63d4a82df6c17fda7409b120dbbdf2eac9e26ec25f0daa664aa7b66f60bb10eb47a76fcb3f06a4d1fba7bdcaef353177dea1904c6d45652f6be0f977aa96cbd92f57f44c207aa70e30bac841bdb1b0ac9a697176adb28d23c50472b05f2627d934bbe89ea5a6b229aa8957afc0ca87d575c816f101972152b3f9aacebdd88ce9b76619705277210d616aabe9aa3e2d2d7558f88a0c9bb0c4e5257bb1637ffd2899f94ff412cff5866398ffb9836e117cf1faecfa782d6898f299207534412f54e550fd2f245aa2a4840d1e582b6cd365eaa19e6ae00fc894a166c1f27b1e4846cfd317c35c3b6a6c3044a74bc0d34a02b5b59d5493d74b18a3ae646ecc19b989e98f1dbf2fb62fd35f26d8a8daf96485455ba627a6797803826c34b4a3079792ae38775a15b1d979b47fd90bd14f54ae9cff05fcee28eb3ee2c06cca30290c3b920cffc568073d664077c116cbb91eaad758eeb934d6027af17668f1907d0b51a2fb5ded0ba6c02f7046e1d4e527709e26b328ba2420e8f639a6dab24b780b585f4b63eba34539cacb64fd0fa51bd63599ff053875275403daa3b1e38c92c3ade9f2c7d83c358e2cfe83d08dc63ca038a4c64d2a68040abd24a192bde71117027e4defd6b4ec95ca4cf", + "modulus": "0xc84e0ffc3df9bd995c6ab6e8abb30751a8ff3b659c9cebbc9f38ad82b89271070aef6d42ffe9052ad60507946d772d1c83f3a525e24f5ad1cd859f49cffadda27c1b164b7d304ff7d68dc86891c41beb96b0064edc1fbe91895ba0142ecbf5f65a1cd1344b75809d4c9caf72a2ba379fba632351d6f2ff0a8bdc369ed5182e08db70cf8ad2c152a7485ba154c836488ceb22a97803555011dcf8d944983863aa9e977134e07e595de4163995658a17405173aefd90f1a04f442c400963573b3ca6faf6a23dba7c5d07fdfdc88885475af6908e0aad52143c1703f54501e51a256ee3e9eeb57a4dc8525b08f540b96500f61aba0d3307829530ea744c067300beefde05928b1273098f9a9f4b4f9798bea099ee2e3d8f32a6805ff9b45e088ca725b92ee554e304619ab2404d4a740a081dbfd75a6a9d7342116a134464a2792efdc5971ebf4f28cb802e4e4ff23d9b9dfd50baa736553c72411432f7bcd78da57f550d69202ed7959a8c39b8ffac45da09686352b548fb9238f2bbe83615bdac3ad5a6b55c8dc51c1c1fb20f892a5f2c88d99486f64737b95c967180a5455b6b859a0ca0053d57131659fd8aa606a647a1bf49f2e3bf01502256299596b8ede3997bcf8102bf41bf30215d740b4a732b06a7a37b39729e0e77862f1a3422145648f5fd7c92e94f09009ba72f0661a5f9d63d1fc51667525f3c349dd180f59d3f", "exponent": 65537, "key_size": 4096 }, - "validity": { - "not_before": 1738108800, - "not_after": 2219443200 - }, - "authority_key_identifier": "0x85a1073e96ca9650f4a7016752a575ca9fe83fd793e3f6e089a95a5bb3a34ddf", - "subject_key_identifier": "0x85a1073e96ca9650f4a7016752a575ca9fe83fd793e3f6e089a95a5bb3a34ddf", - "private_key_usage_period": { - "not_before": 1738108800, - "not_after": 1895875200 - }, - "tags": ["UN"] + "validity": { "not_before": 1392854400, "not_after": 1874275200 }, + "subject_key_identifier": "0x382f55bb2a3f84b250b0ad6a27d5e4221db3e7551e0cee4e5b2724971c13f94c", + "fingerprint": "0x2215b0e6cb4d3e69e722c6895caa0ed7285a12a109a055b0c80902200267460b", + "tags": ["CH", "DE", "IN", "IT", "NL", "NO", "SE", "UN"] }, { "country": "ARE", @@ -84,6837 +47,559 @@ "public_key_x": "0x078c9dda9dcc89c01c0c484baa17859db71ee6db32915d2dcba0d734ce0c6f4e", "public_key_y": "0x606a3d7f445bc0321990adfa3a87479a94cf31d6a6bfecc961e4bb6046d72bb2" }, - "validity": { - "not_before": 1507198631, - "not_after": 1796465831 - }, - "authority_key_identifier": "0xf5a8f9b1e7a992a0865408db2a471c04a215f4d7", - "subject_key_identifier": "0xf5a8f9b1e7a992a0865408db2a471c04a215f4d7", - "private_key_usage_period": { - "not_before": 1507198631, - "not_after": 1633429031 - }, - "tags": ["UN"] - }, - { - "country": "ARE", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "EC", - "curve": "brainpoolP256r1", - "key_size": 256, - "public_key_x": "0x4e3464967650c0038f85b3beb43f319400e80509e034e435d9bb9c5d7975c665", - "public_key_y": "0x645488fc4fbc848dd882cb32e26062bf6c85ffa310fc84d3e584f215363eb68a" - }, - "validity": { - "not_before": 1632314541, - "not_after": 1921581741 - }, - "authority_key_identifier": "0xe05b11319c57ae33ad07b2466fd872b8ac4964d9", - "subject_key_identifier": "0xe05b11319c57ae33ad07b2466fd872b8ac4964d9", - "private_key_usage_period": { - "not_before": 1632314541, - "not_after": 1758544941 - }, - "tags": ["ES", "UN"] - }, - { - "country": "ARE", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "EC", - "curve": "P-384", - "key_size": 384, - "public_key_x": "0xec67ee731b015cd9f1127e1d97bc991467100afc8fc620ec06abdb8275022603e7f35976a160a89a88dbe4e0fa623f50", - "public_key_y": "0xba21a4c9f6aa1029fb91cedb445f1b9ad83d95b18b6957ee2e4507b57b23d264fadd816963e038f80f8dffad118acbf1" - }, - "validity": { - "not_before": 1646133300, - "not_after": 2127467700 - }, - "subject_key_identifier": "0xc1679be7c61e4d98a2984d861ccec768695d4ce1", - "private_key_usage_period": { - "not_before": 1646133300, - "not_after": 1803899700 - }, - "tags": ["UN"] - }, - { - "country": "ARG", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xc9a6105edffbf21e91ce42dc29b024ca8fb2c0c28ba8fcc0710d8275943a058494cb785caa1735f72d23364e1c5580501fbaea283458c47363fcdf475b9f86db803c812d87921142c38eb199b4787a0957368e8d454794c16ca182431e373ab853e5f21d7766b86614e300d4853329aa1bf88082d10f5c095bcf2fc60b371f2a8f37e1bbc84cefd98926b7f499914dd5af7977b9a1113afeb89bf46d1162bf5bf7aa9a47c5a9b22979c1fafd9de434395cef7e46ea13603da949582713e9347df8e151079c108860854486ab31a51186eed42caaf63be699452e113cd5865917f71c0fd352faf2f6cf69b28a395102ad0e471828e08276413efd47017d1bc512b4b557b4fb0386881542c8ef4f75cfd4ac787ff345c886027d54ca0d23894ffcf9cc218ce7e0026e1b304c038b1ab12052e9ef217d3a020ec85141e0948a97d7b87b901edb46a8f6d27b7c52c2eaa27bb5ca32df9affd73bba4134c2d9c64d41e1cef44b5d35f69db5e31df0c871386adff87b934b5923adf5ebcb469140c49d", - "exponent": 65537, - "key_size": 3072 - }, - "validity": { - "not_before": 1328895527, - "not_after": 1842793369 - }, - "authority_key_identifier": "0xc1c334543aa6bc5f3db2a8795d865ab96e7bf6fe", - "subject_key_identifier": "0xc1c334543aa6bc5f3db2a8795d865ab96e7bf6fe", - "private_key_usage_period": { - "not_before": 1369405969, - "not_after": 1525622569 - }, - "tags": ["ES", "UN"] - }, - { - "country": "ARG", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x92d437fd733a6cbf1c80a88fdd08da140fe3257ede9e427dc4421f57cec4d3770fdae4025ec1d87c8b929f0bcb5a7f9509b6de1065726aa9cbbd8f4ce6bbfaa9a9fe475ab1f9f934e26ba0ef5935928d4a948ea25e36947c8f8f49fdcf47be5323240ae86513f4f4301786d7abec68b1018434c810b195d8acf953f6f6b9a4ae27d88846b544056e4f379b5fac9d93ba271f40ae2e63a582e7c54dbeeaeb62ae69594819ce7a78a879ed7b2762dca3434cc9a6c43d93440af52f06a78ad2cc01348e4e5356e7a1d3b2a195beec44c685ae6c12ba01f2262f44d3012f8f3f7f8aaafa86f994da556d322f32d259cfe2e9ae58c3d605c0f25a338b30b7d6760a393a2d0696ca299e1447ece4b5b0f6a9977f833f1db8930e6c0f51ae4acbbefe8a3845eae83645c9a083b05a14c27856945322d8956597ab235acbbcc4899ff1ed193d79e6693f371628af4e98885cdef7afba08e2cd8b89d12ec7f06b5d0a000a0ba6589a44c0a0551d59094ca62a2de6662c43c067a0f8c808d4d873dd1ed4e5f8e57865758b9e191a88eafab0aa4032ea80c9d08c89c38c133d11c1649217059091b3f6efa1d2772b98bb7bedd310c7d873cea76041b18e0e635826b6e5635b64c08d9456da8f4930c03e5fac01c98cd2439a5cb22460003fc81ace45bc49b6cb4431eb7dc2024aacbb64051069bc2a05a7b5e9359cc2410ae402f4a54c2a4d", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1724641200, - "not_after": 2205975599 - }, - "authority_key_identifier": "0x6d49b37052b10c5a424aca90e6803a7f66df6300", - "subject_key_identifier": "0x6d49b37052b10c5a424aca90e6803a7f66df6300", - "private_key_usage_period": { - "not_before": 1724641200, - "not_after": 1882493999 - }, - "tags": ["UN"] - }, - { - "country": "AUS", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xa53bc9a028865713e79f2e4b95195d8c3655cd8e06593b31cba408d71462eb5fc51dd2cb8974d835847bbc2b7d81adf1d636bf004e60ae579f155c9c95eaf658af9a991c989af7416eb4356d810428be8d9f671da31eb4b4003a035cdbd13dc0cab97876679019d49c0c140a563a53721bb6c4760e9932d924245f26051eb7e864177d5e43e3042f9fad85b7009743a6024ac09a3605b4570006af75812647c5102013da74f1ffad60fbd3c24eb0a175fa76a15e5b6fc1a90a93262ce38df3ce791e25a0db22eb4da73e960e9343a271d4f05b903f9cc0802a796bf0b11d2ae525f9811187e4999bba17414249c570ede5b228bab64a221cc67d0ac60086195d61cd4cffe471b0810ddad0fbf3cbdf1d11a48e6aad0d10c8b87bbcf33a30428c6ea19babd3d8af7ecde9f868e7c05ead544a1c02e3c72bb136504d7cae7dad8a581223711a4e7ea472bdda41f862271b61d53693ba692034dc9181841966b258ac9bd12fa32daa4485601a073680e96ccf1876c9c2f57b7f830e7ec0b5ac307c4dd3a49bfb010a467e88c8301356fc8d2042d79ab89c1e7ec367a7c1b2137481bdbb203e128983fb8167f077015e2477174c1de7500480458bc98a25d9eb545524126f2939fe9cd648db6366630390258c28d03bb1c92dff329a6a5241caaa55bf348b6dbef578008310cd2a18af581eee7cff876e0cf13cf95db3a69f3621e9", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1298246316, - "not_after": 1771631588 - }, - "authority_key_identifier": "0xa9dc68c79d9885f1b2cf806c3c51b55f382c0782", - "subject_key_identifier": "0xa9dc68c79d9885f1b2cf806c3c51b55f382c0782", - "private_key_usage_period": { - "not_before": 1298245987, - "not_after": 1392940387 - }, - "tags": ["ES"] - }, - { - "country": "AUS", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x9fc356d37179e527f8b6f40c93628df420ec32d781ade2611e67e3e501f84635860f0c7e5e2b069990ccc6e92509f0950a06ca955f69625ac7da788003d29d726ff9f00a97ffd562d24b3c9c491463583e09bde83f4959651d10295ad2c83ec2d7dd5df7f7800235eb62095950af9cab67f5cd7a8a70f72536190ea686fd7b6f5094b3cee4d9667e4e9924a554839f9ec50bd2188de40c84ba89ee1c3b5f1c2cbd2b55d1bc279d1642e1caf39762fcffd4bd68d73197ce10f4548afee8c0a6794b3f6764263cc879457020da8f0674d0bd8e79731b8c37defd62d2b318cf44b72f0ca3540fb09ee412738fe120337cf604c20236121fb22e91e5e9b1bb73d682e257adf9fa615b26a24b10d7178a7651aef9ec448b9f07beac7c58916cc92064cf4b3feddd6b7fc151aa1975deabf81b6bf439f0b52ed1bd2f7b8e151d19c235a068b34cabadfdd10decd22e178b3cac93c68e376523b6ba99792a29240a2cf44e3e4c6b3e4a9db53ea89e11e62d103b933771723bc87a8e58ecc8439d4dc99b014206a452b2d64ee8afc284799912bb6a8e0f9cc936628c7af7b2b4f9809c20b8c1101461408b6eac5e0519d6c6bd5bed931761e34c0da2b909e87d3034c1ea40a95026fddc7ddcb155f586ec514e04a5413f7d52fc08f4063bd69cc673ad5d3ef5ad4750a7542ae31b576baebd27c43453daf7895312bb95dfc3ded41d06b5", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1298848960, - "not_after": 1772234090 - }, - "authority_key_identifier": "0x2b0f99a34be9d5ae00933a7868cbcd21a6cf47e5", - "subject_key_identifier": "0x2b0f99a34be9d5ae00933a7868cbcd21a6cf47e5", - "private_key_usage_period": { - "not_before": 1298848488, - "not_after": 1393542888 - }, - "tags": ["ES", "UN"] - }, - { - "country": "AUS", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xc3e43368c53e0e97a62380a91e7a42174a6720a23f33d25e9cef5404a3086229bd2ce3e7c7fd6664eaaf10da06b9d0167caccaa9d05ce19d3434739b299c351cf01361ab4a173a0701d7c45aca14464df0a6ce111cd8f01f2830b4f44cc8756d3f917094a33a8c82edfea8294b7a7360d32278ba3b1480b54e97124c476dc15191fdb02c2ff4ecf268d07cc5fbdf52fab37fc1260391d0d8351afbc44e338f43d29f216ca7bd6a821e64340591c3cac1cc6da7cc4a5f15df80359eab26b42918157afc6594d49b37b2e1dc2a81220ed60411da5182b2c055164b73d6d8cbbf8a3454a81ff17d0c24be930126a42bbd9f7bd68cdc68626beea911fde698c06f6abb40e18e380a83ae2b6fd1a95f5f8c9a01ec1883092ba970d0d8e78c65a48ac6044c83d957b2879270501dda846bcde17e107f0790292fdbc096c6703d50f1be35e1f53d1fe2eb45edb7e571fadeb2cc38d98289d9341e98b7ed3ecd79c161310c0b971bf05aa2617a3e6a6520fdcfe83b2f534de67f2fc67de81923aebb7ca528d9887a4773d1a394dde4a8af315dd61e3d693e7d478cfb7b794f7cee8284b8840f7e81b416ed60e445b4f57bbd38c6ed68e16d413f7bf650c1f2ac06a3b32affef51ecbed1edb1e258c8d36dc81e47a1baded896adad72d391ac38f212c40947e75ba9daa7a7fbb874d552ee08bd467f3e37280203c2723f5075ea02a9f089", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1384732915, - "not_after": 1889654166 - }, - "authority_key_identifier": "0x49b1429bf387ccca9980a245831157a35f450598", - "subject_key_identifier": "0x49b1429bf387ccca9980a245831157a35f450598", - "private_key_usage_period": { - "not_before": 1384732565, - "not_after": 1510962965 - }, - "tags": ["ES", "UN"] - }, - { - "country": "AUS", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xce07631e284f3a8a87d7d87f325e4d3493cde49583341c338f02d470a358a001a084f5e8f423f240fd8bfeafcb9716640934b7a58388fc12dcef4af0fca977b8bc1098502db47a0f3567f99305be1d6360bfc980b79e508ce0fa5260f4aaae85fcf3f361ac7c0355465f67e682d53988cb87280b13fb7895b2cadc0247a1f03fe2ce969810d63abf5ed574847e850f2b5f2f5657389a65f6a544dd1c6e61382eb4dabc3db86683d6efc033154dd25e5af54718f347a1b16748b6e939a668c375a6823b7adf00441c9536a2204a6c2f78ed6dd9f67586fca641879e2522ebbd8bcd12ba16b66685b1a3d6a5ec53ce7f06d2cf6580eaf0a7efaa0420c3774b5cb242cfa63d3c6b0da7718561e2abbf438708df1a71a96b1d16d2dd1e8e1d8b85510d9f7b384335d4822779de289832c416c5b02d8bfb2df584bf6b12444b26d6e2fcfe66cbff86ccf5d295f3eb71c5f76ab93ef778975124838879235cc6514ba2257614a9b061770348adabb682ea231166a9f9b550564e3801ef348221b6c3af2044d29d46e76abce1c0e9e8c02f64aa38f1d5e094ce9bbd1d372ada5fc8b2d9daeef86e84a4771cabc970a115690b56177a83d9741cac5a18977195f85ecc9492cda9fa993eb9f7dfebfea6f6b9e20349b6b650b8597921cbd7fdb364e0c696946d12e08ac17384bd2b76193d48ad1203e77a2918902f52d3fc78660da48ae7", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1496282688, - "not_after": 1969667342 - }, - "authority_key_identifier": "0xab0230553c0383e1cb5cccc310c1f2c1c99693c6", - "subject_key_identifier": "0xab0230553c0383e1cb5cccc310c1f2c1c99693c6", - "private_key_usage_period": { - "not_before": 1496281740, - "not_after": 1590976140 - }, - "tags": ["ES", "UN"] - }, - { - "country": "AUS", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xe4fc78bba064981942ab83f25c70da57d283835b224e0f4e2269a8a9db7808f2e5de595cbb0e43a74622d204fd154981ccf7dd911ed4e2af1c0b82fbd1efc6c812b8d40414eb86ca9010e3daf5c895d9cecb14372dc353bc238f6a7cbca1cc74cbb899140fc3a8e875f2d8327e1404a29ffdab498932e90301f4f565cf449e383f66c9de373f5a50bfa6903512e25364d690466cab96627f37c46557a5a8946b9fa4db078b0acc0a441a646c44b7ae224d46f1f02962c8129e66735ee07229f580bf7f0b9799a51f4970a72034799d2423c64fe9ed7775d72d14375f31bb2381ae29c6a06f0de507aea73782b55672961e6014a89850236c09e7168c87a9741348a81cf9c697597ea63f0ca4e57b2fbe96ab4da4cc3b97c6255ba3f12153f749b29a583a4a92ad761b2b2c8b0102f2664bec9fc92f9d492a0112b400f45730a04dc283ca32a3bf23cabcad84b3502bb4bb3cd12fd9d3bb70ca3ea8acd81f5dd52cfcb947f7b3ac8aaee7e16b01f75d76c0f6ac27bbbf4198392e2d5dd4d7691385bf19fd5a3ed3b3f75a01a2ceda0349a0bab4bbeee5df4b96fa0553f63ad53e2eba9985f34533d1670ace18c7bbcb5cab42e9fd45e3d6ccdeaf0aab3d9d196ca30ec3c6eb26d88f52c5fa31cbfe405e22afe456aabc84ebd34965b8aa1fefe717b523ef07a4535d2e2fc5760b22a412b46884d6702ca473268ad5946921e869", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1588640672, - "not_after": 2093561222 - }, - "authority_key_identifier": "0x3617c1e7f56795712e3775708e55833186e9380e", - "subject_key_identifier": "0x3617c1e7f56795712e3775708e55833186e9380e", - "private_key_usage_period": { - "not_before": 1588639658, - "not_after": 1714870058 - }, - "tags": ["ES", "UN"] - }, - { - "country": "AUS", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-512", - "public_key": { - "type": "RSA", - "modulus": "0xc14b71214958715c1d4490e717da316ef0c3e639f6abe67b96ac1ef08257c8b649b81fc5fc256d602f2e32f560c777039d9e40707be24d89f8544892d54206dd45dbc4691ab38eacbbc1ecbc7c8845bd01fd35af5efd382b715bb0999eb212d463f06868d55fdb8e6d00a1ae8b94dca84ae1c6f9111ac53f3f8e39f5cbb7736d847dfeb486f916f49289b47cba4c5b92cd2644a5147d3ef4095c429d6a8b72191c4a126493df5d3ff0fdca3ba83f36cc31675dc52a3a8f3b4ead67af2e2dbb2393bf98c7817af833cf6c99cbb6dcb366799794be95d1e4e35e536b7e6374cb4c5ccff5664069a005dbae7e2947301e77d4bf2c2a5d31b6d9ca864331a859197a0b977413136a30cd3a86caf0e42973f2019317c9b627c7748af6cf25456be71b8ae320543ac04ab5c1d8f6d2bc46b6721456816e81217fd8bc7a05b75b6ea3418ce977349498ae40024101a250f394dcf645811f9bb00a9e1d712f14b6089644c33e615d886c02759f892098b17e6b25cab1a35076218a3c8835dd8e3ad82345c7f0e3e0d77db280c08a65ff9a2a4872a65273026038c29f9a8553fbfda6ac1edb56f1b87eeb2ab6cd262acfd1cfd68ef48249247d2e8a146383370d6ef780930d50b5e83f4b26b9820517335c77662eb1272409a813478731c80cd67ba7c988a3b20328792fd6aa0ecdb9b5df1b041687bc414351019dbd0fa6ca29079a8a07", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1704933676, - "not_after": 2093561222 - }, - "authority_key_identifier": "0x3617c1e7f56795712e3775708e55833186e9380e", - "subject_key_identifier": "0x6296b046700b36867f17e8d3ad48d842d008e41c", - "private_key_usage_period": { - "not_before": 1704933427, - "not_after": 1831163827 - }, - "tags": ["UN"] - }, - { - "country": "AUT", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xd213d1480459a827534f0126d9f17ffabcf5b29ca183031e1f4d9866d5d278b541a5a83c190ea07a5dff6be9c25fca7330ee3dfe12f9655d6c642426325548f436ff7eb979d72138f493e3d5631e1409fdde6da70e7cf4e9c3669905a48a23562487d45e8a3601a4a962396459a533deaa03ee296cb3d27d0dd397ace597f7dbceb9c0c3dacc6de020d3d4f9c1c220cda74e3d9e9c5ac0a7072b44ccfc8b07c6fb44930dc43db99d5fdfca0f3d007fdde292bdf892e99eb730e652432d5e64d7297e47c311f7917b14f60e31c1528855c9a9d027246edaaaa053e516b598a374659d759f79a4f8b7316b3fc9b51a95f71dd2b9559ddcbb6e696d62f38e09ab625c2c87884e1bd89b4bba7f46b8d0e49c38d142584a04bd883bf96ec813f4561b758fa14d1f31360f3e1230ac0e58e081d6fbda98b11245790f0f0117ee1662de32c00f8e3cef6aaba413c9dd4833e9345209dc843f38d464cd78a81ff867496893971f8cc406e9a152900417fc23283b86b298055b8c0ae1274681599876dd90bba8fae1cd3f026bbdffecc657e385a70c223ebf678ce209b4e7de7b4e8eab4e0626d89fc4b6ed16bf161cb4e16fbcbb65514419cd570b1499b00ec924396c782c98c75438b8573005def8d84817cd72ba0fcb39cd668d56b61d1c2c0148f38dec46b969a8e506f9df2545efe38b870d5ea3d310b69f2232bcb98daae41da39f", - "exponent": 38129, - "key_size": 4096 - }, - "validity": { - "not_before": 1302857444, - "not_after": 1784451044 - }, - "authority_key_identifier": "0x1fe1572e9b35121363a50fee3e2ce2c1d187a8dd", - "subject_key_identifier": "0x1fe1572e9b35121363a50fee3e2ce2c1d187a8dd", - "tags": ["ES", "UN"] - }, - { - "country": "AUT", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "EC", - "curve": "brainpoolP384r1", - "key_size": 384, - "public_key_x": "0x05fc569fc7127c5e96f9afdd65ec5abbe5311d7bfb0e98f44e4912d75c7126bed7c6a1c9bc8f6b5803c2d3dd8fb89ae9", - "public_key_y": "0x8bb578b0916ca9e6b99ed6b3b860fc8251a015e710a6290c354b5d47187a86e3d1d6e4b3ffb0fbda143e61db3e011d57" - }, - "validity": { - "not_before": 1412240009, - "not_after": 1893833609 - }, - "authority_key_identifier": "0xff8dea86af18eee58ba2d6ba8cfaab39a169af5b", - "subject_key_identifier": "0xff8dea86af18eee58ba2d6ba8cfaab39a169af5b", - "private_key_usage_period": { - "not_after": 1578560009 - }, - "tags": ["ES", "UN"] - }, - { - "country": "AUT", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "EC", - "curve": "brainpoolP384r1", - "key_size": 384, - "public_key_x": "0x43c3c6026716e0aa300b3b1933e85a639ac183488c235ecd3c53eab01b91b6d0c6de21870b1ea92e2caf8a970096cf82", - "public_key_y": "0x8c5ecb10782c5b9697672a1e51db64883e3ec4aae23002dddc7176c7e994393e3c206dcf513710a82ca2d70ae52d636d" - }, - "validity": { - "not_before": 1567408424, - "not_after": 2049002024 - }, - "authority_key_identifier": "0x2692c7e398abfbe35192d3f26e9a317d1fed53bd", - "subject_key_identifier": "0x2692c7e398abfbe35192d3f26e9a317d1fed53bd", - "private_key_usage_period": { - "not_after": 1733728424 - }, - "tags": ["ES", "UN"] - }, - { - "country": "AUT", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "EC", - "curve": "brainpoolP384r1", - "key_size": 384, - "public_key_x": "0x1ab211f7d5939bf58aa44caacbdfafb354d012fb340e75e454c03302198ccfbaf1fa7914f3e6cc47c136ba36dc103741", - "public_key_y": "0x75657570e7dbc16da4d5e565f9166ed8100e600ae562ea04caeb39ee25e3b8ede1402331fc4e8075d846b0a67bf018d0" - }, - "validity": { - "not_before": 1724052101, - "not_after": 2205645701 - }, - "authority_key_identifier": "0xeeb6b3c86b867ba68e31a0b2bbe1b86d9b1c4ae1", - "subject_key_identifier": "0xeeb6b3c86b867ba68e31a0b2bbe1b86d9b1c4ae1", - "private_key_usage_period": { - "not_after": 1890372101 - }, - "tags": ["UN"] - }, - { - "country": "AZE", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xc4e56eeda25541ac4d55c214a35a08e0038d1b9ff48880363833a79115c5f5dc2945deb489be8a9cd7de4997bebd1372f28fa3b9bc5c1704d7130dc430ce0505fe11ffacaa1d4bbe8828106914b48872876e6a112922a5fcd1c5a86c8022655edd428c3da151d691cd7b5075bb6a4c146335c1bbc19cff136054ef98d8f7ec1acffa8a028d1051949f62baabb1b94fa5080481ffd33f50f42123f978e86224c77e8c2d3632e67022c554658236fcb01eb39cdf0c7d0f2ef04fcb0b6ad89fd860abd55da37a4ce49ed802462772fd003e0f5daf2fa6875d8511beba6442fe422fbd53f48881eb5f587c41997736e250b9da67fe411ce835b6a32393d11b1abe0c0026f9f40bb2508f4db2b95942e2742f5e653176782b760c3a1025f8e4745fb3f0d18548cb694177be385bf60582ad1fdd83d4b947421de49a0f017e0ee4fec5f66599d45ddecbf4e546530e89d2b8771b79ba62dbaaf2069b6c050320b8cb3fcbe3e070ce9981dea3e5154b61a7b99c3be2685d12ea0a932e4dc7a830f41873f1f6aaebbfe27db29e4c3bbb9011a0922512e392b65c035872b0b308e4b5db9a44c9b889a63790560a40525e545ea3f8b3685bd3b7c09117f341a35416cbf49b4864ac64d28a7f5d85edb1c094fbf6fe9dd60ea7888c53fc521cca307fbddc1ea3acac4350a127327e32000f9195332f4d1fb99e25f46bf29cb9cdf4e95d5b5b", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1369666061, - "not_after": 1850482061 - }, - "authority_key_identifier": "0xd7155354cd73a6ff6b5ed23de7e44c099d5cceb5", - "subject_key_identifier": "0xd7155354cd73a6ff6b5ed23de7e44c099d5cceb5", - "private_key_usage_period": { - "not_before": 1369665461, - "not_after": 1527431861 - }, - "tags": ["ES"] - }, - { - "country": "BEL", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-1", - "public_key": { - "type": "RSA", - "modulus": "0x9c2a17e335358292b73feed96080b190e68c887f7d54816ef3d0aabcf30e33c77650a50dc3cf4e8db644b8d2b2255ecb558a69caefd0c2304a36a97bad42b234b2ee87d83a1e01fb6b99b71ecf1a144d2463a7fe23141c2bc0e1ba4d2b0a7e217b84ff6d9c4108f390618808af7cd2503a00e178ad27c1737c0171ebc663942c5aaeb7a7dc33e9d615fe30b7543cd74a5b193e83cc1d2402c40319a22637d7366271a47e0b3c9279b6b649183cdcf1bc7a83e24909be0246862199a23895f4a03e6a82212d0b56891d0f0f10538cfd82fc520570f114c8963cd69f0024e68fbf1aef9bb00bfa0624a62d49af6ef12c54eac3a102d68570d39ff8fb6bcacfcfab0968da15ad7152e5182e4dd9c328c95025809d08e5ae81db3dcfc9472d40715b0945313c387e2157852868c8d95076359b7e6839aa940aba85211ec0eb65c8eaceb2917a6dc1262f442c79f42bffafe0b6bcf5e7e73b8be82f492f848c24959884240954ad5ab23a070ebc7d60514d6e5ee112fbbcb3358486112edccbf0baf914b615c456338513b13b07f021ecca815bbc08274ef7db2b6e76eac6fb757e90a0642b7148acb24ee91bb98638f6106d24748c2d44fc0a66c5b976a383e5cb9d3d6900b05b6f0791ea4405b97b6713913b09dd4ac157c0ade639ea3aa2377e82a48b88db02727830f470bfe7099e7bcce78725fdb0552f861fcd728076248423", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1352296521, - "not_after": 1772891251 - }, - "authority_key_identifier": "0x2c2982988428293bebc40c7930c86cf3802bae76", - "subject_key_identifier": "0x2c2982988428293bebc40c7930c86cf3802bae76", - "private_key_usage_period": { - "not_before": 1352296047, - "not_after": 1446904047 - }, - "tags": ["ES"] - }, - { - "country": "BEL", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "EC", - "curve": "P-256", - "key_size": 256, - "public_key_x": "0x0aaf3b7b60e18d358c2a825261cfa3e39e5a0de30eca208877c3967ed6c11248", - "public_key_y": "0x9b1d7627f89f64f07ae2316446d1d251e0688419be4fe913cb59d94dd31e2748" - }, - "validity": { - "not_before": 1402733939, - "not_after": 1790065139 - }, - "authority_key_identifier": "0x1ee911300c144012e6fc58923ce63607f400761b", - "subject_key_identifier": "0x1ee911300c144012e6fc58923ce63607f400761b", - "tags": ["UN"] - }, - { - "country": "BEL", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "EC", - "curve": "P-256", - "key_size": 256, - "public_key_x": "0x3421f85f829bceebf30488003fa25ff01f6180b7f326fdf63ac80c3467f110b7", - "public_key_y": "0xe80cd98fe7e3a19150dd4443a0d93d8864b55a5c3e2b6345bf04583baa399370" - }, - "validity": { - "not_before": 1431008150, - "not_after": 1819980950 - }, - "authority_key_identifier": "0x094672d21eca27d90bfc404b5f4d704203d9806f", - "subject_key_identifier": "0x094672d21eca27d90bfc404b5f4d704203d9806f", - "private_key_usage_period": { - "not_before": 1431008150, - "not_after": 1599142550 - }, - "tags": ["UN"] - }, - { - "country": "BEL", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "EC", - "curve": "P-256", - "key_size": 256, - "public_key_x": "0xeab2a37b1bcd5cc965b76ad99228e9a1fd624d1d6d0769ad9c3662fcea3b6c5e", - "public_key_y": "0x34e4abd79f4d4ac49c7c2da7bb44c7421f7d0ead2f81afbbe682167ce534e3d9" - }, - "validity": { - "not_before": 1506588579, - "not_after": 1895561379 - }, - "authority_key_identifier": "0x58da50753061c0b13a15891d4eef80a9854fcb74", - "subject_key_identifier": "0x58da50753061c0b13a15891d4eef80a9854fcb74", - "private_key_usage_period": { - "not_before": 1506588579, - "not_after": 1674722979 - }, - "tags": ["ES", "UN"] - }, - { - "country": "BEL", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xbe7c2af4e0899593559615e7a63ff600335231995b36444212c458850206bef176a1b0fd16c3c4cc73b166f4dc84c399ffa35a38adf8841c47dfd41dc3646bb005471df8103c04330ae5a763309e64b975e82f06703d143a9f5fd6142ff6f8308329267cbe957971b33221b22f026c2fe9eac0f3e1f3d650c9c048cdcc77688439d3a5cbafb5258397431689ec36c98385ac2e4759ef38fbc552dacba7fcefb7d886c1d95a22115d6557dcd110fca80f25c9233e45efdab7a277f98a3d137d7b02b38c943cf71642b5b735d67c09740b8800bb17b7c47e616cc513010473ef1887d03fb705cb0764dc479a78188a76f9aedd9314b03d8df30d01bbca9d95668b8b6072ae07b9d0be7cdaac42d6be13c09c60d995135e2b9129d4c841c3a54fd65033ce65e10a4436dd35cc93e2a0f7d19ecc8e870ea0755a0616b3567b7ec56b2309ab282abe60114525a3ebaa0f21cefa5b7d3c1c04edc474a2826e1a6e87ef54067b979f48bf15a9674da750aae71eee2d49ef6044ffebd9e5b57243ac388637763b4cc4830abd540871cbabccab49c8e13e6261ff98547205d948e76268a0bc29fea35bd7a4e305d12b1a36675b34451338ef48c65fbcb71feb4d2e2d7255af1206f3474f17f040dc124bb26c0808a3b841da67f55af0a4a6857d61f0654c42ab7296f371dcc872ef73169a31b92e3875870af2bf24251b6074c1cff55f57", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1572342398, - "not_after": 2014187922 - }, - "authority_key_identifier": "0x80b27ccbe4e44d1cbee885baa026aad278f82b2b", - "subject_key_identifier": "0x80b27ccbe4e44d1cbee885baa026aad278f82b2b", - "private_key_usage_period": { - "not_before": 1572341921, - "not_after": 1667036321 - }, - "tags": ["ES"] - }, - { - "country": "BEL", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x8193211a642eef38f06f7bc97e9a90dbb77e66a84afe0d3df6df89168a5741f15b6f39fba6be8a183f4ef6387c061bc33000484653ddc25e3586f9aa45c879f40e8a5c7c8b458f39ad1724fbb7094a95be463a524ab636b8545ead5c51df32bc95088d3a697d17a693fa537ad557584b232102be9b34a7ec193442864e5fe80edfc366f33edded99169788963998e8916f0b1a423128f6bb25f76f308a152835ae97c1a56a793b9915e1b0828aa8a0baf7e6e5b74cb5fd9bab53561a06044531dda9c93159f097201beca513241f791f134d60f2ec979bff0fd75da7d07ac10527e2863667f539130eca8c45b4d6059ee5c702552ccf266749b3e27c20c2933a929978d9a56a1b6a645e885786b5255968b657a452098fae12cdc30c39731df34f419e21a4e9cdcf1421e2257c5279527ed2b064863ce703630cd57e279ff0ba654f591dc4752bb800ee378de73d67c9d2d94e5842b7e50bc3af929cdafd1a6e6218b20cdbd82ec3e7b15d2909df3ef947b9c1719f8e224020b5f8fdc35c14c7aa0394365a2779132a78c85858c1385a21aae82655f56c2fc1e381e8651a317b3f0c52913dd638ca245d01cb0836ab0282f9e2fb32b5f7c68b69060560d80d76ee9a25d908180858183d831398ea6e2a9a6f23efe9f9f6907ff6ddb47d7d81827fd23ff2ec4d86fb8a3aa66c16bbf8167d47ce5da7689ac740f13dafe2b390d9", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1589809838, - "not_after": 2052741038 - }, - "authority_key_identifier": "0x440765c1562c8a4ec703bade651a17cedfe8fbdb", - "subject_key_identifier": "0x440765c1562c8a4ec703bade651a17cedfe8fbdb", - "private_key_usage_period": { - "not_after": 1714225838 - }, - "tags": ["ES"] - }, - { - "country": "BEL", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "EC", - "curve": "P-256", - "key_size": 256, - "public_key_x": "0x7c75af1749ebc6176c73cf760e7cf1f6994117e4dfcf0b516a91a657052efe7c", - "public_key_y": "0x76a504b1124fdb774aad9567146af433525582157ccd752d043b3acbb6adb4b4" - }, - "validity": { - "not_before": 1639052788, - "not_after": 1962447987 - }, - "authority_key_identifier": "0xf29b05fdf863c5f0fc1903908f4773fd18e2b9dd", - "subject_key_identifier": "0xf29b05fdf863c5f0fc1903908f4773fd18e2b9dd", - "private_key_usage_period": { - "not_after": 1733747188 - }, - "tags": ["ES", "UN"] - }, - { - "country": "BEL", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "EC", - "curve": "P-256", - "key_size": 256, - "public_key_x": "0x2c508b86a1fee917fe3bd1f9bcc572a2ac153cce317548912d5abcdeef94c98e", - "public_key_y": "0x25f848ed7a82dd3d9e932135fbf0a58eb3c85abfc6debfe9c976b04c33772bff" - }, - "validity": { - "not_before": 1732871468, - "not_after": 2079767467 - }, - "authority_key_identifier": "0x0e947be80353c7ef3c68cc6e3bcb071c73dee1eb", - "subject_key_identifier": "0x0e947be80353c7ef3c68cc6e3bcb071c73dee1eb", - "private_key_usage_period": { - "not_after": 1827565868 - }, - "tags": ["UN"] - }, - { - "country": "BEN", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "EC", - "curve": "P-256", - "key_size": 256, - "public_key_x": "0x1cbfcd41b721bdc0af6b70d75cfe51d6662b5bd56ad20d6f7751e0b787906457", - "public_key_y": "0x6d19149717e3dc3b7776553cd147d853031b9c239cc2a7a2b142d6d61de1a882" - }, - "validity": { - "not_before": 1559127857, - "not_after": 2051004857 - }, - "authority_key_identifier": "0x5006ce991ffbd5b2125a20cf5c94d9b978c3dc05", - "subject_key_identifier": "0x5006ce991ffbd5b2125a20cf5c94d9b978c3dc05", - "private_key_usage_period": { - "not_before": 1559127857, - "not_after": 1716972408 - }, - "tags": ["ES", "UN"] - }, - { - "country": "BEN", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "EC", - "curve": "P-256", - "key_size": 256, - "public_key_x": "0x1f9ac02e9f0bee11ae0928a15b59924b4c99d2c57378c227c142e5c79433adfe", - "public_key_y": "0x00c74caab5b1d985c52a99d26d0154d3454ed9d52671badf7dead1ad70c71d3e" - }, - "validity": { - "not_before": 1727450851, - "not_after": 2219155051 - }, - "authority_key_identifier": "0xc4a90f7c246ce5ad69cfbb58c804bf219dbc2876", - "subject_key_identifier": "0xc4a90f7c246ce5ad69cfbb58c804bf219dbc2876", - "private_key_usage_period": { - "not_before": 1727450851, - "not_after": 1885239951 - }, - "tags": ["UN"] - }, - { - "country": "BGD", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "EC", - "curve": "brainpoolP384r1", - "key_size": 384, - "public_key_x": "0x47782eaff086761ed22089c560e7f02154423422c67f89420ff876f73a266c07fb2dd5a0295284584d0ae19ac90c95d2", - "public_key_y": "0x4fb69f428ee73ce8b038182ef8d151f0344223a1c2cb2b97fa0616bed0b9f40b94a8bb5d88d5f036fe6a03797cdaf2a5" - }, - "validity": { - "not_before": 1653809384, - "not_after": 2095572584 - }, - "authority_key_identifier": "0x18ae41f739e784fe0008a4075827a1f04bb53cba", - "subject_key_identifier": "0x18ae41f739e784fe0008a4075827a1f04bb53cba", - "private_key_usage_period": { - "not_before": 1653809384, - "not_after": 1748503784 - }, - "tags": ["UN"] - }, - { - "country": "BGR", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x91864f477fe31a7200168b255b2c6b8200413ef47d15c00f513f078e33e3d4f7014306a0e873ac0b14a52dd7a061be0b385eccf4e1557600b518300790d7e601fd265064f89389f3e04c6cf87854a0c2498d30f9e48a88ba77dbb2fc817ba04a025e2f0d19fd5f48b63af264c674e62cdb8e567d5f267d11f3feb9ba55060130ae5217f99b032974b32e76bddae5e45c521cf321ca416e1663985470c656b01389894504c54327b25fc7b8abbe08d3f51d19de272aea3b566a352f39de54cfb8a415d4ec71113cb60a932db018fc4bcebe457d46089be6c632f98b6b822854b87d5b89ca3bbba1aa94553e78d6173654889c6687d917edc33968c9e5da89c21faa2550952fadeaa36ab56bf4e479334333f4a7b5d1aae5feacc91c8db97c14c604b4826be49326823c19bf96dce802527d0d8b7f1aa281cdcc5b06282278bf13bb94dae6f5d9cb3cd1604fef871e6d434c8bb14070a5915499277d8bafc5581944ec28aa860c7b5ca1709066b82757e997f4293bb06892cf7f942760aa9d8eb0977957ceab6facdf144bd023c87b40ee3745e6180cda9032a2995505751d964dffebf1cd173b23dc7db01fe59061a21b892e7fa56f04285d373db3a8aaa1405ab7ff76d9bb731f6c6e012f8e7c4a9e9298a4abfff34b896ddf64474673416131360cbf5fd75e511f60274f948b2bfa88661e88deaa550717156e0d80b359539b", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1397633926, - "not_after": 1878449926 - }, - "authority_key_identifier": "0x9ee0bfdee2d3d4fced1b3928f54aa7b3265dfaf9", - "subject_key_identifier": "0x9ee0bfdee2d3d4fced1b3928f54aa7b3265dfaf9", - "tags": ["ES", "UN"] - }, - { - "country": "BGR", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x9b95c9bf5ff55fa7afc7a6b1ad4b67fb8db487f8dd5938d370165193390cb30338fc5d6041dcaa77a4f86a34d265f6c46b6e4377c482265a58dc6d8199dcb45b0b656eb0cabcd1663f01bbf7017a20bde3795db1472fb5e24e6049682797505dadb300e0124295d5569de10f6575d49a7f788813686e8e8a463c9a8a3f68baec03f9af2b86b3011d464f53f10338e04a44a46f1403d47bd74bab63aa9023f068700b9970b92088167e07a1828c9c55997e20d13c390a900b0d6bc653c694dff791c821061734b1e55f7298645a851664f9d8d02c52bbdd4c389eccf3587839520650edcfbf812228595e3b3533c67792c5d815e16a5681d5ef710dc2356d3affd046fedb1f70f7582529643a2f3c5bc5f1dc6fc071daecd20eb0f551ab774e591d902b0dbaacc40cb318a4c8e7705585ed52bfc85ffa342605a1f5cc6196071bc22018b9ece265aedfc681cf424ffd125743aedbfdaf027473e58d2117a90bae815c41edc86a8182aa26bf9656256dc02ac8138f30cbd1dfb565e7276888e515c2f379072768683ce25a9c73f92b0415a1e1f376f10369030388668072733fadedcaed767b5865401cd41dff51da8f960a3af1385f679aeb548e90e228cce75efceef49fd2a347ed8e5e99562e7c8cb2db4e881da23db2efd93a3a9f0c02e157835a6b0854d0a6f18d5bd220c071327ba839f33e52642c31bf6ce8dc9b2f8625", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1553084882, - "not_after": 2033814482 - }, - "authority_key_identifier": "0xe1129d657fa6f779e2b418b205db275efb9ef5b7", - "subject_key_identifier": "0xe1129d657fa6f779e2b418b205db275efb9ef5b7", - "private_key_usage_period": { - "not_before": 1553084882, - "not_after": 1710979199 - }, - "tags": ["ES", "UN"] - }, - { - "country": "BGR", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xae38bb6c1820f8efb194b93b45921e3c282b22a217997b6a1fa20c4cd5953a3eea10d586d13603b2bbfe75dcf5dd4e871738ba15ecea861e69a6241309c74bebab351eb558c3357cc4c1b9762043aa7cf18a3fd4eedd49387a5689d166057743b3f9b0a1f6bb6d09316aa9da30db9114f56a8eef133ad9f83b1764270deb575924df19744bd21f014bbff332ac0912c8fcce37bd084246b4988108bcc3745488210bf7a949a23052e1ddd083b77c53c9366bcc82e5010f95b6f912945f1a594680ecdbb1ed64631763d5c02371bcc09b9fb98ad55f73921cd3a6f51bcff9272089eb212f979db7ecb34f23a92cfaf4690865a66ada61c24fdc44664abfc86c809c042382e80c29a845187b48d3d7fa7e38cff517e7d106affd12bfe16e467c7d851ccca5c84bfee9094bc7e7aaa14dee347fb502654b9c260dec0fff54f7807b634beb5265e8418886a3fde8b3b9f63e5f84528a3bcb6d992fbc6a8596e2f7ce9477eb2a8c94856aacf959739fdae5e66200ceea35d623ed320e808d1c403c785928f0e022f69d41d392e4af057fcbef985a1a37252ae1cd123f01fd6d2ecf070feac8fc3573be9c886e47b83fa69133a9505526d1a038b9bae805a407f533bb07e0e84749b8ef73d5b368c0cf082f88921d62136d259cbd2c6bd7dc0732e751a59529da10b2f30726dc02c4d5b68e9234993b1f96b05e2f8d6c207129cf9e71", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1707400038, - "not_after": 2188043238 - }, - "authority_key_identifier": "0xf67637e0aa63fc89d494c9a1bb956056c78c22f0", - "subject_key_identifier": "0xf67637e0aa63fc89d494c9a1bb956056c78c22f0", - "private_key_usage_period": { - "not_before": 1707400038, - "not_after": 1865289599 - }, - "tags": ["UN"] - }, - { - "country": "BHR", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xd664e40ec144d0eef4a3d4aaf6c54e18db5193c70526584689597b9ea8e5695dc9f080e5f37be3b23a5a7f2fd6859ddaafbe2cd9c1948826fbda98e3dd8b06eb6688b4044f77ba8ef99bca1438a82816bd5cfc0950d63744933ef382cf1855b07b763c68cb39a209fab1529cec983f8043db926900a0345ffaf70962dca179808752651bd255f55eff73cc2a629ce6fc838d22283ae4f31a38954018977e5024c320df2bd82e3a4f032d1b5d0093617d110b1580e7fd1914577d8df609a5157c97ca4cc0a79506b70f7a3e15f497725ba7d082deb2f16c3e48e0cda51eedd8ab00eb7b8f37aa5b18f89584a38b1f1f0e00429014a98b83d0682cc9e5cdc4b2e542cb394677a36482049e6203f44c4a4f4eff285742d872ab36836ae631d88c36e5820a539bbc38bef4e282a0fae03d97735f98cb7a9fc0435752d1a5538c44c6e39c58a203487ed87b2c74ca5283be44ded8a3e0179385b2e542545209916b5cf0d5f897bc20deea1d50ed342197e1e9fff129b93761d31a9fe9b80dfe5e318b55497d7f2db45e55dfdb0f6235f08215d2cc8ae0b138dfa92311a9c23306a42dd3ab7b2a2ed7b43498fdd17ac80a18a261ec28a0ab265f3dca128c68ba5874fb475ba95fbd0a21e90127d169cb73bbbec5c25e55ce912b6f74b15c4921f0229559fe96be110b2ce0b3fc4f8ed6c60c9fe14a5bfba36113b6ffd43fa00b3a437b", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1677618000, - "not_after": 2095966799 - }, - "authority_key_identifier": "0x2ca4bfd342ce06cd70bc0d5ee588d6b09c7bd218", - "subject_key_identifier": "0x2ca4bfd342ce06cd70bc0d5ee588d6b09c7bd218", - "private_key_usage_period": { - "not_before": 1677618000, - "not_after": 1772398799 - }, - "tags": ["UN"] - }, - { - "country": "BLR", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "EC", - "curve": "P-384", - "key_size": 384, - "public_key_x": "0x798474ce52eb7a009bbbb5a77356ec14027b4c0e2144a5b4389c912bcae32619e3e186f2d530b14f6caaaca2478f6d20", - "public_key_y": "0xc50c80597ca9f14d20e1599776749dbd2a7ea415ddb57a2b4fa25e3deb2eb649d9f19e04aea200f7afa98c90f1b63654" - }, - "validity": { - "not_before": 1606289147, - "not_after": 2087105147 - }, - "authority_key_identifier": "0xe609e0f56f165db0e4bbf343b828eed326cf8b90", - "subject_key_identifier": "0xe609e0f56f165db0e4bbf343b828eed326cf8b90", - "private_key_usage_period": { - "not_before": 1606289147, - "not_after": 1763969147 - }, - "tags": ["ES", "UN"] - }, - { - "country": "BLZ", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xdb7d23afae55051ecc479a148dd67010c98a0890f92310474156dfc7ee513efafe71fa22accc6b64138069617223a7db0608c79f0e40e99a09e5df00bda8578b146611506ba9e13d390c8ef8b89aed5017b4070b4929a5271e2c175e0030822d0de9c0462ab80d45f10b988af0e6302d7d15d4fb563ae160e704487e72b61f2671aedf393679a1aa18bce885972b2ea42a544275ab257ded86caa3e7287fae46c9cbc99bd6480f74ebeebcfbab9ab11f193c5535d9b8d90d6a4184500eb8850d8b4dc5ed6e5155e9782fa903c27ecb84049fbe49a1e448e2b44f1b172506b01e0944e86971e061b2d871c48a687d53bf66658daafb2c4c94094de3a5c765a496a376be22e0b4823cb36bc3afbcd0c77d98887d1f0ef9d42e04b93d3876adf6c3e4969863552664320e23ba744454df3ff8cb7eaef2987ce8b717e454e68d2a321792f2266759f6adb7c1ede4101ba27a18c41108b37cd932a360d5a0fd451fd16f5d945631df1d21c2f78822f8dd0b66fa3c5c0675e94b0024f084dba0d99bd744032b57ee1ba721677e071936426fff3242187897e1af13a8f586c4b15c32f69dfb8d6098177df503de72046e6aeb86f4e5684d152af6b7b2bc6ff381950af9d2eb3f33b27e971847ae4d9fdaf944111f2d73367ee5089c0b637c8c1e09fc98de32bfab1c74e020d40061c1ecd0a94377856d5d7ec29e098ed31ee07e627e6d", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1665608511, - "not_after": 2157312711 - }, - "authority_key_identifier": "0x778cecd82d25427cb65ae1901a734415c2944c29", - "subject_key_identifier": "0x778cecd82d25427cb65ae1901a734415c2944c29", - "private_key_usage_period": { - "not_before": 1665608511, - "not_after": 1823397611 - }, - "tags": ["UN"] - }, - { - "country": "BMU", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "EC", - "curve": "P-384", - "key_size": 384, - "public_key_x": "0xf40fc43b3bce3734f0dd21810a78c4c617da2d5d0bb074ac3701950163338e7ac992ac4c93fae650d3ae931356b99376", - "public_key_y": "0xeadfc00c0e32bfa3afa097d3990e548b8ebec79484a2ec93768b8356043bc75d594c3fba11c6b4abb7af49dc40c5ea0f" - }, - "validity": { - "not_before": 1705492456, - "not_after": 2220871464 - }, - "authority_key_identifier": "0xe9e24f5c242203cd3e0bbb1a53d760d3fd55f88a", - "subject_key_identifier": "0xe9e24f5c242203cd3e0bbb1a53d760d3fd55f88a", - "private_key_usage_period": { - "not_before": 1705493664, - "not_after": 1865262024 - }, - "tags": ["UN"] - }, - { - "country": "BRA", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-512", - "public_key": { - "type": "EC", - "curve": "brainpoolP512r1", - "key_size": 512, - "public_key_x": "0x12363cc8d50c67ca72ec54793827131a2060162d471c9d790e9f0c02bb014d202b7c76ff63ecc3793357f0265270a89e516481e2ae29516d8d44abf6ceb73371", - "public_key_y": "0x372662ce0c54285cbea98e079d99e04cee097e9272e714e0eca2d878551ce3d695eaee58bcab13ba69350bbfe11dbe714758e76819c45954d4f4a128bad7ed52" - }, - "validity": { - "not_before": 1429816758, - "not_after": 2060968758 - }, - "authority_key_identifier": "0xfc4ce0f76b6557a4d9edc8ca72ad0535517b674c", - "subject_key_identifier": "0xfc4ce0f76b6557a4d9edc8ca72ad0535517b674c", - "tags": ["UN"] - }, - { - "country": "BRA", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-512", - "public_key": { - "type": "EC", - "curve": "brainpoolP512r1", - "key_size": 512, - "public_key_x": "0x751b618db97a3d812ce1373fec887518accb80a7a716fca17c1bd4ebfc923246acfec95cac05f425b47137680fda15be23d481353ff07e0be5bd53c3f9779b86", - "public_key_y": "0x721afa04d989696f890ead5935023b4c8309240ddaceb69cb053cfcf9912e6ac577a150da760d5a6854a1efca05304062eea3019ae157904997202bc9bbf0c69" - }, - "validity": { - "not_before": 1740145150, - "not_after": 2370513610 - }, - "authority_key_identifier": "0xd91de80159566e5f78b79707267b7657b007c7b9", - "subject_key_identifier": "0xd91de80159566e5f78b79707267b7657b007c7b9", - "tags": [] - }, - { - "country": "BRB", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xb4454697737f305a36bad0f55f175de3b45c723ba62683139cd78e1a2333fc96408fba304ca109e2fc88acae86652e27214940323dd0f4cd0961214cae533f2da417e7a954e136fa14811db36b4eaebb2e71008bf2a9c1a0a771e38adbb3fd7ace275ccc2cddaa6a28b825b68874cba9b106587b74ded62005acae257ace64f834ec1b1ccbb644572a910a541f0f7b6c1c30f2cd83d9b4a1d6277a8da474c8e909e194754034b1b70c9f74f81c084150f076ecc5ba8dad832fbb56e837fa9159c7bbf61476da1448542ed3576e390605b9f4d1c271c8c17f0a5f1e0a5851e4ad0b403a61f0f41e5db84632210cf61826fc8a4c4d306d42309591b5d82c150b8167a143863d46c26e713e00974ccd497b268d8e2f759025a1e06bc12a528ba00beaa1ffb3acbd5c60f1d1f20a6d3285ebff47bfea9c69654c12607fdaf0e6388aff1b43a296c5a8f2a245ed30ddeeb2f393c7f799be2cf6f95d5beb266788c3795e7714b030ca886fcff87ea038ff3c49cd23add95230086b19b85359c6a3a57a235305ca64ecde190b4befc1117e0ecb083e1d9d8aba40bdaa828ded8486855cd9d85ad9be4d18f20be0b9459c3c6b1e24045b10ce871d98513e11238e15e4ec32688de25ec28bfac58cfa4b7b2f4f270f2cf55a89064bd567053b120ec3665f805eed784583ee1d46a32d0b006dedf930dd305423b3b36af948eebbcd17d65d", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1489147062, - "not_after": 1938860862 - }, - "subject_key_identifier": "0x39feaf410ab72ea1a9ab5f4130dd0d5360fb7be6", - "private_key_usage_period": { - "not_before": 1489147062, - "not_after": 1607493722 - }, - "tags": ["ES", "UN"] - }, - { - "country": "BRB", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xadc2256a295662d39211b3ec61e63b43fd19df7e8c7fa2f483deb40920f7d441ecc125cfc385b8b4c71cf597751926759e4c853ecd2dc80271fab577c562bc0d2e2f15b71a5969b2222655f7503d8da13a21ebbc8b2bf00095183844b1bfdc4b17f7321c6e3df54900967c10323a2f5a42ecf2db5bfe4d1d053376fd8f9c58b282bffe7f830d97d65645b64a584bb0b2fabc3254912c664b3e02430729437f46caa9998e10131c8a0954de6e4532e72f9c091e224ab78e341c8e3fdd6e3d57eb7aaf56f77a1c32fe335121783b08ca062e2b39bd17818f705e59af852f6b3a634a99d70beb1e05fd70c752a98f4330badb541498139a6de4b343b2988df8187f3aa3c0391a78c76802c98e80d3d23f42d50b564c3b605579de1a3f0f5608b7eca161dbaa29e996032c9c915b46f69d196eba4e53189f1278639772b139b6de5730f55dbbd293a01e85508c9f66bc1670b1fb8ce40af0bc0a6b980d820a44a164798b81b4c69777f140e5efe97e4521eee994f1a725cf5996ae7eaf19ebefa8a3af4736cf9defd92fd8f061893c741a90c058ebf66b334240ee9c69063edec64aee0a4940eeb6440746411746e3c70c3a1b72cd76986710f70c0c06ba826d3d69160742eb488bf33e71ce41b569b23af8874402ce17bcefb1e2e5d306e3bfa6097e7aa975dd3d34f9714558ded7c3a5ad9d90796b74ad2b3f61ed640189320755", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1604582629, - "not_after": 2054296429 - }, - "subject_key_identifier": "0x84935da31051b4304c2cc0ba08d7ed08f0038538", - "private_key_usage_period": { - "not_before": 1604582629, - "not_after": 1722929289 - }, - "tags": ["UN"] - }, - { - "country": "BWA", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xaaaca9813512871d1e3bc695fc02bb10c4b93348ffa80357676f099b92885812e680041dcecb7b9c859bf51ff8bba28beb2482b1931f64e25ef7bab9722aa9f6c4865dfc28be523da30c805a08c00f9bf6db39af1d7887e7a4fb060d9cbd713d3c2b4785c802bdc8566cebca5e9d7aa3c60399d9fcb848d08e8f29a0606917081ac3a3e6aaba1cde5a44855b036e365e65315a3eee201ae7633ec5c9cdf3c3bb0cdffb5644ef71f1ad105002d3c5342fae79caa0191746e5f8010595a2f0b531be4bcf455d6d1d73b1386bbdd602f6589f6e248118f8f6608c7bdcf34ba13240cfee976aa0883c22b141538860d2efd6642178f699c7975be9fb4e5eef58210acd8186dd7030db0fd0b735cbcb619d681c9757fc99ffde851f8b4e2138c0fa7c98027ec07d7d53a98bf3312f8e8172502a1fc0444638c8098915c0b5df4b0abf03b00285d191392fce65924f3bfb8d1c3da2aa65aa05305b51964b527179cbdb6176adb96d933ecf7b5483294b795ea8c1609ae5fca43cc4dec72951db0324426b735d51b4de3a13acca839be4f6edbe29991c82ad8f10e41e732dd58a1cdca8693a3dac8b7ee9b694648dbc4e034f3d86a4fc05faf3e1441a29d07c6fa9e4a4ab38be614aeb5577643885d381ff3fea0845cdde83bb1ddedad0d8409a8328999f643b3a041f152fff99b5fbf17641ef8f12bdbbbb7d8571762dac81753f7573", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1253001162, - "not_after": 1884153675 - }, - "subject_key_identifier": "0x6df1cf841cb85333a2eaeaa7ea76111c025791ec", - "tags": ["ES", "UN"] - }, - { - "country": "BWA", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xb26e6aed204b1c19369b1ad80152109b3c84ff6d8cab77dff82c3ecfbbf641639273de380af93e95cb9d6ce6ac4d0a9ee86e96577d582f55e8a503b2e70c0799e4ae713ac0195f4964a7eb6a2fc85caf1d973b1ea400ac64088f42adab6e7a8e9c94ffdb6a345ec1828a0560b2de444b1b35a7a8c29493fe0a6ccad023571547709751cfff7ba28572d06ad1bc0a15dc4bbf66dbeede46eb617be471563f0a8232c65dab99c238f1393fe8cf45ca742e827417b996d8517269e922bd153124cb59b0ecbd6d7d189078e25b9c8ea7fdbd39e1f0e48261957973a0c20f0fc963264d97c70bb82d8781b46e235df79d8a3dfdd953e47791683f446b1cde6db8ccd3754898b0f80eddc9f735a4c0002ff28fbf2e49596b4810d8e0d41da7551ad83460b730a5ac877f387be772df4c093d86082b7b6f118935c4fc1a85aa80303ec43671d9f95999b81429e8755a35dc9230b3971605ee4ac2db7883e9739400f3d8d360be7841fdfd57abbf4a71bb5c9fa09533d5cedb1354f63062eaf112c69410a05e536ba5312f1bfee6ab4a9d0b76f35dcfc9ec322e20b1d839a5a83c4f499f2c9abf8db25257b13991a4726c5c70533efbcf9fbc96555a894eb9061e1341a85e79c2fd24e0120ccf3e54dfe7448bd1811d6ff9a984c7d596e52b6ced70ab2cb5a7cfcc39fc15e879d6a80be33a839ce6fc872c157644600a694dfc5ff1b7b1", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1542979081, - "not_after": 1984829270 - }, - "subject_key_identifier": "0xe89fbaddcbfe0872cb24fe72f744b790371bfe3c", - "private_key_usage_period": { - "not_before": 1542931200, - "not_after": 1637625600 - }, - "tags": ["ES", "UN"] - }, - { - "country": "BWA", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x8c21baabc459de55cae5dda018d1dcb7337c0e3ef26ce41aca7c03e97eb5c2264c9d001dd9a59ac080f985fea7e3fcc93319d90bae9f4997bb424ae6eff7af3a1fabdb216ebb5cf9d76a01e0bcf1a8ef0925f3670f3dc5f8d334bcc5339c47f564adc840e368da70ea0a1bc5ca4cc896d534c3bd4a92cff78cf7d46739595a1e25dde7e8276352bef2b6d9eaabcde8687587b65cb3bf7287f44736312fbd3b138c3bf608b4b47a75305e3afe59dddc9e2cc85fa1dbf646c179cd13bb004a0a4e42326b566fdf716505d5c9993880588b7b81889fb4ed4493a345313eb08f028654f0c63c3d8124494b0acb20dbf19134c33d132ca0302ba3181c1298cc0edae63c8236fcaa11c824f14af0c0ee2156a17d4a6eb2d6b62498773560c1eff4c96478590b7df1acb169111d35a007fb49092c1fabbe265007b0d4ce7aa854e5b12af8fd9b38b5443cf126a433b82e94914b3ff2d7f69034368f5ed4f64f87e242e0e21313289175762b406cff5f786841bdba74eb6a4a06c7ae2fd833aac6cad9df180fcc00c1bfbd48c67ac0ba36526a90bdad096204fcdaa5b1bef5c8213163d257b5a3b5b9276b3ee0aacdcd5c26695462a21fc2a70394229fa9d4e9fe0a856c0aa07ddfa82ba9bdbfb657a6e21dd8fcad7cf37adf898c9dc935409e6b7df4b2ecf1667a228af24baba69809166e7fd6e674392b29e2ad41644670e1df195bef", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1636646096, - "not_after": 2078409896 - }, - "subject_key_identifier": "0x5e65d3b40b191a78a5476b465539eec6b384c00e", - "private_key_usage_period": { - "not_before": 1636588800, - "not_after": 1731283200 - }, - "tags": ["UN"] - }, - { - "country": "CAN", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xcbe4364c402583d64f8c9d4d3ba54ebea74b22c53d6ceb6e7f5f15100a042d5a9c4304c21877c965a999c1b32fe57878d97f3b8da8cae87421e0dc18eaa562cb1085ec10eb14ed3a46feac7a7414d012add9ebd64f9ee1a1c261c51e447106a25dd5934ab0fde29d343b4211992a9ef307eea4516f4c8bb95f84fa2fa77515c797d471edde08a67b274f2a2d0898fe773e8c8fa2a9584402ebf2eeafd6cb78f6855242765976c796002a894e37120b827e3614208c6710030845c0a34e21fcbb22d5c3c9d6f792cd360a15cfaf296e95a85b04bb0e6652424c4e4fc9236fefb15f5212e712083a45314789ad2d587927787f59f36481cc71c49daa40c547889ebc8534f83de05000ed0aad536586e37a6a9055fd711069e20ae2b843bdea92c2feb61f9f7ec16ac88790a5fcd82c5e180ba202ac1b1088fbfcbe2da93078fe053b4e686b53785e5d4b0889f8d6a7555a242942675ed0f5670af1fd4409502f7e1dc4854e8a0a1a27581bd0c3267e390524dcf4b2dba38a017e32d3f64e29caa358392e6788e8c7b9edd94735037807f030ca5ab68ae6f361256c41964d4f8715a74c991d87664f9ed17cd89e963da5d62905f3b7f0fea85758358f921e8bca7977ec835ab2190b1c9ded7f34572f5c19f553636963777b815c25edd556567a76914725f8410707454aff12ee3f5a80481c731ea1f3efd6665fdcb9a6f95d059d", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1354723057, - "not_after": 1843835257 - }, - "authority_key_identifier": "0x8c8e9769467ead0687dbbdf85ee6e6c5c92f0722", - "subject_key_identifier": "0x8c8e9769467ead0687dbbdf85ee6e6c5c92f0722", - "private_key_usage_period": { - "not_before": 1354723057, - "not_after": 1511238457 - }, - "tags": ["ES", "UN"] - }, - { - "country": "CAN", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xbbf41897330a4a6d79224d04c20d8331d4666a49832c956815834dd40675505ef680896835dbdff8e906676f595d6e1bb1b1df829bce22c3b43f0cc96ee7b801f51a44449281e7bd555f2e97db88f63ed524e0c7bea3789a7288cdc3e150a0c1dcf7509be18e903e782022f7c388268187d5918199079c5fa13f9ef051052bd4921e67361ed9b6fa271bac21a869747eb55bcd96624154bd2fd93b8e05a59f24d70aea2eeb1be8131af2cb266dfc2c34047c4db5967eacb501fd04ff1f3cb7cf13ea785c63466d6481548165afb502fba3302599eae6d792ebbf596c54263286b1360241fa9bea35f4ccc5e1bbffe49f14a6a369f5fb1ff56c5c9ea0776310e9c082d9776b47e1230b2601b4b24521094214daa5dd7ed4692016bbcaf45d1214ddc1d66a59750416b9b34526e0ba9af1ff4b4d88408213685c2da514d01a914ecfab23566a5f2a1aba69b58337435201918a3872c3a448efe3b3b14d38137616e91140067d5a2b60480b7f5f6a2488eb6760b71ef1113f776441dd703f49988b746b30ce224b08e54d99771473359a58c54519816c644307195143809860a4acf89fc6707b431ad7dd5b3dc6b5aef966e21d02c04d01af6fed491209133d27186e8666f7e3c9d2c12924d9c88f41a5f064226e51ba7f188cc8352d04a5cf8f9e8158b7b232720f568f7afc1d2e18b668bb721c25007a41786b278bb2299ede3d", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1505236294, - "not_after": 1994262094 - }, - "authority_key_identifier": "0xcaa705cf9ccc5fa1b5c9919ecdb0a173ad1b0fb0", - "subject_key_identifier": "0xcaa705cf9ccc5fa1b5c9919ecdb0a173ad1b0fb0", - "private_key_usage_period": { - "not_before": 1505236294, - "not_after": 1661725774 - }, - "tags": ["ES", "UN"] - }, - { - "country": "CAN", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x9b17933f74021edd6749520afce8d32e5f40eb67898c08e0116cb64154c6b95066cf374a61c4c9094e410f33c08d0bbf1544790b30a1777d64525411ffbf4465fe48523cbe8b8adc82588057a49d3f2955de4c2e0b39232e600e9bf569a62e085294cafd4ced070dbfb7a3140794c8d6935cfd33652804787fb1e9a0a57389f146af0714c8064360546879716b6f30cc99f2b9854c72305893332a8badecead3cf324254413905e5afe30ae920c2c5146b3ccba09bec8b1426ed2d5dfe2ec0ca04549118df63f4bebb2ad4721a87f3c34eed07449d7e927252bd52af8470b607b62287ab334eafc39a58033fd365f4c8e082f3e9dd606ef2d4dace2f311d5fd338f1da768e5a6a97b563d3abe094fc0786f148bb33d3d52910b024e40647847513d3c1ca907d230e06b223a6b1a201e6958ce8627a476af760a5e0f1e98e43f312894874ea266d21d07ce0dc789ea10eca14bfecce1edcc5431d4ae43162c7968dcb18c8ace9a0986c292f790cb403422cb0d6b101b81c8c00298e3a8a83ddd08d7b1f6efe4d7ebb4bbbe4b650c5a3e25f593a34f4fba6d077554eb9b820b4eefe3cb3f0c023a30712a110476075f531dd16fd454e672a3a021114eb89a5ef24bd59dbb97acf9a2063d79523a525e72f736dfe7401f0b0d76660354a8982da069b18cf484634ba3e2a18565ffd0e41514f6d07d8ab998812a4b6733d5b0cfbbf", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1661864931, - "not_after": 2150977131 - }, - "authority_key_identifier": "0x9657cf853305c3828c68274fb149b0b51ed81e34", - "subject_key_identifier": "0x9657cf853305c3828c68274fb149b0b51ed81e34", - "private_key_usage_period": { - "not_before": 1661864931, - "not_after": 1818382059 - }, - "tags": ["UN"] - }, - { - "country": "CHE", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "EC", - "curve": "brainpoolP384r1", - "key_size": 384, - "public_key_x": "0x7f72accdedae5158522a177ed578f6928218ae0827af621b8250d17008e4537d2e5b706812961486f619fec9a5a71244", - "public_key_y": "0x585f7eb9f6c7b5ee60be45c8e3e413a7702bf21ee9336b6d3968e4826a2fcd5dac90fa434a2d32d964ab7830238f5178" - }, - "validity": { - "not_before": 1360572264, - "not_after": 1808642664 - }, - "authority_key_identifier": "0xb46c62d13cabfa70b7f6d6b4cd27db8596b468ac", - "subject_key_identifier": "0xb46c62d13cabfa70b7f6d6b4cd27db8596b468ac", - "private_key_usage_period": { - "not_before": 1360572264, - "not_after": 1455439464 - }, - "tags": ["ES", "UN"] - }, - { - "country": "CHE", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "EC", - "curve": "brainpoolP384r1", - "key_size": 384, - "public_key_x": "0x58472b6065142e1ab2de1fd44c411d27e6a8e7f5266f0ee89cd2838197f1a155440dffb2c51d9ebadf32724b92afb076", - "public_key_y": "0x2eabe7e0d8a2dbcfa59fb928e3eca7ae928275afdf545a46efc36e14ff3c4d42c3fc7279f986c1d476b2c0340b856583" - }, - "validity": { - "not_before": 1452534420, - "not_after": 1875980820 - }, - "authority_key_identifier": "0x7706c04ce549f026078c3ff072d029bba0631e94", - "subject_key_identifier": "0x7706c04ce549f026078c3ff072d029bba0631e94", - "private_key_usage_period": { - "not_before": 1452534420, - "not_after": 1547401620 - }, - "tags": ["ES", "UN"] - }, - { - "country": "CHE", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "EC", - "curve": "brainpoolP384r1", - "key_size": 384, - "public_key_x": "0x6a70b4cd0f3d67ba2b9cdf5a432362183e31c520f9bbd25941048ddb02ee6a7637b3f545d5990496edde954bce811c39", - "public_key_y": "0x300e21b794e3570b2d4752387dbd1dd7d8663c50eb2e3443908351def2dcc27de3188bd34625620093332b1bf15276d1" - }, - "validity": { - "not_before": 1538469059, - "not_after": 1961915459 - }, - "authority_key_identifier": "0x9711ac45e57afe6e0d3facd9acb26b759e357ba6", - "subject_key_identifier": "0x9711ac45e57afe6e0d3facd9acb26b759e357ba6", - "private_key_usage_period": { - "not_before": 1538469059, - "not_after": 1633336259 - }, - "tags": ["ES", "UN"] - }, - { - "country": "CHE", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "EC", - "curve": "brainpoolP384r1", - "key_size": 384, - "public_key_x": "0x603ef9fef01efdc24110ddeeb05efce0e89311b27ba46b36a549b329c57981728c31f5393b4147960fc5bc8d4c233039", - "public_key_y": "0x093bcfc96c5b65b332f6e4d29be650fda95bac65130d63d1238996decace13c1fb96066f01a4cfdbab787722ad8374fc" - }, - "validity": { - "not_before": 1629810313, - "not_after": 2053256713 - }, - "authority_key_identifier": "0xa7a9f8489f086810cfbf1d06e76d35a55b4b0e56", - "subject_key_identifier": "0xa7a9f8489f086810cfbf1d06e76d35a55b4b0e56", - "private_key_usage_period": { - "not_before": 1629810313, - "not_after": 1724677513 - }, - "tags": ["ES", "UN"] - }, - { - "country": "CHE", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-512", - "public_key": { - "type": "EC", - "curve": "brainpoolP512r1", - "key_size": 512, - "public_key_x": "0x291742afb29c8c70d707cb77a5a69b29ebebb50b6967cfbab5073a9b5972f77e13a2231bd2b971dfdd61544f4e1ef54196825de77b7f8261974d0d7d1b29015f", - "public_key_y": "0x52826d7e4d9bcba4cdc8a909aa5475931636289f1ecb17c38e5e58f2f8084ac96f87e6539cba0dbe184f00df8283b06584373351babde4f43e508965023c1c85" - }, - "validity": { - "not_before": 1696402335, - "not_after": 2119848735 - }, - "authority_key_identifier": "0x01719f0f7c02f2a342318608128db1fe62a38efc", - "subject_key_identifier": "0x01719f0f7c02f2a342318608128db1fe62a38efc", - "private_key_usage_period": { - "not_before": 1696402335, - "not_after": 1791269535 - }, - "tags": ["UN"] - }, - { - "country": "CHL", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x9f009237643f47ae50a02b27b46a8fbc602d389c5c32bb6ffbc9e79c3a30731de5e9735aff9d8680f408a9ced3536df3454b4db7e6aa99cab9d52936237a371e777949ca46fbad36dfa24fa64504f378871dfd3df461b204c82c0f65e3154b456ae2fcc90ffaca0b9750454429de36c67d296777da3775f1060c13ced8026de37ee4f775c7c2b71a184d192b1aa4ad3fa9d7d3031bafe42f7d997ca8da2ca8ee92afedb456df2d6f4b99ae2ee0e8486b2949f42225e2a981cb28eaddb21d9605c34f3702bf3eb08d94b7fb40c9c1c04e4c7a0ba314ba1a24d92cbdecc9b7474e1b08b664018e9064007923732fda8f49ce3e7ff0fe7bbf2c19cb40331da3607987f16ab8eb50638ce7ac9ac7a47c887ce1ff006cb7fedc90aa9fe27f8bd4b0c95cc235ef82cf24b8f7f15c80e7ef7cc2d45968f102dd0bf3c95355c879309d7431859c5772e1a2b0405cc8c94e19e71e567c33e0b19cd7c90d8ad7257e7427799e43e27a5d99cedc678268a87fbe49332527d10da1e6bb2fbff2c689299a1999", - "exponent": 65537, - "key_size": 3072 - }, - "validity": { - "not_before": 1375315200, - "not_after": 1889481600 - }, - "subject_key_identifier": "0xcdc98665667531c4adcad874a2a94a72095eed1ca0ac2ef14d53a2d2c936eb8d", - "tags": ["ES", "UN"] - }, - { - "country": "CHL", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xd747e5ef752adb92b6748c31f6aa1db17264aed210ac48c4390ad240bbae9629c89b07e83b848a43091ec3faf63b215ee50034750c6f5b2033c42155707c05438e0f00294719677ba24eee7a38d9547953f051313e39c0e9ee27e41b0114a2612e5a871b66c0c142c1a81fb72a745b5d85946a07ed0cbf19c79319d0f2a02a620b63ba7e69561713c696aebb62f0c4b90ec899e206b24fae3fdc11ab9b24d680debcec8bbee1f433e4c3a73028a3c3cae8df9903df9f472ce48ea26d13cba1165edfeb8b01481f15a0e6f1d7db75520807f4b94b74c1e4e8b52e9a921fd9adb458e4e1bcd5aa9ddcebd24b524f424e4ab4ceff3b351f4877a7a8522eb36598884e7ad58f1b2e7e0dffb9c63b8762ebae30dc5aabe74494aed177f131d5a0a6de8627ffe8169886a3b9f98da445a1109b458b4c32680b58565764925e20f12f33620815b080ee11daf59170644d87fcddb44cd3337285b71b2bc0d10fe75a8d3a5abcab5c68874251e03070f2038bd91cba4dfb0662923cf606ea0db9fede5373", - "exponent": 65537, - "key_size": 3072 - }, - "validity": { - "not_before": 1470009600, - "not_after": 1984176000 - }, - "subject_key_identifier": "0xfffbbd044c4e6e0f4aff946162b80f5158c9b965e6019a6b65a09d8133cdb7fe", - "tags": ["UN"] - }, - { - "country": "CHL", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xce4a7c72b80db52674b0bb4422eccbb08525ff0379545644940b52f99bf6f8870dbd5b998f90ea0be616c51ea53f3b60b7e9c956e8297936617ecd6ea5602cfc0a56a79cabbb4ca2a261f92772ade945085c59038c4922aa07d118afc3621fb44859cef679a0fea4ec6a6adbf557c5e545e51824cd1cb9bb30220bcffd9a3b42d9b77bccf54c48c5be670ffe6170be5bb9b5871e50424d71eab6e6935802fb0821b155e5ac328d68340c19e21de5847d86c774e6f2fb41eff72982312087e91551cdd5e3eecdba40b348d83f66efae94757e5e0048e3ee50606e3c5d4d79ed6a3e7e1260651bdc05d6b92a02df428daf8935c6671b5b850cab25eb78d840c8a3a26eaf3ca7a66817e42ac393f72c1aba02ea69e19b657744dad3d23922c0757aa0dafd5b279b95dc15c23dae7afb19fed16783ffb2faf6e27a10ae9151e7b96c6eac424afd02f83a30def62fc0e7183d064e7253d034ecc32feb345a4ee54cbe4237732fb5d8991dd9c037696d0f421c9153c7dbab6f9c2b78172f8b5615132d", - "exponent": 65537, - "key_size": 3072 - }, - "validity": { - "not_before": 1627776000, - "not_after": 2141942400 - }, - "subject_key_identifier": "0x449cbecb9806e4ede53d10adad3ea555ec50dacd25d13b0003f42d0c85b598c8", - "private_key_usage_period": { - "not_before": 1627776000, - "not_after": 1785542400 - }, - "tags": ["UN"] - }, - { - "country": "CHL", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xa2e1fdd6838c27a31b68a568358d4a02f8e807757a2b8b0265c155226476d35dd9953ce026fbf1851b7f81d9115a94033275bb5df2b6300cd4f794733f36eaab44f8743afb286b49bb478f45c57cf28ee00786c9d7889d671b7fdd30af128b3e762ade819e7924be977b81add9782c749dcb614751334360651f91cb6b6e6cc25bb99972f07b393675f7f92e974763fa0f66c4a84064f213f510cf209503b70c2ddc44f4d661c9addf2a6f0ee4c13da3f906c291854ce29498f814d751552c22c953430b4e16c9127f337bfdb21663e81e009df6963a5ddd477c9440e75fe1558e7385482e81a2098c6c07876fe5f3fa2265485d40d8d03d6742c4c4335fd805716b2b96eecae0ed538f1268a9c3430f3887111beef0d1297c1f712afd51069213f1d38ebfdd1ec0d630e04408982d3d2ca7fae316eacf8711c8ba27e5f581aa2fbab7ab33a323fa9391e866649f1c540d59d975a5dfa791b2fd29300cee45b9f3586d9f928990d32e12834f9758086f5eec285a414dca12fa0eff07e5591c379bf71a0686652450d6018e329d73472c90f80cdc0aa94829eb945e21bf88d6b688f418d2d3c08cd9de0e24ddc2e6b67faba04b3891290f395ef022b515555ee77a1c0d635f8d9b367403e77128ba938b39053ff2d42806a72ece717177c9f3c83647e0583f6a5cd1c75120dea06625206510aaa8c9c7244ddeeec838089faed5", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1716912164, - "not_after": 2191593764 - }, - "authority_key_identifier": "0x2c8a8a4a1274530eca426c6298b69d0cf0dc37f3", - "subject_key_identifier": "0x2c8a8a4a1274530eca426c6298b69d0cf0dc37f3", - "private_key_usage_period": { - "not_before": 1716912164, - "not_after": 1874678564 - }, - "tags": ["UN"] - }, - { - "country": "CHN", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x88665f13e2c105b86b3983d10ab145456f902ce9bce4fe3ce95f9dc2ea152fb4afee319a5407ce5b938541f9318c257977dc444f52934a97ca523d27c38df5311dbdd48b7c9a248263f2067a46a6c2c7c9ec631953c2ae008dbde933d1864127587decbd43e659b21e7c1d938165cad18ab44ed4ed9e8a4a36091477169572e75b4102097d03258e0acf580a7b080db03718a627fe94dc3f8c245088ac7a696f3939e02fe29e3f4ce7f40c677a7045b32dc26793513a1a2ae798e47adc4d77520c26354ba48a6580efa79adcd2db7d488f83008f0f7301f9c889cb50329ff8abcc6ff3dc2d4272e3b006960d1161451af7f675493a3a22a63d751dea5081eaf77d9f86cb9a4c7d8988f1dc1de4264320dca34c6f044a66058314ff65e8c1cdae5ce5f947fe7a1f3294e19bc91de2bdb4dafc38522144a76f0e6bb07da62a750075c6f5b02aff05d2d2d507591b63fcc27f9bd412612337d5c0f993a373821cfd04af91b1cdc754501d7fb9641ee45b0413c00207e2a8833c732122d0b4811d1fb8aae780c4dfd868cc9ffb456ccbb680d9de8bcd4cf7d1ceb53577d029bea807c6907f2dbcbafa407e899eb578d257ea456582586cb6c8c266e2f0e16f72bce3a9d45c84a5486d9840f23ca126ab534b7055f3a3ea878bc191a6fb0a9fbf01a14e5fa7c2726c075201b86e3008a46d2ec77eaaff1f7c54bac3bd2ec3ca5a8011", - "exponent": 3, - "key_size": 4096 - }, - "validity": { - "not_before": 1231776001, - "not_after": 1862928001 - }, - "subject_key_identifier": "0x84435319dec4b5236eeac6720e82c2250050d6be", - "tags": ["ES", "UN"] - }, - { - "country": "CHN", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x93c3f21f1695c67c64b35f5d93733b28db18a9da3791fb168d0cdc6be9cd60f250676edd1428afff34b890fd55f110783c70c5c12b8fc5b1eaf21ce39e6906761c0a4ed86fc1a27fd7854ba3876295f86476316be8a68473825f4e8b77d5c20ed17a6ad90d9e6ce0dca206e73dac017cf3f5337ed2141bb7a2fec7cacb5e74e476f4aa34a96507b2dff3ffcbc84ba4d63aaee15250da31324e5865961794abb6da249f98105e7fb4c14eb852fe8bbcbcb1e354079bdefdbea6e45c8c27ba6cd5113c03c132de87b8fb2685555d67bd6956f47b1befc33477666b1e306ef13bd55f43a58431d3054ee308fe1aedfa6c59eaa90d5138a72eb2a9e85bfb1ec48b8782308c9197faf47ea9bd2de1b0096d3f4a879ce5d172d4b95471edb7bcb03c4b886812bba020c141397ca74aa36ff8047440e04afa61c9ab426361859e2daddc5d3d99bf151c9339dcbe7cc348e1fb5bbbcecf21310839b4b9790d87d9232e37b559ba52e039a7ba8896437a566b8770a2ecdd077d746bbb540a21c57ecf92967346cd63cdc8881fe295478013245fb63daab5f84bf5872f886ee1af7da645c1a95e8c64b6242d97402a86575698e793931faeaab4b37b83da04c2cff62f4a2e4d86811ca34269bc11011a0c268429337005a07da439abd6306bf74de24141bc3157069fc47ebf95171f3b7f898c635ed63504a405de8cf3e384608ec2b5756d", - "exponent": 3, - "key_size": 4096 - }, - "validity": { - "not_before": 1231776001, - "not_after": 1862928001 - }, - "subject_key_identifier": "0xca87d838621c555b6a7f1d1e392cbe63b4ac2706", - "tags": ["ES", "UN"] - }, - { - "country": "CHN", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-1", - "public_key": { - "type": "RSA", - "modulus": "0xc61a2cbcf13d49593812946a28f29520a791c07882e89039aeed01b3dd928c2be7942bde5d0178d0c39d566c566d9c288749192457fb2f9e540a0f0c41515f9cce4b5f733588b854ce665ad29f43f84205eefafee7c6bc471104c6ecaec53bf166c016addf5a9f29259801979697653a3011df334fe110521a7ccefef3e3e0ef8bb940cad81bc38e31c27b072237ce1cadf01c01bcb39d1b7616cb83906d8da310907d809b7d1b0fd7851f69ea79619720a117c7d19c9efa06ec097646a71e5a41ec8636997266f9edd97f00f0d015a10478425e2bf47fc8a771a964a9909733aba4f35157204fc6728d8f0d88faa614c91132bca2d87bc715d90473bea7f4c989f2d2cb7dbe822deb5f8d10b7c58bd6cd14a56ca43d7c90818d5e6bc5ee8a2966720552357b3b3f63ed65403afa4dec9ae1d49ca06e6f32bc4d7af3494d5ea3e243129653a8cbeb96f569d0b0eb5609864edcee269cb427c4f894fe7c2119ac10028a9551696811f7e5ce04caabad90057ec8cb65436fd556698a662d8eb8b4112f20a84d369acd1885d08adc185d63d4a55b2eb4b9eb967cea2f1e10d880fd73a0aa8e6a9f6469c847a543235f86f3a13958753d3eeb24db7486f3a270ae550031d33c33b2741fe17aa5dbe7b097372a630e14251a564282dba2392d51252e942ae473c764dbe80f8dfee9333fe88613a83d8504a7dee5e55ea09c3203244d", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1289404800, - "not_after": 1773158400 - }, - "subject_key_identifier": "0x1b1faa591588d4b5520ba8e7bf7ec64f9d6d19be", - "tags": ["UN"] - }, - { - "country": "CHN", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xa0abeeb7ec835eb7daee42ecbdef45455ee445eb7ca62da4252dca535a0ed5040b6375c84e517e6af030665b3cc9b71a7a12c0e5845300cfa9b7ebfb1c1e7c6c984ecb646265967cef3e61268998b8d685af0715721cd6a1f758ad30cc4c1960eeac8947ebaff5b2a933d2261575922d21892d197b654add703d17d4caf6cf311c2b187885e5e52df2faa154ccf0ebaeeadb153412e0430eff1c7496a6ea513fd98f5af27121b0be2525582f309974b702c70f314b958cd631235fab1bdc7569aaf884fb74b49c409763eebdd0b412f65c6331802bd8e5f31c609fb24350618dd08b2b7eae8771157af5605c26bbc03786f607c1143a815fa51d47a0bc0ce967d1d49ea06ee43530ddd221da9e70342a21b3b443da7b5da83f5c09424135921fd1ea3041da95d6d0e17d75fea1ef3930daf0a0046cca0209b6c03b00c4e768eefdb2dabcfe7519c19814c51123610f202b83c988c1b69b7cb9e9a477d3400aed5f0e0936012e9be9f2c9f2ecc3fe1fe35db5ad60b33a7a4cfb9d462f648dccb8f44b75d39d7e77f1613dd847c64bc758ebc23a72a114c6dc83f337e3493c4a0a8e7e8fde34c8ae441d4a5e28d2515c713bb7ba5b9b5e711dd252dd04b4a1a3dfe569cc33eb7a86203419aefe93bad3c26eba79902050cafb41db1e2cefd5b8863c9f95cb5204a50bf9ead2157fd6f3e4ea42184b412f67c35a90e0db4ff2c1c3", - "exponent": 3, - "key_size": 4096 - }, - "validity": { - "not_before": 1307980801, - "not_after": 1812902401 - }, - "subject_key_identifier": "0xa14b66506db9bdf9c07674ea618a9b5a88d8acdf", - "tags": ["ES", "UN"] - }, - { - "country": "CHN", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x9a30f63c82595aac59de2f03da2ac929f59eb0484df5652d151fcf7d1e6d4983f79c762bea44236ea4bb8ad8f4edb9250fb7774409f50abca9a2e295744ccad55011ada5d59b22eb594e49ff7076f283e57d3206583a1c6735af751b961ac4f26584272aa78d093da47050c73fbfe92dd4a9d517c4ba64040c2a3b8ccf12ac76df4a315b81c2b7fb73975a54b18cdf5378300f3d5e553324a7198dae18bbcf1a1feab05207fa5790c1bf67830cb9be47ea6d10ccd3235a48eae793b803140e21a0dfeb402d36ba0cdad775952442a6148274248178050756c8c03d5b4cd7cc17fb2d09a2d04cc8a04a43a6d7db8b83b1ff84234f2de8b7084138b40a327e2e7572adb1bc7171dcdd246aa4b4a16af0b583b6f48256cd37f5d3511ecaab424ec694fa822a785d35da6593d7b8545f62e26ce5e06fa1b73e8d6ad59163c90f656cd2a496254b414cb2e87ec3a3c41150ece85a8ccec491c0fd6ea7a01d914268f6f9d2a7e01e5770e7fe95dfb37f4230a8179d97b9808dae31598159157fe8e65283b5d119c00be7d98585d0b727a6490cec8280a3108a72dd031948b550fd0433abd52e69ee166302df23c544c749ea0692042883f5bd07817f92e9797c94610c62e1854e4667c7c4d5ba51056ca31e0d56db6657640ef95566b8f305990a243a3ccc058303664c0acd38393df4e2a004ced76d54fb5dda1b5d53048e7b683405", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1329844455, - "not_after": 1771348455 - }, - "subject_key_identifier": "0xee43af8f5ece1251a235d1468c9c8938d0563011", - "tags": ["ES", "UN"] - }, - { - "country": "CHN", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-1", - "public_key": { - "type": "RSA", - "modulus": "0x9a30f63c82595aac59de2f03da2ac929f59eb0484df5652d151fcf7d1e6d4983f79c762bea44236ea4bb8ad8f4edb9250fb7774409f50abca9a2e295744ccad55011ada5d59b22eb594e49ff7076f283e57d3206583a1c6735af751b961ac4f26584272aa78d093da47050c73fbfe92dd4a9d517c4ba64040c2a3b8ccf12ac76df4a315b81c2b7fb73975a54b18cdf5378300f3d5e553324a7198dae18bbcf1a1feab05207fa5790c1bf67830cb9be47ea6d10ccd3235a48eae793b803140e21a0dfeb402d36ba0cdad775952442a6148274248178050756c8c03d5b4cd7cc17fb2d09a2d04cc8a04a43a6d7db8b83b1ff84234f2de8b7084138b40a327e2e7572adb1bc7171dcdd246aa4b4a16af0b583b6f48256cd37f5d3511ecaab424ec694fa822a785d35da6593d7b8545f62e26ce5e06fa1b73e8d6ad59163c90f656cd2a496254b414cb2e87ec3a3c41150ece85a8ccec491c0fd6ea7a01d914268f6f9d2a7e01e5770e7fe95dfb37f4230a8179d97b9808dae31598159157fe8e65283b5d119c00be7d98585d0b727a6490cec8280a3108a72dd031948b550fd0433abd52e69ee166302df23c544c749ea0692042883f5bd07817f92e9797c94610c62e1854e4667c7c4d5ba51056ca31e0d56db6657640ef95566b8f305990a243a3ccc058303664c0acd38393df4e2a004ced76d54fb5dda1b5d53048e7b683405", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1359437949, - "not_after": 1771348455 - }, - "authority_key_identifier": "0x1b1faa591588d4b5520ba8e7bf7ec64f9d6d19be", - "subject_key_identifier": "0xee43af8f5ece1251a235d1468c9c8938d0563011", - "tags": ["UN"] - }, - { - "country": "CHN", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x937e9a6b091c3266229433553747ee88e6ddbe75ba0a761e2efa6e63d3c350ca23b3aad5aef48980d5f8ce7a85c77763697a1eba75dfc5235403e11c01b247513398c69cd48b2ee12d3f333f37a8105b5c5e174405d750d7c8acba371fd4cbd2139e4cbe33a943ee0e51ecb9733f2e6b2b9aaf273117a315905465a5863493c991b14419ab31b2b0dad836d8b97ebdd3d506ccaafb9f01e2a4616de70f1fb43f40adf9b9811004a79a9a2be48f46142f31a1c6939e14d72be5f5aee2aad7777921a322b04a30e8706ad329b49628adf9def8525eac1edf31cf502643360ede6f2272a152d3229b0f90977804b48f5cbcc555ea0ad5103bc693c65114361478249a945d3986b91885dc930587c7864f774024ab7c7aec0adb1441364f8c97c8a7eedca94eaf903ab17b0a79f75731957a5c3d633ad0474d7f9c1a7f7a2213f7b02ba52373d558cd68535216d1d141ba27e050707196cb7c910697a00bda21143aaf06e31ab6fe4a546867dfce033289b46e8c19a3bd6bf62deab1287fd139c281dd9ef6b20522128c553c8cd773f46257936d9e042823bee044d7e2492dcd2dd48aa293db56958a9376d60de56eb26092cbd9f9e6c810e4aa5b84ded16b97dc98478a28d628a6ff688b06659f469199e9d3e6898663d0cfd9ebe49bc2a30e6b1e67499a32639f86bd2e9ebec16ec3aa3ac20534a0a73d1589c658c7d7e19f24b5", - "exponent": 3, - "key_size": 4096 - }, - "validity": { - "not_before": 1373472001, - "not_after": 2004624001 - }, - "subject_key_identifier": "0x6d7241cb2b21736261194c02d339eb03c71d53dc", - "tags": ["ES", "UN"] - }, - { - "country": "CHN", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xb9fd808638d8bbf9ef4f73e9d2b44b530dddfd5fd4e61f9c656fda615a289283052a93fb7dd839d05263d8b5787846fc5d9a8e754f91c1ef3b036063481537cfaed2ef8e31d6a815d8cf2e2a0458ecb08e66357a114e5986bc81dd73219e58ac5c359f9d6d1c4470edd37d7eed65126d7d68f9c9278ad56057ce4ee1bb5a626a36028a7e6bb388161332d68975fd963ca9af5264163fc98748d4a6fea70149d7a6aeca9546069a92662f5b819fb57d47f56194d22581c2b8f4fff3c498b32e4b285f72a3ca78a46cba04c230ce0bc1f73e4f8fbda4bc469bd973002ca1fbdb36969d399a5dea176341f504b38dd71c146fc7f49cb809a4f84144fb6624e1f9b4600549ee04a56e10beda7a63f0bb231350d5a2890619c9bface6f20dbf1f6e79fdb84afc3d75cc3a2d6d6b5b07da7bfc915c40819b57e6b218e65f605cf6644b001fb3d504b6306dacbf27920ba44d4f7c0aac745095b14bb5ad3b48c4c74fa0c6e431abcbe730f6d59e2c40a599e732629cf830c631d7702351685c06cf4c9ba14f415b2c48807b2c1be5209892ea14a78f11474352f17d0cc169c7cbd3d997126f55e41f4a2594cc437d0027f11d1cd50e4652829a817eab531af4efbee3c340df80c38c28e672f731d73e58302ac10ac712dd0507b812baacdb510a0ebf27d820ec7b0d320a2e5ec756f09a837581975f5cc22ad5c47b06fd47d98c96fc79", - "exponent": 3, - "key_size": 4096 - }, - "validity": { - "not_before": 1373472001, - "not_after": 2004624001 - }, - "subject_key_identifier": "0xf1530790aab990c8bf8c36917e580b1cafa969bb", - "tags": ["ES", "UN"] - }, - { - "country": "CHN", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-1", - "public_key": { - "type": "RSA", - "modulus": "0xb012b11ca817bb5203c2a84b4f95b55e22ef36ad53cd33650b32b2b13296324badfd4899aa278cb615f33dcca1e76c2942eb557dd0c291a467f5ca22abcd8c36d4460fbeb4d1b0cf7f2d112ea5de4212da079c3337aad72abb867efe75626304caf9b45b6bc642e46adb7bec05eab42050e0dc62496f3b640bd5e46718e1fc11efdda893e589d5862823d4588b47645982f2dbfcf5c45dec1df778becb410f4e168845a8498453b9af784d47c762d8802ffecef2b0786bdce65e0c689e11bb68e8eff169dffa6ec0575cdb147f5ffe77d5085cd407dba1a839aead100f03b63837a8c50ea2a700fda252841d0714b22b11307b8ca4e19eabb97540bd75def526521812cc04f7475b02238ff23326bdc9ff17c5fb1ba0847c8cbe4122aabc7817b653032f816647eca49175d90321d34adc31f176e55ce23149b4c5f0a6fcd6e2ce74ccefdc14ade2da9ac3eff96955af04cbafe57b9380b2cf400fb74d815a061d34c1c46e0aee1b73a7d5d4f72f95c0af1ea81224210c3a3fba2fbd77d83c040664be27f4cf4ac610aa078263778231e39385c018fc80d77bdc15e27de928a14f9a521ab269098c024116d9e9032c789412f4fdbf8782c1c136bc85dc81f16ab506634b5f10f5a0b523af7315a61ede9f5f1a91b27978305b3615b43e13b3e76f4cb1e6d1261394090c234d6f2f5b4e731bca2959b26b6244a4e3d477bda1ef", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1427472000, - "not_after": 1911398400 - }, - "subject_key_identifier": "0x4a67398a1d0122c53d4057a76149345fc3e70234", - "tags": ["UN"] - }, - { - "country": "CHN", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-1", - "public_key": { - "type": "RSA", - "modulus": "0x91efcdd362b7e9e5774ed72aeb3e012eba556750f7420430652a12a22c23074afd38607e9bd323e8548a266c63f2f3d0007a30d6591e5eeb89b968e341935f8acf3609f3cfacff7cb6ecde409f783fdef68aa43866aa9078dc05d1dbea8e26effcff6919b5c5612eefdf823d921d864daf6738d09cff25f42ba4ca0b380599d24bfba218d6a417c88a4537163430f33c1404ac6fa9b592c6b6b4fa4b3a36b68ea64ba2958ba6c8012a4e268d4d24cdb9c56dc999e45e1e968a2de8b9a8b1b23de10f7b198f34e06c21b2a78c61a0b69bedb4c182d3251b3b74bdecc152ca81fdfd8dbc9c28a673104da9344ea774504c142f3329285d4902a609293e0ee65c65a1d0e8698513c6d180252fbcea2bd890f371a1b7da4c43a6a34ada6b9900cb4c4f8ac73242527f85c8ccdf39ced45dbdda1a45bc35686eb694e6d052c2fd2c5c4548e8e2c8f0f6e6484ca6d347439431ce27cac0d0e372220b97ed036c97c97247b12c690f725cd02cdf66a375bfb82334d79f50b67222a6812d676ff27857a5699d99e2b5ad28d3c3503347836cd35fe42f0ca23e6203d36aee2f53f0144cf1e3f572db443884ec6310c64c0efb7d7051f942d55c2f1981ba3ac7c505588818ccaeaaaee560e0c6b00e83dd57f7aa490695333e68eaa128abad0e17c4289fd5d932b4e663e3672aef68049e038d553f9d52f312700d3b4e8d92d878b21ad11b", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1432752131, - "not_after": 1870047806 - }, - "authority_key_identifier": "0x4a67398a1d0122c53d4057a76149345fc3e70234", - "subject_key_identifier": "0x6b6226e45394f8fafc75e9a787ddeae8cdb64f93", - "tags": ["UN"] - }, - { - "country": "CHN", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x9cc8eab13139f069888e72af59669028b284ed8c6635ac4758d8b798f03c67c1dc03ff8e07a554c0a631e33a9f4abed80d188d751afd3b78f1d9378a2233a719819b2b9e483382213e5687b1a284367fca4bda1f6a65cb410a6b9db030b94193bd668410a37f3bf25c97a3c52a6884e68dc179a57a574e11a3aef15dda77b58e9a90d506203549a53ca8bdaf5b6e7cb16426eb069f610cfe3da6489a7dfa7f52e414d88609c4cdffc894724d00fa9f00391fcb64f3b2fe91e049108fcd38a9942bcaf8a5a69756323e84833dfed2990e35549e003e959b087a4a80cb5fb906491acdcd2149c8446f0b292edebc9b47beff8c6bed79742f05b3f15777727732cb9fe169fce5dbfb9285c6d6d7a28bc0cd7adc6c6c47e6fc2cf2bad8ccf4bdd7eecb9cb8f10596395674edb51c8d054f910fd3af63d19b357005ad83f002e89141a6edd6eb63d6c3408f9ca18c78df7b0cb695381bbe4b183fd720f02f1b1e6327b3dfccda31dca1aa65e6963d15472a40aae57b249458ff018fea7da9542349c684c4756eb21ad2b01628666c49a7747fa41b868972c2251fcf4ea160d4a478ea5f1c9966af373204dc8552d7ba613bfdef4cc2bee221fa4cbab4ad45340640e92dfa7ab4bbbb89b391667d7ab1da8162ec442cdaf3294ed5a58452d6053d5e45c1fac86a869d11785f761946a9958f4c4d99554046689bddcf8e4080476ed7f3", - "exponent": 3, - "key_size": 4096 - }, - "validity": { - "not_before": 1461168001, - "not_after": 1966089601 - }, - "subject_key_identifier": "0x5d891e7914f6fdffd40a1bc6f10a5e5dcd4bca86", - "tags": ["UN"] - }, - { - "country": "CHN", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xb5d7c0712739c3e915c84883fb0cc5e1a0e0d3c50fcde1d64b4f929fc215f57ac4e8719c08ff47203696022f3f5b6fe43b98e9220d2e530f72475cad27f07964a4f9965147cc405c5ec871366d02ee979597504f7746d8b1651f3f898997bc201a74aa98cbd14a8689c0b5ff29b531250e45fd810811d99952bc0768e99d45dbd4d0dea0243cd1cf00bca24365a0737edb569031039dfabc0fa222d47fb89728b7dd1db0edb0b122ae4c1ae5eaabbb8706ccd361f59a1983e57c4888fe8eacbf56e50902dd567e9ec3c370002e87762871475f54c912b375f28d001114b963b9481ba828038a11c98fcda1e32ec132aa01812ac80e39b4794e76049da0dd01860b141e7430676829a48831461e02b125ee286e9ec20411ab3f9e61ac41a8c2e9ef75eefb86a40043bc9d4c6b8074df764e51c4d172e8631c2d144b4d8449efb75492f7ad5294f8238d5eed9a4e82d71106d421a8fe8c4d481702830d37284686968d28e26c8bbcc48753b5c8d4e35d75494748bfa99bea48b0d934f5e2b897a375152f0744a39614b5ee026fcb9314d0ede89e265b2cd613ce7c3c01837cb3eda89c9b6876a823666a1c869da6e47339b6b364d72924228e92004d5b9c30f873b05de6e67b40f80a27bffd07daaf8972c691b456a5d1b643fdb7b97fde21381f4ecedc63836153ebc3583442fc7b359399f5032c1f1ae01e29676c8162c9a793", - "exponent": 3, - "key_size": 4096 - }, - "validity": { - "not_before": 1515600001, - "not_after": 2146752001 - }, - "subject_key_identifier": "0xd97aa377e654b220811995335e9037f5d75eb40c", - "private_key_usage_period": { - "not_before": 1515600001, - "not_after": 1673366401 - }, - "tags": ["ES"] - }, - { - "country": "CHN", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xc01067d444568847bc0c152f78a4495b0567c13a8fcac977430725c4cb53a452f396e911500dfb966d90d1bae933889fa5afef75331eb99f74268f7ca8b0fa0ed8ea4761ba526dd291f8ad4b39554434b7e68b1ed2023697e9c7df5db07c69d90afaf5844835980aebe6d964edf3b92f983c462fbc2458b6c878fdfda8cb7e3b70cbba051f0b7e02a55a7a5296dd0ee3fa83ee5b812c0054096b36acf61097f1e146ab1b29f525f40edeb51df5cb5795d5ef304a6a093110794278d1b9b440fe144cf5027d1efc129cdcce99b300bf16a64b13197310c3d138557bcff0a95208c29d8049016dba60f6e75872494c15f1f291728b2aa51a9679cacfad1324ec7f98604bf8af39854ac07e288a3eedcc275d9a05ca0fcf0b6b00484f4a1d8e25329847ca9982c1c42737638b58884cf742d67cc42be4ae9b4a259abec032f59d6389a43af337b1c731aa05a7fb8e29cd129c19a33a23e2160f45314141a78cf5cf1b0ae14d904c9c3eeb77dc08d7622638ff5bf366e7e66ca5aeeb35e161d6a9e4977940bc222ff7bbcc50a95ed046e101186ba23ba92525482ca22d6d0dbe4bdaad64ff9e1929f89b7f1148c7ac2fdb3b3ce15743eea6d224917053afe639932bf3f3cf175f0935c331322b339d69dd1fc7b03ed3ab3b8733227cf1ff14a848eed7bc9c213ec534b59a1029f74c393a7e6bfc5930b539cf98d0355ca26b58a45d", - "exponent": 3, - "key_size": 4096 - }, - "validity": { - "not_before": 1515600001, - "not_after": 2146752001 - }, - "subject_key_identifier": "0x78ef4471335459e698ad94b175b927be4749f03d", - "private_key_usage_period": { - "not_before": 1515600001, - "not_after": 1673366401 - }, - "tags": ["ES", "UN"] - }, - { - "country": "CHN", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xaa564a16fb1bf8aa5364ea46bf9979361ba05cf8a79c3e32c929e12987b185e5cab8a67a3f9054e62ad491fea67b36b4df6a6833917db4f9b50e2a4de8e4f8aea5c46598697d082174b8af346cf0f9707e29304aff4f64fab92dfaf3b56d9e58b2838d8f72ace5a7b0697e9f1294d69869bd63394203dfd6874d6c7f422592f03f9372cbcd70a75ab6a19a7e1ba089d1c3e446cb595e88cb0529a496eb2b9cc13296f5dde31c20dde5d93a132e905c343a654ad8d8792b48df027ae7cf077b8977bf1b48a581aba7e9a2a4c51f535eaa190fed3d0ec5193eb9896b87803a711164d1538c6963194aca6430006aa0b4c69f02d40644198290de4c3a96880f041e5cbbdc6527c201c9367f610a664c816d918b9ead389a5362a828acd14d124dbc0dd83a86e23dae6abb2e5cce1d264e22ed2f567bf90576d8baf4a39ad702d9906a210f91da69774f664eb0c9e51ec48ce17516b5403de86ce340f8e00a28b5bd5a5ea614d20f873b4bc2545c23f8f668b70a1e63d0cd53a2cee4deace50731785ae048731396436ca059dfe717f8a6a52f0c084cfbf44b80b034129704587294ded5efc612fcf88e17778ab559aa2c3526127d31fabed889c08addea0f62c627cfedb0a551091e3013b20471cb127a205598a0db9f7a3b39e4c590f20a04853ed7eed649863d200df30a80735ad5744d5a432530aabade5847888ae43e7bab8f", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1518148484, - "not_after": 1938743684 - }, - "authority_key_identifier": "0xf17b4ffb276e9e0ea0aa8f7559b414c19af13629", - "subject_key_identifier": "0xf17b4ffb276e9e0ea0aa8f7559b414c19af13629", - "private_key_usage_period": { - "not_before": 1518148484, - "not_after": 1612842884 - }, - "tags": ["UN"] - }, - { - "country": "CHN", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x813b5c7ba6c4c8fa9591923935ebb1432f768cebb3a2086c6bafdc575a94f845c8b228ad667334b1bf7428bdc1d229581a30cd2cd4ad6d74c2a736ed7aebe4f4850b822d471f1e9656cde12c7b053eaf3259a2fceee2c362dba860db73147e846cb712018b3ab6987be8d6ea308cc7d0efd5f2077d02699e4138c6d8daa267452f5e597bf1c4139cfde0b4dc76ce9d275d3fccd1186fddc7c1f3476e00df0e1dc84a8a8d1f22289d9dae9e5a60dc2ffea640615ca7b43eebcffaaafe0c183336cd5c438308f248a13ccc473d68512e0e952e46e6d76576481ef5fbc7beb51d44b87c67f0ac434c536e5ae1407f759ef4ced1804846b39447b9169fea14b660b12970a847ed22ea6e8294b010fe376eccd09c681f6e57da1b8c93c9af1669d5a23476d9aa86cde864a0c79eedc046fdd07b2771e24815929d508c5d0df1918bcfe13462d054eb4db4bb46a22d1ef72980a40345f6bfd19cfcb21d79c1fdc2766ad7b381015bbe7a4f5cf8c02f5951ce240d81cb09d702f1aa55d91e3dbd989c5af535feb0ebb8920df6545b75e3962b66aff519adace4f66f6e5ce2a83f45ac6b81e85fd7089fa9c2b1f7005f8a18b2243cf3e6c4e35cb9dff49ba012e8e8cf2676bb4eadfea7ee12f5a82e1a8bfc8ba36c27a77add79146569e0c94c8bddcb13f68648247e7d26e2a4aae1994ac51150c698a1c8be04f94c5dd49f63f0530925", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1530936978, - "not_after": 1972440978 - }, - "authority_key_identifier": "0xa587528a4d42c40334c827f491a6f4aa6862f7e7", - "subject_key_identifier": "0xa587528a4d42c40334c827f491a6f4aa6862f7e7", - "private_key_usage_period": { - "not_before": 1530965778, - "not_after": 1625573778 - }, - "tags": ["ES", "UN"] - }, - { - "country": "CHN", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "EC", - "curve": "brainpoolP384r1", - "key_size": 384, - "public_key_x": "0x74cab51d08e2fa62a70afbfeeda9ae3742abf882e003caaa282bdd8ef9986a23999f3ceec5a020100d17c3427f333dca", - "public_key_y": "0x69ea12813ed0741c0f9e281436d68df95fbe7b2b7ac9df73a2d298d48083711221bf40931fc1aebc6203743fabe20e34" - }, - "validity": { - "not_before": 1550652015, - "not_after": 2034405615 - }, - "authority_key_identifier": "0x1ca2477bef6c35aedf404edb5db2730c347ba773", - "subject_key_identifier": "0x1ca2477bef6c35aedf404edb5db2730c347ba773", - "private_key_usage_period": { - "not_before": 1550652015, - "not_after": 1708418415 - }, - "tags": ["ES", "UN"] - }, - { - "country": "CHN", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xd61c29d50bc595e0d7621f69d96f55c5221cdcf7b87796b83927f60fe2b5ab3470aa2ed5636980fa7ecfa8d20d4dc9d8365f282bfb751bd2624d3a100b9f12172602318cee24b4fe90e6b4236a47747e22e8110a4a5afc82f01b74b00efe50b236c80cb530f5b099809b27d9024d4e7c730fe58bf52d9fd3b9cba05bf28d596e050ddd30feb5aa64c7a5a96cf6726b5eab77eea9d6ac3ac1df7d1d647bfae6f1602695456108efe9771f9535cf0f5ec1300f19ae7ed33e4f86a6463b2bf888086414fce507b0d381e7c681995b566d5a520dac4c76ae1858bce1eeaf832a7c0e6875b6d2ad5a639ef333226273425bc2f10565be202d808d8ae7fb5e1f6b89bbcb0a1e42e26171ecb7d137ed8bffab11ec2366f241561c050679cbd9c79aa378278503976247f03b913d65cf39241e6b3ee73f956fdf5f1b1e8a4ebc90d2cc9f9483370425ac9cf99f0603c488ec8097ffb141df21958644079805e59f08fa625be1fda705333a3cbe2c2f7933629dbdf4d0d0aa1e6d364ca4569a7926d030974db7eff50db0234bbcfdff54945cc7f5e31e2331dfd36a8d3be8ae38f76318f7f4fcff2a7c4ae619e28a8b3dbe369da3d33d62ec6177f2c7d7cfea2a58edbf960693e8774babc82bd77fd4cdc208cf6ef20abb693967b954b15bf513bf8dccc06417c9c068224b4ac1e21e3f2fea20b3ee03ade126f0cfc472c1fa4fbbb46553", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1612489038, - "not_after": 2033084238 - }, - "authority_key_identifier": "0xc5ab86d840d177ff8b1813203a201170c5dc6c85", - "subject_key_identifier": "0xc5ab86d840d177ff8b1813203a201170c5dc6c85", - "private_key_usage_period": { - "not_before": 1612489038, - "not_after": 1707097038 - }, - "tags": ["ES", "UN"] - }, - { - "country": "CHN", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xc560115c18632efa41a6a12237a41de335657b9ee88da9fe323a53b4e2a17c32c3b0ac8d3205ab0be4b9a6e834fb94057e442134f12d8fc627fd41843cee067133a06336a1ecec58c6cf4401869357e2783d2167b2040432ea4ded24fbe91d7efc4eac251c239899b2cbd7340553322d29ab4f8321285884cb756933363170019854a18c6d8c35807b33db55a0f3370e1e98df6bbfd2f7bee723de441d21b472cdd89cea3718fd211d6018f0473f35c5dc5b51892eddfe4d3ef68ec8db662e15209b4442ae4eef269df44ae83e35217a39d7793efacadca78763b4824839de4c69b9d95ea8da24f5e4d033a2322b5ec292e8cb4dbde4e19308f3cbfd2d68baa09d25584d3212c1b647795ee20596d7685e800613ffddc17914590e126de3610d041b0c9b5195c16d213da2f763a945b3ef4654a66ccc33512119476c2ec879100586db5007dc8f29ee097c3327a9b52f77977dd36db22d7378cfdc474fe49e50d27da318aefb5a2017f0113c8b249793d75de221146f909716769874243c0f51be81a37c5d2c5d8c79dabdb84ab4fd0687ba6bfdf523142d376fcaf5a2f1357d8db883506b226b6c10e10e20585743d6be2d49eb835223cb688707a372aa8c123bbe380c3b3ee076c62cd4c1a0c68de08f995795cf9a9bde64fc2d06e130a1c951e124ef137d477df0fbe204ade7e3d6da017528b90ffbdf36c519f5f186b9e3", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1632381040, - "not_after": 2073885040 - }, - "authority_key_identifier": "0xfb56f66665f4352da058d3c05e3ecafc810592b6", - "subject_key_identifier": "0xfb56f66665f4352da058d3c05e3ecafc810592b6", - "private_key_usage_period": { - "not_before": 1632409840, - "not_after": 1727017840 - }, - "tags": ["ES", "UN"] - }, - { - "country": "CHN", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xaad6b9f91eea79c22459d2577e2b93434f049ac9a66858b27f86633c32360c5180961ffa57ae10f45af4a2e49713e508288bf969197e3b56b91a88c51ea854043cc3b3023316355864d953dbafb8d6f26c0eea4a14df323f80662d7ebd82cea2753adcee0f063f40a6a201d18588c810a26de6db1a0193c9bd668ecb1ba058b28e9fded1a6dbb4f8b378a2acefd95fa6f0b763efa7d361bf1ca06bd7a83d9547379a5861decb95ab948f93d0d4007c22fb5b70f8536ed0e6814400c727b7bb2fbe70c18964f9dc4cdf39c7d4b60266ba8b7bc63f627828380676afb81711c872dcba03f1c4c2d072f12ae7410b2aa319f2e509dd57898f5544b5620f0f2f168a803a2bdb0759516669bbcb60b8d46b6c9a48418a2adaa7c70ffd47615e48d57507e17cd84eacdfdceb1c88ff95370bf8e47be2047da9349b21993067b3f200e7a634e3bef1d195f412812e41d71090f36dea6706ee43937e34a5e9df6558fbbc1033629762e927f7e4241b286b5420ab854943d5e45965fd12f194d15400f8326b425de67d8c44c74816fdce643c5e120332b2f559dc6538cc388a856cc0f45c5334b8532fee9fad492b49571be8060b3ad69bf78a6edcb01c7c8c57a424ce01862c5c36918c45b1079b5619f5330e0dee29a699f0972acd4769d0f2e6ec538dce36b98101ad531ffc04adacafb20ed45cb51adf26b621aabe9a2c0a809c550f", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1657209600, - "not_after": 2288447999 - }, - "authority_key_identifier": "0x89d6802ea9504573bbe5ba6576a9ec1240b0bff6", - "subject_key_identifier": "0x89d6802ea9504573bbe5ba6576a9ec1240b0bff6", - "private_key_usage_period": { - "not_before": 1657209600, - "not_after": 1815062399 - }, - "tags": ["UN"] - }, - { - "country": "CHN", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "EC", - "curve": "brainpoolP384r1", - "key_size": 384, - "public_key_x": "0x6e2832adc2235dd31b531f34330d487232f2e0142c46195e5122d03a761419c7176c47815df6e8c97adf47564240642f", - "public_key_y": "0x5327ebc044573f977ddd091b86f56e6955c5eda7e1fa5a2d88c9e5a256b6ba45385f421fb73e926702fb37cf2b3b979b" - }, - "validity": { - "not_before": 1696925098, - "not_after": 2180678698 - }, - "authority_key_identifier": "0xa9dab981520dc614b120409518beb386c1f886c1", - "subject_key_identifier": "0xa9dab981520dc614b120409518beb386c1f886c1", - "private_key_usage_period": { - "not_before": 1696925098, - "not_after": 1854691498 - }, - "tags": ["UN"] - }, - { - "country": "CHN", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xc55f7dec33c6810977625d9b64e5cda6c8ea730861d579f7fadc73b1f341abb9a58a65cf6d4abaeef50796988884bf81d570dc7f4a68d7b1f301d61afa9e8b52c842a5f7cb17e4a72ea1c3910a99e229f38bb9c353e20371afe0ce63003b0ab434276b4c0ead978543649232433dcf53b6b83d3ad82f603e955a1913f86852bac312dbbe2125a15636411ede21929474948672c3a1bfda9ceb486af155333e780c58d3aeec0347224b14f695847d732867876984b66e9850d58920f78b0886b8466d4ffa84e2a39c793fc6422a2bb470e6f729f43a2cadfda21385c06d9dab2a0dc1f6b9a47283d8ca13cd889cfc073668c606697f409c6fc972a0fe5b44713610a26a50686dc4a2468e5a2bc85232ddf57b41078acb6464bfed0ecc33d03fc9aedb9bb4a3f7431582aca5281860eac44a23f3be4279b12a23c5f1535593991384151783170bd767903517c6b68131f2f9eac37bd50e6567aa64727dbfb1e378dc597f7893997dbde7e96a6ee99415b6cdb9854088d8df7bcff4e3caa49acbbfbf65e93b22f91355e2ec13b65d9d2e701e1e3df4f69e7b21c39aeddde76d72450d99542661cfeb6c8d52b32bee4b12203bbc897004ba2a36ed8617ef997785901a7eba70d988998a893de5c80a3dd71f3c032919ab90301e3b3615c7de1709701b865304c06ae6780404bfc2c13f4febb1dd58c88d8923acb3fd7e16d8feee85", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1701740714, - "not_after": 2122508714 - }, - "authority_key_identifier": "0x75a9e609d5beec283dcc0fd13144c663fdb5f79a", - "subject_key_identifier": "0x75a9e609d5beec283dcc0fd13144c663fdb5f79a", - "private_key_usage_period": { - "not_before": 1701740714, - "not_after": 1796435114 - }, - "tags": ["UN"] - }, - { - "country": "CHN", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xb707fa4ab80a267e454ff84e1c6fa6a6fe8261c6d7264d6cd5fd962e884e7a8b68c2ac62de7bdbfd39b18aa0423898f03c3d0e7915d32983c534d70985272e7bd701412be66e9b46ddc6e4b0c54385bf64ddcb0edf41167e771ee3e5e87f425b03624ed37881ac83843e9ff8acca9aa70d05fd0efdf2a9c053eb09f716769ac5d6c99c7cd45b3d3c662f92edcffe6521962d9982f5d1917766cec7823d2138397e1301ecf77ec3a864756921009547599dfa20da6640e994c95aa216c2fe678cbe4866a424f1707991444e548584c8f94ce98b8d132e08e493b0dad5665c8ceaf12f3c2d4c28c0c139b4470310d46c1df692be9338fcfc0f5907d83662e120c359cbd80419ccd6de501deb10e1022a47613f64d5119a00400b8454017ed55882731079c901190797298a9ea4dfefe6254070d9dc6bac817beb7a73684d8d8104e0a34475b3a751081b7d469fb7cc25e8aa42c5177fae1bb1514b4a9ecab6c26c5786318aee03311d04843e6e8cff3cbbf79dc5117bc49c737c309dc91c6d1791c9a6c3f323811d42d0d85ebefb17526dac62458bd09d09c4a0c31aba06c642b6764879417fcf5dda51505eadf1ea17c08faf2006653d9c4047b2e47152a4e57a462740b60b8d539d013f283790a46b6dba2d93df0712165323a2f54bfa2c3309092d51ffb1855059e8df586b03627b8bf44cb3271ea0855c68e29f3922401f17", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1726824734, - "not_after": 2168328734 - }, - "authority_key_identifier": "0x839fbf3a9cdc566916869641a0d354f0521b9fbb", - "subject_key_identifier": "0x839fbf3a9cdc566916869641a0d354f0521b9fbb", - "private_key_usage_period": { - "not_before": 1726853534, - "not_after": 1821461534 - }, - "tags": ["UN"] - }, - { - "country": "CIV", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xa40eaffe56abd4ebb98d1b1398ec94746e499df9c215d1e5695ae84cc2ed5a35de60a953145b695bf611521bd92a5168fa955158a7247ea0c88cb51627cd572f050d1d8962d2bab7ce45c075aee365824e5d73605a3e57305149775bc693357ffe83c845f3c547d63265ee5d00287d1b8eeb5c28a824bbb26e7fb7ec2cb67e423ff253f0bea0680e81cd2775f3c21fe5b07ad90779aff897f494e40318615f154fdf407a2d0685df4fc479ed8cc581b5ee5f33d6ff8bccc1e2059123c6eb5c144e03db31ba9c48721c268c7621ec5978aef06dbadab0ce930e363a342b759f2a1d0037c0c0ef8730e683c2714e4d1187f23269918f8cb0dfd5e0ee171da3c6861eb4d42a44d782d66ae411400d98ea429718a0e4c0f63d5e47a9684fad3b5b3573ea224d42e8bf9541f877051f5893715ad2f535c1245996b68ac725fd49fc6d7d9f55ccc384f8736a7f5549924b0d67ac08c4637ac44fb72cdb6a71719411ae7ec13cb020451d68828b6052cfac57ce54d1372d5116d2b1b6440c589a78728ca049c2b4c346213c9b677717b1b75f99e64b2ce59859edc7da34ba04f521706211ed0c8bdf9aae5cfaf748999e8772daa422b78ab2e57302a7e2697beab5f6e02bf7b9f48ec2b891ae72b2a47e48ed775e3a2dcac0541dc40c1e9acf8bd7ad8754d650717ddfee48f608bdc79be2cebcf6b9711c27837605ec5afbf8996f0cd5", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1427421600, - "not_after": 1848355199 - }, - "authority_key_identifier": "0x25479b665844ed9e582980557c696b37eb831422", - "subject_key_identifier": "0x25479b665844ed9e582980557c696b37eb831422", - "tags": ["UN"] - }, - { - "country": "CIV", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xbaba3c290adf2b70cee4efb42dc0fc8a8947290569def2d2d2a9e9b4a4a33b50f78ef5aaf1f60449e4d7cace05ee5bfc08f0bbf3aaa5aa427e268b708f3b0a3a82e77a3b0e585adcea2c38529b7a097003291774692425f78c4804fe0c706521b85a9f541431892ecdaa6b2b66e2907fd0760887ce69119b986bde49e86f212c29676682709d31691eadafa8e183dbcc106eb5a0c81e851290fccb53b557d86aaf1d19343dc1568b4da0208722cac567f3f528ba2db29d8e20b3d3702c43ce8b7eaa42056cd0d1ad2af6c87fc264a5c3c2ea5a475f3bc4804d80a19f3ff6e4e402006c4383cb9eaf4b45241fe3c585a9fcbe51cdd26d0cb46d578b4fcedf516d5bf9d68df27ca448e0c4571baa2c0534419f6f30b52df4d336098b19ef4ce4f52d360ea5581d5f31d60ffb1ba55b87c82ba50ad057d2067db8e36b87f5d0e32cb3563ce4dacc1545132daa310c940159ef9ad596b1413169373c85213207f946152ac7f883a6cefd1b4f00cc4ee8047df97aab23ec4f6308126ae276cf7c6e5bdb5378488f26bf176ff070e2d6cbbdabdadad03b3ed4c4a737df849c1f5bc6b66a320a72f0c54a794e02ae4d73e5c261c1689a4c2241177a2669120f35f1ea054c3a391659e2814952ddc7b68f488ca45cd998840256ddd2f30a1e3ab71bb55ebdfdab10c62d7948cb6f4bb7c6dfb3bce93f044de80e13de66890596960834cd", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1607683663, - "not_after": 2028019663 - }, - "authority_key_identifier": "0xf9d1ebcabc50f2bdeaaa8a744a3cbcae7aeef0fc", - "subject_key_identifier": "0xf9d1ebcabc50f2bdeaaa8a744a3cbcae7aeef0fc", - "private_key_usage_period": { - "not_before": 1607683663, - "not_after": 1719485263 - }, - "tags": ["ES", "UN"] - }, - { - "country": "CIV", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xd2f839c5a6ce50fa26a82be7cffa3ac26a35004be446b823b3e6120f125d29e6b32e552934ca51de6ea6e9e2e16720b55c67065b83ad2e5dda180614bf46d5e393605e79032145e29272c2c50cb071d641363f07fabb4aee35d8061631d8d574eec409b262b7b76a88655e7964e1c988ce1ac5a7715454eaee7feed73a20027ed2f7c8bd55ca89ad44a0fb1f899f253945321ae394e858ae9a22056ca94a6bf432ef7e8c1545f201f598cddb8037eb8a895cc590ada8ec284e24bfb989ab7de347e471193665c2b11665eebbf10aba8374b51dc803c6accab4a3c4b5c6c93691abe1ebff747ee95f3cc1de8ec0824b58d3dae4648aae60f30b09b847bdbf4dcfe8e27cac60d12585de1db38849d086d41c298e3dd86f11a6d6c474c2d50053073e4bc3ec80d0f3ed7b0c650f9593b6df8094997405071eadb81d7747e611d5673e43a782f4e98540a52389d90a5cc6257972b4f3220f7db0105c350750d0e26c00dc7e4c0920305c337c4679e6d1bf165964ad5c05426ab692c076cad0532baa44f3759b001de8bddaa828703ed2cf8db7abd1a8c2e27cde7ce1526f88a4a3dcecef8d79a25a7fbccff9c4078972a9ea793854e1c69b9389bfab6695e14510593b05f33216343c66bb8c671416f0f7e0e518f4a175459ec6339427e0f135dd498a53cddce8db8d4201bef393eef7346f1bda61832b626e3e185ccb471da796cf", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1718813112, - "not_after": 2136989111 - }, - "authority_key_identifier": "0x243ba2a524d668c1ef1d5e41f2dc5edd8204a08e", - "subject_key_identifier": "0x243ba2a524d668c1ef1d5e41f2dc5edd8204a08e", - "private_key_usage_period": { - "not_after": 1813421112 - }, - "tags": ["UN"] - }, - { - "country": "CMR", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-512", - "public_key": { - "type": "RSA", - "modulus": "0xc92fc43ac574da555d21e8f80df31801721b9066177e2ef4f5b900e0edd2a1bf6fdeb93901392e93a04eb80ac5164896ee9e768cdc57e9f05ea3f9c974d229276f7d5801d8e3a4bc8c648eb5e3632ce7c3024d636308ec3aca5516a7f9b4d19b45c1c22fae9ca453026aaaa6024b0633be071b8fd707dc539bf9263390fa1032448ce3e048cd7593e2f718b91cde879323dedf7851402a897153782505856354259372ac82f3bdf289151951e6f5b2dabe03eb07250bf7a9551426963c95ef11c620e2f57cd4821ac7430bb689317985089bc463ae21347d5d572c714e281a7d6f7cb1077c933ae52dfab3992546439793caffe3429cb77629bce594da9e2f53fd4f9ef955a6bea1dffadc8de3e9399fb07d584f45bf07a4a70d20abf1866008c63846ed3e9fd2277eb8fc29572122fb43ac51d1726d55609024018cf4b6e2e2ae3ce8149196d1fb91f44035caefc6012b14db6e0c3b711c4c46361c309dd08cc298068a0dc46d89a0e4feb81d7b9f1aefe8e5d9e5eaacd2e12cfc347ccaa3a639ea363af95197e64b94362dcf947ac729a731c6429c6047ba7a473e370944353eea64223e1c74e3ed7b02cc82a09e206dd0785254634a2143fbfb67b56550ad91118e889dde5c169fbd907b80be55a644b9a6af4f139fe04e85a7caf47ae332ce6b0aa914c9982ad5fea6069e11b541aeaa5522723730cda2361232ea48f251", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1622037372, - "not_after": 1882101371 - }, - "authority_key_identifier": "0xdd1cb8e7cddb6bf303a555910dd6efe28ed2e2aa", - "subject_key_identifier": "0xdd1cb8e7cddb6bf303a555910dd6efe28ed2e2aa", - "private_key_usage_period": { - "not_before": 1622037372, - "not_after": 1716645372 - }, - "tags": ["UN"] - }, - { - "country": "CMR", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-512", - "public_key": { - "type": "RSA", - "modulus": "0xdbf14b57b0f87038c638f3dee76609d641681d584f6453a29a996e07e3ae088560237ef87f5e278756b17f342ea5ac98977c8fce209df0465e36c25520386eb89911ae9911cea687aa8f96b71487b492c7886f42d18d8a88fb83d753b1c7095401414fecb4d72b24356313706ef55ceb7fe50ddb71daebdd0025fc60f149b454aed9a67f549667d9ca00706a0fa3bcd74b1f4a2d415f07d2ccbcacc4b99c5a277fc1bb4b2d16748587344e76beb57dae5400035338b4cb3be83af82a853917a3fbccf4d090afda506ef5c49b9ad070ff21ae4d51de1a3cd3cb94efc14d28f998fde876031c5fba7362a60970afc6ae527f94d03da146f21e27a6aabeaa3f3c79c2a9945edce3a9667ed63301abc90fba5e104c6ab25754010afecdbdeac8a2f37377989a47aa74d497936481128f64843b8d9aa9ffddf06a19c6c615366e8b8a64fd8b92ca6f6fa254a501bc48d1f5e226ae54db3f63a3ab3d9c49895d4857bdeb9ae67fd79745440acda405c991f700f389b42a9463fc9e4fda8c82ac4729ff38d7b4cac87a94ba991da896d7008ae878024833b260e3e5eeb6f92d8df153e62792b059dc968f9bf8a821c9d70c7c348f715e08c18acbf9bce1cfef8218064c8c9d5588b316f477211e449613976ec0997c6fb63fe95e1b420b764be8fdc04efc5c4532cea24ea5e5f1f17c5777b1ce0671981d9612bb230890fd090045bfaf", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1701354249, - "not_after": 1961418248 - }, - "authority_key_identifier": "0x93b785a07abc4f8d2cf21e525f1fbea7740506d2", - "subject_key_identifier": "0x93b785a07abc4f8d2cf21e525f1fbea7740506d2", - "private_key_usage_period": { - "not_before": 1701354249, - "not_after": 1795962249 - }, - "tags": ["UN"] - }, - { - "country": "COL", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xa84b9c724b8cafbbd911bb104ec38cd7e26dc01d88dbb7a7d8c47d1357d45b51be2da70a5afaae96dcfe00a6979af9606347047b7514ade13696ab3920273a514084762c86b52963f3a7ba8209e7c23a3bc263a877a2a9adfcda32a419a40f91b4ca280ba2ded61e5706bbaf135cf280a4a87a83affec5783586278e6aed852ae7ace1ac81e654b17c5350d1979ca9a4e1fe9662e8f56cf1f2084ff8c162269c70e73f5cb9ece4dc634e0045bc47d80a271b04396ab6f231e52ff55a64b62d2c4bedf76de3dad122b875de1e5ab8c14622b97c1123b9665c099ad60d1f29276ea26566604fe0a518fb65e98c06c23a1c1f2edeba6797e9b59dc362862afabf2475d392fa125786844901a97836a1688ac012749a77e5a32d4c9144a0d927cbb054fe460fa6dc1f9a39f3a80e7990134db67cf1dff4a672530c54bf0e6e76fe6b8440bbc63cd0f27eb972fe1277e0e525d70cc7523112af2e769e8bef1bfdb1672c0553df60749f2a3fdc4f1a664fc3564a8da6837bafbdad03e2e3725bd5205d", - "exponent": 65537, - "key_size": 3072 - }, - "validity": { - "not_before": 1433877130, - "not_after": 1925754130 - }, - "authority_key_identifier": "0x8d205418d2aa9237dcb3072520176b4d49f2a6d1", - "subject_key_identifier": "0x8d205418d2aa9237dcb3072520176b4d49f2a6d1", - "private_key_usage_period": { - "not_before": 1433877130, - "not_after": 1591721681 - }, - "tags": ["ES", "UN"] - }, - { - "country": "COL", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xe50be15fd569e4a6801375ddd266f026d1b5dc8aecdbb06395785e5548c250d23198f2a03e6855dc3c2a85699adb7f0de7fe954f272f517af481a113bf65b40ae65db345f5aa478cd7bdbc129f508576ba65686243d646e6471976656763045ebc367d4bea81caeba7c46a6384c0955bcaba3eff2b821c51934ff0ac902e757034c4d64b11fb5fa0683e6d1c61b249c85e5ac9752285122e618d3c0072fae9ccb5287c20ab6ce948ce09f6e04c177fa6c6b82adcbaa09c934a8e169b746bda26ca58d0e0111596faf96701b9d4ead94e2841bd315e4227a2d2cc84ed279559f5fdcf001ccdba1945608da4dd10d5c9fee0b4634bb62264e69d2a481fd60b1e25e57e2756c159b79176efd50ab47f156d45e6c23dfadc69b4e49ed2c92fcf31ad6febdf7407b1debfda2d722ea8d4cde6364b7f2af595bedb82d2242c3806c5293c56ec39fd5b1ec6a511b22b81b3c21212d7451b49cce7ff0fc2b33b2f09e3bae312069d9c0ef778d84e221985b11d5e55015c1e219ee887f084ab5e8b22bcfb", - "exponent": 65537, - "key_size": 3072 - }, - "validity": { - "not_before": 1591381867, - "not_after": 2083172467 - }, - "authority_key_identifier": "0x2df0d5084f6e479685881ac1ea47a3e0a2d138ab", - "subject_key_identifier": "0x2df0d5084f6e479685881ac1ea47a3e0a2d138ab", - "private_key_usage_period": { - "not_before": 1591381867, - "not_after": 1749198692 - }, - "tags": ["UN"] - }, - { - "country": "CRI", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "EC", - "curve": "brainpoolP384r1", - "key_size": 384, - "public_key_x": "0x76b75fcd3050edcf78fbaeb47b799cc732d7e45ab0a1b67efeaaf1aac96aeab56147e1b2d85f778c5eadfa68767df62d", - "public_key_y": "0x19fdbc2fbe9135316da0f211f7c96aa7ae79840a4681a36e49054f7ea25ec48d60f61df7b2653d1f1db205cae32ef3fd" - }, - "validity": { - "not_before": 1631977218, - "not_after": 2073740417 - }, - "authority_key_identifier": "0x8c48b2e335de2047e8be7bd0e869d1be467839e8", - "subject_key_identifier": "0x8c48b2e335de2047e8be7bd0e869d1be467839e8", - "private_key_usage_period": { - "not_before": 1631977218, - "not_after": 1726671618 - }, - "tags": ["UN"] - }, - { - "country": "CRI", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "EC", - "curve": "brainpoolP384r1", - "key_size": 384, - "public_key_x": "0x280690820ef6beba54506cc114d2326d593fa30f84a7908c1480a5caed5192acd9b1cb4c74aba872d7f5c85f4c5e3621", - "public_key_y": "0x8014f0df558adf810462a9da4e628941834f940d62029ddf3c0f48c04b94955c9be1ea01ffbe5726666f13db97e43536" - }, - "validity": { - "not_before": 1723478585, - "not_after": 2165241784 - }, - "authority_key_identifier": "0xa491897dc83d382e70eea576dbb35423180902ce", - "subject_key_identifier": "0xa491897dc83d382e70eea576dbb35423180902ce", - "private_key_usage_period": { - "not_before": 1723478585, - "not_after": 1818172985 - }, - "tags": ["UN"] - }, - { - "country": "CZE", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x9d161abe49c4177a9000d24a7423017f9c4bfe31ddd6c78d58e96449913555c94e8214f96faff17a5cb197fc82c9b4cf102fdec28288c35506c471c37152c67eca3b41e27e76b6d5982c13799e4b4992c3f668154cbb57eaa324ea06169fd09b64a508d628d54961b507936a5793319427e6071b4e2338460828d72563cd9fd47a3559dedd8b8819d4b081453cc853d2553c430e65d98bc75a902273967fc75e6781a6923e54ab35edeef19017f4db21e76199f9dbba5bf21cddd4103319815833905d9f20e681c2ee6c91fa3c7b4f3f275e79859209b548d793f9a82c5f14ff8113a3ba84475124a09f4a21122fa0fc0f93640023824fd0777a1a050c12ccf47664f128770964059770368a7304eb1bbff184f4c07df74e6674e73a96103dc2a68d4be882a63cdfd5509b0632a3eb39d6d56b0087b661c74784874163948b3a11ec0cd69da51ac16086bcbf3520b5f507e74512edd66ec14bba59b52242ee6f9838ef18451aec5e9e7a10827fdc5791b3c966813adedfcd258bc74856b5c037", - "exponent": 65537, - "key_size": 3072 - }, - "validity": { - "not_before": 1301011200, - "not_after": 1782345600 - }, - "subject_key_identifier": "0xeba14f8f3c698adab6109b123528ced4654a0859", - "tags": ["ES", "UN"] - }, - { - "country": "CZE", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xb1e20a635d0ffb319f0e0a14d0c6d9dd4c7777cc0d37b291461049876c589c882a0c24ced3419df197df11e4f582ad2ff1b3b48d0615ed31ccfb31600b65acb94aba340cdce804cba06deac1dfc839a388fa542a55fbb6e6e6b559d3093822b5be4f3e308601a0743adeb7541142de850c4bd6512a314737de0f7bb2cc2bd027824bed39fa7bc6c7250a4a4203577ee77243bd5678f73e477f6af30759bd26492bc9ef4767987dc598a03d29f53c00529cf7fe11fb09ccf7862e13dcc2e5ed89d3fd9c73c2d8702dcb891297781471f1947ad0a976793b4317fa399424547089728907ddfeb219f0f782205790784c8c232df0d4e98c06b4e6a724a7edae4787f5f864ecdf44ced9cbf1601c6d89227a8584ee78d32034f5aa65974110df55213e84089d3222febc35437cbd7457680783ea5a2ade1b5496caf42abc065fc53aa22d21f8e9e3071ff83a05f480e2ea205e004ab8693c5229445a2a33abff9d72b3af1d252f84353ebac6949f9c3a4508db449955c38e6573371df6de7098a059", - "exponent": 65537, - "key_size": 3072 - }, - "validity": { - "not_before": 1458805750, - "not_after": 1940053750 - }, - "subject_key_identifier": "0xa6138b319205440e90ddc68ef6c44bdf4e357d50", - "private_key_usage_period": { - "not_before": 1458805750, - "not_after": 1616630399 - }, - "tags": ["ES", "UN"] - }, - { - "country": "CZE", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xe6410395787d2ff3fccc4e5fe1ef0ef27bede7a0d140b10e11f027901ddf2fa98c05fee36a6ed28638db973033c4d12da755cb3ae251782a4ec45bcb6750acc633fb6cd9e5653d05b8b48768db5b0a44d09404f333d00e76ecdceff80a0278956d9c32a9423b447bde79d165b555a30cfa11c1c0846a125d7f8ded15a309e2248eb4bb91af118e6af3650bafec4ff124d993375543995f7fcde940695e71b5de62dfbd61ceea7d10eac7e05f563f7b90eed740f399ceb49215b23b3f174dfeb3c05cf4961ff9dd880929a3a90738be609e4ba5c09373dc2752c2c8826583a52ab9de46d3a19ef4723b1bf3de65293ac7b30d760ccec5af2d51bad8f63e5297bc2f5cfa6d1cbf657cce5361e09e9772918b3bb506458bae62d5d548a47fe670e94f861182e2e0bd90f4d8974bd7deb458674df1375336a80c48108dde5606d6412fae4aa31d88067035a56dcd7bfdb2a9a514212f6ca14de8ee87ef9c491f24118571c45c9c3d89e77f2438b2a6b28636187dc2e3b9f94e5302f461c3d1577965", - "exponent": 65537, - "key_size": 3072 - }, - "validity": { - "not_before": 1616490536, - "not_after": 2097824936 - }, - "subject_key_identifier": "0xe4ea61beb215a6c402d54e66584fa8a87d50e341", - "private_key_usage_period": { - "not_before": 1616490536, - "not_after": 1774310399 - }, - "tags": ["ES", "UN"] - }, - { - "country": "DEU", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "EC", - "curve": "brainpoolP384r1", - "key_size": 384, - "public_key_x": "0x6bfbeec69de72c66a668ece1aaf1a264a3c9b288fb32d059e92c3e5d5bd4d7b5014878f4479c13c883d054555cd90ecd", - "public_key_y": "0x136ec4cc346489cdd64e6943f333864ab9dfe442dcbf8f69c19e71d035ff317fc032fc2155caeaa65b493d191d399ac0" - }, - "validity": { - "not_before": 1383130182, - "not_after": 1809129599 - }, - "authority_key_identifier": "0xc17ba915f75cddd26b3d609a2354de12ee3f0ec6", - "subject_key_identifier": "0xc17ba915f75cddd26b3d609a2354de12ee3f0ec6", - "private_key_usage_period": { - "not_before": 1383130182, - "not_after": 1477871999 - }, - "tags": ["ES", "UN"] - }, - { - "country": "DEU", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "EC", - "curve": "brainpoolP384r1", - "key_size": 384, - "public_key_x": "0x121060db7e1b47fd7d565812bb71cd155f628ece000855fc5b33b49ebd9a5d7e76ad209555a24903bf19e5ca96477375", - "public_key_y": "0x5ed1f02691364e6350f6e4061600c6c4cc3f6744c1148b704f4068c46e94d803c1fca97ac980708a3324937112e5d243" - }, - "validity": { - "not_before": 1471951376, - "not_after": 1898121599 - }, - "authority_key_identifier": "0x1bc750b147a755fa2f2579206e55d22fe2e4279e", - "subject_key_identifier": "0x1bc750b147a755fa2f2579206e55d22fe2e4279e", - "private_key_usage_period": { - "not_before": 1471951376, - "not_after": 1566604799 - }, - "tags": ["ES", "UN"] - }, - { - "country": "DEU", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "EC", - "curve": "brainpoolP512r1", - "key_size": 512, - "public_key_x": "0x104468cc978ae27b2d48ce5672cc0ba3b5e6830b9f6af14679d99842965da27842e6dad404d2d890d356ebdbe5e6f6bda1346bd5f53de5e27f9ca250cb923771", - "public_key_y": "0x146ec3584ea7ead25147e4d95f400ac70da4830a2d3569f6450e2ab2ce6ef9e36837acfb878d5775a20afe8c883efba4c992c7a7a4f483ea77b2b1539fe25b8d" - }, - "validity": { - "not_before": 1558344657, - "not_after": 1898121599 - }, - "authority_key_identifier": "0x1bc750b147a755fa2f2579206e55d22fe2e4279e", - "subject_key_identifier": "0x741a44ad4bd7b6fcd5baeef11e827e58a5981c24", - "private_key_usage_period": { - "not_before": 1558344657, - "not_after": 1658361599 - }, - "tags": ["ES", "UN"] - }, - { - "country": "DEU", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-512", - "public_key": { - "type": "EC", - "curve": "brainpoolP512r1", - "key_size": 512, - "public_key_x": "0x8190956c09b852981dc52949f3463b8efcdfe65e3e5a51d1c0dacf27c75e8252cc0840157a21a97bd9b4c927312afa8ae0ca1ca515f98cc1150f9a768d4d43ef", - "public_key_y": "0x556abcd3564bcaf583f53c6f40918155146dbab57f6cac0ba838010345e3dbc7140d82ea339a5747d48c53f02db42187d320ed4e275c755092750b04fe72ae97" - }, - "validity": { - "not_before": 1637648655, - "not_after": 2087423999 - }, - "authority_key_identifier": "0xa40a5fc380ae3e59af1b32d6136aefeec8ca35e8", - "subject_key_identifier": "0xa40a5fc380ae3e59af1b32d6136aefeec8ca35e8", - "private_key_usage_period": { - "not_before": 1637648655, - "not_after": 1737676799 - }, - "tags": ["ES", "UN"] - }, - { - "country": "DEU", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-512", - "public_key": { - "type": "EC", - "curve": "brainpoolP512r1", - "key_size": 512, - "public_key_x": "0x322430e449230c107e9fa1b74a826e05338477b126acc1ca2ea1bf8409aa21f77be978b061fd159d7633a5556836f92d32abf5928b7aa046e5be3901513c8e5e", - "public_key_y": "0x6a15230c0834ec9da3601316b2a358f5830e8379d273f442a60c7b990a551d74b211cc6e52702046ecbe69194f0ce5e7055ea2d7803e9cd3467f842169e7dddf" - }, - "validity": { - "not_before": 1727759875, - "not_after": 2177539199 - }, - "authority_key_identifier": "0xe8a62993eae208aa203e49d7649bbae1ba3560cb", - "subject_key_identifier": "0xe8a62993eae208aa203e49d7649bbae1ba3560cb", - "private_key_usage_period": { - "not_before": 1727759875, - "not_after": 1827705599 - }, - "tags": ["UN"] - }, - { - "country": "DNK", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xb0b3a944c161a2b7f7a575059035239cce282ffc63e326b133f2f2570b92d1537f56960b9b646e2649866783237f7dc8acf56f4cae8924a84c760082562ce1385dcd247cc15c43815519980acbb56a004eb1f017c191f9509a6b345b49be7a9aee43c78263defef3ec44bdecda98edc7ee3becfc952c07600736db139f61072fdeafbbc32c07eb968d7198a445fecd626aa105d2e1080efb92e874d9b54315b240d70d2ff7e39cf91037ee0b0f2c2d6f71292c50c7037af50d745c3aab1ed695e3b172e6011480b0918d35e61d66627c17f9f4f540c14247ce5abbf83f62d5f2077d90b6f3a31c69d5cb7649a9ff69336355ec7ce70ac162bc600b0790274d22326c7d6be0f1fb54180a7ab4495a96ec9a92996e7d2cc1b988e7914a89712fa9e0ce85451b3d6d200f9ae3681f0139a7ec71e62bd936a945b93c934de5dac6d7b33f6716d9ab86a10d17002c0440e730681fc064107abb7899319e3bdd8a2782ef8014d2c8881cf0e2396585beb986ffd705d9116de92d39dab45e79ab22c467", - "exponent": 65537, - "key_size": 3072 - }, - "validity": { - "not_before": 1315219642, - "not_after": 1809515842 - }, - "authority_key_identifier": "0x5ec388ad3ccb913e8a3bc461034ca558ba9f2917", - "subject_key_identifier": "0x5ec388ad3ccb913e8a3bc461034ca558ba9f2917", - "private_key_usage_period": { - "not_before": 1315219642, - "not_after": 1468451842 - }, - "tags": ["ES"] - }, - { - "country": "DZA", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-512", - "public_key": { - "type": "EC", - "curve": "P-384", - "key_size": 384, - "public_key_x": "0x0ed33530a94827a0779a6e9f5886631421d59b99284357eb4a039be6a3d91437a677a23e2cafbe31be4ab58948c0a82c", - "public_key_y": "0xd9c2a8d6e9a095c2f38ef4ef5ad0a8c5195f4399ff5d61e0991790b53c2adc255f20233c30688fb37c581b277f026ec4" - }, - "validity": { - "not_before": 1424736000, - "not_after": 1903219200 - }, - "authority_key_identifier": "0xa9d38fd58e176b5a40c684bf8158a32b558f8472", - "subject_key_identifier": "0xa9d38fd58e176b5a40c684bf8158a32b558f8472", - "private_key_usage_period": { - "not_before": 1424736000, - "not_after": 1582502400 - }, - "tags": ["ES"] - }, - { - "country": "DZA", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-512", - "public_key": { - "type": "EC", - "curve": "P-384", - "key_size": 384, - "public_key_x": "0x8aca5f821170fa4d8233c7f23f795792af42e791045bdf55989684aa16d1027d27541b0226d665c50e0ff76f91f5aeeb", - "public_key_y": "0xf6af5178c02204045aa43002c893ed2b800cafa1e42cb47f80a21a6f0c3a2919bc5242c21daca5f4ec3c270e5620eb7c" - }, - "validity": { - "not_before": 1580342400, - "not_after": 2058825600 - }, - "authority_key_identifier": "0x5fed4cd3bca95f5c8f3673c61aec837bfe2b2b51", - "subject_key_identifier": "0x5fed4cd3bca95f5c8f3673c61aec837bfe2b2b51", - "private_key_usage_period": { - "not_before": 1580342400, - "not_after": 1738195200 - }, - "tags": ["ES"] - }, - { - "country": "ECU", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x8d271793c4296a82ef21aa3c8c67fae8d98ac5178fa2057a93056b648d7fcc170815c674e07557f97263e8e3632c8edee587f8e49f312fd46dcd935fd062d6d025b33f512bf8a5097b4872f0fd907b08bd57b878c3f175a48248839a333dd0c87d7d8957cfd64162997bf69884c181bae06975db4887832ef1ab4c70905d58e9b88db25cced3f88f7fc38a261bcb140a4776c6e886760dd0a67aca8226791006e0f62249b11d2dcb3e7f412713b25be232c0ac810acb2910814a3c67be134246264da009c9ff8a5762e8f3094f9dff65bd1f0baaa42a6aa123323249a5457e0b7ab314f417cf20b1d1cdd8a3035ffa460c7e536c86fa74b0a5790da92d59344873ceb9dd2f6e8fcddb4f229d424203a6b76b31d55b2b6906abcfde8668641680165850ba38c741ebce0a01ddd15f32b093d5f9550d479951a774a5599c106e8371e909195dae1b4e6d3df296b2d405f63faa80e2764767e0148cf9171239d2407cd2d7406fbac2895a67e33918fd9a20114532af9e857d4b5d6c516a848f7edc78737e0ab68985e1f4c66c41c596530eebe93dba58c146416582f8e487babc9b62c323bead9071aff5fed8ba15f881de283823f7a380be89ab3379d8cdb107eef0794925ef6448e710a0b612e6da6d029d42a34c2410f0e2c62f35380065e6707d4d289e34440cea2b692d3abe215d258e2ed462c6afacd827f2e186e4979f05", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1598299325, - "not_after": 2079547325 - }, - "authority_key_identifier": "0xbe277306a40e7fee8aea627e51c79097f214c0b6", - "subject_key_identifier": "0xbe277306a40e7fee8aea627e51c79097f214c0b6", - "private_key_usage_period": { - "not_after": 1756065725 - }, - "tags": ["ES", "UN"] - }, - { - "country": "ESP", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-1", - "public_key": { - "type": "RSA", - "modulus": "0xd49444ba301772e2aae812c53ad1d31af3c2eae1fe9b1b128dd416c5207505df173ef0dbd21f1672efd23c76b3dccb5874de60e3805b9173319c40edc4552aee3f28c89463ee48295a62180c46d49e801a3984583983e49df67f6f5204363778779efe0a7566683e5f867e9d94fc40f2034cf7800a560e4320086525304b1a87e7a7911ff97cac9f1e8b912f6adadde0d0fd1e6940b19ccef59ed0222ad5d925c307c685314b37761d66e0def85801b1974a17379369be1bd795c8e6e4b3543e388159a460d65eac462f68a7c169f083a44b4809eb048ba31f27e5db411dc5118030e9f432dd080046d48562d6191cfc19abb5efe95f59b8df1e7978100e26019f9b3b7cc54d2075a70c3bbcaf017aae4f1e03ee116c3b876e7b1f3f8efa3725baed9f1f6dd0765a24eb0eb672460653bdfeee45beb5c731d2ad4cdc3848355ba85ae27ab989dfc7a04a1714fc3d937c123e65e85b2c5b7854740a0c08589867d881907dfef3061a2260cbb17ae85cb0beeca4dab9161a760377ae1d7b1be71b3ffc019f6ec97da081a6239bad0af9a7fdb9a1f49b474d6b9187bfffd8e25c347aa5012323d42072a64ee541a51d2816618e6be6f3c644fba2eff794d1d63bf8ec143255438173621464f771af726cab1b9488d42e0f914cee8fff8d9925b21a07d564887cea854d8096744837a3415467d2afa03264bb89ed784f212bac4647", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1342006475, - "not_after": 1823254475 - }, - "subject_key_identifier": "0xff802be03df40f1c17cf378b47180c01e91963e9", - "tags": ["ES", "UN"] - }, - { - "country": "ESP", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xd49444ba301772e2aae812c53ad1d31af3c2eae1fe9b1b128dd416c5207505df173ef0dbd21f1672efd23c76b3dccb5874de60e3805b9173319c40edc4552aee3f28c89463ee48295a62180c46d49e801a3984583983e49df67f6f5204363778779efe0a7566683e5f867e9d94fc40f2034cf7800a560e4320086525304b1a87e7a7911ff97cac9f1e8b912f6adadde0d0fd1e6940b19ccef59ed0222ad5d925c307c685314b37761d66e0def85801b1974a17379369be1bd795c8e6e4b3543e388159a460d65eac462f68a7c169f083a44b4809eb048ba31f27e5db411dc5118030e9f432dd080046d48562d6191cfc19abb5efe95f59b8df1e7978100e26019f9b3b7cc54d2075a70c3bbcaf017aae4f1e03ee116c3b876e7b1f3f8efa3725baed9f1f6dd0765a24eb0eb672460653bdfeee45beb5c731d2ad4cdc3848355ba85ae27ab989dfc7a04a1714fc3d937c123e65e85b2c5b7854740a0c08589867d881907dfef3061a2260cbb17ae85cb0beeca4dab9161a760377ae1d7b1be71b3ffc019f6ec97da081a6239bad0af9a7fdb9a1f49b474d6b9187bfffd8e25c347aa5012323d42072a64ee541a51d2816618e6be6f3c644fba2eff794d1d63bf8ec143255438173621464f771af726cab1b9488d42e0f914cee8fff8d9925b21a07d564887cea854d8096744837a3415467d2afa03264bb89ed784f212bac4647", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1342007234, - "not_after": 1823254475 - }, - "subject_key_identifier": "0xff802be03df40f1c17cf378b47180c01e91963e9", - "tags": ["ES"] - }, - { - "country": "ESP", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xcf5dd9c71ea4f3d72f76c9b467dc6091047bc96062a1c27bea4262141957a5e6fb41076c14d8f9f845e0e0eb072b4b59d96ffe093f182a263035725977295a2a92b9fc648e99c87405f9e2359e672dbe30bf4e23ab771604b8dee40c6e6bef7ce01aaf27d7a47cefd54d5b0ff5bf45c9396130667c96cf0172ad19a1d2419b3853be6988cd50e5b14fc018a09f73bfe8a5b6c86beb70eddf6aacd87fc13729c4f659f7234ab55973d7e5d68e22c5e5cf49d4b6d5a838066a18ca928e4da1d9e656f1ffbf1f52e6e2ee8c83d18589b952d00c4c4af7d84da34bc4c61aa312c607f1be2f4be78143093233927a16ace52b1807638c60b62d13079219a15697a3ccd47ca7b35e8bc790d56d07ece49a1ae82890dea0283bb801591fb4842a7afba9d1a84c6fdf7bf6419169c578235cce4d9a606350ce7a766a8ae6851f577528e5718133c0496433dc9b52db08dc166b1c980c942af487d619e15d37980d01200f3bb1aa7d8436ffe868be4c85c6f39c31bdc93465d69eb81991581992638db13cf849113f091d7268d53352da759ad1c8ec31541ad09a445f7c907573da8d9ef69ade75ca3de4c8282fc51e9fe7f693f1a9fb32eb2bbeca17f57730e7a96de41acc88a474e12bb7ac472a0d5fefbc8987e88e6d8aba03d69d06aba48cf4cec3c1972d8eeb691fd1a14d2b07ec3e0baf33dd2537c2c3ed80b58540452a911d7073", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1496831611, - "not_after": 1978166011 - }, - "authority_key_identifier": "0x9a49445bcf277569b245e1231b7cf99314d76637", - "subject_key_identifier": "0x9a49445bcf277569b245e1231b7cf99314d76637", - "private_key_usage_period": { - "not_before": 1496831611, - "not_after": 1654598011 - }, - "tags": ["ES", "UN"] - }, - { - "country": "ESP", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xdaecf0ff44fe977fe56e2ddb52f72fa8ba5eb1839a0397447664269422ffdd8196b74024aafcc48a858fa37e3be4071b7e02370c350a4f583f98ae6ddb4d48eb461e7efcb9dc7d769f17153dfac6e2b21c9f299ee939cab48ff4bc95ef446cf47b7cd57c3963859d9d1128b859aa1b850d8ef2bd12baa2f9faecbcc1ebc89de5331baaf02926790153fdcbf61c771e92982bd6d70a6b347bea0240675169c4ea455416576ba6973ee7517bcb43f33dc3c6657c8aa08afd8608889ddd22ce5109adb3e83aa83e3afbdd0eb45dff73d0bb18b19d31bd7c34f0755c9282930086c59481679ee6323b544b2d3c57885f45c675163b0160597b6bad7064b383f021c76fa222dec862792107c926645e540527e933499dc1735107593d534f4a5efcedaf9540250ec26b9f61a6b99c95883836ccaef7c9203ba30186b5a418ad5ebecd5f0587dbbc7ccb322effbfb3a4d703e263e0f4a5ef80b6dc2b35d86431d269fc9a7e26b7476e0771cee366221b9eebf1da918f13e4c218874d8790616e09b5979a246b83c82074175ad072b73c02cc60f53691d83c54c3cd0669e1d8ca15985addec263b239779c4f096b01c7774e443a1542be5b31df1947b7978fefc22381db4d99a96922c310e154f9d6d6ac4fffba23aca791a9552e13997aea947975bebeed5975c7afdd69f9772f3b595600de8711c9197848859d9a54ee500dbe6ef9b", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1652861213, - "not_after": 2134195613 - }, - "authority_key_identifier": "0xa977d16554058519c1d040fb6355627074829100", - "subject_key_identifier": "0xa977d16554058519c1d040fb6355627074829100", - "private_key_usage_period": { - "not_before": 1652861213, - "not_after": 1810627613 - }, - "tags": ["UN"] - }, - { - "country": "EST", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-512", - "public_key": { - "type": "RSA", - "modulus": "0xb8e750b7340d399621c4f3ce3d0726e2f8a342a729b763a78736dc51f16fad0d25ae41df582cff9404f905fe2936b1cd37503b6f8646f80de673414059cd4f4adb41cb782e1e8342d53f883ca3efa5ffc50f72a542c07ec1bef070a7f8a89c6e1e1716230b33e4f38d06adb1e2fe3ece58144c4938fb24f4a9e37d7acf187fc97e02ab84c717477edbd2d14c47c4e04599f399826e164dee18baf14f6f336d38a4dce42ee37ddf4102b52068d09339fca87661bf7e50154c79c6314bb8e7b841bf6b2036fc0e7277fdbfb0405bd5d540e59a998c283d5f206f72f5cd291aceab6604552368eafdf88dc42776c9d449a22a3f7a671164e1a86403d75c3d8faf5e8fbe21a8050858459c93015db17674561c28fd51e8bdea345aca39865d104f09c0946b973bcfe0270f52ee1bbfcd00a4d4b465342373b78d468b04375d3112ff37f0a3209f69bab2efef8669ba42384f9e751779034506656f5dec39736bed00c80b1592acd1f5638c17f2efca236acfefaa43ca7acf7bcf74bd904ad6154434aeabb5e45d873a2de94925219677cb1947fc12da6bf2616422693de37804301d16fa01119c949eaea029d7363017893431e3350ecbc86e9f3028551c5913da994199d2eb47dda0e8adc9939dafc34ae7b00f83c1b73201cc25bbb390853eb3ac0ecae060c176a33b76abd75c2f4e2003b6e4c2718180bda62e54db940e59c291", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1607338266, - "not_after": 2025687066 - }, - "authority_key_identifier": "0x55abd26f857eee40e0614adf983e2bb6936c55bc", - "subject_key_identifier": "0x55abd26f857eee40e0614adf983e2bb6936c55bc", - "private_key_usage_period": { - "not_before": 1607338266, - "not_after": 1701946266 - }, - "tags": ["ES"] - }, - { - "country": "FIN", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xba44a8daf7ec438509707744fc84974a0a9f398b85c3413d8809615f27e6797ec5cdb3a11cbc68d63069ae73ed0629494b979e871a4a64b8107a99644b5777e615eab1aa834ebec27ceb2b8fdf2f63aef23e2ef66d3667b2f338efc3db978d1805210ce8fe81e3c5edd0051be551eb40a8da125f9775aab31e7131fac3ec8ec4404d0bdc581c61d297347f015c39a65afc27949f8a74030e1c490f4f40f6891429296607b22c8a45d7777e97015d262422df2c0005ad5fdc7296116247c5e17666fbfa1139a86be6bcd2e798fb9a1bca5fda3df3f257d4fd0628451afa883fe493cba40dc5a9d373e4699c4996d66afd43728e35bce25a555792ee7f138e186ed294fadfe294b24928153f615ec065e8b81ba9a90bed9f2df253c33a4194137b8f47444acc7561b20bd66a4221dd47337573f30226c4dabbd9b9d09b2c55543ae1f0c440d72ad1c79f989db80b60b79f706fc2469418b614bfdfb5408f0aceaeb2a98d0aaafc3f85c8dc9750043f5dd13ba597e357908842736260b96ef70e1fb8ce9597db0ca0d3e48e6aeb42ec4acb6e92be96d04c27f889920a30f63c29529f80b6bea1bcab1ccd69f9c035cd550bd0fec61891503bcad150e4dd74f6ab76d58316c997d3c63eed35df544e75bf60fe99159b70f7e3f6184f70a960d338fa346a55e0ae95af8e8770fdf3e1be94dc2326f9340731b6451d2af5d4c7bb1e45", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1447233366, - "not_after": 1770801366 - }, - "authority_key_identifier": "0xc1eab61995d429f8ae2660304353e38a4b17f5d0", - "subject_key_identifier": "0xc1eab61995d429f8ae2660304353e38a4b17f5d0", - "private_key_usage_period": { - "not_before": 1447233366, - "not_after": 1605086166 - }, - "tags": ["ES"] - }, - { - "country": "FIN", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xcc6f7d26585b0d8952f1318d09915537205bc632f9aea428db53ab44e981c0f1965a34078a75f1acfda2f81fa5283e2174f5f7eec923a7448a1e126b89b8fb1fb8aa3553e917f98db2e9cf81ad7659d33316da0f4a82274c39dc692452f51331a2311b8a734e07d269f62e6c2d0a0743b479bb95dcc9da665feb5120ea128b5194ae14990b96ffa03c3cd4571c488fa64dc9898ed16533fe1f0dbe2a8b8631cd3c59704811f2ad5bf073e835ceb79c01014a2c0a201ca4f96b8eac6d9cf109956044b8ce92de91f8cc46ffe0851bac22f422b2bce0f1131ae77c7331da406b9f07347e6210dc79d89703121c36b175c47a81f9b7f125c60e0daef5f7eb0100875c7bae33294530fcd00528f4ddfc6bf1889ea67f0ecef97ed01db0542d0c20774103eec5c61fdc1894d10790d97a73e0fe1d276b9b18ebbe4faac82d3f00115a7e85188702af7641f63fd3bfca426f1573aaf0e76ccd23a4d673ba89ffbda2d75e36c1f6756bd5ced583120caf59e2ff7cd9866c3ae15c7f309f627ef0749957d1b2a746796d041309d18ceed35a2e2326eb8745b7cba10315522c5cc4745707fad18a4a562f3b66c793274263b2000e3ed45daf2c257d0f0d6ec8ce3f371a3203a9bda7b41012e49c601c24cb8320ddb78dbeebacbf8335a70a63045082cb6a8636f4fa3a89a419f329e5209596f5d5df5a0605828de6369b5aaf56de13c0ff", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1454054810, - "not_after": 1777190810 - }, - "authority_key_identifier": "0x9a594b5bf9297a9d7dd9a9a72154b85900d24642", - "subject_key_identifier": "0x9a594b5bf9297a9d7dd9a9a72154b85900d24642", - "private_key_usage_period": { - "not_before": 1454054810, - "not_after": 1611907610 - }, - "tags": ["ES", "UN"] - }, - { - "country": "FIN", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x8441d7e7429cc0978bc9fc5c0328ee0333e7382c3ad068ccf78547bdafecdee804442dda8e2a81b29e9b5459a5c8a48a9cd05b94e57566dda9a99fb2a34e829467968f9e0f6f97c1d0c2b320623a02e19d90126e16cc037ce001903cd525fe820c805b3cf2f29068b544df1af164c896b6466c245431e28f5ff9f47c74c8c7ee297c0cc7cda59288d98e4e9a4ec6a66592f140b2d39e1f0182c4109952e41bdec1c178ef44f9e8ee4d2303430f08f2f057d30441db19a16401328e4ba298041f8f897d99487f1c6147335cec770232e59a8feb3729677a405520aeffbecd668dc3739fd5b81579c21d0f060479c4614e118af0fe356beb768c3527994078c154fc1b99a9ec271a393bb5338ab488150c9d631cc9e3f66a04db16e7a9b433b8d6287a833c587a5c377a1e8c7d15d62465a439b481d9736c59fa5cd75f8d23436bf98788e2c62049891d5143b664fddd512e894216cf98e50636cf4344281273a7aadfd2a38e710bc88db765daf2f22302b78dd53b3fc5af0ad9521ddd5ab89c45523181a898a41c1818059273bef85738c59913254b4312ced7a831fe9280424f58d871ef228ea1812731705938fcd154533962c03291f4f387ea0fc8b9e94185c05c5e4126d1f6eaf3c09eb3a95baa297651e1f07c6fc3c5b66912f9c9e8dcc8826f45e0502ae31638d701506fbc09edf13fdfd8f53abe07ee05ce5611118e29", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1594883192, - "not_after": 1918364792 - }, - "authority_key_identifier": "0x87589c29d9769cf5b7ea661a3c8ca5fca268be94", - "subject_key_identifier": "0x87589c29d9769cf5b7ea661a3c8ca5fca268be94", - "private_key_usage_period": { - "not_before": 1594883192, - "not_after": 1752649592 - }, - "tags": ["ES", "UN"] - }, - { - "country": "FIN", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-512", - "public_key": { - "type": "EC", - "curve": "brainpoolP512r1", - "key_size": 512, - "public_key_x": "0x10bd0cb472ca330ff84c0ce076695decdf5a7e520bdac5ec3a316d3cca3501bb20ddc398673a4b6d28e1fc21f8f928e76c4d3a9e96d6ffc179c333a4b94bba6c", - "public_key_y": "0x7980714d2c14165f837c416cce07c2381c1c3db05a9a3d6d8fcb5c3804579e24a6135416311b401dbaeda8bb29ea577dbcd735d9c6df0f60d11715085d84f839" - }, - "validity": { - "not_before": 1649226252, - "not_after": 1972707852 - }, - "authority_key_identifier": "0xd69f6ca7f2e0ab2c5afaf19e697268364d31d393", - "subject_key_identifier": "0xd69f6ca7f2e0ab2c5afaf19e697268364d31d393", - "private_key_usage_period": { - "not_before": 1649226252, - "not_after": 1806992652 - }, - "tags": ["UN"] - }, - { - "country": "FRA", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xf0a362d5dd579a816dad303dd1f6d8c34be29548b3c23d46fcee097b2c5a00ccedf81d5aeee96ababaf60af6c2ab5451520116e83a2e77ec5ebc51e0a66c32ad8f9045f5809ae5d4a604ca66153abd227a3fc57e5a4bf8e5cfbcc0300f5a1ac9899dc676afc40663633812894a6501ec3f916f198fc842a78ec29252c03597b468ac2f8193f6c4c746290020733c5cb77e9bf4016c96e356f14f57b84508569a851e6a738ffb2436d4b6b29476aa2a8d32aafd4248e903f03c61ab05e86e9d2f705077c36b6d358b9ded234991a8e27cc6a30a6a1f900f504accea31aeb4cd4bd51afcd285ffd3a539ac09fe09ac1db8a6fc42341cdc69b7d3ee48148d2aeb941feda86957c6929a0c5609d49203e869e412a79dbd138f916f00873c8592496cf6ada235c2862c50da327ebb8aac460c248631ee86469db7b2381496d01af1f8c45471d34a40870f971b25025fa261275c8e8d36789028aa82a6fb51e5a55b249363b9f4ed05343ad321ff1931b2464f72ac1ae140b11a9eeea6a03ca799c842d94d808ff4176b21f2070c4b0f0a9c2470b50808db511484cd94f7c258d8f97e73ebcacfdd701d34bc2c691494b7ed07f78b4fb85b2685839c74e50b8595090d8c26a6412a3ac540dbe91cdcc3fc0b6a8b9674471938b73e907a948bf737730e9b95b25266ab973627ee3e82fad89fd48b969e25b89f3e1a028fae889894c47d", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1291852800, - "not_after": 1773014400 - }, - "authority_key_identifier": "0x22f38320a573422caf46ab8c3dee764dbbe5c502", - "subject_key_identifier": "0x22f38320a573422caf46ab8c3dee764dbbe5c502", - "private_key_usage_period": { - "not_before": 1291852800, - "not_after": 1449619200 - }, - "tags": ["ES", "UN"] - }, - { - "country": "FRA", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xaa55588329ece95c591d5e7aaa621e78ac78b484f2f23e442e97689f9e0c5c42917be63cd3be01ed00532dacfe009461353571e713e69e0dfd4e78e35e9ccbc3370480fe4bcab3520a0460e73adad7f33da4586eaefea4649282360594af16d7ef51745f94cbe4d645d27a5e7054707aaeae588efb99a33405f41717d54d035353f4cb8bd80b809dbc27bf73503900779b678c824cdaa9f3b66085eaa0023c61bc0a71a51c0785d34930bf0a789db0598d560b83750f7b8be18b3e1d766e575fc28902975976e40898fcce8749fa198d2197fc2e22e8fac342096c24e61eb0dae5d73a521602499fb80c0c85996924fde12f4c0362fcfcc2b7e2c59459ea6ebd703db41721387a9600cff5a9aecd33e2e8fa384bc2d6db4f5e4801aabea76392cee78a223781bf90c3ed91db9b28f79383d5caed39b107a4b68ea44572c8307f3083ba11e8773ae8f56b9d4ab63ac714267fc806b7b2fe252260a8071fe106a278c710845cf2efce6ddc9f65e32bb97306e132d308037d5d3803af23e52799aace90d58dbb8735eeb2dcf0f4bd5506bc0f4ac77238baa5640afe6172a16e4767aebc84d1e9f98464faa37a8bc0b7005668bc9ca7ab947991690f8537c12ec2fb46621ffb33c2c20b20475fa09f7a8a531bb8e6010fcc8fb4ee967e54d765d948bb71b8343f157c5df1df4665f0f05eda1c577f7216fa0743aca0dee37cc0a0eb", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1441324800, - "not_after": 1922572800 - }, - "authority_key_identifier": "0x0fcc3251e4e92a50658caf6a6871bc9e8fc86d59", - "subject_key_identifier": "0x0fcc3251e4e92a50658caf6a6871bc9e8fc86d59", - "private_key_usage_period": { - "not_before": 1441324800, - "not_after": 1599177600 - }, - "tags": ["ES", "UN"] - }, - { - "country": "FRA", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xc0160f9d4dd49a2f80a0e4b0d7f55a70ac36f645af9400cf84da3413e9b4c3d4a72e62cf32819c57ddc282a35c979ee1fcbd5816c599f30a5d8a47cd8a72df8f1b0431d5c251705ba136e9779378dbc66d0e0a873cacb1c79d88fd7652550726834618030b89db1dd019154984f55733512f4b853954447bb1c6d9b54b56c551990b6f1faea7c31af5b4aa56f391fe3d718ff1350989fbd879065ad14699f77cd24ae82b0c48ab3ba52017f7ec99052a35bbfc0e1db2a0f70e721d246905c3ae56f2d2e10c1c05a36dc6bf7d2587db79bdf5347ad3b59aabfda10b820c4690c9f7579111b7c66ad7a40c7fd8edfd3c4725502866b53aa61e0cc6047bb82fd4b644ba993d2c7739732f6299c7befe94aa020db44934dcec04ed2fdafa9bfaadb09bd7cbfe0d55b149d281fcb1496dd4013fb2f69d585af9a69e446302bc3949c2acb5b82621b282915b403d405655eb77473e5ffb9e51f8893d059a3f89f20304f7c51976024ae3468a9c8b47e784d334c288a44322a035e86dbbbc724100cffb1da2eeca9c28beaa5b1c63fff84134e1efde2519d6364fd5f2d4a988e6db642ba6fef94f916e1870620278416817e41080a8179a97db48e7efe2d64180749005ac2b8102feb4eb5eba6e16bd1b774155aa65c4304134103b39505ef36ff62606efaceb98be5e67b278f7dc3537f86d92fa6b23f68380e661062e6305ad72a763", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1590451200, - "not_after": 2071699200 - }, - "authority_key_identifier": "0xbe8a2ed6c9f9204e3a270308974decfdd97dc5e6", - "subject_key_identifier": "0xbe8a2ed6c9f9204e3a270308974decfdd97dc5e6", - "private_key_usage_period": { - "not_before": 1590451200, - "not_after": 1748217600 - }, - "tags": ["ES", "UN"] - }, - { - "country": "FRA", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xb8bffce6f30f3b501280fbec7ad212dad81f6aee4345078b539f4c631bf82cadcf4d9afe70a86c762c60a710df7de90c545218903719cd9ed172e240dba309300842597eb03dc8e0744c75b1279dfccbf0af1ae30d0c95a5333e61d2f938f3cc802591913c49730baa84e0a6c72c1667bd261c741c8cf7edd6987ffca6f6e722ada5a9a5a7ee39687f0e67415040cfa1044d7d9cc91ee12c9ffd1081740e0aba98aa5054f1b81cd8fa50742c38b71122d6814f84889f487a33103ef4c20a4777b50697297583734afffd636127bb8c1e90760b06df2ea072e45d0a254d683eda50d39dd8ce2bd822d6d0fbf04215fe9a2bf485609ede4573b798b0b815504a2b78e39b3ecdbc3f07135a22e714db4e54372980a1007b938699b87c91e01f6e1f41849fd51dfc1fbc469cd566864b09915911dea49033951a444d319ca5b7e3fb8752611fb487d9fa803f0f4040f4f2c165fff1bf9f7981756f6660c9749c3398fd9ec80690a82adbd4b6184c722c78ec648f80f39d3528106e84db5a10c0cd2b63417c6ecab4419926e2653dfef5d0b46897ef7f08fc4dd0ee2015b59a5f9a002d545e6bb8b5636a215a3255df68babbe0675301c2623ac971860b24a468dc836a06ed4a06838e34fb6473dab4bbf423bbcee82611dd5cfb1c86efc1c91ed21603bda88e553e39e8b29892587bfb2db3ff2943caa46816dddfadfa84b74ebcbb", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1739923200, - "not_after": 2220998400 - }, - "authority_key_identifier": "0x8319511c9de1eeb87891003537c958b76f207742", - "subject_key_identifier": "0x8319511c9de1eeb87891003537c958b76f207742", - "private_key_usage_period": { - "not_before": 1739923200, - "not_after": 1897689600 - }, - "tags": ["UN"] - }, - { - "country": "GBR", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xc3583682d60ee9db5e77f3cd27f02c8657aba30c70a21ebc33fcafa8e96b5806a090ef29cdc8a4a286f750c4f237ce89a207d460ded39854cff2ba8f4e7807c655fe1b60e7459ff7e24de2806ea6823ba8b3dd0a00c80b3dcb8bae3c4620d9f5a81e3144e7805c96f147afb13d6c9baab3d469efca9eadacad81ed623fcca82263d72350f553c17de29352f937ca3eefdaa902fe718efc5f90ce9b35027e5f56cd92fde396b2acd2c8a83a7f5712cf7df298607d072b8e82c5dd94be323d293adbd25b4f53467aaae53e92bdd23e26b5501da24b53e1f492917ca0fa8c59680fb17c952ac642944639b385a06315c251b204dd922e2f86a1d40f1fe3626e602d8d9ed0870c5d0e86acb0e3845557e63cbb327d9effecd317a31fa337aeac6f9304eb59b63dfea4d7ec7ac94891d5d8b14f4fb4db1aa4a88ad5b339fe7dcb460f8231f5b0628a6ea75c3fc252bf00c0d54d850d489346f3753a476a0ea237caf9001ce729bb2ec2cea6368f040a2b1b1108a2133effe4ca369d043d58a72d0ac1202138cca1a370b26d576da079dbdd6c59989f1e40f670af27e28231ed3f7a5c7f1f699b9ab217f7125993cda5c0b25147a0c37d08098b85d8b4f231303b1df92efaf03e31d92de00d6971fd4d43971c318dccb3f1fe908520f5aa788eade562d0b23f85ff76340c5d181811b2c19529387807ebdd7c5ab09d971f0d3ab516ad", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1269439321, - "not_after": 1784903521 - }, - "authority_key_identifier": "0x4531a5b73bcf8bb27c7fac88c74b4505f6c936b3", - "subject_key_identifier": "0x4531a5b73bcf8bb27c7fac88c74b4505f6c936b3", - "private_key_usage_period": { - "not_before": 1269439321, - "not_after": 1784903521 - }, - "tags": ["ES", "UN"] - }, - { - "country": "GBR", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xca642a5806faf32560c8a2985785294325a30e9fa7d46b823fd6b0a20dadcec3383fee39dccf839381a4e17e82574c1599dda886230a5c0b7808b78b92e7318fed38de2327b4c6750f220f3df70055e716300f45450df1e481769cff1e248f7a993692a01567b7bcc69258dbf0c92a5474fee16bbc22ef85d88e57bdc26741c33ad471dd90e18775203d9de92a53ffe1f7886bb354da4aa038861023a4d5efda7f49728315db29ab8590e0a53f3f72cf953ad437f8753ed1f8b0db8e57824f5ae514462b46caf022c094a9c97768252b45b9ceb69c0d4f92aaeec183149a57da2a2ae2905bd5f033c36bae80c391099898a1df627be2e4a6124834f929121ea64e8199113554960abeadd6ae026e25dd624ddcb7ac03985e4d3394a3e4701516bb60109148a4ce41fd49b5f388b630f624c1b4f2a1440acc0928615725b53b4624f3d1a37b504e694b57066a94682cd6fc8ea81d2b38278b145c1a81047a37f455e538ba48431b726529b4e9f656d831ce69e37221a29fac811124a0677160c88ac2295c727dcfe5ed8eb021bd3ad9fd6173580d81e7fd05ebd69ded171fd9603c84c72a96994aa75febf11734c24950291bb21d1a01af3a56ac7a907914c8f9e5c6fc03f411fae326cd6b7ca9b02d26d51546391fa1c0e6b27d31f1cf493c7e78e14c970d7f9e1a170d302b4b2d9f852a1ed95a8f012cc57a3bf61766321bab", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1363008342, - "not_after": 1844344542 - }, - "authority_key_identifier": "0x4b0e777526b78d1f0320195868e27a5426a06ed2", - "subject_key_identifier": "0x4b0e777526b78d1f0320195868e27a5426a06ed2", - "private_key_usage_period": { - "not_before": 1363008342, - "not_after": 1521849342 - }, - "tags": ["ES"] - }, - { - "country": "GBR", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x88f01c22063767c95ad9598e8e164690c7d8401dde1168ea9d01c092faa1f833f4e3e855ca782d1638a1e8453fc153ce47937e6360b81f4e956285b279af25d563814a1568729f2abd3d1ef81037247bb3822051af1691a249577bbaedf2933cc023319c9c24db41f487313ae02210239a5b5aee52a0652567d552d2694b1105bb03495b5719d5439fa4ae1833897340d0be5d24f95f1e2a3f6f6ce5d47051d877e2eb75777f03a9cc247fef2d651e07901a5488ddac3b47db34809c3e4df25e26e13a752d6fed31649e9a87ef6532fed7dc26f44174c8bf332b9f4f0ec668beac21272c570c7a58ba84e063219c6f973014595e7c31a4b07ae72b9d17e83da696c27475600e2d18e40ce7b2f629c6dc1c678108f3c7808730113e75c1eb641592127bf1275825015afb7badceeadfd2c416bed7041283fd447f38246a3a7f3b2a8771f792f78ad7a6c8ad249035ba9aa273c36e4d924b1323a1cba85d0e8618ffc65901b031c988deb77741f1b42a51b9909e71be9a7e379c0fb0bfcfffe1231c469d23d4e084e97c64f804dc1fe09baca22dd6f076172768194fea15dc38f7393dcf739b6eec3bc0909e07c8237f7c7092ec875c9c8080cfa5213f429b807021e6354a2f4c395f492e535222d690b44a351c0fae91921d19172cbe0e6558cc7f1bea4f72fb5a18787a345a28fa6f850981fd59385ca38907183a279e5b545b", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1410438817, - "not_after": 1925903017 - }, - "authority_key_identifier": "0xad4be7657eeaced2e168cd91316f61807f1c91e3", - "subject_key_identifier": "0xad4be7657eeaced2e168cd91316f61807f1c91e3", - "private_key_usage_period": { - "not_before": 1410438817, - "not_after": 1570233961 - }, - "tags": ["ES", "UN"] - }, - { - "country": "GBR", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "EC", - "curve": "P-384", - "key_size": 384, - "public_key_x": "0x60a2ff75eaad3c327bb559ae164c018c58b14f1328c4c908239e4a9172245294776b7efdd9a703e03bc857d1ff18de14", - "public_key_y": "0x11a35b502d90728fd46d1a56db769458131a52f52564f602cec8ee5f51bc6cb05f309203e4d73d421f0ff09fbc2e2c21" - }, - "validity": { - "not_before": 1473416791, - "not_after": 1988880991 - }, - "authority_key_identifier": "0xdb1d1657c76023089b0139e2613c082134b57ca1", - "subject_key_identifier": "0xdb1d1657c76023089b0139e2613c082134b57ca1", - "private_key_usage_period": { - "not_before": 1473416791, - "not_after": 1633211935 - }, - "tags": ["ES", "UN"] - }, - { - "country": "GBR", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "EC", - "curve": "P-384", - "key_size": 384, - "public_key_x": "0x56931fd7d42942eec92298d7291371cdbac29c60230c9f635d010939ab7f8f5d977ccfe90bd7528cafa53afad6225bf6", - "public_key_y": "0x1e2af4d20831aed1e6b578ccb00e1534182f6d1ee6bf524fbd62bd056d0d538c24eb7f2a436e336e139f00a072b0ba1a" - }, - "validity": { - "not_before": 1631881078, - "not_after": 2147345278 - }, - "authority_key_identifier": "0x499e4730278520c57cfc118024e14c1562a249d6", - "subject_key_identifier": "0x499e4730278520c57cfc118024e14c1562a249d6", - "private_key_usage_period": { - "not_before": 1631881078, - "not_after": 1791676222 - }, - "tags": ["ES", "UN"] - }, - { - "country": "GEO", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xd4c7c1bfe5067da959f70ca6b7420900d55fce5f5b59b2fbf2cbeb25cd679c491a1102949b02670b4df3b9add4a2144bcfd0f57e41879535b4558efc8ad3383310c4733b817682612315837bdb4d1e369313c62a75a3cae2016520a8dddc427084bc01b51e7fdb8063b66b010cb05aac0c8eda6a7bd55eb580df2c610d9a5c19e3a6cbf7afc869da9c3d0418bddae5409e7b8b0dc431516ca973cedbee742ac377425d137f5d21bd673de7acdd64b4b298d385340a217159bf7e6cda9c7cd6851bb78d17ddabf57b0bf8ebc1b23e9c4c20d98427d79c3bb649c49f17442f7b22c9b7459252c5dcc5fe074ac8e908d483538ae22823fc23e634a038eb9ef2254a3b175d5223fa09c313a36f1196a2203c0d1cfbdead56c2ba05c4563f6aa756cab79ec3e305156d5e275f1b59a010e3317b55dc910cfcb794a831460fea9065a52061e543e223a12c265c837ff854054bf99a0ab58c4d8fa49b594d0488201560a4ee59b185c002cdabc846a7436470448487fd3edb29d362b1d8c21d87fff2f2846ce5980e825a94dd0fa3801b2e5af979e2988d2b5384724d458c12dd95adf28c0f88c2570231b3c83aafcbe7c5b61474079620b17c9e70c72d0c14b4661ac27d6132940bd9f690ceb2b0f85a48787f5973ff29bb26e5617755210fcf85569124767d3a3b8c24a1c21b623a1f97a079b5a3822c28e31a0a514cf195ec3902f9", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1310049570, - "not_after": 1790865570 - }, - "authority_key_identifier": "0xf9d3e031ec4f581ffc8542d48a6f01a52f72cb28", - "subject_key_identifier": "0xf9d3e031ec4f581ffc8542d48a6f01a52f72cb28", - "tags": ["ES", "UN"] - }, - { - "country": "GEO", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xd52789029f81b63e7c3487e6cd90aac349568eb87681f53e026b5fcfeca2c1e4d33a6ca92deca22a535715da5ec6775841aca17cc419047adb7be84a2324b9494eeeafcfc6cf16a14deec717f77d7254d9e1100afc586960b0d1c93c3905a19202cddb1b58a36526250965dc492d91a17bacb26c123a615b0c6952025693f2aff487eea10e8c7d718d4ca35169945264cefb1f36dde9bb59c07282e11fe87382f6e3386896f6c2a465c7f4ef1f6e654231213839e35c26ab25c99f06bff66b4db0bd1592bfab2f26bd8d19f36f0c1e68ff84592b62b1d574ff0aa19d283daf360cde5a9ec9e596a4997629cb2300fa58bc86ead0d782b9aaf9b1207b577ce8f8b4ee397e601b147136f1cb370ffdec7a3187f69b8b53692d1f63d040cdae0219b4ffd76e51740399b9778742766a67e9a9a2d935ebd2c402ffba7f6d883da7fe8719846bc8c754f4468f35d9b09a3926c2cb85845ec750ff8fc0185ff130c73027c9a5632e8779ab6d6b09e02e803226157dbebfca13ea1562e56a3481b66bc655d4c66e011b0b0eb233c28080f66a24a7edbc5e4145472f9b9912ab2870c4b2e21167b602db0f7c85f81230a23e823c9ce5de2e2939add6d8b3e21b99f5cae37a7df5ea54ea8cbcd69716b7ff03f6ee3c6ca54ca6a5e63275e79b0869b8ac8f1c8dc1661704149950dd63ccf5700e8f38cf80a84fad6017237d1f7e2a896145", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1474546508, - "not_after": 1955362508 - }, - "authority_key_identifier": "0xb72bdc6c63e79938e0ed2b9b5b770eb6574e5a33", - "subject_key_identifier": "0xb72bdc6c63e79938e0ed2b9b5b770eb6574e5a33", - "private_key_usage_period": { - "not_before": 1474546508, - "not_after": 1632226508 - }, - "tags": ["ES", "UN"] - }, - { - "country": "GEO", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xbdbd4d5a3b608371843d65544d65f9737ffbb065aae613b66325ff432e38241a9498015219c82a89e32d02294110cb23b000223cf2670d7ad2c0e5294648e77ec88a4c14b408fcfc3bb452aa6b9e242d132eec8bb656bebe2c2a05dae9a74abcff2449a258c7dfdab25b10725e5ee935220af453348f7c830832fce3354cbaedafa6b22af1cdd4da9c91c49f9f268e5e191fc2ce2132ac78dd4abe1399b89b0ff7a74651f3de10508d5f520b6a97a78e2d8b9c34f89d0d14887a81fff13f0de3c9159ba7a169cb81b2d3e608905accfab8ecdd1b7eb2eec760e56c3506dae8d8e72b2e566f788374287b4ac7d9c90c45ed4d708a62d76f8eb92753dea652d37d54d8eb73a209df2f729f9f3973763b50be3dd0d3efa27775585acf7eeb4320948adac621c78df9adf6affc1cc104f9c149c73397c55050a9cb1dd3a080f2206f2aa142d026049f961aa7482451f2ec9f252e0bbfef4e93098ffe7551f9ea9c5ffaf4e65c8e99c37f57540aef40613f871594aa15b34528dde85480d85c303c3b416c3fbf0ef9d008d01c8170118a5f9654a3e8ce3fb2912d52cb9b58187b58c146209ae9bfd08c806c92083ea8965851da44108eb5b84f71b9167c840fd8064d3bd6962818a525b2dafacc573ac6527370ce156d3e6f6186424958cf7043061739a4bc6d35b720962a7672b1c335361dc0a94c05d9b59efd4299a6058dc86f43", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1616598992, - "not_after": 2097414992 - }, - "authority_key_identifier": "0x2954167ec053e4df177dd98dd1255c60542f05d9", - "subject_key_identifier": "0x2954167ec053e4df177dd98dd1255c60542f05d9", - "private_key_usage_period": { - "not_before": 1616598992, - "not_after": 1774278992 - }, - "tags": ["UN"] - }, - { - "country": "GHA", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x8030d76deb08fdf4909c4d1b57e1282dca3154da59115002bd7d9f8f4b1a2ac871c3350ef7bdca7f904973da8c105f4cda8e52a2832e29518728e2d7c97b2fa9447532b2fa16450e2dfb08142db550f7c4b910f4e990e4ff7a6bd6d3b097f9792294114f9dba5dadd95241920791528961604b253cdeb152ff4a741225824c106c625ada3db56ef07b61e19aadf4d3706d6dbdb39e7c242e265a336ed2876bfca1975d1a7ea854a3553197025e6b023b2e75521b05ddf5a885303846c69dc7278683ce0ce6e86bce2b935649af3bf6f66164278d41216dd39582be37e564935b716d1a8b93367999e96c109c27e8b47a9d2e3f56088f2b0ebc538abb550b45a25cb809a822a2fb2ed2db7685e2e86cb7a8af0a2ba1915340e2aedbafb26869d954e818dbe78202e6311cf458da19595a18f43f2d5d4fc430b15eca80b936ca8e455e063c3c25bdfc11d1ed9d84a0c920afd7ec004ef0d502c6f0a366b6e516916b62ed64de0048e8a9edac311a2af37e60d69b8b10069520cf3b771a28cd75de199b3f5d1af159873f9eb3f7ce3bdcd9508ffc5cd69e463ade1915b07fe94b3d60dcee4b3a433f829cd644d8654bcf15566ab6f394e65ce065d9f314309e88267061642c4b554ea5303b1603dda58c3f2203af15ad4c55f54d31a2310a0cf08e2a1d2061bc8722d22156d6808c8be6cb50f0eb782b7c12f090bf8dd5349ab6b3", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1620730179, - "not_after": 2102064579 - }, - "authority_key_identifier": "0x795fdb3b217ebb36350089879568481038756869", - "subject_key_identifier": "0x795fdb3b217ebb36350089879568481038756869", - "private_key_usage_period": { - "not_after": 1778496579 - }, - "tags": ["UN"] - }, - { - "country": "HRV", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xdb0aa3565b20657eac2d6cd7d4f52fcfbfee4d28f56467da94ba4ff89d12b01acf57cf1abfb223ca233e3891e1be016fb12d4ce0a0880b9376a993848f5c0c910d485232ad7574cfb28639d605fabe611841bcab2ea2c0b1949f74a24a6b358036261f19902652a071f67613da8d45d3761803e67c4cd825192ff262c0e83d619299b161880a32ceca55dca08a7a1629005ad9fb8aca34786de4498b2e8e067b50dc6e21858b5e10f224c90710e89f2def50c3bb8a1d5f45ad460f4ec215f8bc049959d4863d5cbe817161cb4b8469126b9e2ba0022b9a69a3410b54d3532eab60fbc2b1c8c0b63ece11a017745cfff5791ca00b3a97ef2e4b959b8b6eb3bf012704dd6ec1b1052c977cf8884e47d444f697156aaa3bc2718b6f1466293735700ab66176fb436f890ab3f95ec0c8cf66db43652af3a94221ee6b6ddcd292b5c01e4f0bbc74e3004d79a47f6a7bc8c8cd5e858f08bc26776c00b00fbcf34aaaa34c0a036fc67ed55e16a357755f8ff8eb62d2c2d0b8465673a1ee2b0eab11623c9dca86a000752461632c5862ef8f04ee6c447cc482b79eeb2577997764ee6b472630493f3abfc46d7bc46c8f968d9b46f68003aa524ce9042d27a8e7cf188964473fae967879add03deb91199a73da63cd1505ee604ee951cf7fefae32e12bdc6a3453fdbf7ccfd566d435ec8cc63ebe73c971464b1d4acee2eb2e1498c72d77", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1367230610, - "not_after": 1840618010 - }, - "authority_key_identifier": "0x441fc8944f1e875f", - "subject_key_identifier": "0x441fc8944f1e875f", - "private_key_usage_period": { - "not_before": 1367230610, - "not_after": 1485578810 - }, - "tags": ["ES"] - }, - { - "country": "HRV", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xb0ed886f1988433558156b9dcfd1d16b3107998102961764721b26ea6706ab4a8ca932ae398ea03caafec75e8a7bbd963a9c030512a56778013c52bd48eeda0507c92ce0e153a4fe1871b9d76f2cc6c483c2de82cc0fd9428f526ff0b7af40bb5ce541f1130bc7d131bcfe66e6ec61b3174755f2104a0f71910ce4d59babc884db3bcbcb93b7132a6089f7e7df1b2d823bc45027a88fd28350e1c8042c237c0dc65fe368afd5141bbe03caa4e06e557ec34383cc6e0622d1634c0520993aca29409e268ebed90371167e5aa79cd23b00860edcace6fd7e5c22aed4191544856a07ca2cc167a7a0f68afc9b568045dfd7a2464546575694d649affc4598ff0ca5c013af8a84a1cf99bdea6a1d1ffcc17be75ee04cad8f12d541a543502c518e5c0f1cb6e44a277f58daa2c66e0d3b44c14a69221b4b4d9ae288f01836ad5deb6a709dc914dabadec995a8a502ff272c8d3e46ae5e037ab425783d0e4a3ec536d4a18b4f3eef0bc7e21aafc3e21922947457d25d66f7d9e234eb683e3572ac369330bbf618b3710fc651456fb0d3c0e0672e04677738e8b25a39ae6e3c9894fe293d2529a019cadaf4a310137f7edc6785a8b9cf6d8e149c8483b2caa0981b263527f2fabb14f33ea6142a023ee2664c10700f756f026de225c0b12f357cd5342432e6008e0802bd7901464293f3dbe06a2b4fd23ad39fc76d770b984d81133ad3", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1485258599, - "not_after": 1958559599 - }, - "authority_key_identifier": "0x4e70974937aa9487", - "subject_key_identifier": "0x4e70974937aa9487", - "private_key_usage_period": { - "not_before": 1485258599, - "not_after": 1603585199 - }, - "tags": ["ES"] - }, - { - "country": "HRV", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xbb6a4c8fb7efbd610c038ceedad1aba185aac739e22468565453751e552f912a9d5e9baac8d9071f4e16c91e75d95ed8d3c5bf99340a1ce5fe6c4497d95862a9ab549b8def8561928dc811272ee4d3324d7a5e5653d689f555a7a14f1550940b012f69af5a431dcfe6bd24cbceede0a4270b6378b99bdedce954834e2e7dd698074dd1d41dd6ecb419f1b2ecc6bb980f1278fed48464eaab145dfbefcbe125b800e32fc2b781f7e01d4b5c65be3f3c55bfcc78b3707b08a67cba737435b7065291ca8ee00874cd6c2d7970c62ec21c77bb9fc913f414dbb84cf988dc2fab8fbb5bb1b183c3fb536b0f601a4f8fe684c45b95509a35b73ac6a304c2511fcfa1a425cd6857c4ea07d74c3fe10541e3cd97e0fe072ddbd4b35e34b0aedebb34521196acb9b30474bbb69ee7babce8eabac03441e2cb884dd8c0c8561bad5d06eb76436b7c3258b0cdd446ee5a2f57f2d69801401a5c7f9a89aab751b52331808afdd9c84a027dede1907a72e2ea647bc074490e038d76977a1e99a72fbd331582383e68e278136493b3407dbd879527b1b4a5101f20b28a4fa8f15b64ea799535432bcd318a74f2f052b4384067b8544a5e68f669b39d2bc9c2c9f77668f31a990fd1bbb366f2f5e686fa9ead071c635ffebb50213d088931a1ba5d48a30782ea677b3578033b8307d8bab9c180c6ab1672f37bfe548427d49059d319e25511f533", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1603353268, - "not_after": 2076654268 - }, - "authority_key_identifier": "0x462349da3c204308", - "subject_key_identifier": "0x462349da3c204308", - "private_key_usage_period": { - "not_before": 1603353268, - "not_after": 1721679868 - }, - "tags": ["ES"] - }, - { - "country": "HUN", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-1", - "public_key": { - "type": "RSA", - "modulus": "0xaf390b2c810ea95dc28e3d667f5ef46843b15823a7a166b76053a9f65df66f5a0c5aa01cc4a454632ac295b6bbfd733c0626a15cd8cdc549d9f6e47dcb56453e457ac67b54d3a3b4ad4c7ecaafa4bacf925bfb675f4e6229aa928a5e1a9407e0f8332d2b406193195ace3943f58b98e4795c57c662b187c9d9e7a9dfa19d9b323210160b6426388c519c983f8ee33e9c89118acb99e032b94b14150e16a66cd54c55e7285b044ec42904b838576b54fab2a4cffddfd31dc3f60ff6eca0c4467b34ae6dd323f2fd88d63d4d907a83b1ae21e4d0a52ff966dc04015ec1919217b52ea2e30715ca85f6597dbc08ba334c1b7a8f9dc774c118b7c0fb7c105cef48fd572035ccf8c2e9d1d6c920f1d8e1842c0d73370dcc9359caf77abda5dbb643f08594b8ad336a8a168aa06ecf4fba95b33d30384cbde78dcd351c6a6a87a0a8722e295c08af4a600236d2bddb97060ac60817604115f2d43dbf18fa99ea836543ec9cb81d0107a260357393b03e09ddad749ab32b15a1e8be43f4d20d9fe63dfba55e8e0e50945efe0058842126f349b5af77556811c70bb9f79704271f752d4702a1166def9f28eaecff2c191d0812c44bd5c021ad7760b94c23ed8a540a3d23550aad3efdaa349870dfd3651d92dd5a69594e66e0e83670fae7664bfdcfb3a16604667f4bdde95f0dd0e7d040dae44c64bb8a5d204215f1975230d141afd4e9", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1343890194, - "not_after": 1762073394 - }, - "authority_key_identifier": "0x30fe0705cc85681b566e45bf8c2b0e642282ec13", - "subject_key_identifier": "0x30fe0705cc85681b566e45bf8c2b0e642282ec13", - "private_key_usage_period": { - "not_before": 1343889356, - "not_after": 1438497356 - }, - "tags": ["ES", "UN"] - }, - { - "country": "HUN", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-1", - "public_key": { - "type": "RSA", - "modulus": "0xf15eadcd923e089bd9e0e5310424b35ce37df5e71b42a284c370402b2ef72524bb23297df72d845693e2da093a41eaa59e1fa20c90e51142c48b89cd5be5e7acef55df7239a17a4d09c381e1a3be9e7758e89af9c71df2f5aa8bf55f1c2eb2ffa0023ce1c44cf0b015cb20ef5a260e04598633795e036bb3bbf361180ca7be0d94a950e7be6569d03f652d41f9c86f7274ae7a100f9d445f838af7647b2e70c4e74973e774301001fb1f2db032ace057c0727cde845e12a4adf5cca7b69e038b37d3872b9aea34ac4c288c8109f0fb45d49863c651e85d93e1c97aadc820ba1b779e9386073729481b8f37022595acd0fb1d358c2ab2d4490245a8e50a1d41acd945878963bcb0ad33fa18c183f8a705dce2dfaad091e474d4f67751b6654606f713293fce96016d7447203d31c1fa34132719663822d794436df16a963f424ea5bc4cfef778843aeaff9ee482a7c35d68567635816c7af8a4941e7aac84bc9d35d2deda01a17496e9c8ce95514b350ba192c33651ef5d5f9617751d070998e418ff43ebaf9d5b05de0c93f0ecd4cd34822f13149f3afd16023f1448fac963b1c419be03cae2250ff3e973ad769af4bd6da92dd23205d6d3476f05eb70430cfd5a164e7dac6f94645a3d8c1799e1ab7a21838ac89a70f09cfaacb4abdefadbef6ef01ea5bc0ae1f7aa77f55f329d3d26ec6a585420af81ae807716a954d0369f", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1435825088, - "not_after": 1854087488 - }, - "authority_key_identifier": "0x9103463a0c1f43e5ddec65b874e2043714559046", - "subject_key_identifier": "0x9103463a0c1f43e5ddec65b874e2043714559046", - "tags": ["UN"] - }, - { - "country": "HUN", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x8e7abba0683f04cde46a354c4cf64f6f34ee9784b4edfc5586081f1c3eaf62596b3415ef469f04db968b557dc97354cf017fe7c87fba837925785bd47698e9e402d2076b64a5cfd5e6586cd20e7274b0b6bd046ae7189fefabac49a4fb6586012d0e207702dea3e9fe2995bfa19f8ef65edda1735739d0eb1174fb035f8642a75ee82642d615d808954b1a3c3dea990eebd29c2708ad73ca8b1eb0828cadae7c030d992ae5c8a4e2c8f970370fd2c3575aef920479d5e7675e82e66e0a6672848edf2e4a04efb9eee17c3528f55279f0b74a80b2a73972cbb6c3f1893b3209817b285fc81c0e458d4be858dcdda6b58b960db95a83c066ffd65a5d48ee49d2cc572381a86dc68e4d4db8cc886e5a6aac32316c09aace4a232174964cd3df9ae185453846806e1acb1263cc5f55e667533246d9a1b8d187477a88088c3f7de5a75f152aa4456f1e3be6fa6a12a8ba003105645119571919b36ce38c749aab3f74c242018df28ac5c8615407c0b359ac5ec85e8623d74dd4b099bb8e1893484be14612c383f55627ed146acdd2d21133dfba55d012fcfc690c22af60318f37841245960cd70628cde08c1e6eaa94ba96106d4cd38e2e4ccf302a51667957681778d9cf2e21d20dfdc0e89c8104bd8c2844b23d68e8d97cc162beacd24ea473fe35657bc6d67c831758ffd5d093ab8ecf0cf3a61ba7ff3eafbc306737fc622a2521", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1497355200, - "not_after": 1915531200 - }, - "authority_key_identifier": "0x13baab8a96ce9f422e60058c2407ad734a814411", - "subject_key_identifier": "0x13baab8a96ce9f422e60058c2407ad734a814411", - "private_key_usage_period": { - "not_before": 1497355200, - "not_after": 1592049600 - }, - "tags": ["UN"] - }, - { - "country": "HUN", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xb717e909af0f01d5f12002604fdcdcb153a44fac49fcbb27a9832003db2914e4940d7b4873e43bf8b11a29589ac100ad20ece286a04bc7af418ad29763a4e0bc52a6b95af3898482b37a4b202f352b2b57417ec0f6969de90163f17038aa0b8f40efbeb47e0aabe4a7be530d0e8dd52cb24b7d8b870044a974325c313eb9fa12c2f9b519b16d72d5f20a5739021235bd6bfb694518d0cd5cdacba3078530345f50464fe86b1f6d17fe3be2521c7e31e855fa8af16ee3ca7d73145247736e80c4558a109ec65a2289e3bec0d1514b6acba45d02fba4580da295b39f3d3be4150fbc6ac2a0136926ad7b9060d266ed0fbd264f1ab19f2ca7f3a1cd626a2b2d06f47e9ddfe8144550a713f78d5e2d78b1ec473da9c395a1bff6300324b53fa74747f3758c22df5b23a3952648c5c6629e432996ca53b001274bccb5bd9aab3d4473fe101f74b2d6f9eae3475003f0adcaed5ed631f2b842f9951e00f7ce3b3e25c668d5a0fad0b60d9eacb809645cf1f8a2316f6e0f3597147b482477c702bc8c26296f812e8697bc62aae4e6fdeb9e6cce46536720b3ae7bdab253b19856cc7f4a5d46889a33a25d50946a2916295a464a49101bcb0418d38162e6e8cc70373df016b8f4b7b39759136b01c1d02b65d6db792ab6026b5ac089eedd2284bcaf65573f5212e4a1dcea776dda1ae01671ede5d4ec602949ee48b1f95541718c5da88b", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1585045800, - "not_after": 2003221800 - }, - "authority_key_identifier": "0x89f5568866ef111478257660831041f8835431e2", - "subject_key_identifier": "0x89f5568866ef111478257660831041f8835431e2", - "private_key_usage_period": { - "not_before": 1585045800, - "not_after": 1679653800 - }, - "tags": ["UN"] - }, - { - "country": "HUN", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xb225e10c3a1b8bf353c67cf3d86309bcef70c1d56dae48d147c5b024714c17eb409e48646536e43fcb5d400032661739d2c24d901dc6c7fd2e7c53fda233bb4a091f37dde79e66a2a963e04d1571d9f48f5364e2030f04789bf27b2559d591db4bade3e87e94a5ede6c35565d5be7d78d23366a6207df53c22b856e1c78d4cd8ab068573be979abebb35eb90d3412c6587973f713b36e32df60ac2c9d287dab6fdad79550df69c22a7e544e1212579ebce4989fbbae95b68560178e34c534afb90b07e6c139a1899b170589561cbeb422fe0ecce351b9d1a59fa62fb987bacf9cea637892002e93b18fd0aaa18f3ca16d355400e00fb90db5ac38dfe647ebcc3dc2ced5706c63a92001446e3d59fa242d2a7b54cf4e13a97bcb543bbce62cdb4ba46955bb1503d7be1a0ee8d21472645b3a3d82ff2839177e68b7b131332184d056be8a1f18791249c9f612ce310a3e2f099df93ac4edf3b77095189be06c19f09b5e81b49d9dced2f4350dd9e3e5ad494eced92219b946addb2963db4cc115ce99694ba1acfbefad577677ed20ae3e672a1d6b7fc89d97b087ec03b76eae112fc033056ac93d4a29f2239f226cb39e0aff93885b9926d9df3dfc40f39f3ed6267a77220e860c6e69fceff3b264ed86008b7cc895c7d0d21ba6334491a3c6b19fa20ad0c964cd5d335b6a6d25b729650f87364f5d86b07707478893bf7ab3dd9", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1591084227, - "not_after": 2001311427 - }, - "subject_key_identifier": "0x400478412a8b2477ac7bce9422a3879e42cf0e9c", - "private_key_usage_period": { - "not_before": 1591081200, - "not_after": 1685689200 - }, - "tags": ["ES"] - }, - { - "country": "HUN", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "EC", - "curve": "P-384", - "key_size": 384, - "public_key_x": "0x8ad46bdafdddf62623d9a18dca1f14fab8e59860bff7914ce937c0cb6f5206cf22b83a4151fd6f7de1802f33550ab0ca", - "public_key_y": "0xe75fa1796b0265b023e7c04159dd9ca5c5d847f61da5324c0fb790991492376332be18b2294732c962721502708225cb" - }, - "validity": { - "not_before": 1603185303, - "not_after": 2021361303 - }, - "subject_key_identifier": "0xe5764360a2e8881eaf4ead4f01b879bc466b2ec6", - "private_key_usage_period": { - "not_before": 1603185303, - "not_after": 1697793303 - }, - "tags": ["ES", "UN"] - }, - { - "country": "HUN", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "EC", - "curve": "P-384", - "key_size": 384, - "public_key_x": "0x837734f03e35c38cb35da36e3581f64fa38ff6573df666d2094e15da16419360b4b0ebb30cc12a22b44526f64da09ef5", - "public_key_y": "0xe7456a4e24879e5e6d217d7155af612bc99ea622511bdc4e1321fdf27449cfc077aa7c8834e7a186bd6d5a7ecda06276" - }, - "validity": { - "not_before": 1681376400, - "not_after": 2099552400 - }, - "subject_key_identifier": "0x9325b937f55d2f64238c6bf9a2f92813a5309420", - "private_key_usage_period": { - "not_before": 1681376400, - "not_after": 1776070800 - }, - "tags": ["UN"] - }, - { - "country": "HUN", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-512", - "public_key": { - "type": "EC", - "curve": "P-521", - "key_size": 521, - "public_key_x": "0x014fcba993e286f2b39db3d66c3d2f38b9e6a591bcd83d1f2f439c9c885cb1fcef4b9148967c09f8b2cad00f1ce60578a81d54538d9243ea774025cb2285e427c2df", - "public_key_y": "0x00995c39d1a19a48da5c2ddd496a082a74944cae6d8b8cdf7290cbe5e3bacdfe836efbcb58e5add39d68d81c8cd2501ba1c93a9f7c8c90de7f8e077cb71004bc98a0" - }, - "validity": { - "not_before": 1720083600, - "not_after": 2138259600 - }, - "subject_key_identifier": "0x160803462370783db622a41e6e9689f1bd7680b4", - "private_key_usage_period": { - "not_before": 1720083600, - "not_after": 1814691600 - }, - "tags": ["UN"] - }, - { - "country": "HUN", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-512", - "public_key": { - "type": "EC", - "curve": "P-521", - "key_size": 521, - "public_key_x": "0x01699103e8b7b1508d573119b1f0cb12719fc71e280ce22c91412f7cdeab31be2425694fd5b4cb5ea318d5abee1dd5e1dda55e1295d65e8126056458d87ef63aa8c1", - "public_key_y": "0x0192ae31014b77a182f2ce5402b7999c93e51c88d45f44a4761c1263138a24008e515401f196b28fd22e2af002fa59e921ac633faf74895c1a388c0b0cb2f59d8564" - }, - "validity": { - "not_before": 1736413200, - "not_after": 2154416400 - }, - "subject_key_identifier": "0xa6ea9fe3701805faac2c1a82157593951fb31149", - "private_key_usage_period": { - "not_before": 1736413200, - "not_after": 1831021200 - }, - "tags": ["UN"] - }, - { - "country": "IDN", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xf16b4df06b9d880572deb5b0835c937bf7c2756c47b9446cd89e9e96f44b574cf912580d568d762e7fa6cfccd2da0288d02ba4f737abdd5f9443451015707e5143789b73628933c376db5f1b7614f768fecfb9b980ee21485217891727f584ae03d5e39f46078abfdabdeb72cc5c42e9a164712fdbe2781cc9a3881f958119470d7614651426847e26d6ac78b642e9338034206daaae0a2ec032002cc5afac1561e9501f075c755d5a2cff921211a22c43ccd1d48002e28b0c5e1e67d54c9bc59745f1e1d5b1891eb39086b68917789f6cb6210879e93bd48c08b61ca316352ed1184a80c45da98ee6eb87c71e3fce7c5967dacf3c0f8cf9fe523985b66348086996019088b85901f03f3afbfc9883c072773be8155a3e76babd1406c01a2f111f7333ad2a38eb89a7bdec7826b8b42a438710e3a2bc73d01f96b811558bc91972918e8dd2a56d993963342303e337c6906ba40ba6269fc9415bdd0499643e159d561f14e9b3a0be8104f6b11c7d7842ec750bc04f3ed7d80bb1c152f5c1630e4bb7e77a0336e470ec278498ae5c306dbb2fa3d3031122c4574967aba533473e74d155fb674c86452fd8c65e90a6eccf85fd9c7cc7bbea0d7d388a76a09c5a243bc3c266a8ba0063f209062b5738d65b0c5d691688f47e77f1b0a68a629a71efc8c5215f99d284e43d5e9b6fbe0818968012b0a44e8603d49e37ebbdef618f0d", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1545128030, - "not_after": 1812968030 - }, - "subject_key_identifier": "0x2fdb3a5d60999ac5d7695f5327987b5bab29c94d", - "private_key_usage_period": { - "not_before": 1545128030, - "not_after": 1639846799 - }, - "tags": ["UN"] - }, - { - "country": "IDN", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xf1604076670afbc36fcf2abce6ecaaecb71491123e90bc1f5815d825c947abb8eb1dfda6a1f2977d80e727921c838bcb763dfd7bcd79b86140ca1d2ff971f0321060be36bd2c4b11cb10bb41a1fce507fcd67f31932e46b67dc9e085618d3b013f2cfe0fa91aff71b06e9d2f6c974deb8e507b097aee864882cee82e8716ddd8a6ff1470d2c88b10d7bb977f48a5215d726a4c48db95f8b188c2208285a2de9f9de947f99fd1cdc5577aadf1bdb6ee8f2f0e7985ec43b333dc25dc5f3223bce806fe94a2da514e5315857df56494fb52387811a16a7110713be517ee4150a7803775d8f74e1e0aaa911802f1bb59f88f2aa12e8524b9b53018445d6f7761c4bd29ea84790e38fb09a995e3b1aa0435819f938e707699af4be57b39370592257aaa303b24516d88f10b800148f765a9df54701917c7bae99a4fb2bf39d970f3029d5f4e83000dc7309facb51bd0adbd691bfade059d0eb418714cefc19e62ae6b2c2f29201adfd8192d44e4fdd7624d13f35de3d5132f6d00e5edaae37328ddf9a0dda6011eb129e679a80f5be12966953abf05a728540b1e279752818a95c17e19f2aff901cdcfb7ac67f240cd9d430506bea150a50071efaa19a77292a32a93c11c7d3fe75939ca8c202e9b0acbfdd7e86645c2278ecca42ccb01d0ee76ef3efe714bab062bba432f8753d4b0ec16999cc58066c88c94604c8de5c22edcb9ab", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1638949446, - "not_after": 1906789446 - }, - "authority_key_identifier": "0x2fdb3a5d60999ac5d7695f5327987b5bab29c94d", - "subject_key_identifier": "0x77623b37d09cd6fb9d2ca570a73ee88e77d60459", - "private_key_usage_period": { - "not_before": 1638949446, - "not_after": 1733677199 - }, - "tags": ["UN"] - }, - { - "country": "IDN", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xd127294368b771bb8496e204cbe5df4992518a618e75bd283c85111d307cc47d281925e9147db393e4d2d042ef84a95a4e0481a90e9cce8184152766cf557ebb76961836438fc0e3571aa6379a70c660201f3a1df3a8e19c9bb38f9ef8d588711ca35d73afab4f561a0373bb1d36c9e0ff873527afce568d904c5215a5c839912ea3f613ec1eb958ec6ca04f69cc74e883aef29f7392b0804304fb2b56a1366d33106c7932a99e805cb5a0d9050b1b2e30bb89ed9ead37e1274b2dc27a369d312dee082da031dbb772f9af7034dcdcedf7b92ebac28b60958eb54f596a7b6c32dafb3d72cdddc6f6abaec10a71321539debc1f1c9662b9fd4e9df599a7c6983425b5043f68fb20842ffda9d8f78d2985909c4fe9e16171807c9aad31b019c12b52105cd25cad0e1fdbfc9bdea90787626ed0be8b5ad3e3278c5df170705740c54069cff1b9176d3e945e568103ad94089217e70bbeb69edabbdfa83f3d526199d606254074cf0e11c5299a14e525abe5029d982612f03b6cf3231b5fca896eeb6f4dd3f2f7d56eafe098eca7572cf56d989736bed3b61e32d416e6e00bf8b243501f4b68206d52c1157395bd790dedfb89574d5517d02dfbfdbf88e81d333296166bcd421da49a64d89eca5cb1ffe43a9bbeb2c77cf8f8fe194a21cc5b7564a17aae8cab54bc2f3c3f0563078d369e5cf6f2f2ff5f331e5dd10986cb93ac5edd", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1665975435, - "not_after": 2146877835 - }, - "authority_key_identifier": "0x77623b37d09cd6fb9d2ca570a73ee88e77d60459", - "subject_key_identifier": "0x331edd10ce8012b5418852081ad0cf36e87ae89e", - "private_key_usage_period": { - "not_before": 1665975435, - "not_after": 1823705999 - }, - "tags": ["UN"] - }, - { - "country": "IND", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "EC", - "curve": "P-256", - "key_size": 256, - "public_key_x": "0x5520ece5eb8ab0c41016b211585a88d0c80acc109917ec2830a1265d31c6d441", - "public_key_y": "0xc6c40248aad4baeb6093ef04d6ca1d5233837a330e6e391c8de4d47313df4c0a" - }, - "validity": { - "not_before": 1690365644, - "not_after": 2182329044 - }, - "authority_key_identifier": "0x7d79684a30a5b811acbef68ebb26068dc9307875", - "subject_key_identifier": "0x7d79684a30a5b811acbef68ebb26068dc9307875", - "private_key_usage_period": { - "not_before": 1690365644, - "not_after": 1848237921 - }, - "tags": ["UN"] - }, - { - "country": "IRL", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xa13f339ab79ecc5a7de2933fe21491b65a29331cedf618edfccd0aacd10dd17908bc9367c46f71b62a53b1fd9256c512760546b8045233cbd22758aa567767e866b4eeae8ea4a3694e24bfb611a03535bba9a9ab106a9e1f42bdaac7d0e0ee4d52272549e670323c374d836ca1c665420d9ffb68b107d7d6cbab2a3270731d8f98acc90eca8b178c874e3e087e3e26cab7cddda37df25b6553686e2045ef4c87b2cc33727802fee962963e6395a5c027b9d3a2bccaecd23f019df1b1288ba91d5ca547606bb9791294ad282ef8e209ae79748f32d1e9406611564fa79b32595d476b2d1122b2939748439cd8ca36be7e5eea4c40cb52bfbfc31d7d4f8f2b7c7da68b84d70f5cb59d46cc229a281e5d460bb66416b00733cccf23a01bfa66b08e7dcd4c296d2adb4dfb785ac358698d9c551702a04830c697c7b726dcb407e59a5b78e1090e2b89bc6148800367bbf42e54eb03900c9f753a4ec2f78f905688d6ae3c27f2a5c033870e0e9be6aea727e5b57576fee1521b2985d5f91546625f609857ebcb84dc05b5631ceb8999f37f21d177d8e3d06869487734d8fcc08d8c42d0a4dd8ff9f093bf4d5922fce1959a3096ab06efdeb343bbb7399b0f2e176d6c2a2b63826afb6db37d13349fd3df33b2dd079c11e57065857b2d00b8307db6a1d86ba4eb57269006ad4f7c51fe10c7b2e1c7b3c246e8dfb2dc53b02d59da5413", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1294313971, - "not_after": 1767701371 - }, - "authority_key_identifier": "0xca1527731c2c4f064b3f9ae888bea622b03e5acf", - "subject_key_identifier": "0xca1527731c2c4f064b3f9ae888bea622b03e5acf", - "private_key_usage_period": { - "not_before": 1294313971, - "not_after": 1436328571 - }, - "tags": ["ES", "UN"] - }, - { - "country": "IRL", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xb643d14dd4724ade812779052110ef153f27680db7a43ab02520d4d5e99ac7ee0a9cbb8699f16075585fc8673892ab2212ec30905bf00e2778a706fe37d493b12f05fb4db79384681ab67f5d0a8c565ebee780d59a33d96f4c42e37f0554082607cb7bfc8df9c71c482460a3fe80706e3c7a86cb6e870d1613e91e1372ae277fe3cd1d2195aee047d6c5d923d17ec86b4a6b7469b26c88f50864322ef1c2d023fe0368c1aec9d0da609beef4a2372ef4220a5cd9bffa2955d6d382399f45049198dbafda5033e2982fe7d27227591320427f31a4c36ea0a048e9a9d51097b36cfd00a1184a8a013f47c82d11eea4f5d0262a374e88bf678462248aab3e303a8d5d485391bdca8ba260ac3bcba49e31ef0c295dbb52250bebfe8bcaddf8e7c9322f4812af5a6082ccec8ef0b6d93fc9162ecd5b5d99819816de05f96f9d39717e485fa5ffa60c2ab3a390e5b25d3f1bf08ffb591956447f5b18f8222c161ddbc3bf76105e7ebbaf62d96e5bf22d1e1542063d1943b161290c6c9e35015b67499ea29f45a69b73ad698f31ac7945484bb10ffcbeaf0fb10ba4ca7cd853adb3a70255d3026d37b456627c63c0e83816a48200656f98715c72232ca5171dee72d5782eb03efd298b198d1110fc660f86a6dc11d9c051aeee75c27989088be5eb8c58cd80a3aba7c0dd63c1b5865ff16369587251d592469a92d9157b2c3827d5f9d1", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1450363302, - "not_after": 1923750702 - }, - "authority_key_identifier": "0x85e6855769c0a7d93527bd8a4dd39b391488d574", - "subject_key_identifier": "0x85e6855769c0a7d93527bd8a4dd39b391488d574", - "private_key_usage_period": { - "not_before": 1450363302, - "not_after": 1592377902 - }, - "tags": ["UN"] - }, - { - "country": "IRL", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xb429d7117853f6789d52a271bc53184e28a9a32a6b240b6d39769e0437c16226bfe90455993156d4ba38fce25ac4559c02293e16a6d72900eb53264e6a98399034f54c471ec3f57e241f38e7e247c580c30bbc2f14f079baa572f8e5e8bb36e26ee9e8226a2297e4fb8f154ff534f4a4437f8f2dbb7f2f121447b170a0ec46e15aafc843632d03578e50bcca866d0268609de6ef849bb710e7ec4596ea8c84b1644b02c573175c225180bd28a0fd6089504be6fb50801bebc4b08a9a8c5517d9a2986310dcfe71b8d961cabddc62ff42fa119f7ef96dd96fd9da2cbfd16af369def743f4f568a284e451d61046a63ae30572ac57ffaffd0ab924512867d0835751d7b3b29fe0da1a451ae8b62ac065ab1332137e35893306d32893bcb832547ea6c7d5edcaa0cd1351fe938fa38fe0fb47fabb5cb2465d6ebe54147de974a48614bfb7e2e89eb892d681ac1d085254322c999527386a455c7e4a9ff7137895cf9b3dabedfdac1007005e8218d92b0fb6fda56a78662bc71373b3887a46873588b154b683a776060184570eb72f05c981ade19a86462c9f03e40105dbc4d395cff6e9b1d2f6f06a84045bc91d99c8461c5893f30eeef3a546beec6a8b270ffe10dc9db2bc050265259355005fa056611da8f19b1251e30a44a2f3e50d141a949f52ba4867d505c955a9458c8a9cda4094a2b0029ea517ee1d79a74932e5607857", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1591611890, - "not_after": 2064912890 - }, - "authority_key_identifier": "0xb0795aebf7bedd03f6325a73cf62898640d628e4", - "subject_key_identifier": "0xb0795aebf7bedd03f6325a73cf62898640d628e4", - "private_key_usage_period": { - "not_before": 1591611890, - "not_after": 1733601290 - }, - "tags": ["UN"] - }, - { - "country": "IRL", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x8c21a4ca1bafa6f4db37950252e21d156f715a4040590584d2237543b382d80e78ed33ce49d43186732298e7c5441c8b60554b10c8d527f11b27969b6dc29e44826c2ed95bad8233027c3477ede9ce66a81684bae16dd19af1bf365599dbf50b1df9ca1ade038db0a722de45fb08d52d63c104cd7895bee461ee766be28d6e76771157ce7fc79ba29b29968d1731e264fb1538e0193fdfaa095a6bab5fb1b2faa6413ba3d3c8ea5d78d01629b1bf7f1e1b6b2ffd3ebf5590e2a95aaff786b0ba1e12e23a10eebab9f5de47a211e8fa9a9d8900cf55fd813696c8e414d6d5d55be148c5e7d36592789d6d4a7e4f8dd4e39de91f83b612443a60719e99ad0e9d7540c6b41bc6a2cc13dcd092cbc8c1ca1477212354de396cadfd8f0014703b6733abcd1f0f27efaa42eb1953c5609627923ca45fce86c334d5113d807c41ca735d49624fc003ac93082093ab38bf07873a3667371fdd1d5f2cac52e9692264bd8f7d8f6edc2fdc105bc7a6591ad51cf5adf62d7eceeee7242ebdd838452199ab9817e6c81e23d0f4956de776ec052d03b47b4243fe6aaa81f3461f415b9af091882990264d2c4157949ca421fd3b0a1e4bcadbe1260a870862c1c8551501a50a3a0b7a2aacd2f05f2c7aaccd813378ec36edb7162eb2afdf7f38ddef9eb5e8cb13fe4b1c7eeade3eb253ee841fa18c02210b2152c5e48c1ab44fe5ea036ecce41d", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1738669208, - "not_after": 2211970208 - }, - "authority_key_identifier": "0x85eeea6a17fe35088b935c2ef6eeb0b9f5e8fd02", - "subject_key_identifier": "0x85eeea6a17fe35088b935c2ef6eeb0b9f5e8fd02", - "private_key_usage_period": { - "not_before": 1738669208, - "not_after": 1880658608 - }, - "tags": ["UN"] - }, - { - "country": "IRN", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xe766bc2e10937a3b61db4979e21807c25c4a3b3af7fd4bcf541721b3a49d13337f5b1ae448d58c3b637afa2280f4b07e983818a8c86e6d041cb94b968c02ee87478514cb6f8fa98af08dd3f82962d49ca4de1ce479d5daf70a2dd146bfa38d3f1afadf3a994d773d76d6caaf22024533744df53e1a2ef4e4d3bc34169230e60966cdfd7f1579398e1be64e258e6a108d82f9758dd6f32dda641dcf4c309ceaec952a159d07fff9d08bce511dd033e33b6fca895accb440df31e15af8ec65804843b28a9daa5513b26860c9da7384cdac37a6205812c1aae1e06582266cf08a18dec2c2727a525bbadd2f5e781db10a2863a1add70a22ab18bf9a385480765a811d8b446d05685f238e653215a97b18bb5374d42ce491178e5d175b7b3855c4c8b3476408666610e8d7445ce56886f66b3e0fc9fb60d5d86be1ceccac3eee6965b39ee29403354dfe794dfea3f7f87330b4805a7940930d991f91229577f5d67de4eccbca5a1d688d06e9ee8a3d484e2016788685822220848eba4491c932e4f4abe33fe27c16807aa7cdce6694d89d7a7d9f712cc18dbb733517ac75b236fdc725b14b5c44499aa305afa580e6325ff42dfa1fa1f8879f701039a26678b9b536cf8fce57cab7efeb4ede16ce76c1466d79f73b3ddab3669fb49ec342345c28c31d08b59cb164d1db6e545678e0b986c9b7b3cfb3760d32f8781fe5b4deb4e23b", - "exponent": 56611, - "key_size": 4096 - }, - "validity": { - "not_before": 1502797523, - "not_after": 1889527523 - }, - "subject_key_identifier": "0x49892e694d1c968aace1b64043dcf4cc318276b8", - "private_key_usage_period": { - "not_before": 1502797523, - "not_after": 1723722323 - }, - "tags": ["UN"] - }, - { - "country": "IRQ", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-512", - "public_key": { - "type": "EC", - "curve": "P-521", - "key_size": 521, - "public_key_x": "0x008007ae173c25868a0812c82a1033336aa3352babc2b66c2780451b3adad51938d4797139424d6cfbe5517961bf894236ea69c0dd0a992166e4091cfdcdaae8ca58", - "public_key_y": "0x01498dce41111762d115437b13d0297511bc5f8192dd48136ac8357e8cc0dc5b4f2503074784185ab9b2c73f2db8b4f6e94f1ae726221ec23dbf3e5363512bce341c" - }, - "validity": { - "not_before": 1673433090, - "not_after": 2033634690 - }, - "subject_key_identifier": "0x51d31a2a2dfced3bc0f54124d4553109b3e2de58", - "private_key_usage_period": { - "not_before": 1673433090, - "not_after": 1768300290 - }, - "tags": ["UN"] - }, - { - "country": "ISL", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xb016c5ae5c183f07848d01dc01ae19b89a104a59310bde16997eb44571e1fd46cd8dcd1142265defcce35a899b087d24028bda45f606d03a7a7780e3994f768bca6de76c962b73b53ea5b4c3b919593e3cce76de0cd3519a945ab3c091aac12e94fa44f6b4979a92483d05eb1ab342f19c5a10aaa1bebdd1e1e10a904cffdc5e9adf5c702c2e6aaa33814d8944fc240beae9316620a376ab0dd531388999d53dd82f1758cc0fbc57af4d173c52de79bb0f1f45b6df13e3c85437ea1dbb5bf184e65a63c0f5a23e9e3a6b7fed16a05510898fec6ff16a50ca92c772b634ffaf12de1e925a628f43faddc2824c8b15f65d784c54dffc8fa6dd6034f36d6c9d7707", - "exponent": 65537, - "key_size": 2048 - }, - "validity": { - "not_before": 1359590400, - "not_after": 1990742399 - }, - "authority_key_identifier": "0x857ff56a53b6c4d8336005d9ab5e80206773c74e", - "subject_key_identifier": "0x857ff56a53b6c4d8336005d9ab5e80206773c74e", - "tags": ["ES", "UN"] - }, - { - "country": "ISL", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-512", - "public_key": { - "type": "RSA", - "modulus": "0x899eea8c7a195940bfa246d50f660e1a2f0d9fe48cdb7316c811a70b8fa6813e72b1be9fab8ca5cf21f5d680c80d6c1a955391abbe82fc4d13659b81b234444237f3858a23b3fd0e5f0d06fdd3610d65e881fbe2660ca6627171471d1e4db3c5584db16fc6f1774e8a8ac2c2f729190f5c8fccece382f01fccddddba3b649a67d662627d5f303a665fb1900272d9d5adde8024fceedea244eccdda7af522cbc7dcc70313806300187a0c19a22deadc62af8d2fce4b58424b838376247924fe4fd586de26e58628eaecf7e5aa5e3e6b3c6781cf8cb95596099c36411d195674180856e8b30c4b831b3422fe19ed0a3c58279203007169e78b1385e8687a4aa1e22a22d5944da9d52294150535ddb64068fe861855699e847241bff25436242bf728d7fc8cd501606195a5e17c74d79b9e5cbe1a54e15a62ec4c5d7f2857367528c93017b5e34b9178bd9418b065e4012620424c70d53e55ab4d078499955835dd8e75b1599da603c575860a358e1691369a44eb2eb0f7e570a345c47d96e3edff2a361faddf89ff63c1ad84d32b0639f7c60f53c473de196eaf6eecbb5d5dc432bb24d1b1943f3caa6b23ebb79d65b5cbd3ada9380968f6a08638369ccab284d3f45ec44dd2c1c7702cc240e0e968f655ba3e12bdaa0be0a44f691ef4dfa521c949bf54bbf659264d4f73f11ca7d4be0bfd4f4a3963d964cddd7fdc9b721ba739", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1547474245, - "not_after": 2028290245 - }, - "authority_key_identifier": "0x7d2ce680836a0dec53eca9d3041de59daef70ecb", - "subject_key_identifier": "0x7d2ce680836a0dec53eca9d3041de59daef70ecb", - "private_key_usage_period": { - "not_before": 1547474245, - "not_after": 1705154245 - }, - "tags": ["UN"] - }, - { - "country": "ISL", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-512", - "public_key": { - "type": "EC", - "curve": "P-521", - "key_size": 521, - "public_key_x": "0x0091c918b5de2189c13b00cd156c1c841cd3338ce52f77835abdccd02d8653441777910bd8d2122a41b58b566537c90f6919dbbcf24b34915809d0dca216e7ec4928", - "public_key_y": "0x00b9486f897de307eafbf5c807ac394cf045d45c5bd338a002597355d04ea3b31edad45e2035e2a7de4dfff6a98140f8e7485ad6548d1846647c0931d6121e79119f" - }, - "validity": { - "not_before": 1700214903, - "not_after": 2181290103 - }, - "authority_key_identifier": "0x792f6308892687b88a4e4873554a01005dfcd63a", - "subject_key_identifier": "0x792f6308892687b88a4e4873554a01005dfcd63a", - "private_key_usage_period": { - "not_before": 1700214903, - "not_after": 1857894903 - }, - "tags": ["UN"] - }, - { - "country": "ISR", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xa78476ed00e46ad6fefd0f7101662dc8a4a7e4af38361489a74a117d8badcf2d3ea081383bf5ece6937ea1ab4941bba905ddd5c41b4914170d4fd6f5f66679d6263f87465be0c3a0da0ce5224c2bd8253753ccfc9fccedb546dd68d8214ec2383cdb9d6c4350a44642bc5b2348416ca03cf66dfd005d19bed32410ebd71637ff52e03a7d51dd0ad5fdc7c738d43a2b951b69c384ed23f6c79770d69cdac77107ec2a6722ae1907a470b6955acc3eaeb50df41836fb922610db2ec0973cd3dbc4c8a312a5e5c22fd75232dcef6ecea30a04dc9c854477bc2e7ae55d1fd537dfa27a3353f2f86e1dc68d58b17721bc4e506a99b299900303c8c0ee71831510e346a7147011045ed9d0e8b6737a2a5b87dfe5e4d8815c2ffdc8ccb7bc7276a1fb34d475eac4bc8494a2946b55049d7b84327e99eb53b5511dd86f2c686300de2fb9c00a88f65db811f188bed86594b7a7c5633c74467e89211d6aa018579998d0004ba26c6e30ff4b6cc2d8008a5e4e71cdd35f6c564e7de55f62c2a0ca5d48e61d735534bd61f9415404573b14a0c46171e3c3c54d8b611ba15ba2f39cba30706900af6945740ec31919b35548e9f08d20a4f4253f1e0e79d849b4d3120a6b40250df9676b7fdeb9f207eb97c23eefbeb04699071a586c22e5a98960b9bc190b8889c367f297dacde337fdab4c6c3edce7d3b3f69056408f5d21b692425093de21", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1368596991, - "not_after": 1857966591 - }, - "authority_key_identifier": "0xd4be4c0ef674b601e83f733964851681d06e0f9b", - "subject_key_identifier": "0xd4be4c0ef674b601e83f733964851681d06e0f9b", - "tags": ["ES"] - }, - { - "country": "ITA", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-1", - "public_key": { - "type": "RSA", - "modulus": "0xd18b58ce2db34b3437a5a90501f7317019d499dd83e261538fd1fadfa8859a9e98eb9d5c1732ab0e900a59b98ab31e4c483aabc5b6d4dfef676dc7d7bdfd5649e92b55ee45126315c9a4620119f1a0f55a4460b870e830db4bda2905d6a73540054684179d0c98f3f7962c0048c6161321dfcbe486a36a1d308e9986e32ef77a4ac54100e9142ef9ba6f6ad19feb8689d5c88726ca0a0386942055d0a436289494559e23865d108e272e3a5c5909add04f9145bcc1e68de761b2ddad869165c5a578cd222b17daf612f026d6988e918a9a0d03dbd74193eddcef0ed80dd3fdc6a768ad856ff16949dbd5efddcd2bc3e8465e9991f2cd411b7457d6de41b433cef425e249a966bda423fcb3b46cc45cb71370caf31f45728217c2fbb81a1e10a7f60d43a0ac18d99131ddd25b166d799e8d366b2a08339b021104d832075d52b75a8e790b2b1140777401b514a3cdca2856a3295e1b73ccefaa0c415953fc4a78b227b961403fc3e65d55e0421dd3e8054202d5dcbd4a4b927362a732ac77abb3f1da3318fa90042e108b57ba08d62f1468d2b2c9ccc1dbc701e6a3dc925907e7638c25fa6b172840254b7afced72ce5c37b867d1d0284c187aad4e361935968d6bcb03d66848e16d0943e6781da82693067aa74524e6814c163270bc5675a9b30e11e61e696bbef4bb428b503754e7b35a89249a33afd8f928bfa4294aa3d365", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1320921950, - "not_after": 1801737950 - }, - "authority_key_identifier": "0x48cf841228e6ce66fadab3ed96fe4ebf37d7124f", - "subject_key_identifier": "0x48cf841228e6ce66fadab3ed96fe4ebf37d7124f", - "tags": ["ES"] - }, - { - "country": "ITA", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-1", - "public_key": { - "type": "RSA", - "modulus": "0xc65ec3c9465320dc795071e65350f3a760c274273290b6bebf001fe07b6534fb4c1ec3c53145d7ed19ffc14a47b71f07cf7fecf1c73ded6d013a3137dd7a49072add1870b66d0b589d8fada35999c3aa885119ee0084e73961e6a84fd9ef2ff56991fe49fca29128700919925665356a2d579e10c768b1dc120e3a5ebdff9eeba45a7c90dcb0861f184df040ba2999b4c316bde69bd365ead292ac99ec37a05ea0c4d4b3912ba2c24e8c0385af1d8e22a27c491cee434630b3326ff2ef1acff70a7682f91e999eab674957aeeebbd7d97aaef5931eed922247500b4c21ddb8fc79a34390149e662945b3468213bc4f4f5619c044d25f05ff9ffa23c41d4b51b9f647eb5caa975d63e799f681bfc516f539599aa2bd1fb305b207624c14c15d6e4298f5c7210a7dc5508a2743f4b72265ac49cc569ecb8775e2545e8ebc1682a3bfd60cbcaea140f99496dfcdb69786ee5f75f05d76dfa3907256ff939edc5e2ecdd3e4941a9db04ddc7234e3e40e51e162a4b0f741c07ca6136e1109a8e45ecbfc3c0f59c23ab830029fb15ab5a60200ee6546ff3792335c072777f8fe2ddc02c7416f7c2c00b732e23441b539942dad32e775edfd8e66d582ebf7e16b3377e53c48df1d5d09393c3c62beca0ca54f619435d2e942bedaf98754dea66f4e8ea6bb0cb87931cbfb153b069cfe6f0a2a965df92db305c534e47c6cb22c1ff1d961", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1323858544, - "not_after": 1804674544 - }, - "authority_key_identifier": "0xb0bf3bb9ecebc720974c1d13a5905a1a613589a0", - "subject_key_identifier": "0xb0bf3bb9ecebc720974c1d13a5905a1a613589a0", - "tags": ["ES", "UN"] - }, - { - "country": "ITA", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-1", - "public_key": { - "type": "RSA", - "modulus": "0xd4b7b29ad7c995e4a3430610c583cb79b2ad42babee92a18bdbd277969b8de00f39803d083116f785ac9fe4f30e5b2ac64a67e39704b15c355a077866e1d2b6641306a83dc7e313c31abf784839588bdaeacdda690324f83f1c113abb7cb72906323250299c6e5005249646b4844fad1e57a2926ea35c5899e86f78ab342e49d94b0e25ea3b969dc769092c5f422070da64b23204ae8d7caccd005401a4e5879fba9a9402cb2d797cf4e804deebd5a1aeaceb04b18d48d7a1e869d92474ff72829de52036e10307de992d27931bd8086efea7d3ab7038db34685d5e335b647a43fd5b60e429834f167a7819f5d706d90915acf272feabd44299d6fadcea6b3a83a557bcedbfcb73690700cdf7acbfb1003619cec7b849a55c16bab020c9c3c04cd31fbfe71dd8da648227e412231e4d359ee40a3dbe494e1b875b01717099f3b4d7ab7b812b07aa475d7ccd53ad79a44ee5b92e775cd3a205144618708f9e7cf11b31813adde289ed4cbc913cc72c14931ee92e8b0a517775ebc3e19150d0aeed2b9009b540d22ccc338674522df6c0a48f6aa25b9475a59f1da2aaab0fd93d5f3dc986a91a95b5147ee46ead5a1175e7e90b5892489f8a0fddef2e3ffe17046f45215f5e192cdc55f44f5c762b94f20958c9e3fb9b12059034a875407359cd920188fb9178d9925a4b501d2924f547ee4385fb5642a0ec42547c18e97c55c69", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1463577719, - "not_after": 1944393719 - }, - "authority_key_identifier": "0x852df7a70a512d83103dfbc9f628cb6b1cee5591", - "subject_key_identifier": "0x852df7a70a512d83103dfbc9f628cb6b1cee5591", - "tags": ["UN"] - }, - { - "country": "ITA", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-1", - "public_key": { - "type": "RSA", - "modulus": "0xb5f670d358acb7e78dfd1d72aca126a4969e1966bf71740b5be6720163854078831610f31ae304c7c173e11c71f74019bfd1fa27aac3f6bddc89a752040dad9b4a81cec1b3e7b8daaee4f0d996dab458d9843cecb851af897b1844b9268a83dfc090c1e17fe12ec4a4dd7d5def464f6fec2984cf3ac2575745eeab5c1ac8b9df0efb969c50e81e3bb85a1c046e416b19df4be415c691821adad93bc0429417d26ce39aaf3a0f969508b6ae180fec5f52b8f1b20403a49d86910017047136b361214359b2daaca26d480147aabcb4e3b41215452f09033d6ef02755567ee63209dd3d5545bca522f2fac3710962595631d42c5c15a0cee26c65cec2313e8481479803de8a1435c82d5c5075b0ee69d54458a9a43181790a1d1e0f10a6b74865aa3bbc699021c6ef1e5b152368058fcf4dea9f10a54ddaf88306f3af92c1d4baa15f3ad0744e1d7f02c8d79eb2f4eb508e61f92fe586948ed3a038e48619d6420d47586cd46bb4747d036a7405a090fc73a44c417e4f3bb41fdc0cf88ba655f001fdc4104c67f922e7ad07059967a8e390eb28d3a5f34a6b15bdb991a29a62f38e2bc240f0ac5e3d2fc2ae125462f994a3fb5ea6adfd820ef6c602dfda389e8a871c78fcd71ab57827f733b0dd370cd085be3a23be22a4d391dbbe47751af87e1a8fa694c7e14bc62159975c158195b6b41325a485cdb1a406600df67338920f85", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1473155011, - "not_after": 1953971011 - }, - "authority_key_identifier": "0x436ce3921d10922307efd7a2f577ed7524467f1b", - "subject_key_identifier": "0x436ce3921d10922307efd7a2f577ed7524467f1b", - "tags": ["UN"] - }, - { - "country": "ITA", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-512", - "public_key": { - "type": "RSA", - "modulus": "0xad249db0ac7e6bcac3673ef6403393d9864613783f295061620cb334046a1e9e7528cfd1affd3647bd6bd1ba96c616c770a5c135af9bf739e9e2d9b676cb673c9943594fc2c84cc4aa8dbf33be385658e6924631191dcfd60d979f7145359983aa6be0b5eee93e6f56810c51852b6a2eb542265d45c8e83dc28160b7a2e098a9378db5fb83b253bc1941cb5e3b4c0b2a691262a9156cfbe6bae5d6045268803d3a0662f8e04506714598fcb06eea0a74c3e8563344ea70c04173e7da5e64cc6b2affded0164705228c18609eb1ec7040d8f6bf710758eb5b86a7fb9e3212283185ca8e428edd0ac9a6d5fa46a5f7bed78a32acddfb723d4be5a9f1aaa476749064262df6548e0cdefc00e7367f7b15884a276f61d44cbf59ac36561bb51d29ffc3bf90a8feb8d09a279dd5f670effe5739b1fd401936cae6c5b9848af86f8202190e65fc47fca2a1f6cf9518e37754d95ce8c6931c6cf99df238820ffc7c509f502e87f94d3342d85389b264f540c5adbe6fddbe9651994f3b4d0b5c7cb7b100f2058be8d8c65c2b590b29f58247834dad8edf6fee6d4c97910a8432b95723af817cee1860af7332af37c7df0cfa6aa1312f6a385cdcb6682ec6cc84f84a5aad99f3af5fc876b1b263e968200a95e0a1d039abcb696cbdb2a67a6f49a1c775338b907cb073aa8777899a10a1b35736d10809e82a9806335554ecce64319030db", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1588152643, - "not_after": 2068968643 - }, - "authority_key_identifier": "0xd11a505e15adea5a61779ca4a2a991ec3949d1f9", - "subject_key_identifier": "0xd11a505e15adea5a61779ca4a2a991ec3949d1f9", - "private_key_usage_period": { - "not_before": 1588152643, - "not_after": 1714296643 - }, - "tags": ["ES", "UN"] - }, - { - "country": "ITA", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-512", - "public_key": { - "type": "RSA", - "modulus": "0xb6433137035d6cb7b827a77bf7695e3538a9b9b84e07b17b26efdd8f8a382f54c5827bef8abdf9150f8a0ccd26eaf4792368990cfc25b84814ea2cd2ddcb901124c83e26c63384328fb5fa154233bb35631a4134483d1390b1005e8e9d83d5a0ea7c9f5f149690ad099feabbc35f5c94873cccf7ce2b7c5b280a9a22a2aaa7d933d5000f39e7a0753587cda8213437be960eec712c9b155b57524ef7323602859453eebd3575df4b2756b18897d4d289055da3d2c14cad276fdf2ed377de3b4b47b3c74077051ce31a450563bef4940a7502bbae20c747358ce22e641cd026574a35ca23e9d82b0f76b08328c5b8925ab7eeb5968c2812ad003201951a5ccaf121c5980302a15c92c339ae2ac9ca7d0bb899d0bbb08fd247a82d55056a6ab7e1562a29cb527a44f3d3910ab83a77fd2f4793d19c1f7f059961dd7f08d4a0d273ddf6ea4688f551b359150f115cbb279586720e4dfbd8df26bc38745ddd0482d94e6ce40d7177acd5794352cbeb5dfd52b800ed7898a2ae49323eddc8349502caadc115a02e65bce3ea7ee892e4a258df54b8ebeec4c5ec05729c732dbc5a9fa9eefc2a448b31950ea3e3625a803d6cce9bbf6653ee21a8c24924129c45fa040062c9d5cef5afcf8778be892571f9d6aae10472ea7a804a5fb95463d76055a6e614ce57b89b63cfba8a55898241b07896693e853054310660759d447a23e7a42f", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1713345202, - "not_after": 2194161201 - }, - "authority_key_identifier": "0xe94a91197072cd256951790e6cfe2386edb09d6e", - "subject_key_identifier": "0xe94a91197072cd256951790e6cfe2386edb09d6e", - "private_key_usage_period": { - "not_before": 1713345202, - "not_after": 1839489202 - }, - "tags": ["UN"] - }, - { - "country": "JAM", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xcdb92a022907ccfdbc51d1459667d89e74e55e8d58bf0373286c60106f9ceba02914779fb9b2dc1f1151cc888cd891137f864f8cda0b167aa592fb0a6b7c7c1628924ebce189663e7494c8a1cab090009930866da8b3aebebdd7e37dcd416f0bdb823847cc91b2c00e972cec13f0c4d6298dc4ed646d6c2d0e2c375bf013380c30d218c0b9aabcd97f32c4ff8c8d12a1b7078d6f15d5542ee9288e45e356a5af469d38017f0c46c2969a7ab258c630ec50145c1778f4494d65e6d5b022323db7db078ca7b932cac31e83e993bf8deab06dccecebe8c693054915826b88cdc5ffca7f11562769aab9a4db645a54174b308a4845130164eea2f12b309123f9bc44c4ab866ceff466bb70f06ffe9db563d2be94fd66715d3cfb91d9451fa9fec7d080e48b65c7e814ba818bd3ffa560a41d3756747dd95d35fec735429c0c7686bd45137bcbf9894647fee1b9f6521ccc9125f80d4662b3c264a59f9839ff8d7c41f7f0afd29da721bf07dc249a757a8a85b2726cb79c16ffc16bcfb04daa534da53f045d3e2d79a2293afe29de593a1a71d5889b7884641c900f0b31d45c03260bc1f91b62752e6b5933a4530939601c14569396f7e6169c0cbd8b28b700ec2b67e511777df80e498ba5998fb5fa180d86937c1f3758520f4f715ab426e3856a5ae885e1c3c7ec5b6eb47515a250d8740fc5bfce2d55084cb72f5fd2c1af8c2081", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1668790216, - "not_after": 2160494416 - }, - "authority_key_identifier": "0x517de4bba24aff108bb604ce3a964e93f998547f", - "subject_key_identifier": "0x517de4bba24aff108bb604ce3a964e93f998547f", - "private_key_usage_period": { - "not_before": 1668790216, - "not_after": 1826579316 - }, - "tags": ["UN"] - }, - { - "country": "JPN", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xc7f1375915717020d7868493f275522e35ba870338362f7d01e816cdc1ad7c6168d338c50350a5e5446ac5abaf62ede04204070460350a8bd6786ae5c95491cce2f58a6718b1280b39c9e15580775dcae87f879bbfdf96f93c0d75cf58cc0c1c8fcacd7799cfe8f297210f963c29043977726fcd18127c6e4fe34f8e455f1523c14bb418669bd3d9fc32e1f6747a1e3cdb9dfeed595e4a64ced26aa3ed3973686e7aab5e7448b65b86939df230fc6ccff00029cb08f47cf308f88427032c4c282f263ce472424c8410327a13529ab2cc47aea4f444226eb28b877c0bd62a216167d984e745c59c98c6892f3abe918c0aa2e75f9e80ba456dafcd95e775e7d0b3af0866e2beb802eef46dc95863e0bb40901a3d093434fcce488357efb878dad973358a8ebd589c02fe55b2ca6c0a702f6bb5f65d960e97d49258a68567eb6aa1cd214294e828d9386df54735dca65223d26b6ab34135afbaf7e7b12cc85a01dbc88da38733d650ae961d04e162735b32d9713e19b291c7442172bd89d7a226d7115d6750babc07228a1b4152ee79f84ac7a857ef0fbe31cb3e198718cbe2e26c646dc5dd577c2d8474f5fc75dda98f38038c475add7eb01fd3a537a4b438459447dc53282f4eee7c52d3a7caca2639555e1119a2ed64ae8dfccab0624025879eb6203947ecd7ec1c5ec85544a96d338754e4c21d12f0b45ee5d889878fba146d", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1368508050, - "not_after": 1929258818 - }, - "authority_key_identifier": "0x48458e886926a0d0b11d2b422fc59b459be1ec7b", - "subject_key_identifier": "0x3fa86a16a29014d552b93cd54cfb9114b6b31d1a", - "private_key_usage_period": { - "not_before": 1424396400, - "not_after": 1873429650 - }, - "tags": ["ES", "UN"] - }, - { - "country": "JPN", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xaff531595fac7914b0d6a253c44472b7206b88f3e5712b9317f03943705a3f9966f55306b5b728cfa9b88a93feb969a831fb82c52db75c08e4c93466ba3798ce4403912082ef31a6080979a835ee16be1ddee99e0182505b8d719463e72953888916aa72556cbef6458c556e872f4056ed64dc3bde2dfb38000deb355bec49547f1e35e1bb898dd502b45f827c7b71648ef00e8fa97f334aabcf32d832c560f1b3db2c1c5ddf2f2c1012e6e786fd3a95388693b21ecc5be77f79076fa9c76caea938096afe20c1af20d857f887609251666ffb659b33ef03e431cce0735155651a6db141d956d9674d124830c5853ad12af213cfc916b093a01699ca222c5b2ffd93a9980febf950a952bb2c434f931cfd09b326364bfa4f6bf4a6bbf7552ebdda13c190e5620ebe0c79d01ee358ae0042f16d8555523c1133c81c6035e275288a3990511484b6836fcf9185e31f02bc52c20de08318d22ff979d16d64b854968b304e1c41b31db65bccbfada6edd5645137cda7273bb9e892953b07a496c5d04dd753f06457082be293c95416afd1cfdf787a5f29b021dc1482484b1f9ae212d9ae62fbba5915dcc1547de8965087013017c0e9e245266aacf83069453071dceadac0faab232a5e1e436ba2b7897eab8669133dfca3981e0662e0772ec930cf0654efbad22603f7c60fab6c09a2a30bb862959337e544a5728d14f9d7715ed5", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1424395692, - "not_after": 1929317292 - }, - "subject_key_identifier": "0x48458e886926a0d0b11d2b422fc59b459be1ec7b", - "private_key_usage_period": { - "not_before": 1424395692, - "not_after": 1929317292 - }, - "tags": ["ES", "UN"] - }, - { - "country": "JPN", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "EC", - "curve": "P-384", - "key_size": 384, - "public_key_x": "0xa1ce23c270e8ca3fa9592f5782670a6e6519c9a6a83b1d8a0c9aef7b935c1340382c83a813ea3b9f72a0a95851d673b3", - "public_key_y": "0x67e34f9ec0121e836552e44ae439aff792bad44043adf2695cb1dae6fc7a1804dbcd595c5a71c91f6e33f132fce23436" - }, - "validity": { - "not_before": 1560921319, - "not_after": 2065842919 - }, - "subject_key_identifier": "0x6ab4f29282bd9647f6ff2a02f7944d749e978463", - "private_key_usage_period": { - "not_before": 1560921319, - "not_after": 2065842919 - }, - "tags": ["ES", "UN"] - }, - { - "country": "JPN", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "EC", - "curve": "P-384", - "key_size": 384, - "public_key_x": "0x09cc3c301640a9223442ae2741880ad71ce025ef2b3b568ac1e973e3a508367af6c99143951a59bbe6cdc368e113b19d", - "public_key_y": "0xff54af0b31d356daa074983d0670407d7b7cb46af3ea40151c7dc865762b9b19ae7b76a1b3672934d68560932a4089d4" - }, - "validity": { - "not_before": 1713193200, - "not_after": 2218201199 - }, - "subject_key_identifier": "0x57022bac6c44f1011f1d0cb4ebc913281fd5ae07", - "private_key_usage_period": { - "not_before": 1713193200, - "not_after": 2218201199 - }, - "tags": ["UN"] - }, - { - "country": "KAZ", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-1", - "public_key": { - "type": "RSA", - "modulus": "0xb8fabf8e7c9c97b096d13b5aad5814afb8a3f31cc8f4f9526c3057282a5e16c89f538d711a82699ffd3a11c3be7206ecdf75ee102264df6466cc5fbad69413cdac2fceb36ce9212ff343984a718eb6fa2bbe9a30a47b79ef554a9c98fc63b487fe3287b37a09fa241765e6c51b8984a4b6aa25f7e6b8a982bdb966e17726828af6bc901474f442090bf8e456c84a933f0c3942b2d571d9c5cb54b00300b07a72219028890a2abe672aa6415f3152dbcc710b91861ca3f8254fc69bd2aaa434aa88f2a6421fbc44f0a48a38cc4268f0a8df4bb551b45491423676d441864102abd68f2b54cdbd90a32253891db219b70c34974a8e2ff593942e48f1a4be2fc547dc8c323acb4e7be0d2a6a1509b180fa459fd82163d98eb5907c338a1cd9221fe4577a2c8b937a464255b6c5c327c3703ed561f297de1a6be4682d72978a35ad927bd3b8f9f8e1f5b9805719542b2c523dfd9872d26ef55936452ec93d871e07e6b3d012789e1399bd6f248d62cf366cdbf62bc358a64abb54d1dbb60b03e24acb2d4cbe0851f83eefdd560ba41b4ceeb3339dd21790b2c9805ddab9a660e3fee82676457010d65f983caf7b556236259f5b939acb65fd3d836e03c688a524099cb136a831ac9344025e0e678787b044fe184ae095790cb43887df03e865e516dfe2f7d7041d2173b6718dc784a107e2a21eace60eda57c3b57bb478c61f95875", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1562651994, - "not_after": 2043899994 - }, - "authority_key_identifier": "0xf621b8b766e2123c39746ab89a2a9bf673b694e4", - "subject_key_identifier": "0xf621b8b766e2123c39746ab89a2a9bf673b694e4", - "tags": ["UN"] - }, - { - "country": "KAZ", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-1", - "public_key": { - "type": "RSA", - "modulus": "0xb5a1f5550e4d4e21ed4e453e97f25345d54df5e706881f99d1b1460201829749e0b0055a709ed16b99a87c457a8e81697c3888f281e64d0628241408e5614f857839d5db13a0551e85189dcd61e8241c44f764c65887efe00c0b5cec271460d0ce4310f9846fd173fd902f7aa532c2e8b662c375f1e7e45bcb243264a3b7b5ea9de2ba6c3258907b22c7e51a93c2b2c2628fffba577e12acb61dd6ef29fe89f14a0ecf0b7561e4a398415019dc5372dc5d2aa51426ddd929992d194e90b97279dc4843148f8d29f0131af495c6467f7e7bfc5bb61e00adbbe0fc40d05f29d07a9a381080b92fda548c9a12ece4a9258cdd7c662b93eb46a6bc3c4f2afe93583e8206333afe62d6760146dab3e8919336a0dab4a6b1afba115d1b396a7a1f6110f3099b2794e8c1ba7d02e9c8cdb5292997bef42ec1b3d2e3115fa36381b81165e5b5b7a28a0ba597466c90f34c00772f39cdb84e5f452bee20ac3518d71858092859f6b2db552ab6e832b584ed593b873cf58d2566fe9d92f86eda1c0d0c01519ae9141917efc0d50d959d0a5b9549d42718b011e424bc3b40d7ef8d2359cb24b93212d610cd83db96bbe177d188d3f294dcf9d3b9616b836e6ef306d950e9de92bf0bb864626e7ac39e3d98176b9a89ffb6ae8ba42f953d3a14a1c049dc8448600045d88e0df68e2c4213e2660fa5f4aba7fb059de2e6b0c4d1cca0aa3f94f1", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1582170883, - "not_after": 2213322883 - }, - "authority_key_identifier": "0x803107b82802803c148769e4db61f762a0e9e44f", - "subject_key_identifier": "0x803107b82802803c148769e4db61f762a0e9e44f", - "tags": ["UN"] - }, - { - "country": "KEN", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xbfe4ab84a68b9d0d8582d1dbc4b1d253cfc481fdcd7a4b862c02b1108b8fd4e989f0fa6da44165ce719f38417de532bb7a2239276480812ca933c5d1b67b9f94ea575dd590c3bf2af4e64fb955ac33b8443eb3f35f92098c34fbf5c46070d3537e25212a5b2dbbe922ce8a8e43f80f96535a1077e0f161799b79b6c7316048b190b5d0f04d0d89fcc60603c947602a39907584caa169f8d9182ffb832cfde609ce9e27c73599cce67d77a067d81673da371b6af6fb3db630e38267d2285b73a447532539496b6ac0241aa877f0bb24ebc61d41d520d920e4ee8a2aceea99f8f6d7ad90968a1f544fb671ef221e05399b168e15c876ddf4b7a7ec7f36a7d23ea6adfec5778aba562ae3401b9cc092cf1c7317e22f8d323b1eeea247c9b5d0913b0d3b96b65874c9f9afbcb22134ef9e8379080dac9919f9b85f3f3771fb5e4c2cca48d1ff5507d4d09a39546d6e67db52c9418e0aa1b292386d583bfbb37aee3554bfa6d9ccb459e92e0a4c2f368ad028e2d80b9b517af0104cfe6bff322d6c72037ea20eb15153327027038f622f6fd3b300bf8eca9324dd3892ae79335d07573e638d69a7363f71d861d7f6626e30f1551ecb54d2285758d8796b396c752dee9e02e5bfc844a5aad5ea46a477c6366fb160a001512449f727637d88b06fdbc2cd09f5f0ff87aa1f962c067b2d84b87be00718e13be6a1ee770794a270a7aa71", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1503435600, - "not_after": 1984856399 - }, - "subject_key_identifier": "0xea72ba70be84f2d464bf256cdb9525fc75dc9398", - "tags": ["UN"] - }, - { - "country": "KEN", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xc58d89f49ece5480d31dd9d8c07888a47f169d3fabcf40ea69e183290ad4248c09ecf0156c217085ea418cd18b7792d83bc79ea297ac01720a4fd51312cf3135163b9bc412fe209eb462bde6ef48332e56c95ca4124f246ae7b4643f52713caa594eb7c7ed56a41d380f7353dd910c448df985613066bcbde5a6f324ebb2b3d4e74208d43766b0b7e48d914284f1145ee1e4d2779b76b88e3777ec4ab8d2aee928c197de489bdd273238150e200d9c145982cf617ebcc865b8cf4a1b148f2adf861f34894f4aa2165f0519e6b7a485d97301f1a4c32ebb599eb113cd786649c8212ffbe982acff0536d1a71ccefb16d1143c5977f86255ea475fc87b5091fad87035106fc7e827eb9c0829007a78fdc219da2c14f5a21cd99eb4033ce54feedf2e6cf633963fb44830b704bf46ef387633f72cba9b727842188ab81aa2844dd989dd4cce7f05578fb2d4e93d689b04a2d93f9bf5b4e02072ced0a87604c9f04c5aeb614ac7894c8f7ac5f72bfbeca7ee8394276e4ce1cf30d235d6d59c0f0bacef6f92509c5223556e41761e78f1b8b1b8a8bca6124f4d0dd0bc8cb00eabf44616e40656fa8b4d4795aa8d9bb68bc7fd00475fffd807126a39567a24f248add85f7fe45b0167f6556b5d8392505eb9cc3439b690bbdc90118ece28a3f9d73d0ab251aec321598af6000f201e52c4d4105ffb95a0fe4ea7e51bdfbf1b1c7a451d", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1566594000, - "not_after": 2048014799 - }, - "subject_key_identifier": "0x0f6c2bebcdaf02c032b09c66ae1c830dd5105e3a", - "tags": ["UN"] - }, - { - "country": "KEN", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xc91e4c37e22ab74ef21541ae11fdd21efac80c5cf371e5ee57f9720287af0ff2eeb6c1c63f676909fe5284a1df6085480811f433e3915e176767e62eb83c61c976f044cae6074393af7978d626abc56366efbd2720dbc0cd9df488fb10dacce6ae74fe00eb8d57727abd1a65a6aa4202819a0fa1c37342d41c4ab2d8377b7258efe24c6cfb90925502c773717dfa906cc830276922f26d38600d9114b25d7955ce1a53b075f721e3acdc20b80717e2bac204c58f021c859eefc299e5e64432614ca09ef6b0aee0b5913609e20282074d29ccec7404627a716df3c1ebe9ad98f28ba0c476422579af6f8fed03c7dd41cc62f9bb3dfaaed0a1b41d172a1392f0bee10d4f1ae98274e25db89939b6878a460a7976c20ae1670ab8e523b6c87c72788f6d33a2e2997b6cfbbe38d392465e8c88ef78fa16bffa71c6ef3e49867efd1c0618e7fb362ccf444c6a1cc3833a4f0ebfd79545539e9c5d1bfc3230fcb3f6a79d8133364100824119221e1b1d1104dc7325ba16f78cd8672aea6fc251456dab7dc55606d2ab7c0ad8f59e3c8067cd3a8b4f0f6ba880a70e19f72fa7c3449f5b6e12ae92db76c6735642b894bf8ce89df19f85e9cc88586c7b0533a5de163cf805c65f96ea819fbcf80ad62f03e629bf8fab22e83a8f50710ed339f23cbd9c812b0bc771e43d0d7656a14ad196a19f151b23152cba62626a1d158f43989f8cf5", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1629838800, - "not_after": 2111259599 - }, - "subject_key_identifier": "0xf9162f83096b2c21d7053dc3a6d43519a5b5c03c", - "tags": ["UN"] - }, - { - "country": "KEN", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xc3efa37b542b66bb0fed224e05baf76d6a1a224d4b2a41bd7c325335368ad0f1023aea490ed47ac9737a2f9b193c7a15eb781bdcbc9618866a283d7e99815e36ba5e096c3218eed78884a2044d0e535151bf384aeff6ffeb7e51c013b4ef3546161b46961b05ae0b9d23f108873486c8d3a4a37b05a61693f16207e26f25a9877506114bfd0f243377d3fa1795f66ce7c00fdd092a950ac27926d243d906b645b91257109ffc5fce357a9560461ae4aa5dfd05eacfed7bc54c6816cfb7743364a884e5f9dde766df1873f006d40e591bc36c5f81a4b0beff215f2b50cc3c964878ad4bfa47f87167a0dcd2f013565e436581573fd3e24dbf3b987dcac2f785ff2b9149dfae4e48d978071f752cd875fbee1b6cd8ffc61e483c0f3bab6d93fb377c4072779b3e11e2507bd6de8aa27814f9e079051be09a7f4d00ab56166a0780b6d9e4522149d458c35ca82724943a675fcd2c39dec83c9a7dd4f14281ca3ef9246e851ff8b9bf2c3ef9295480f1723e64a931844e2328db7cb230b1c11e41e4dfb0487e72dc0303c3c654a09787be3a60603829f01dc208ea95ab503b3541c7d977abe112d2995ca2a8a372340a77ca294f5d7be8ebb1f3a9e21ff56863ecc7e37c61ecb4e726699d86580186c1efccdc4d88d8a5e18ba45b48d8715be2df13207f7593d7829bb58d00856feffd68e66c46d0548fff06cff0fdc8fd4a782b4b", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1692997200, - "not_after": 2174417999 - }, - "subject_key_identifier": "0x3ca34f91d667627418296e147913368ac7392dce", - "tags": ["UN"] - }, - { - "country": "KNA", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xc4ea1b14b5eb3f0ad7260500f392d19fb4a9d76b53e7b93491f30a19a821e1ddf4f083302ad07cc6077aab4cfeef9c8ee1e105a09c6ef7df50f30bf7e2bff838577e05c3ba7e872e28ecb5886c59bb6129aeff346b60d220716fe16d3b8b7901a794bfc5fa9e4e28f60aaa29d379b82136e1513fe926ae3968409ad2973e31200cf211ddfd275e7c1be7a9b7cff133f835a0b05c3c29106ce218fbf933b875aa7c1d5033d11bb6cf16d5b1e19c74308f9ec0a7c3666ae5129453dd4c1d11942f11702cae7c7c679f663983b7af5e6589cea51d65b057a2ca748522636e5e9c6b3fadaacbf18151b97ea70167405b62fa68e3adc33a338fda9a2093ec0d435eaf0f99010b8571166d466ceb9ae96aa4d2d1a64c2ef78e670928c5fe601861beb7198acf7a4d70156e5773fff9084dfd17bfbf012a29bb624dc0293cdd06244933db9addb434936d9a622fc9b81b02624f6918679ce9297e2dba73df62f621fb2d261ea5bf28d46b12e19bfebb2722b70c8587ba4bae32f2b194b82d675aa35fdf0c8979530fc5f5b040fbf98d920b1a4286092fbba7f005d02bc19ff4667f4f8f414497d7fe4a7630b63448b532c8c5e8dc7f550ed1245f631f7ae5d4caf87d8c870d7735c770dcb3e5abb7cf63ba873d83c5950a7179c2a47c294d150e5a976484115ed1abf6067c93dc2ec54b156b5021d78afcffb784d8b5e4f1a32a9cedef", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1291904140, - "not_after": 1765291540 - }, - "authority_key_identifier": "0x1180a3510af829833dd2d8f06ec1962ced245e98", - "subject_key_identifier": "0x1180a3510af829833dd2d8f06ec1962ced245e98", - "private_key_usage_period": { - "not_before": 1291904140, - "not_after": 1410252340 - }, - "tags": ["ES"] - }, - { - "country": "KOR", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xc7fe759c6acf9ea74c6bdce1a0605834cf4973892b3344811f04f566e4c5d3e08fbacd1a6db4fd6b4fe6ce412c89c3a71e1064c33559826c428a10db0b5cc0673f024f45408db5352838b4c0c77c9d2f06e3caee0ec4c9135e5dcb9e1c05664c7e68d9a69855d78a4fca8b26c42bad1b74acef0457df01433027875689db78b6c02c0cca73a9b22c917feb513937d041eefa8c5055f8c0f13dc4ff063616d970ec731027e1e9b7e612e85488331a2fd2638e4ee0122d01f4c8d453f1a2ab7912f92e2eed218c09d22ca61075ace99007365472255ae4865ce66413261f49f9f658ddebc7bb459b5e6dc17edbf8fcd9a60d1b541875ecb7a48611df6591ec4be997a755773043499b897ef5d4e6a3bb87232b91bf801b6f4c51950632c430400870db2fe61b296f1f7996cce8ed46a5de2cb7c073591dc2b5425aa468fc72660328746d131342ae2a6d97f9f4172de2d5c4f37fa9aaa5a79c987b97c4c6979510f19f5d7166aa88e4a0bba617aca69b4f14ebe9c129d0a48b15263cf70315608f", - "exponent": 3, - "key_size": 3072 - }, - "validity": { - "not_before": 1369989716, - "not_after": 1851346799 - }, - "subject_key_identifier": "0x7c06261ae37de33ffad61470e5abbf6d147d27f0", - "private_key_usage_period": { - "not_before": 1370022060, - "not_after": 1527811140 - }, - "tags": ["ES", "UN"] - }, - { - "country": "KOR", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xd831860b69b80cbe11a9f15c45da1182431bdd5413e2c493540c70708274dfbac152c0bc522c6928688b6e5b0f790b384f3f58dbd7577a8facf8e424bea338c4fe41b120600abe43a28891d05cbf2f4d5a8a279853b860707463947398e271339ffc77bb024ab724a67d2dcf684be6202d8dc580b1d0517c6d77342df7b01d641b149ca19fedcdacded8ee5d96e28a4991d1255843e491122d8299f857a099011141dd8ac9b4d6e244f3506af844bbaa2bdf89758410ffc9393d4ab1091433942d1b3529243585320d62b011596f8bc425f8ea4d52e361e2de44aaf484ed974dbdd9eae078e62af0a7376461bb6eb107beb8eeaf8d3f4117f9a1590bab1692b285f9337a25d6f27c2218ea5f37afb32e27c6e04b6ab2522265fbeb575c2760ac3a2ee2d236fcc0275ffb211d5ef222a9a00af25a349441b6d3c393d9b1dd71914eb9fb7aba9488354114442dfbe3782ccd92cb520afb1c2659e42fe77d79b8537975a22546c024baede46ea6726cb102433738fb0ad41902f494ca132327fc8d", - "exponent": 3, - "key_size": 3072 - }, - "validity": { - "not_before": 1526279232, - "not_after": 2007644399 - }, - "subject_key_identifier": "0xf37f189c575b626b041835f5fac2468e8c687a17", - "private_key_usage_period": { - "not_before": 1526311620, - "not_after": 1684108740 - }, - "tags": ["UN"] - }, - { - "country": "KOR", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xbcca84c12aaabdc2371193537dbe6dd9d9e81ecabcd32054487df6a9ef1dcda021fcaaea028ece0ff135a70f97b49f280db497f8ff54e21977f024014b049dee0e1dff1302ddfcc2ec9de97b69c3202e2e89285c8c8874f03f562f14015a0652a6b7aca5849354592141dc6129e7537dadb091164bf1f3fb1199807a08d80b917b8369b0c7a435ccccab894bbd4c7a539443500e2a6f83f017c364506e3c28ae5db07dacc683a1eeea6ead7d591845e9935589216e7dfee6980ffe99df534f54dc7b17673d7343d44fd0b943d0de74e4762da0f8c77abcb37dbe328ef8c0e42dc68ef87d1be4dfbf7601fecf5a63985b6566f5d1de1f65a143cc438a6e9e563e5ac97c09876bc1608b9b7dbb613b3f687f52a79bbd3a442362c916410f976749bd129be46db6386baf357f1b489da21f51e600a93b0a4cceacec2580ccb5d1e13f99d753b66237992a05437dc652e11f99b41dd0a00eff59ea4dfc009d72046fa712a69d0f951f906d5466fac78525cb0125d11485a0f735ef0356958ed9678b", - "exponent": 3, - "key_size": 3072 - }, - "validity": { - "not_before": 1584584249, - "not_after": 2065877999 - }, - "authority_key_identifier": "0x4c324f1cfa651f073b71abcacc5c5e7fe8a464b0", - "subject_key_identifier": "0x4c324f1cfa651f073b71abcacc5c5e7fe8a464b0", - "private_key_usage_period": { - "not_before": 1584616620, - "not_after": 1742428740 - }, - "tags": ["UN"] - }, - { - "country": "KOR", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xc9428590bfe3dbed8ed38530ecbe0753c53ca7261386b36639cad9b80940f6b42328d1f215ee26eeb85e1f107d99f8a12bf66a3110ec776fde12f1bbac8341a8cafbe6a12edff8adee6fdc83c6e2db56bea08eb9627166b42f9f211603830bac8999a4ca63e7c3035347b4904b32fc19a0de412067b0f6a9a00dd081a86de91dd1afab7a336cbc72e378c1c1642c002b0e4e595f5abbda91a2a18a311ce1ca2147b1bb10a1fc552a58c1e9e99144dd9945dcdc7ebeafe4ae0399c5c0d3b2dcf434334740dcfe08d53fdbbd4a9efb8fbf30f16259c835f41c33aa242fdefee55bcdeb42fb5d7bc6a626bddc1ac72ef94f91be5617aa9f76a5f1c49e5527db910c7c5fd1bf94f070bbe2833401812a1e648d92516ef3186539b75bc6827b188f0ec4f45e35d41370c513fc7cccd779b7b8b60bb7a3ffcbbcab30a376a7706d5029c560a667eb92a9a5338cc4c49cb66f1d4feaacb81b877cdf3118fc9b73573605c5fbe988a05dbf124ca07cce839af5fd0e4c9c7d0be90fd7d9df088339f5281f", - "exponent": 3, - "key_size": 3072 - }, - "validity": { - "not_before": 1741594649, - "not_after": 2222961448 - }, - "authority_key_identifier": "0xb38a488e1f3f4b74cd35a916ce5356db43319dac", - "subject_key_identifier": "0xb38a488e1f3f4b74cd35a916ce5356db43319dac", - "private_key_usage_period": { - "not_before": 1741627020, - "not_after": 1899417540 - }, - "tags": ["UN"] - }, - { - "country": "KWT", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xd277815228930cb690acc3d9c2d2965e0bac2239dd783fc25b18246475ddd5d99adf363006aa1cbb027ba26d51cc62c220e5df8ce20ec36573fadadae4d01f1a292eef1542dd1b79bb63bc738be979127fdc0d4e6a920090e2a13c48e97f95d0038514d488c7c78d80b867754c1f1bfcbe82f4c2ec5f7fa53c79c0235ffd89d1eb81be8b6d9076ed3275b7f36584f27abef640c7c0b9160ea62bdf0c472f5d47d71ba35e80863f13ac73482ff3de76ac4555d33bb17a84456e9d25238b338ad5791b3fdcf70e2295cc3f5dd980a89ffda25a412b1dffe4843afa4fcff8a89762a8deaa1a1a0d3d8011f6491c3c0e76b0cfe25a70c3c0f8577e74b37eb346d482e3e1ff47ace4046408db29f5c5863cb5b9965309e346245c7a12b19f9e1a2fbde0eee9405ab1337b21b027f97038e09694c94a70fd3e89738a696a2dc5190e4e8ae9e274a7953fe63f01886c1c1aa4d00eb55286d859f090bb7f0b94be29613b853d5be34f2d3c076fa3eb65fd72356b672ef8ebbde99e916a23a575c3b915fa125233175446adb6b14b26dad01d8657021e79469fdbc9deed7a1cc3dbb5d05570d0423605bebc0f1a978cbc763d462e3b3f4b6dcd69e13db3861d46a2e57d7edaf9b3a16021c407ce4b416e5ef80c358e1d521b7bce2e043f645e51680e34ace5a41eed44dbb74f6de244aa22a61960febe8088a90f9c8074dedbb2f393376f", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1459468800, - "not_after": 1940630399 - }, - "subject_key_identifier": "0xa34a661715946fbac088a89399a9477f554f1fa3", - "private_key_usage_period": { - "not_before": 1459468800, - "not_after": 1617235199 - }, - "tags": ["UN"] - }, - { - "country": "KWT", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xd69d51f370a4529158c8eb24472d624b05828091d244dbc7f3e254b777a9a0233d05f840318c155d4aff9343129ebade97fef41286c4aa823a2073b2ed330b169859151cb5493c9c29a61fb08753fc0257f13b9ef25f50c4f4ef7e40a7905a13c6dc906494a847c59141dffadde7d276915e611afe7c5951944847259ec1ac3206084d257dda3a8baefa54a84b639818a08d51d24fccdfb3e40ac4a84155fa024d63b4981045771348b5c4903d1199f7fa20627d5adef5e75581c9ab225991a4559973343cd6c5970c479106b7666368ecbb456235707d4573e18b665ee845086b55445f6b3daf004adcbeca8c4688dc911ea44f84626a70cb71882ec8a2a982350527bb9dc319abea8ced1d4112c6aeb561fbda8b528edfcae8be40a2f1c6a8246583b8e7ffc75b494353d99177ce3d7fd4e8a8e07efd8697372379e05cd4ad59a3597f2c39d3c8ba052aae51e9a37da0ff977d1c1de4163643ec2471ce5c0ab9b0e699b008ab697d517e7e7b1cda3e79215f538c4050e41356217ebfe264ad953a630c3b74b35c5ed1c84ecde2df9c179e72092601c2bb06dcddb8c2ef4ad6276a5fafe341d3df6958f372f34071c62cae549a12cc78438f586779b0c2416971974f494769da00cf277bfedbacedaf66e737bedbf47df86c641d426e03b59f1605e7d02008573e573ba58f61d8d01af13b2b9870e48eb7e266a978d904e091", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1619827200, - "not_after": 2102025599 - }, - "subject_key_identifier": "0x6c14c2f554a9b63f45f323339f733ec48b6b1d6b", - "private_key_usage_period": { - "not_before": 1619827200, - "not_after": 1786406399 - }, - "tags": ["UN"] - }, - { - "country": "LBN", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "EC", - "curve": "brainpoolP384r1", - "key_size": 384, - "public_key_x": "0x2110763eaf8fbbbf22cd70a0d1de0402f63e5432fb3f8cfe348a25cd37ab6109c065fe64c37a1a02a0599f47806476ff", - "public_key_y": "0x641f95c03999fae452354bbf255b3439ada47453b72e293869756c79e2f801f12a2a2ed694e0949b9b9b0ff34f1d177d" - }, - "validity": { - "not_before": 1531785600, - "not_after": 2013120000 - }, - "authority_key_identifier": "0x6c17211c20901464d3beb833aa83c538c2a757be", - "subject_key_identifier": "0x6c17211c20901464d3beb833aa83c538c2a757be", - "private_key_usage_period": { - "not_before": 1531785600, - "not_after": 1689552000 - }, - "tags": ["ES"] - }, - { - "country": "LIE", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "RSA", - "modulus": "0x9dddcae1db6c37d2a9c2b58b63fa85a5ef7f436cd89973d17d998a37cddc938099642ce4d828446a10b241bffe2c76ced1a0bd5e4c399948693141dcd8f51c07377c8c0057b487fabc88a0c470c0a74dc56bf62f80acbc908572b51ba017de529966e2631814894bd342a244fecf80222043f6140d509b15e1dfffe14861e2519503be7f984a2688adf15dce7335093af2bb0085ed48f2a85734eb21573e3224b0778e9e3e3be1a45393551a53ed2041b98ad707643afa7ee295a46928a4d2e440646b20e50ed9851821dce14487b42eb3770fe608814d3c96992695efa2996194049c8cbafe10de058d85434c3a6c6d567c1e8912b337ba0332f69a27069888179999e45695960f629f404c62b17430d5b7ab4e7564680755df714fb0be73c21bb80b06490e1fe5b14179b44f97ca86d1fa5101e165c141cd1565946d1920df91fbb25e72f27093b4059958b2ce3c7d3ce75a0558ed4b04c9c84c96ba2ee2cd47b14914ad8ec123d360370d45943a25fad0d1135407a65bf8e77b3d51c5ea4d89a143425400085373069b2d1199d7e97db9368ba376c94fb83eac6a9540ddfd5f31639f399cf414eaa1057144a5a4173e9a98ef82e1c737b7d9c408b7717adba6bab5b4fb72139cbd6b01c364156a53579c5ecb28f6978eb3a3cc86da96c76bac8a223bd040d86ff1405ca7f519b2beb68abaf981f7ec8915ea6624dd1a0e35", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1463616000, - "not_after": 1971216000 - }, - "authority_key_identifier": "0xb34a79a223a4e17df912f5d32335d829d83f1082", - "subject_key_identifier": "0xb34a79a223a4e17df912f5d32335d829d83f1082", - "private_key_usage_period": { - "not_before": 1463616000, - "not_after": 1624060800 - }, - "tags": ["ES"] - }, - { - "country": "LIE", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-512", - "public_key": { - "type": "RSA", - "modulus": "0xabce5b65a77f34f14bab55b21914b3a202afcbb48ca0316e81df87b7d7bf6377d99bcc453ad0acba589bdc005c51e3576e77eea4086a4d6dc9b1d1ee87b23ba6895bff10891442d10eba0afb6aa57ec79a30d037ecee71126a39f7b1c8bb6775235237e9506913d1fd3ae2369f3ba3cb4b5e6500f63186786d153192ae7c63c16592174f92a0896a412cc0ace267bd341a69487c4d17ca24f0afbbfd1ab2ca1b16cfb6cba02783c1db7887425a4c6ecc3b3741560b24c635534dc4b6bfd06f41329744e17e6e8e50cac59a49e424ef200f0b366a30b6a9387463e52cae07ffd565a3294350b8b4b5730b77aac5ac1ea912f050b14625f7a00ba17d477092b795f9d96c8ccef48a976cd423fc7ab217c95ed6df2ae11792dfc36fee66cd861c5cd52b7563453910b35b9c7a0728125852b1a8694dade6e7b3e7d41ebacc6593cdbab385176cd2731390d58bb049c4fa0f37fe27b85c50072325074f777164e00accf98d473432f24eea72d6bfdc4e5294fd1de4926c92d9edc13546f200753ad3de755eb1a3f3da090c0c226090296f3e42300995d1cf6ab238d108fae23715b59d00bcbcf8df59adf7b5d51ee2ebe16a0bd555e4112ea9d6dca5fd2d31bc8c2705592eb88b0dd941e4f8820aad55fe34e373e0645bae39c8c53954f3f1facfeaebe62b8434e3ef07844b0044e898188f45108c8f40f180b180b941c052b3aafb", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1513776156, - "not_after": 1958083200 - }, - "authority_key_identifier": "0x3e2b3e97c8e2727afb29fad435693fb3cf3fbdc0", - "subject_key_identifier": "0x3e2b3e97c8e2727afb29fad435693fb3cf3fbdc0", - "private_key_usage_period": { - "not_before": 1513776156, - "not_after": 1611014400 - }, - "tags": ["ES"] - }, - { - "country": "LIE", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-512", - "public_key": { - "type": "RSA", - "modulus": "0x96d3e43d4dfdfd4cc9eb0ffefe90124aba901bf4b84f0450eeb135398d47e6042de17e6cfcf1d2088c437f90f492015470533427069f1ab0c8d919f1b35a41224bec813391c485c7732e55606bc3162050a01249df54cc19826e64b3aabc37bc4df0bb8482085fe981e253ba034c639218690ae56bc463149ef896d54e4a5f8976260134a26c4a88f46d65ee9c1917596eedf3e02c47d27978b1240aa3460fe1f34bbd6761de4b98b56a499d94295e492cdb4ecda96ab5a5f9afc46f13e866d7af340c8ef4f19396b706f4ee843ce0a4c90842bbfdcd24256ba41f86cb8e6aa7d56061a569da34062c701d67cdcd0b3e39866387ea0d74b27c85f718ee2de14aee0d6183a881829ed346cb52dd947f43897c4e5faf019cae0821877b1c79d0b38c8666be5b2ac19e64fd3ceda714bd0320f124148b1e52d57c228f67b5322d599e3d0325053291bf04cfed0d002982abf513053db30789bc8832b0c285bda434d71ad0692c08baeada0a3e36b165197f4888adbc45ed22cdc328a148bc77866ca1e72ff8f87e1140d2fc648327c02db065110b3b134ebdaf50ce8c3da8f08a1fd0172d880cceba5326f510757f879a4dd245460e97b2b4fe09adc0a5367ddf0d3def9cac1d4b052f7d6f75f981536a04d807c850ce20354a82f774ddead77a7e314f8841f4284d99014c20339b4206d98131024422c067027c553a8683f4f4f1", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1610802074, - "not_after": 2055196800 - }, - "authority_key_identifier": "0x7e05bee6ddd5590584ed7e782a9d6853f0883a29", - "subject_key_identifier": "0x7e05bee6ddd5590584ed7e782a9d6853f0883a29", - "private_key_usage_period": { - "not_before": 1610802074, - "not_after": 1708041600 - }, - "tags": ["ES"] - }, - { - "country": "LUX", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xb52bf8e76940fad47f77eda186d0e1494384068a95151bafbff8a19ec33440ab693362aa3bd9ff0ef1cc2bfd758a8b3a520f5711a57fc9da0a0800f7f781c5f9378ee9171f56d7bd80be609085ed8a0f5fac58b73a1424c19f385cdd5efaa7b3e0078efc29d237aa036c2e163f8a2825bfd36254e16feab9f9f7ea438dab5e074e9bae8629ae2bca4bde891333782bb6f486d4ccc5a55338421982b193f98035458a7072c7b2b63e761676bd855becf25981c396323d60690bbd81ecb6fb2d7d0db236c9b9a840451b12ebe6400d14fb45124264dbb05336f74e96853e1effb8038fa48162e63f9eae2b7722ac0e0c0dcc5f87fa51ca0922464aa5f114421b32e593f88dec3bdac0ad56cbbdae5598d5cbffdeb32e23a81427193f037964008d1c709fc810ab0e0b874207cb8ff801eb3ce65a6e8294151b62bee6b846ec55c8e38c439ae7c31362c257e1e7a13e1c3f5ee4089932ba041aabea55d3977305a7891fb2d9c7b22a098e547d46e151e39fc06f3507d41355cfb67ead14fd47ce731052346d5ba310beb0071b82d638bc9bd710169483bfb48ce0c5e970af4a3949bc8b5b527594bd5b058fca31daea9c09441920fe345b063f6103f7b5ef00b9d795b77052dfd64b8e7c473bd8c2f7d5d56e25870162f1426b30b8b40507c1b0ebc28e54d6642284a8273aa61455e2f715dc2e31a931fb39ff01aaa8755ca44fd9", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1401709624, - "not_after": 1848829624 - }, - "authority_key_identifier": "0xfde86962adfe13e0bfeba97af5994060d0c03c09", - "subject_key_identifier": "0xfde86962adfe13e0bfeba97af5994060d0c03c09", - "private_key_usage_period": { - "not_before": 1401709624, - "not_after": 1527940024 - }, - "tags": ["ES"] - }, - { - "country": "LUX", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x9f5ad3cc8d8cea9456269cabb62e43ca075cacfdfaa7e74f6c6cf7241fe521aa099278714fabc79baf1f0fe23ad1ef188e1f5a066e5cd8df19020e0bab6b7511fa2be3678e4d582727fc2feedc5e760e7f77cfd4d569ebbd3e8cdfa09b509d72128fc8bc049464576ef8ec89840f8762b080f9063f8f4220d38fdc2b4096a0c40a04881bb501bceafe1239d57cbfd3a8036a4513586e7955eb6320fdb6cb80f98b516d0fc754952770388fb41ff621c2e4f10b5511303dcf3f5caff1f9e7efa0546a151d60cdb4d881b9f88cb406eafc7132dc92e62bbf2f04def97b143acd131cb4fd0f43eb74ee660c002472da947b3b20293aa67b6062e1b509c48a76c0e4f9da8199db79ed07de9412eddb740be8ed99797311fb7e1c42877f9e1c30efc60c04f2c70203d65c6019b94fc3019e2824981af17570df8f1bcff2af9dbbb44dbd11912dd2898200e25116c4c39c274fb61608ebc9bf0085b2a89fddb6ab4c59ab56da38a3e392fb6e011c666976f811df5f4d3068f3bb5df9d36ea605db831a80c73ad61a2e90f46a9b9d5e572437b0848cc56abf7ae8e3bc6acbfe9a5ba0fb0db602f6c5f0690814bcfaecf21d467bb93308c57ef36e7dfc61291e0d8544dd56f1954814283eb83a3b828c7d9dcf29c428b9b3ce09a2093d8318389ad7ddfd029069c2213a25834c13c38c02bcc5d9defd8fa424b9781f143c6cc22a2a64cd", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1415799007, - "not_after": 1862919007 - }, - "authority_key_identifier": "0xe38bdfcb0aafa79c5046d02fdf4f3c8c7b3a472c", - "subject_key_identifier": "0xe38bdfcb0aafa79c5046d02fdf4f3c8c7b3a472c", - "private_key_usage_period": { - "not_before": 1415799007, - "not_after": 1542029407 - }, - "tags": ["ES"] - }, - { - "country": "LUX", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xcf797003842212875a9390e8777f292532ab7748c178ac3b2d270b79fd0fe1148b7fa09a10ddd3a7bead5134da47d4da2d1174b6881540d05612632870d8e56fc53c57dfb12ce46b139198aa34f808e24ab5b24b3fc72386bacc3f20fe8d6cc58630bc5d49e2efa8ae145558c95c2fe92359be46deab033f132691001fb443b977b3b2b8570e96d8d0aa9fd4f8cdb8108d697e86df0970f0465544068e9145ad6a1fa1278e2dfced33776f1846f941fad236c50e333d8071f50fb1797712f7bf45b74f576e221136721d78e2c5293ad132f743b1bc1141382f2827e238445ea6ee2811c9efa85eb25dd0f6d472c1c950561e52bb3741d1318c9b61e7de8a0fafc04896fe167c77cde0ae708062c0ceca2d91a32e1f261cab23a65a5d86e52b4880607f4c692950c818f33dc736a759ee492e7e243a8e6e435114a3246053b3cdde6ce4691d36cea78031c8a7f79f8ab23f4df7ee964ed49b934654aada2e6edb627bf9dd4ef23c878f1243110eb971762b02c83bf2b81db5975b1c48911494192ca36f471cf24633e092a084082b979fc093c133d0ee5bf6d65a21ec3fab5ab9006f312518f3541a372a80ff6eddd78e3345fbe38ff041b9a27aede3210b9094c7f1f087130d75e7b4a89e46129a0fa40811d2871a80e2ed94cbdf6ee62feb1e68331cbedb197cf35b7209407c2d9486492e1dea737c32064b79382e27902c6f", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1415802665, - "not_after": 1862922665 - }, - "authority_key_identifier": "0xfbecd94ff459a443d1acb1b0d3e6c1e372a46b38", - "subject_key_identifier": "0xfbecd94ff459a443d1acb1b0d3e6c1e372a46b38", - "private_key_usage_period": { - "not_before": 1415802665, - "not_after": 1542033065 - }, - "tags": ["ES", "UN"] - }, - { - "country": "LUX", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xca1a01a8f4389fad37949679a14f7d1aa256c7a34a187448f9ff38a1573f35ff78894e258174a8800921b518024229d50abe758dd3d29d70192ba9403ae6c1af58ba676d621c7c8b47f9036409e1f3847ba2fdfb9705f17ecb5844a5636d416b99f4f70b5f5c37c9e28e3f418581ca291b3530df07e79e9c76ec41f8ece8f149b586ccc7a5e8edfddee25893194565951505520d156ba56a5c0cb36406f41b23ca6b22a43fec16e2af619712bcf465903cac036918d04f9787cfbd6bf77a311f14b3bfc74bb881e1c7dcfd70997ae30deda3f59fc5cff4fe52c5f7f9c0e9fa3b04e236f4f7ca2cd46aeb3eac68df2d82691fa14d44ab8f92c07a4e8fa21f0a04718fcf9c9b47da1368b58bf537f05ab512f0e23efbc77eab8326b09e6a10b26e23b3843299a7bd257433d2b48b1fbb1a651b36d7d84dea6af3e31ec86f893956d8f0f883f19be06997f08211edc3c29dc7e67132be2eff156b8ddaeafb542746fcb18536a2bfa627ecc064aeb13e40002ef05b78f529f04db67e8e900d52c608694b5b8133bd68e5986d8c4efa1293d27792eb082a54662dcba44234c8699b5fdd53e78d9ad66975c6c5a6d4e62ced4d88e2c44382872e51df32386d92c009818471b3ea5ff17d0db3428ca5d091dc0f62b5b40e2e31fc6a789aba154f0b8339f4ae457fcde584729f73ebc33eb79eed703c883eeb4f74d0b0150407d3c85eef", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1526991713, - "not_after": 1974111713 - }, - "authority_key_identifier": "0xad4873f7edac2ec8b4597e12e261704d3f7f83c8", - "subject_key_identifier": "0xad4873f7edac2ec8b4597e12e261704d3f7f83c8", - "private_key_usage_period": { - "not_before": 1526991713, - "not_after": 1653222113 - }, - "tags": ["ES"] - }, - { - "country": "LUX", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xa80db84beefccc9236ebd9e17c71a3021a4c4a606eee229c341625e7b7517153f6e6b52bae9c9ff201caa22bbc58e229bc30fe44dc00ecf546c118f0873faa416a7be61eca76ba4d8fa482eb0be1c1ad0496cd6bea739a5437ae0f715c900e352403e8f8c91e770fc4b7e45b397f63387357c02b4d402f2a555aafa62565390db9677dd3bd398a972b49fdf9f67c48d463dd13592ccc3ade823486a207fd2f0d78e7f7d185003b62619179f87bbfbf258226dbdd985e3294d0ffe8473afbf85f0a989a13f4f47ea8a056a8346065a7eb4779a062004a66dba690bed349b9d3bed3321e3b46d880a22b51995c87561a2f21c52e367f2900dd68fecf3f7622596c32689ad19fb85e15fbf9e5bb40207ebd8feba4b95c4fabc9281173cc6529cb22e8230984ac2d22f2da2732f39669e2ac258216f4732ffec7933fdf676e391adc293539bcbc8c42462901016ced5001b9eaff229f2df7ea016031111703a5b7fce287c91088eee78e621ed78e56553446ff6f1b86998e957a5a0b625a811e9f555aa454d5ae60af8daee8e7719fe4b46e77b33b81fde80849c26a7db78dbe76f08a8a7fa6554bf7b0365b453c0133d3203b732d6711c31746bc5c77a7dcda2ae481f41225596ffc55998c929c1a661c590ab8acd731c3a22560219400d67316021078aa9370684c522711fcd789e39116a8075850b9e38967c947e72bfee88ed7", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1540914333, - "not_after": 1988034333 - }, - "authority_key_identifier": "0xa059fc0312954dc13ad944a620c09e679ed553a7", - "subject_key_identifier": "0xa059fc0312954dc13ad944a620c09e679ed553a7", - "private_key_usage_period": { - "not_before": 1540914333, - "not_after": 1667144733 - }, - "tags": ["UN"] - }, - { - "country": "LUX", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xac366d0ba2819ebdc0170ddc50e0c17426e2ad3a3e909fd5b58ac13563e797c7e2d814ea8e4a4e0d209bf01eba6773ef1d137bc5099c91f41dfa0a01a0cb1ea51cf37c686bc12461acf3aa5efd8b5ffc5b25c8757e2363d7efe2e707bf054dd840a1d53f85e1b94f69571889313694707a72e2ba657c00a6b01df5149654316411eedffb901e395ea860545839eaee338e5ea8fa33afe9bca07e917d44741ca28e82f651aaa0c2b1f0abeb31238b6096f067cf8015caf243f51c0a94ccf07edf3020109821841162049ad6c785c9c011347982c09a110b1d1ddb63aa937c343c57b8993f6089df437b8f6b4f47e17a71f28b3cad7e8173eb9905762c24938a24d9c88b50b1fe3680fa75c030c0d6387136d539a3a1aaa387599994a65effbff9ccda5b98e4477882711aafeaa823a50b7fbe40c1438570b059b8d149a9ed3d4848885d62f596823b9e50597e461ace7472a5a59e33328a7a00f78798e4f2002095f1c75db6257cdcabf3c8033c32366f4797e1f18080c4bbbc4389bdf5acd4bce4e8d5c6c00a2af116309607a53172df6793c3deb704214179b800056708967c3bb97f6d111940916fcbff26f4ac163c283bf66dee803c6bb4f40abee401164003bfb872453841f5309cbe6fc453589b2578b9ad4f356969e4d540ff97f85ad3a79430354e2b26970f09023cea81cec771edc6cbad96b6deb9eab29831a16859", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1563541686, - "not_after": 2010748086 - }, - "authority_key_identifier": "0x1acf47c798e5354c8f9f55aba89af9e3c73c9d7b", - "subject_key_identifier": "0x1acf47c798e5354c8f9f55aba89af9e3c73c9d7b", - "private_key_usage_period": { - "not_before": 1563541686, - "not_after": 1689772086 - }, - "tags": ["ES", "UN"] - }, - { - "country": "LUX", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xb202df8d04859a26d49a9b2066afb4ff14b0b219d54a36cd7fab8696033d99204d367e3ddb216d8c4606ae272bd01665e7dd2aaa96c6972d6c04b38260de2a22c839057f6033e545b94f7963ff448282e4b8f2f10b5e1752c2babf68ad73ac1405e5c2d3e639a34106d37e324e928b641f7539ade3a87fd4699a9ebdd7a52a708d4f460c1667b25387c87932435d6398578b3431664a4cfa50f1aae6800b0faac29798a8eebff76fa43c2f4d568850199b98c490e5acb24946329d2a6991d2c175e3ded4e5bbeca3786e9dad4028f31a9c116de59a81c22252806e3c870a8b3f22f6431c4dfe122efc22fe4a09563964f31f6ed75a2f510c6b584438c5e64c9312c8365b053fddff327acc55bb3d62ff7fba3884d7af01c6ff1b481f3f10b4dabdfcbb64e1e94872d0de2a6dccaad0529caba51b661a69f7e27dbb55cc3582409815fdd294bb2c13526b16b81eb869af6906a91ec674ed1e1a059a199b8ab641bc21bd6e26be732668bd40542ce271738ea647da5e235714b75bbe32c8a04804ea5061a7df6805246cb161cc7d1a52f8f76d35b0f901dd00fb724f83325841003c3800bcb273cb606a56e6796b501bd2cdfdb983e85b2d161be539dbcd270bc4d7267fda0c35f0d3f92125690eead333a2ea5a4f7bd3f8a31dd0b97114c727bd74652adda77134416432a38df1d7f10db7c48af2f7ac2f51228cca8ad2fcc743", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1689166692, - "not_after": 2136373092 - }, - "authority_key_identifier": "0xf6e17fdf8c33867d7822dab6065266554cfe6650", - "subject_key_identifier": "0xf6e17fdf8c33867d7822dab6065266554cfe6650", - "private_key_usage_period": { - "not_before": 1689166692, - "not_after": 1815397092 - }, - "tags": ["UN"] - }, - { - "country": "LVA", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-1", - "public_key": { - "type": "EC", - "curve": "brainpoolP256r1", - "key_size": 256, - "public_key_x": "0x16e2246498ae73cf0210f92513927aa5dbbd2653d55afc0ec19290490cc98f79", - "public_key_y": "0x56e97399cf90584877abf8449fc6697dda915f671958c312ef2d37a83a5dc959" - }, - "validity": { - "not_before": 1447333878, - "not_after": 1833973878 - }, - "subject_key_identifier": "0x8f7faa0b418d162b202a71fd631acdbd965ff5e8", - "tags": ["UN"] - }, - { - "country": "LVA", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "EC", - "curve": "brainpoolP384r1", - "key_size": 384, - "public_key_x": "0x2e45f02c72dfecae3d3ab95ade91faaf4ce59e0f9802b68428f1ad4e77defe60986325968b5898e658913e98f98b289d", - "public_key_y": "0x0c1275c474365d807a1e7306e2aa250a347e5f05666ccfcbfd27316e54688de9dd94ecddbe2f69ce7802a53f179613cc" - }, - "validity": { - "not_before": 1500448127, - "not_after": 1887088127 - }, - "authority_key_identifier": "0x96638d14483a7e01abab40ce82dd9b756f467194", - "subject_key_identifier": "0x96638d14483a7e01abab40ce82dd9b756f467194", - "private_key_usage_period": { - "not_before": 1500448127, - "not_after": 1563520127 - }, - "tags": ["ES", "UN"] - }, - { - "country": "LVA", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "EC", - "curve": "brainpoolP384r1", - "key_size": 384, - "public_key_x": "0x8631faa2dfe474c1c0f1721cff79f7877c0a69f94df9467671bcb564575bd64dfa3b19c7d1c69566ce43698d4a945406", - "public_key_y": "0x69e28357be072747f194bb3201ff1ba1ed20d6a78c98f9603b500b544abb062c5ef0fcb1f43d3701049715abab841dc6" - }, - "validity": { - "not_before": 1564560367, - "not_after": 1982826367 - }, - "authority_key_identifier": "0xc4c1e1e1040dc4fb0d074e14d383a198e0d9b269", - "subject_key_identifier": "0xc4c1e1e1040dc4fb0d074e14d383a198e0d9b269", - "private_key_usage_period": { - "not_before": 1564560367, - "not_after": 1659254767 - }, - "tags": ["ES", "UN"] - }, - { - "country": "LVA", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "EC", - "curve": "brainpoolP384r1", - "key_size": 384, - "public_key_x": "0x65f48a6a05d2a1a7f038a0dc909d572023e42e119638e48097436185f6f46b4007ca81ce970d679e41574ad47223e782", - "public_key_y": "0x0d560be7bbda5a7081f729c0f530ec4053f849add568bbf30047515327d264abaf867b35c87d24a1f8ed3dc039138c0a" - }, - "validity": { - "not_before": 1593438359, - "not_after": 2011614359 - }, - "authority_key_identifier": "0xb72748d1e35062f7f6bd5b2df43eb8ccb8601ea0", - "subject_key_identifier": "0xb72748d1e35062f7f6bd5b2df43eb8ccb8601ea0", - "private_key_usage_period": { - "not_before": 1593438359, - "not_after": 1688046359 - }, - "tags": ["ES", "UN"] - }, - { - "country": "LVA", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "EC", - "curve": "brainpoolP384r1", - "key_size": 384, - "public_key_x": "0x3961d8e4d1847cb47fe233d3b79df96e0e39ed015b5aa1c9c07714967b1df347d0e706a9c943f6664a8e8650d62119ca", - "public_key_y": "0x08b59c24d759da28a9fa9cb44a3afddc3193ec2d5cd54caabbc33aef0d0d7557fa43e3828489e761bfdb9696d75fcc10" - }, - "validity": { - "not_before": 1686579308, - "not_after": 2104841708 - }, - "authority_key_identifier": "0x862248006c65b04b7811443961eaca7cebcc5d2d", - "subject_key_identifier": "0x862248006c65b04b7811443961eaca7cebcc5d2d", - "private_key_usage_period": { - "not_before": 1686579308, - "not_after": 1781273708 - }, - "tags": ["UN"] - }, - { - "country": "MAR", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xd117354e6a325829487085292aead342687329eddff8bd8a6c1f3315e7eebb5d5d73f84c2b51deda3352998ffd758eb062253b94002c0aff3ed49a002e1739b565fdd9645807b021dc1b9b673dd9f1ef69c24e8ab01b6db3c51b99cea61ef60e1d1eb8a953338119af791ad2c976faf0f3f8d4c6f353d13efc58285cc7ee8438b5cf7cfc0a887dd81a60d6b618dc42caed69527e85616b757031c4f51e6d2dbe1261db77f3bba27f79a231d75e51ed51dcacdac1e50b560994fe86b4676a402739c89f2054625ebcc477e5586eebec944d71088d37dbf5d6c98d9788e262591d2f9dd898b0039b6b25674a84bf238042c29a7117fcb2331722c46e6653713b34a5a3c2d710000066c181c5ddf4442e4d734808e7cd0cf5d8892a01be88b42d8f6f7faa4b3edf38ffecf625971a16dc8e6a7a0c94aa2473f7c9fed979409e3fcd98bb60b428c5896f2d848e40b56368f6fd1c6c1bb67b77199bde4432816c993463abbbf39cd894bfbb2691d6759f00781aaa9b6c1338988db2b0af2868a18153e2514677d2e6d3d751fcf64bc0b8d55c3a53dc7e2bba3a7213aa8ebd16a6aad448f238d3b0a5173d97980671972c282f947b20a5899879a2d0706cab04b8aeecfd4573de978b7821becf159024be0c42d9a896e508b30a53a89ead0eef405f57f5dd404fad3aa97e9b2c610ba6b32f1e7bc75bed5a008d8c7fc2d0557dc95f7b", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1519257600, - "not_after": 1776816000 - }, - "authority_key_identifier": "0xdb04dae635a2cbecd63f8d60c2060efd5df719e3", - "subject_key_identifier": "0xdb04dae635a2cbecd63f8d60c2060efd5df719e3", - "private_key_usage_period": { - "not_before": 1519257600, - "not_after": 1613952000 - }, - "tags": ["ES", "UN"] - }, - { - "country": "MAR", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xc997d3bd8ccde3ae381dcfa9479584555a3b13c2b6aaf17de426b2e7bd562787d9b01d240e9ce15c3dfc8cb2b0f8e4afd21189fea99565f44e1ecf641d63aac64c61a969f5911b7489d07bb8b207e58d11e846b607c242284145993acb7a600644fd3fa396306500bfd3e9416667b9200095bb83cb8963aabe0968e85f29655f7c52ff753d918d9905932e173a224f1b9dd07aadd977e44589c804c42580d2a56b0fe4a425be05bc84c347225cd3ff5068316cd6ac49b167cca8b0d2be18dcd328b4b932245e7b73ba38422a9651eeee80d3298cacc57da9b916e5750adebd8c07e464c941f140af3e8b1c91e0baceef2362a8316da1f28cf3f5b9dea72f2444fa7945ffb02c75bbacfe209947b45e0d428f181f09b9f46853a9e931f2fc682513ea95ab9d7db3f7581626224b983815c092377d4d8d89c006f1f27e8c1d86bc0d3b70ba7cf7439e89cb5ec4d6a7baa603cd157e2d0020d19f5eba01421fc066dcbb1facca9386354d46ac47a0fc6de85d46ed6eaef82ab5be76a7f5134de333e5258fed07e4f99e7b34f584221bd1be73ff53280dd8d1fdda57bd142eb0b96f4fab0de84463e70172cd7b3de984cbc44989c4ee4a6e698cbe5d2b90c43b09496e6e279e0623e06225baee7222b44ac2df50fb6df3fc82d85a26633616e5d106e6057bfa7c64a711dae16a072a1252858077f47f1607f3fabf480a76618eaeb1", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1611705600, - "not_after": 1869264000 - }, - "authority_key_identifier": "0x91fb674b8082ff4d540c9ab3234b7f0ec85debe3", - "subject_key_identifier": "0x91fb674b8082ff4d540c9ab3234b7f0ec85debe3", - "private_key_usage_period": { - "not_before": 1611705600, - "not_after": 1706313600 - }, - "tags": ["ES", "UN"] - }, - { - "country": "MAR", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xbc4d38bc649e93852f1ab2ce49d5d13e0b0b380b7177b6092ff4224041e337fd480c659297342c7c2cd3813fb277330c274d50f5c15762b011beb6dbdbbe2cacf3abe0781058c258a7edba0437c53edb1bd2bbc3847a4c15abee9c520c5ad48a549e03b1945746ff60d052c527dd9d37eb96dfb20bb7f1adb82fae2bb840a4baf269a196e58a4896d5801a68bee444ee27e57c1a0347bb1af757146abe788b9c76329beb974c607b6cc8744273de53a4654e07d4a5be23b0071f96ccac8a26220ab6d04087d8c2062bf9741b8fd308e971fe7ef20f0b37dcf37b7aae670727df55c3b2245d2883fb0ef047b38068b92fdb086ff02ac5e3e8c0ac19f01b88ec587e2000b9685f6f4bcc4ee4d439ed851934286595d87be3f6b7eccf3bce07bd6b81ab79026d17da7447448c063bc9464f1fcc4cb0909347807ebc287305bfa6376dea6beafb4c48bd6c21ec42978ba1b12d2a74e5be32c5a49e4d9b046eabefd55a4cc1dcdcf606de8e0745d02a84d0c6e0f15ca2f25baccd71a472552b5b7a81bb02f1af91d6d5635ee9084fda89245b143f0e4b640ecf5863db7a160360882837a2b801a24604dc7b1432654d846427e7f0f9bfd784cce3181bb0ddb4a336a2935a5385d258a45cc7295416a2c015b17aaf67d3ab4d22e07004d3b8fdb6e05ecce224c79e5a6150eda489e56d043730248c6d1886662eb3080124d51d0769a7", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1699920000, - "not_after": 1957651200 - }, - "authority_key_identifier": "0x41febf894cd4432a33359f5590124b2b9fee6b94", - "subject_key_identifier": "0x41febf894cd4432a33359f5590124b2b9fee6b94", - "private_key_usage_period": { - "not_before": 1699920000, - "not_after": 1794614400 - }, - "tags": ["UN"] - }, - { - "country": "MCO", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xb90cfb07215a87424656717e9d19efdd105dfe02f267ba4a8017cf0c95ae8db42cebac88c66d9dce5690c358f4a7613868d2f6341c806195c6801f8090aa8fb2a09528e1dc1307adefab009197863ae3fb8ab347f563c620af059a8ec6e549fdc873a3b9ffc209a2948d0d1b195ca3d3b1d18048328f3692aa88eac4bdb1ffdad5fb79868bb1102f5c9369f9068f58adbb2d2887b31c9ed3c6c14ebf1a25503a0044ebaf933644d876110af0c1987f2149c1eda26f0566dec1287432a00732df16392ebddf1cc345f56bb8976e5a4e470a095e9612fe8051110ae9b2c38a4bd3dc4048e248318af874452176311e2a85e22dd623cc86608b651d9945fc8934d2657460e97ad64aaa72a86cda2f431f35b87451655bcf0793ace54977d8d6c7f19b5da9a6e864a3d735e669167647677068a12dfbe64bdff5f21098246cf611ac9620f73eecfe101236b6e07cff855b40286177d0696b0807782d93961a09ce574c94d64e6348f53ffd9f68d16a24b43375b482ca99bd5aed66e8fc857600ccfcc47a0846a8ec4eee10d7b475c8b507885a067513c0b2fe132091cb46060e20533a670ca80bc7424d4bef189cde1be8521b199ac511d673064b4ab5e59801a1fa85d6a252bbec3bdc3522bb7561424fd1701f2bf78a6c892d0a88d82410b2cccdb3c4134669cb8b08979d2c604211b1493911d95f045f403061c8de451513f3ab", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1610546968, - "not_after": 2028550168 - }, - "authority_key_identifier": "0x30329c7cfe7d8f02edc5125ae0eb57bfe8858929", - "subject_key_identifier": "0x30329c7cfe7d8f02edc5125ae0eb57bfe8858929", - "private_key_usage_period": { - "not_before": 1610546968, - "not_after": 1705154968 - }, - "tags": ["ES"] - }, - { - "country": "MDA", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-1", - "public_key": { - "type": "RSA", - "modulus": "0xc57311ca1c839534e98afe81610940324542b0998aee67118225530229a864da4fae392ff514109240bbc0133928c73375289b1fdd8f764e1dda2603d2536f2d47753daacf6be3d5e6a962c445f84ad584df4461f64c239f627392fce4702528fd40c01914abb3680f09117cff7f82b2a459e13324486c91b86d894f1d33bf139c80d80cc36458d364fa5256d939a95f482c055d128f056e9226a8efa1e70446e138c75689990cad0974e3cfe3f1d907fcee8a155d6a84186db3a43f57336aa67583a4f1514c5e8178cb2d6abca85fa962b0f3e637d521cf8cca8def6508e9940e6fa3e7af9cb0c3c9ee4fc68990238e3a9a3d6d8ec3a6ff7ecd77377d76b161047085af2d10717aa0bf0f05f2740c41220807424b426ffe55cb00f35001aecf95225ab62dd25141e2532395a58e597f0423c75ef1f844a6e11d6f60e4f61b119b0d3a675d6aa05a69abe872f61cf4d6a06769925c8831dee634be59afa19626ce4c51a637379f6b13117421f4fb79c4f007dcbbe1c33246d7db13be7f8afec7b7b74baa3ccacc6cc104150cafd312e3795b5333c1cb3e907d62ce36cd161b8f775d4bed140f0afb046d27689a713b775ff043cc85fe50e03eb4c97be9b0e1650cefead0f1cf7e5410ceaa9e1867c5bebdbbc05522a1fd68b870658b484e09f8be4be2a3d44dc02ec32db88894b53835afd95aba18ec76beebba7401b9a7b507029231ffc40cb5e3df3eca806b9d8a61a8f962d9b3ad1f634eedc5a63b39480a525f1f848437331a25ca359bba15d4ce1f0d743f7106289fd6bdb593bfbffe67f24f2bda6fec5cb9dfabf36a4b5a76d63a7eb3730d77e07e190d128ee904a4f6ef43b892e54b9d3d9d257f64b81386280197cc055350ab6ac3be2c01b84248d8f18fa6ae378e585ef7aa3bce26afc5dafbebfbd9011dc218ed7c7b2fb7765d0e52f6ae74c0fc6d8be630f3b696ccd1f7757307ca7ba0f08ea39f725f6e5bf9a598f5d83bfebff1fc08f8fc06a627cd15a3fc5a080cc8e99b61b864a88b67664fa7f6f49d5f2ffc92eb509b7b61e66ec52357ad70ff71b5e8fc036ece79b6cca7", - "exponent": 65537, - "key_size": 6144 - }, - "validity": { - "not_before": 1299074708, - "not_after": 1772460308 - }, - "subject_key_identifier": "0xc59dd59ee7e15cbc2f103d5299ef319f3ef910f6", - "tags": ["UN"] - }, - { - "country": "MDA", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xb0023651a30bc8896aee80e5174fd15ffd84802f981ea3e60f477586987881f76cae80ea1bcaf8334e24afe2511962cca9de199207c16a4e3b048233db6bd760e5c82c19beb6d35f8d311ee978224e6ed20ef995df527c7b58692157e64d760326f9624fae33c1e251c546b8d8e230327456c64c22f94e755f95e2581804abebc3ba52f217be46a753fc37e191ca5fe8f42bdd1f1690480f1b91d6f396a5f429ff7fd402aa7db68e620666a2937a6e4d64c903f58d80dba83c13a4be59fdb3f39480f72a5fbcdd61964e0628cae9030dd27b6787bdf8e69c0d2f9523453894ac055c4a6426dcc1fd94afcfd8846f434d6bf65adfb211857b77d77aa72287dc84455970198c9bba9d5858e6ce05ddcd03f329a70d8ffba30f2e7f280386ae15a3adeda32613ff980ee6fe3016f1b591e9586ffc14df1fb4a7b63c9b3916ad91ac7b7afe0e11284cadb5f3d97c66577bd4fdfd1806e004614a5351c4e28bc065cf59a546fd4c7a56d924456dce4f30f1287bc5fabd2e4bbf68d22197dc9991af4f892d28aa99c6c4ae6b71b3c6d96e0e997aafe5789fb8e8714ae6f161210b18390b2ae7a682060901645c301002e784772ec3090185d672da450d7ac98a00016020f195fe9b5399083363802a36a6331c8ab2e9cbc2904f61d549d9068f3b40e7f54f7699eaad9007c7a1c7e6fbde37c6cf7d3efce1400920938a170bcd79c28113ff0f95e371f608a9d5616c554488cc62245fe39211f5eeced26dc68682a085f0f33387526a8bdba56d2215a16f85a6ef6da14c223ccd1146d251cc480bea84a197681938d640f7a03e11f8469c547341bbf5da8e67ace0fdb21810e7368930a47095f494f603eef97c608e9f92c3443d76207b58cc7e21a88fa0c2fb08d62a40ff381db78a658d9f64690647f06279c2a9ac1ff823c9cda544e993ab25b1bb29270ae5121b78dd5a8da69203ab800892e12d71748ca914566d24fe222418d4768e8325eeb086b40bf354dda0855126fff7c2b9fe5fae996cf6759090325fa1720996275f4d4cc8baf91928e888eb5d895381eca47f48b6a4737a3c18c7d9bf", - "exponent": 65537, - "key_size": 6144 - }, - "validity": { - "not_before": 1500361561, - "not_after": 1826521561 - }, - "authority_key_identifier": "0xcd3cc520b508a44e6d518dff33fa36cbde108be2", - "subject_key_identifier": "0xcd3cc520b508a44e6d518dff33fa36cbde108be2", - "private_key_usage_period": { - "not_before": 1500361561, - "not_after": 1605596761 - }, - "tags": ["ES", "UN"] - }, - { - "country": "MDA", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x9ba4f067ec24aa6126a2427bb5e4048132302ca2d2ce769bc443b3cf9acf3217912a7245ab30f3095e49133b9d4808c46c1c1bb0288ac267c37f0026f5078ca4791831255f40f494957d0a2e64c56dc4e94e19c061e962c6074d2567a8eb8fd59ff8df1ff179d6461e4e44c40fb7157068cbca3c7321c76ba3773dc382d9a4d869297fe1e63b7d72418940588908ae4565eaf1e22179e4efa88f6a5d6e31119c23e215ca5baa7abd085c3fdc5086d70a55c4633576c69bedcb133598a32972c8f2185272e974578b82e410cfb0a29860fc4292c929637dfcee56d01d65ba66cc544b0e626f7e6aeb98b02d2e0758c2686459dfca5d944184486d4b9f28b252eb4a9bab39e36d1b14024f3c6d1a83c48fc70ae35dae9bf3b83689c92a42ea99c024a76c4248bb48dc041c9fd3a83eb9fee5dc69260e88bb4638906af0342590d308a443bc08c59a2514a31ed891c6bb67e28a6d71120bbb46e679a464a0a4ad77f6cdac483390ba64b8b0a4a393cf0be5c9f12db11d1a1a383d7f32a1e90e5b302d95e2648c889cff121b65b9141b315a27577a40e41f503c90ad005195381138eb197bdb8e4499627d40e8364cc1261fb32f49ed6d3a6f3eeeca2cf6de911d9a09e599d722305f81e775b13ed7396d941fa002473ff890628f7455c070c0652e21069792210dd27a238f6518c29103557e684bfc0c07898c655d194c2cc2ed7bb15d580c2ccb33d40fdea44ffc3ef9de66d34215e71d4af6108bfe2e90b4ad6f99b33b37d57abb2b149dfd73b8bec3c6df5b82d81735d3e46a2a46dd02b3c3d3476fe9f27e5a33b4e3e7b1db4c6172718652c4b957787cf307b22319600c9b5357fbcedba031b3f38ff75210972b204a4c5f44ff2190193023defa8401dd51fc930326e8b72e07eec721e42f4bbdf47b0f0d278a1ce8aae82459532583bc7514e3c0191fe0443bf2bba27d9e0f774b0136bcc3d6d036be04f410760dea887142773f3b9b8066e3436d241b28628078ad9eae07bf27cff7273d5523b47dcd4c66505b3bca93535f7a0516b17615af67a4f4a2c7fcbce67fbaa02c3cad0fbca169", - "exponent": 65537, - "key_size": 6144 - }, - "validity": { - "not_before": 1515587478, - "not_after": 1933590678 - }, - "authority_key_identifier": "0x705c773c133200fee8ad8952768c9d066bac6105", - "subject_key_identifier": "0x705c773c133200fee8ad8952768c9d066bac6105", - "private_key_usage_period": { - "not_before": 1515587478, - "not_after": 1610281878 - }, - "tags": ["ES", "UN"] - }, - { - "country": "MDA", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x8e9c13b53be0f57836cf41a699e4e782ae6049b128f7bca5f9bae57e06a2758600652fee180d2a42476d73778dc00d740c2e8da688702f45aaf300116a96ca1e62afe9714ffcfb021b1065bfb0db56a8e9d3b8188138392e8af907f356991eae4171d9ba2f4a338695048d2e653e5fce9c222917778544400fa07fb79b668e1650550c098eeebe30b6d07d3ac0851f3f24284f7804cf68a767ccfc104391ca6cbf9809bcbfeb28b7fa7ce085a2286ddf36128fbaddf7e90aee64bcc3b608177b7341af441318d7f2ad93b30e9f2c73a50e4539066e22f1c3cf9d3a4502bd585753ea5f36ff11c6b1f96c06219bf21ce478668646f76de121f65f2f170fe4315809c5190739e580edacd4c409f1b88258c8500a49a2df7964678d3b01f7d57d29025c41e1ed2c6ca106dc22e82d12fbc27bd764246f79e59f14a443dabe83962d592b54d82324e71de2cd02daea9943bd44d37486438a6fee6767609aeb310f2fa30b3e1ef5ba1970efec54d6ff79031fc2c9b3108f216865f6de640afc200a7ab3eac16863e46d485ac83ab1b1d140d263407bf19a11edf2d28ea43d257a2b951717dc25806f6d5149602c22f9fe45d84d41f6a8bf38cf9c55496337a9f1f116d6ac4a04c40360f7a1b6b1c6b76812bbb9cdbc6cc061eff616adef2f6a3a1da792672bbc33404c2cf676dccd09bfb33d8ad0e9a7b2d4e297bb1d0bbd2378920913f4fbda14680f30b12dd861a8ee25c3f18a95bde8860502ce939c7be6dfe8cd306a775c5ec403f97b63cd73d222239d52f204a9734e1663e320f290a7dd6c953e25bee9c68ce0087d726b2193f991d179f01f51cc66f6e145088ec85b58547fca423aac651a37ea39c9e62b0545e29f0b783f0e737c2868d3d27f52858878bdd23985020a89c5dc1061d0771158b08930c2df21f31e7c342ce201bdfa8a16be059e8b3be15dcce67bb95f9560d18df0a8315ceab7cea41a00c8b5ce95b30390c911c3534f6eef48f0adfce87579740e8a8233906647a215aa0aa6dd9a6c3535edf43291d49516a57df0bf8269c24b5889aca8759fd8282d50d58bcd8fabd487", - "exponent": 65537, - "key_size": 6144 - }, - "validity": { - "not_before": 1612336666, - "not_after": 2030339866 - }, - "authority_key_identifier": "0x9e0878dbd7bc5289c39902ac172e9cbada9d2326", - "subject_key_identifier": "0x9e0878dbd7bc5289c39902ac172e9cbada9d2326", - "private_key_usage_period": { - "not_before": 1612336666, - "not_after": 1707031066 - }, - "tags": ["ES", "UN"] - }, - { - "country": "MDA", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xdf0a0d9e42383025710f931db5ddc33102643f0d9727cceebc6450fd67f66023272c51cabed729af0a259374e58224c5d8683c2266bc1efad3759b279e553e7d011765bd6fd39cc45045a95d7d8461e0f0ae2de6745a5e0faa5a8c9c3e44aff1504e096cbff531c528ae420d479019864b2fa9d3d0dbff0701e118f1cc48f07db89a4162658df5567c3fd601f5f91c22df07e930e713f65775a958d8235081d81e89283448928bfef40ee495283f4f23a75598a51bdb81464f324402a2075d565bfe7922ba72d6a97c12b0e2ac97ae8821c2b55311c759d0ffcd9aece45d54fa49a5d734ef094c67e2c7aff65c9af9ef128cfcc3593fd1f2867a0172335750066b07d31c5330b9c0db99479f80b4f9f1e9805484f0870a74504cf7b568d8da19b5a7ffc784f792e9af88e1bdb472e31b6c51bba0b593c743fe4dd53faa68c25c6fce8d414400f724842fd314f2b84513e064244309255d7a42347c14cdfd46df4196c978813f01b4b65e20415c679808b440b99aff818b07357c27371de537cb7e1f3d38c5254b5a317a46dfe91d9cedc6bce0b48377fb2c92e3c7b56136deee5ab9113c6752f3f1a219f7efa19535c31b7d59bdf24d3500a088c56fa986478c0538d6ba2afda64babd57afb77362eed7be8d0530cf04963885c401bbcece98d9e69d1cf7e225939ad567a32595d0976f40f7162e00ebfda2ccd28fc542d6eb6e795bfb3adb5b5ea162cc13cae3148543b81aaccd68f70fc83646a35fd1351e668b4c1fad01d814f38d10ad34cb02beaa31be861c8ad0d69d0eec1498f1e877189a925e156514e5906a1d9b16060f9e5f60e3f2e6b05f623be4f38c2004b765988eeec80ff3572679639370eeeb8a026406b5b39ac3ba84c21b952a9ba3eee98e07f40f438fa0f95fd2d35756ff9876c34b73217f11b25932a01da5b613d3133e4e003e8b5084e72bb42edd640516f38fed947f90f67d071c380659241bd414662f63f51b6045963d28d4b0f25504a884d48ea24d2879aaaf9cce172bd7fc637efae9438f10088f5220fbf272c9611a44483857734b1156a90a0b17f669c90b5", - "exponent": 65537, - "key_size": 6144 - }, - "validity": { - "not_before": 1706086328, - "not_after": 2124089528 - }, - "authority_key_identifier": "0x09dc7a5bf2cba4706415e14e1ac81baf36947de1", - "subject_key_identifier": "0x09dc7a5bf2cba4706415e14e1ac81baf36947de1", - "private_key_usage_period": { - "not_before": 1706086328, - "not_after": 1800780728 - }, - "tags": ["UN"] - }, - { - "country": "MEX", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-512", - "public_key": { - "type": "RSA", - "modulus": "0xbecc9fedc6ebb2ede36493138cf8cee05da57b5abc35becf062e1cce9bb196edf4ff6dcaa8e61d65f898ea63a601e8234f395041e3621b4541e1429882064eecd13feff1bf6123e5ce23354dd337aa1bc78eb711c97602d8574a21b336461c7133eda48f6fe7386b55bf1d8e8691ae25bf63b4cfc793e7f82d787941fc34022e194ff98870622e0fc1da78d39e9ee14236639adbcaa66fb2f488a59ff478176125072dbfa8223df2f0ac98d1f0f15695a9278b08b0873decef880d378f0577c9b1f9488198f060dd140a365d1f90387cbc9f8ba68453cb1b1d198b2875c87dcae9bf61ff54c7722f770a6b42ce3cb59f3de3dce9457d361c5859c05071fba664da91fb1a9cad08089656c761201d890c0a829e5d0c63cc6c710478515962e6b5675183085b2d60011ddf1b727cb33cb9ba8a6c9ff5859c546626be9e9d59917690710d6d31f8a2a8c03be9d61016a6b41817eb61807436027db51c5200316131f4cc3f4367d317c18ee6383c41d841fca963c180cd8766e703f888d08f5ae3bb3d4e709cde248cea9c7fb08470b70f916fd1a453bff4473c28ace2ff2365da00d62fd4a90090c30b085d432671826711308384984bf8e1df6ae5dd584c224a39d32c16771663728653e4a6a2152bf423022d37b91596ad9e148b80a759b3d7cd8571b12694c3deea30e9fa7ea878c0c739aa6e2be75785fc9cd9d68ae0d4b753", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1626284492, - "not_after": 2118247892 - }, - "authority_key_identifier": "0xa02bba6515e01950d0daec3ac942fea4d8359c54", - "subject_key_identifier": "0xa02bba6515e01950d0daec3ac942fea4d8359c54", - "private_key_usage_period": { - "not_before": 1626284492, - "not_after": 1784135123 - }, - "tags": ["ES", "UN"] - }, - { - "country": "MNE", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xaea1e966a294c205208c90d687316042708ee4d401fa5c71c3cd144818a95c6fdda2382b95569ce87371c5b50e0c84de03f73205e8dc5596bea819802fa89917db196e879b358722d45f45c7467f3725bf04ac03b97cecf661edcb97f18981e0cd03684ffb945f67d91d912772a6f72aa784fdb707b3dfa0e174447918f91e070e7303493482e0e8416141ceeb0b3cfaa832bf9855cdc4a0ea247befb434543237e27f73d073a9d657b83ba290ed074a8d4796464dc18b6b55a23cbed158a87f4eaf662e8b618ead8ff239fd9ff46b9204e41487710b508ca7eec10ef19dbf0d13b4b5d2068aabb0b199098dd242406b1eb987a6411113ffa17113290590d9a783bcc50a2053ecfbabaccd8142c6ffc3da215addb0456c0e8bb30d79e21d81cc1a1dd3e08fc57fd20c634a9592b5249ed324290e4eb4920e8d13d48794a70aedd166b962d4f4d264ace33aa14530ac009690a85a5a6f884fc5920d99dc370f83d2ca9c8cdfea82941c072fb70c6eac4c7cd65ea9824f6cb123f727b28e2e0719e0b25a30e3080b23f36a1f4c24d9807cb10c98b553331928bb9d5dd447f4e08c31193e278b68e815a16e75c4537b99131333998b46e8eccd6aa49bd231947d30dbef7547ae5aead9235a26047e09b01a17a352798398284706c03645c3e6284aace04792fa3c4f505b7b46d8d9e4db37c9b3725eb986aee993c48c52d5eaf443", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1356652800, - "not_after": 1837900799 - }, - "authority_key_identifier": "0x6d427f8f82b602a6db8aff7b8fe21b649ac4e75b", - "subject_key_identifier": "0x6d427f8f82b602a6db8aff7b8fe21b649ac4e75b", - "tags": ["ES"] - }, - { - "country": "MNE", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xc13a74a4d2af083b28a61e6aed07e3bc548a704aa7b2a38af60eea8c9e301227cf9e3e9b9020e28d940ba38d49cd86bc10445c1981400debbf32ad69b258f9a38437e87c5f47a414fe2186875bc3dfc68c82e4f972d4b9fbc21f0635063685c4c9c4d3aeff2d1b5f82c273f9d9e20454723dc0bfcca0dd580fb755f192e5316ad990b42e72e3af0b40c4a58c955ea48f159f54e623ae358ff064be7629ffbb9d362dd3e48d754bb3772639833d4a24dc1f6737bca192f977b7083b60ee15f8f50aa93670db66ebe518c7cde71c3bbced9b10bc744e4723de0b525e86531a0c542c60f1f4fac36ecddb17c9d1bca4566cff125221a2eb297f1b33bec2593cf8eb9b0910af74e94e5079d6e525fc2c32d84e6b3d6e9c5e974481ee0b47d173537e0336f5945c58b6e3468944a92ec2bee32960994aa5c854f9cc7cf49f22182313c07e3a188a5dd44b075dc2c41add18fad4d5726b6caf23e4fab0038b55ed92a2f2e128f419b7089e68b07563b7af6f34a25da636f059f1adbbd7ad8a1fa6ae7c127cfa4be8c76abe9faffdaff8699c60759807d0b9c7b38dae51d31998f38a86657387b93011cbbd82b3efc113d896f204c1d15817c06905fd92b32abcd6a6a9e08c807d924ddd6e0e75a91e8b4eff4b97402a8b0c8a4cc7a5aa60143bb518deefe59633fd7c101940aa0ef7c0a1e97d362b15072bad13910d50783f1b6a6e8b", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1511827200, - "not_after": 1993161600 - }, - "authority_key_identifier": "0xa9e82c1e721ada8fa4e802eb994b2f83f5498b41", - "subject_key_identifier": "0xa9e82c1e721ada8fa4e802eb994b2f83f5498b41", - "private_key_usage_period": { - "not_before": 1511827200, - "not_after": 1669593600 - }, - "tags": ["ES"] - }, - { - "country": "MNG", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xbe36db27281830deb229524386058ff55ee56fec3eae3b03aff700e9ccd9e5e534bba19febf5105542bbdd75113a66ee95dacf491429d7f25d21e236c2d6655111d78eee87d065746ae9e197f0e1c2f434d91f8e34835959b622d523f4aee7790c10db7fef79933fed06ab446c966c7f34bc94cbe194157f921a342c44eec76551fc1c6c8beba8f46196c690355e6c445b33fe34391f8e8be8f3916fdc7e703b7db6b6aa25d003b1f908aacc66c46b8af281054e67241364e7c35ac44c00e559ddf4aa65048b0b4df45b1084487ce8af1bedb7c6594f60bb3971bb0d8094c3459f24257737fc8aa7d97aae8549db7646653bd30b580dcfa3b48308c2318fc6ac487f0d1360f59be894140686b8229ed8cdcc87553bed4438b90538d44a98e9e25c7342712043ec359c83c97382522615e5de122b8d3857bb94a59228b3c1e813e1a4dbd02791cb775154483b3c0af8eba23b7c92a368c47338fce41e7d5c9b0a0257f03365729efe8f485a2df5f4e6a3deae49dcaa28dac92d5d9753b31bec9f7ce81e85c91598e34359530252d5db16f926977635f91ddad5e2cbadf561d45da739d3cf5b0e55834dbe46e9e30287e2f8fe0968da66955f639d0f418eabd4a17324d5b3df0a4008d06bd51716f22013ae8b1f79094476958ab84c9eb79295bfd29d6681537721f8055061afdc825a443f85defc43197230217da05533f32b71", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1670814713, - "not_after": 2117502712 - }, - "authority_key_identifier": "0xb01a35de26bde8ebb21c0b918658200207a44118", - "subject_key_identifier": "0xb01a35de26bde8ebb21c0b918658200207a44118", - "private_key_usage_period": { - "not_before": 1670814713, - "not_after": 1796958713 - }, - "tags": ["UN"] - }, - { - "country": "MYS", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xdb239b51311a1f69c5b920d49206e21a4124ee424e2321f2f46088cef957980cdfcf1e44433b9cc611f484b7328dea3dfe75874d46dc7659b2a0c866aca5420b32b7db7becccb5f912fc801e00e09e8752164ea64f14fe8fe9cef2ab55c5fc6ebe80c272bf4be881ba5dfd874eef8a357bba2bf62674e24a688b206799b6bf123f96159659250edbd9402d0975355228c2e6670e9bcc40a81b85e157172e8d5a89abd2808664cd30ce4579802a18ae0fe53304e9352733d1ed4c726733d2e91efba5d51ac8f490c81b5419a8b21042da9f61e54cdef133a6e7ac7a59502e1706010b86eda36ac70d00d933b2ae214be0bd2741da0c39457a05952a1ed789d53f7d10c54a95085f38818f9ab8bcdf7c13b39f0efdf3eaba2cdae94f603f07753ab12a792541fa8fef37299af35ca4ab3115b01d9dbd733486aa0de86b88048dc8aa85892e18b3816be3ba4461adab881662049fc0be17ed3a1ece887ca408cd2abd1547cbf5f89cbc923d562660d48df541664b0334edbc3fd59ef9242c6beaf1", - "exponent": 65537, - "key_size": 3072 - }, - "validity": { - "not_before": 1564139145, - "not_after": 1879499145 - }, - "authority_key_identifier": "0xd54dcf907ed448d2f40e059a3932b4660c9ec2db", - "subject_key_identifier": "0xd54dcf907ed448d2f40e059a3932b4660c9ec2db", - "private_key_usage_period": { - "not_before": 1564139145, - "not_after": 1721819145 - }, - "tags": ["UN"] - }, - { - "country": "MYS", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x9ef2b47a698a02d9a466255127741fd72147ff74a3036885fa5c74fbe3404f530ecd9462a85a10511145955cd9dc1dfe41248e565d816c512d8ab8b6cb2589243e66f15071c10aef12a62ae1b54ad3dd476ce176fa17ba830c922e1ab895ba3a8cd13b95566ad371a7866b1d34739ca093b0d269c3501802a87b103928fb2158dc593ce9e1fa5e2e8a21e4739d3714f7da1d5d50192c07dd9bd6c1f2acfb4905f554407d2294627f0df6ad5bfc802d9e428a57adc05bd9e86b7d4aa793570b48455d651cf26114f3fa9c8939dc118d0192a131bc8c1abae9f690f58e37807d200ba33df98dd1477fcb4a445b870c298f5a56579bb55bbf0f083eb637a26c4e89051e46cb23c83b3ab347d033ca666f29d9ffb4e8f2ae6f574fbad79c03e67c9aeaccd5c1e2b6e6fd4902942d56ffb1410abf1d05dc81c23bf93e7fb3d4dec3efcd71e13b4ce715c828c25f57028b168593b509ca080cadcfd2a9aa5a3f2a5f7e7cefc24b5b3aa0d966b2f75513ed60a682908be00daf3c122dd12c68ef835757", - "exponent": 65537, - "key_size": 3072 - }, - "validity": { - "not_before": 1671075532, - "not_after": 1986435532 - }, - "authority_key_identifier": "0x264d30fe7de3c25ca4bd99daabb36b458d29df06", - "subject_key_identifier": "0x264d30fe7de3c25ca4bd99daabb36b458d29df06", - "private_key_usage_period": { - "not_before": 1671075532, - "not_after": 1828755532 - }, - "tags": ["UN"] - }, - { - "country": "NGA", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "EC", - "curve": "brainpoolP512r1", - "key_size": 512, - "public_key_x": "0x0cce7985c06d97f303bff6885121f1103dfa1c3021b6df80dc33940528283a602cf32a10fd34e02ef8e19e2434f09e7bcb8b19398ad87a1bdd59e8d5035e8d60", - "public_key_y": "0x6161de7332fce8fbe3b4e2787d568b7dfdb8bf13b3a202619a19defcb67188f628849d3a19e6a3e9609686f68b4cd52523ab2eca44ff42548b396d12983f78fc" - }, - "validity": { - "not_before": 1721920069, - "not_after": 2052832068 - }, - "authority_key_identifier": "0xb37c6ac75a677d9e4d1e7afac1debc09bdf7d39e", - "subject_key_identifier": "0xb37c6ac75a677d9e4d1e7afac1debc09bdf7d39e", - "private_key_usage_period": { - "not_before": 1721920069, - "not_after": 1820416069 - }, - "tags": ["UN"] - }, - { - "country": "NLD", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xe80e2286a1e26bb476828313d4056fc5c49e1ac0deecf3cb89656c650a7480917c972797d5b8f20bbec740ab86e97730255cec352ac9eb8350151398566f758f35e326d7e4618a62632c4458ab2410e411663f604c255d9376369d909eac246b79f9e9dfc47034e810fcea43d7aaa7da0441bea379119b387775f807a456bca1ff119b86de0eae33fde09eda6e90433940eca5f1a6cd474d66193c66067f594b2d1654ce47e044694ef6a5b51be78949043521072e149010b6f95ba434ac06e82822dbc95c903b80f164db991b0289ad76ffc7f8a15317446eaea3a0630ea3931d44f6841acdbbdfae912aee21ef0c75f51f56a07c97ba2a14865ca3e26f63dc2f9f75d957eca4426ac6f60bfed618314d8f695d0a433772fdfd81e4906ac20bd5fd22a7686c6b29d42838554ead4dfe14d88dbe8cd5a2b77bdb637db4bc52ce8000d2a3ea4f80cb56ec33112e4bb89c44f4d28719397e08a4dc638582ab3708924f43a16c0a1f5b6b2d9d306421ca752fc275c01eb50c0d8a678c06136132d6c425beac54416cf8a2013f5ed32f66d6f6bf9b60975aeabbba81ef9775503accecab2b1db44f53123765eb751fcb2f8849f30b2200e40c2d4b7be034c434de3a1d25864c152ef2b0a7082fd5e9a0ce7286dcc2fdff430d3547a3ce1dc2fcfdb4b50e8f8b2ec4179120dd5b05c3b262d1def20c032996e58205eb07557e7d8f4d", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1392940800, - "not_after": 1803945600 - }, - "subject_key_identifier": "0x47bbb81bf0c3984096acf7f3edef9257dea77534fe56de0d80cc7c93805f4241", - "tags": ["ES", "UN"] - }, - { - "country": "NLD", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xc655ba75cbe85165a08662c1e0efc62b3aa62b945aa075e37ebb57cc26a455e30d0a71f0435567b4410e5212b4827e42fbcaed16663031ebb9ae4837da1061e067b02857993eef208d2c64a42036ad32e54293a3145ca0e8dd3e1038f53564ce6adab66c597c1c591e4ebdc447181ca08ccbf6e1812b3aa2eafee3360e72765892f5139eb92b72638623751fb48b8c1c5553ed5fe6ed6442b1a2505616aecb935afcc04a47b2be077840792399856b93f03be495336b6224d5231b610ddb751f8dfc02fd551eb4071cb739aefa2675cce75bebd75fc59f8e69ae318507dc9560313d9bc969e93e76c6679afc0cf641898fce627e33482c99d89eb6822b8d98ef085fa5a26e66d6f8549469dc0bb66e04833a0dfbca7d46108dcfb6ad712ceb2b5e3da21afc5a9a0a6e20a2e9e55d77a5f0620725f9703e8347288e5dfa0e08b9364bd9b5b1e14ac87b2e70a3388357dcc00dfbbfaa098dbfe4f92ca6fdce62b2bb45c2bb5586da242d072a64275d79921ac5dd16c640045f133279bf76e96c5ed623df70275eeb03ceaa30d849968dbbe859de1ff4f24d5da41391215201515205453de1e4a0a2e6bf9072c95b501cf2e082ea662edf1a93f54484e429e838f99e493b9228e2e0c1ba80eed64e0cd209d454495eb7bb8907eee2878c7160ce459a652e751e9fbfa04a5e8a6448727fd75f59e2e0546d49365d0e01568bf4fe41", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1487635200, - "not_after": 1898640000 - }, - "subject_key_identifier": "0x1800c0ebcee2e5e3bf2f150f75a5b6245d5499707886496e2af2ce37850e2d30", - "tags": ["UN"] - }, - { - "country": "NLD", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xca3b91805c9a052c864c5314faccfd45fc93ec1007100dbb74a3be14d53501f54b89a97cda5066f1ad45ee42a814585296b885350047c5767617199601aa88d674d868c9dbeb6b8457d9c75a03b1f0c6672ffa30f84e9b110eb7520e480c031d803a0ab2b7ca000b014fb06d38acf8f1d9905998b19454cdf99134ff5cc1683ec99b7356139e7d8184ae125f076a498ca1fc1d23b753c2f75bcc644c9b960fdb243f0abe5d276647341b3407b2f960f0bec199928b723994e0992b3580a3fd4b3bf0bfe36ecbc6cf34da63689e9e3a9bfe58cfd331ec7c821c8d678d111a6ce83c0a7ea56dfdd9a79bfdd5f65baa07b244ea7143eb06e511230778fc8ebb0079b761071496e0ed73ce596eaab7b88be2490ce08c4e2b8267ec2fe64bd7f479d7db763df41a27eb3eb835c57ff783a24d62a803f3f91fc5515f9b348d66268e5f8381b0295b2430d230daf73951e71ad567295a89e3c20c388e979c65c4512645d6ae663779f3f6921db3bb7e6fdcb6c4d43443c1202fec68e6ee8d962bb79b60e33d6afe1e44c0689a8ab15166015c4086145174b0c7898f72e5b12b1fd069de7cc6245ec434afe3cb30aec29530547316f14cf8e053cfed09cf22c57d85ca73c2f5e049d3faa066fdf993bdef0fe970323a63f23543358a65090c58e87326d975522947e9de1eed40e0cef2b674b46363bc6a34705e85b661ab333d1e2ceab9", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1529539200, - "not_after": 1940544000 - }, - "subject_key_identifier": "0x38e3cb31657273660c4f733415c1803aebd8c1f390be3cb1fdf9e2314dabfb71", - "private_key_usage_period": { - "not_before": 1529539200, - "not_after": 1624233600 - }, - "tags": ["ES", "UN"] - }, - { - "country": "NLD", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xedb926c1da808c8b014daddce244ff88b62291dd52dbc0918a19b19b882c92cdc1cf479966a134f8f0bb31949e80c50d05f2533004c331115c02f08def0a0faeb51713aa6a776c4e26ee7cbac68b768bfae45c24afc2a046de573bb4633c1f2fec60bf7aacf6289821aef65dca4e81d0ad1a7200e1c408f489b8706b71e4a123bbc964600317c1f5c3959257f0fc8217e338662919874622a8e44bec22a1020ae04482a16bc28d6f922fe27d64771c709912c14f888c4542638ae80c8f6cd74d968c3c0558bf673d88d0b407612fb8bdd48eccb33f2375de312982fa9bfde28258371fded762d85f2a7847fcce5ac7d16019643bae1a4cb27bd9690dbfd1f6393d3597adc9962a18ea8295bd6d25fec112134a4e2bf610d3bcf145921edb968be330b4022e75b490b3de3f339c744a7fe676c39628cc553efb7c38ffa3b395f2ff500986372f47681c4f073d192c47684ed546fb77c13262ad45f8a05ba7ce90b67fca28c4d47349fb35c24c478e75e98316d69d375241ddd13199bf89a63fe89d2613a1a7d7a6a6c85fddba1c5978617c55e8b5dc2a35f0c18b9e7b9a756a010efa1dc2695a613ee47954367368eac65263a1920099edb0610e94d6386f51269c5ec46ebf853202d83c5818e16e6fb3974440c923115ac15eeedc797e4b5819852f498f71fdb165eae0320d080ed75de235159c5865dc6ba83b3bb8c1a7afb3", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1624233600, - "not_after": 2035238400 - }, - "subject_key_identifier": "0x54dfe2961c6cf463df081f7c707da6990024e69b5a42770541abc92fec95a5a0", - "private_key_usage_period": { - "not_before": 1624233600, - "not_after": 1718928000 - }, - "tags": ["ES", "UN"] - }, - { - "country": "NLD", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xd2baea5091f4ea56ef17dbe4a761269dcea1b6799ebc8ef08b30f77b79cf14aa9b56c846943f82f55291c163f8a1b4285429ee1b873c97e9e463f878c29329165c5227d5bbb9dd03aab734b6468a4760aafe6f59a011fd1476fbb2be0d499df95e48ee7d5d77f6e4fbaffe37b95427d3904ce92d3b7eaafcd387968078879964c48aaf7f5cf6c90b25c227f138879cccedeb99330050583e71ebb0229f679c841563172ac86d122fe94208d503cfdf0204d3363f823215a9638bd9961f761843dbaf0fd117a407d338f43af535c3aef27d80e9df0109fea5f946141f169facdae8a25ae430855080e69a48f082cd8d39b985927a0bca89125567f9f9d159e703eeff68dbd47f956905aafb198d05ce60b3e738cb1837ebbee469c6be2bf4f57ffe04c8a095309bfb9610586ab942ad8af01ad0152f3c6ac4891170cb9eda76b05b6e01aca4e2693da8d7a9773812f4a1692cb63f237ab0ad6a0e09933d5c28afbf6553130e5a0cadb53bf419847bc964f3d37328865afe79a33993a16f1860d1af45e0563f95b8c81663a94199cc2ec480c7fae7d65b309dea129011cc7c1fe55be8f159257ce743df400e09685f17b0b5dbbd5b46c4ac559904640dc91a9d9eeb588363889ddb1cdb5f017af7e2061ef077c2ba61c817ed2fb930cb71f0b63feaebe893636b2595981ad497f8434e64af82f305488f29a872e70b89bcaaf6a1", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1718928000, - "not_after": 2129932800 - }, - "subject_key_identifier": "0xf2423ba9c13c6815d65081792bf7307129046f336c2389950b82e998ac3bbca4", - "private_key_usage_period": { - "not_before": 1718928000, - "not_after": 1813536000 - }, - "tags": ["UN"] - }, - { - "country": "NOR", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xbea54665ff4b833bdd32c8055ce0a2cf1ca2333d93c036a3563b6b5e2e7e3171f6dbb7779db97d4961ea9f1644e2657fd4fa74a48c66f1f0633ed289f97f88b4bcedf3d58d832f75314c0aab6d12a11015e0293d06d8def66a2ffa8b2de2930a49a069135fa0698c8e13ffa7ca741969289ebf127ed9643b6f3c3156361d61d298170f3b7fe91b5c6b4a52c653113ead17542f06a19eece0b105eed8bd005290c7744cade202e109c3c4d51a6a17f50c0838d8cad6c70d7f9d3f727960d9c411b70511531ab415ee6ab3eed41890b0147ef82eb65429dfa208218ddfd4dd269f34339349e4f83a4443fd157c844c4b8af5aaffdcbecc61cd6138abca32f50a05968254837337a45cb9d7f725b98969a4ee94d74ea8a94c6bf5c2c12cdf569c9118270de30eb208e19823101b103c6d93df77ff1bedc7d92d31ca9a42f7e0674426a376969803177c3dd2ba04ec56c395738cc9afebed972cbe496675bb56cee48363796d0271efa756aadd44c1659bd53c22a9758e12b68aa47356b2af546a3d4860d18799b2275939ea6c08462ac68e40f9013cbfeb372501d5f81851b024b70ea114ef6d298cf72b6a98fc23071bb647bb0070c7e401617222b916014824675845b9e6c09eb34ad85e731d994c2246548b95afc8489e3c4fa3e2edd2a5d263a11bc7573b692e834915c0a9ae2f871eeba1fee03096d13d628088e5328ad7e9", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1290762755, - "not_after": 1764148355 - }, - "authority_key_identifier": "0x9e131c3ba8446596db86bcabd6a630e19b379d39", - "subject_key_identifier": "0x9e131c3ba8446596db86bcabd6a630e19b379d39", - "tags": ["ES", "UN"] - }, - { - "country": "NOR", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xa7ebd58a1583d810dd66a561f46cd81746b41af372f1dfb4cd846b2a73fa7e1e85a54be85bc962b5b9ad90e7ff1678e5a9abcc9707d346a000a7aac5c6264bc6383b3e66512526fd2cedad9a0fc80d93f9cba2b9663de9b8a47aa954d2e8024935bd5af7bc249a48f081ff9822afc200018aca6713c654b844bbc9bbee6f14c50cd39b23d431160195475cde449a8b7276d08377a026472bd7fa0bb4a49fb6060e7fa89657a452b35f9efaca91e005e90937ab76d4f9dbb9957774df02865d4ffbc2923fd2f59efb3095f92fbb7b3c566d3c37ea9c86b63052fdb615f100562aaa7a1ad7d1fcc185a10d70f242362b93bb6bd496c62769826bf3ebdb785bec499986fdbf346d9ace1f5be7ad290c44743bbde1494d7a695c124bd08b8b79779f1fa708a61cfb0cb741f66bd4600709574f32d86f31c790591d4699ed5930090957ee6582224c32d21fab64f96af3c845451dc0767375d7877c3ce3ca3867fc99e3828a2900c57d6ffd2ca1db3a8af86e872a5c4e82e9d0da09d4dd75f60fb1e143d3c36bc7b9341ba8e821a2a8ad51095e784623e0833f1c3ba5b6d172ceeccab5aaf7d2eb39581d9f9baac0dd977aeef8581ba82992788310a0a2caa7d7ed59a56c27e6ed0d21cca437cbc53351a4595c87adb72e40f30b4af2891b5fe46efed3ecfb643786b70971d393b4797b15b0ec968a90eaa4d8c006389203a9e62bad", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1336650604, - "not_after": 1809949804 - }, - "authority_key_identifier": "0x8c717e41711bd2920484e269231d097da9f67758", - "subject_key_identifier": "0x8c717e41711bd2920484e269231d097da9f67758", - "tags": ["ES", "UN"] - }, - { - "country": "NOR", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xdc040558abe53f3572abc0d126aca33b140f76cc016bbd6ef3e56aea0d7d46a622f3daf6930667cdf379eb97b2e44b6914a7eb3759d9c39a8a16891701cb1d3006aa9918653f5d67dbcbcae1044f940304349fe58620170d9404017045668f9c81a8cc4794d32e645e4a0c656739763b3aecfc450dd4c1e9e5c0b739128361de8ce44a76b9360f614dd18285b09ee4fdff463b4923589940c38a92f29d06045891db8e310bbf0f5cbff721d7d23baefc3359b2030753a9ff651306c186f5b2a4f6fac486dac4bbaaa8d3b8b67a62c2de2bb72ae2fd041f5fee51463730fe9f2b31c970d2af2810f5b608e4afc6453ba5b7bedda4fc61a52698050a08edd82f2a3aeb05c75ffa0e2cc5fc352861be020aba622073cd270942bbdabc6e189455e40ea4ae1785dfdd93706bee92082021831404fbd16d22e61b2ab80f68d5920d9df85e4b3b3a0af294ce2e891907716a86761f3a2fe661dc3ccc3b4ea614c135a5ba6fe3cb893b973adc359e0e7c8f42b1f312001740b7577c2b8b28b676b7619c7ba673ae548424f0b6d58e94d50b1f300159bdf645a913e075cb393fc14e30c7a4663a1c7fdfa7cab363a6edb8fba213750d40cb6b93046c6558302956937fa1246a39dffeb215377671d6dcb00660d62de3a36718644230bf485dfdfe26c48518aa28bb73a095ffc40a98649040aa935796364a216aba9fef4e776739e8af2f", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1494231342, - "not_after": 1975047342 - }, - "authority_key_identifier": "0x1fc3783f6d73221d8f67af50a5650078a8a14a70", - "subject_key_identifier": "0x1fc3783f6d73221d8f67af50a5650078a8a14a70", - "private_key_usage_period": { - "not_before": 1494231342, - "not_after": 1651911342 - }, - "tags": ["ES", "UN"] - }, - { - "country": "NOR", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xdd1f70c380b4d29733bfd2f658b0e47d31ba4f1b9ce5af14afe7e715eeba17ec71870e3d447c42483c3e9b2af4d80cb6a32da1f393a168e1b65d0dd0b103f7e67c570486bb7c975c9f72cf94674831452e51a47aebf525695c6ccdd5432e586702d433058ec63e63ca4070778b690998a1abbb1dad17871bc37fd4a32805c140c7500ec06438571d4878d5171f9f80ce99df52e3d78bf7ea1fa87d658fb60973096fae81d74180d12661ed4763a5fbaf3e2d3bccf3d2ab759632085f9cb25f28bc1aa2e2b046b2213550b3c04729510b48884ff3e29b90be322bedfcd5a8b27fb8fd48bfa50038c6bbc4025619ea8124acd3dd80f332fbde41f63ac1727b20802494f4b5fc52b40a448164ce6d9a7d65a69c9c73100823ef7585a28b364326edca5ab9c30f0088e778041de1d7badd3de07630a817d8df65ccd58fa91dbfc0602bd01fb4721ccf6f14b13af5462fce2b3240c9bba850b67fce21451947ebb1fa9d462125729c7860cbb0a9e8580b6ad540a086e60da7e10567d8601caa0a4c252ddcd77200221f538040aeea42725f4dee3e5b7a55b4aab99ccd618ae6dd223e511af69efbee8e0076643f738be34ad6f788957c0b22f3c8ac109d39a73e584c4ebd1b532db45460c64de6fe02163ecd6a66168f40a09884b6a47aff29fcde37f71a7a8e1b9ef94cf1b26066b27ebf687d1c43f56b7869847f1327244a7d75cf", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1651133909, - "not_after": 2131949909 - }, - "authority_key_identifier": "0x70f756d2c18b5a088c9e4746bca9ac1fe6386ae6", - "subject_key_identifier": "0x70f756d2c18b5a088c9e4746bca9ac1fe6386ae6", - "private_key_usage_period": { - "not_before": 1651133909, - "not_after": 1808813909 - }, - "tags": ["UN"] - }, - { - "country": "NPL", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x8276c57d303930614b14cb47bde0caa3ba4695a3838f812d3f99d3ca722519f291332d37b2789fed0812f7cd31c0ad80575084de137735bf7432dd47a4beb61968842a8c06ef21a0a84793ad45dbccbd5f87f73976fd7d2bd5440ef3195a88eb8f8611daa8529ea0ecf60e119cd8c46b0c0619bdcbdf857a68659d7ee40411559f9b7bbda58a624e1df9b889b6d80f83e5e1e25c86502e104f4592295f85735eb987b723486ab663414b976584feedca8a7354eac87c5adba3b47a8feb9920693f53f70a89b1ee66172e39fbd6470f0fe19c01464c4157e0af8a141aed34b84c0d68f68632617c0d04db5408260d46181b4c7003a12113dd06b6e7fac44efbb014a9f84a3a75d4b5e034d667e08d696afb78a4921735c15cb74a414c6c2c5352bea23553da5c8badb211b39d1a5eec2885b93184365853431327ed954790197a37a2c7e11b4450ce852eae2f94bb40d05a2541b9434bc3fe62ed0b64fbc542ea83a14b19084db030d2f070f74fb0b7b26aa2792824c61c3dcea87b1380b7d1d1f86e5f3bc0ec309f9adc58587b2d717083c8e5fadedbaac0f2070effa8ae5540d46b86b4e2782e17c70a42d088532503411b41b7ac7715bafa9cae8bf91311e146aa6772e2c5108fd6ba3096f3a9acd3300c577a10da73aa25b44a742d24e25dd8a712a12d2213abc6cbd69fcefc7237f5135c882562a2da65d39bd85ae44261", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1634981223, - "not_after": 2077435623 - }, - "subject_key_identifier": "0xbf92958fc8f4c01842248fe197a66e0ceb0889bd", - "private_key_usage_period": { - "not_before": 1634981223, - "not_after": 1761125223 - }, - "tags": ["UN"] - }, - { - "country": "NZL", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x99e05fc77700645190a1e6f99f7a0f06e57d724672df439d36076d60ca874cc367b76a62ab995c18f3d30cbc9b6c46e9c9968779d69bdf9b1a6d2b62bfc70a778252b93cf3d775860f467fe8a9ef28ec9fad291930ac777fda3e7a80dba25d8dee25995db764f9a17819a743feb9113a10b45742eb424e27ef58e9b000fec2f04e7c29b6e60a98b32f28db8792e63705261d5411c0cad03d4587b42b1d9af6d5e560d5b77383abb85abb65db4876e5e21670d19f0cceda4cff3aaae94c5b76a572fc9d83f62c5841cf7fafa43a432acbef83f0b41121a3ee853c9506bcb4310d727aeee966f3542d0709c0baa1b9dfdd94d0007b708c424c8ed011fdf80631649ffe54b49b4200fb4cfc159b6223bf46168bd04fc21a481a36966590efd96afb3639d119d84b4b97f7d97c10c0d58c324187156ef297f2e905b22df527e2f850e377eb8ca71d08c8b08a7b8e987ee47e5d3c1fca3f4ae20382b211622aaa779a86b604706d7c6862fec5bd2fe1add329c31a55d6579fb580b53dc2144887a3a710851f9d24b402918bbae9ab19f2471c15a6ea1b6e95ceec1aa3365ea1792ae7231ff07b84e49a9c99ae929035762ee192b96997e3b35a8c646c53259db9c31b4c719c08ad232f557bbec88ab10b8cf528b1046c5ca5905f8c55247af44b4454141f64ed5577b3b53edadd0a34cbbba5d7880b16108e69442def973a8a5be261", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1440469872, - "not_after": 1869102072 - }, - "subject_key_identifier": "0xf9d6c969fe97d184eef2c1d7e520b66032be3df7", - "private_key_usage_period": { - "not_before": 1440469872, - "not_after": 1539054072 - }, - "tags": ["UN"] - }, - { - "country": "NZL", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "EC", - "curve": "P-384", - "key_size": 384, - "public_key_x": "0xd839c3eb261454194984679f06e269a89479a85c24998ddf32cd52ab1dce287cf3eae5c57bccf4a819f88f6b1b997765", - "public_key_y": "0x6c0cb60ed8d3a10cef81be68ebe2326fd9bed31cad0765a584abe53b91477efde925a684cbcba9b61fca6e77aac66e47" - }, - "validity": { - "not_before": 1523835562, - "not_after": 1944171562 - }, - "authority_key_identifier": "0xd69e153bdf94986c1ad2e981adadc331af71be71", - "subject_key_identifier": "0xd69e153bdf94986c1ad2e981adadc331af71be71", - "private_key_usage_period": { - "not_before": 1523835562, - "not_after": 1618443562 - }, - "tags": ["ES", "UN"] - }, - { - "country": "NZL", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "EC", - "curve": "P-384", - "key_size": 384, - "public_key_x": "0xd00ebb5deef604501faf9313e88129c0bd250e10be9892e254045378c9bcce03662b39deb4373407cf7578ddabfdd58c", - "public_key_y": "0xa40697d6258986d533d22f2c68f27b86c32fdaabd569ec6698ff074e7e6c3b6cfc659c3dbdf0882185a7491179340332" - }, - "validity": { - "not_before": 1618275819, - "not_after": 2038611819 - }, - "authority_key_identifier": "0x9f0e2c1f92584c08e45bd30df8d8023c7173fa8d", - "subject_key_identifier": "0x9f0e2c1f92584c08e45bd30df8d8023c7173fa8d", - "private_key_usage_period": { - "not_before": 1618275819, - "not_after": 1712883819 - }, - "tags": ["UN"] - }, - { - "country": "NZL", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "EC", - "curve": "P-384", - "key_size": 384, - "public_key_x": "0xd94289f5b218fea74abee73da50084d2fd51b7e6c6fa70b37b4e582a41ccb9fb0b7de4ad6a2bd0b998b5245d8b075fea", - "public_key_y": "0xeb30c1d11b8ce0a56a3206ca3301f0e4624249866bda9d8d1cd9d79b95740c946d328644b8341fc07644ee2877053911" - }, - "validity": { - "not_before": 1620866032, - "not_after": 2041202032 - }, - "authority_key_identifier": "0xae693f2659eb9a83652d11f7ff4631ac3b14a035", - "subject_key_identifier": "0xae693f2659eb9a83652d11f7ff4631ac3b14a035", - "private_key_usage_period": { - "not_before": 1620866032, - "not_after": 1715474032 - }, - "tags": ["ES", "UN"] - }, - { - "country": "NZL", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "EC", - "curve": "P-384", - "key_size": 384, - "public_key_x": "0xf2c39c8f22ded2b98376aded078db1c1f4b510aad1f20a119c4cdd1242433eac7b764d80ab7c40006af6d62961292533", - "public_key_y": "0xff4d203211de15ae45b9836f878e9a6c1c90c3fde2af66dd30d9cd40911efc1a2e0ace2a7a0165c979e1978e635ab857" - }, - "validity": { - "not_before": 1707781443, - "not_after": 2128549443 - }, - "authority_key_identifier": "0x0a6c72c8782ed0e0b9ca100b53840d1209cd78df", - "subject_key_identifier": "0x0a6c72c8782ed0e0b9ca100b53840d1209cd78df", - "private_key_usage_period": { - "not_before": 1707781443, - "not_after": 1812930243 - }, - "tags": ["UN"] - }, - { - "country": "OMN", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "EC", - "curve": "brainpoolP256r1", - "key_size": 256, - "public_key_x": "0x7377ac96e00c303fb231479de9d3ac10210e7d252cf7c7ba231985ba845bf6ea", - "public_key_y": "0x3b8aa75001c44b939a0a9cf9cb74b1dfb08be72a2704e5daea6aa85e7b5e2e30" - }, - "validity": { - "not_before": 1405382400, - "not_after": 1886716800 - }, - "authority_key_identifier": "0x5c3c835c76755b54782d104ec36cf5362e26dd57", - "subject_key_identifier": "0x5c3c835c76755b54782d104ec36cf5362e26dd57", - "private_key_usage_period": { - "not_before": 1405382400, - "not_after": 1563148800 - }, - "tags": ["ES", "UN"] - }, - { - "country": "OMN", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "EC", - "curve": "brainpoolP256r1", - "key_size": 256, - "public_key_x": "0x23557d023e96fd874ba00700e0b12e598544224ea8b0fb38bc76321dd7f0a5dd", - "public_key_y": "0x69906ea22d19ef067add0f08f51329381b6d0864de2228688c4ca61cfc51e4c8" - }, - "validity": { - "not_before": 1562025600, - "not_after": 2043360000 - }, - "authority_key_identifier": "0x594e4df6167ca9ead0cd5019eb994b15c7c3647f", - "subject_key_identifier": "0x594e4df6167ca9ead0cd5019eb994b15c7c3647f", - "private_key_usage_period": { - "not_before": 1562025600, - "not_after": 1719878400 - }, - "tags": ["ES", "UN"] - }, - { - "country": "OMN", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "EC", - "curve": "brainpoolP256r1", - "key_size": 256, - "public_key_x": "0x22a61230f2249d497ed93cc302395f110aec2f9e4188a64cb96ffd9b5bc88434", - "public_key_y": "0x91a908ba62da30b98227d6cdad17b3bfe34cb49ac793c98b2235b321c48e1dbe" - }, - "validity": { - "not_before": 1717459200, - "not_after": 2198707200 - }, - "authority_key_identifier": "0xf29f2ed7dd639d2ba6a24426b3ad4811e9ca273f", - "subject_key_identifier": "0xf29f2ed7dd639d2ba6a24426b3ad4811e9ca273f", - "private_key_usage_period": { - "not_before": 1717459200, - "not_after": 1875225600 - }, - "tags": ["UN"] - }, - { - "country": "PAN", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xe21de271c95471d95815fe35ea9454e6eeae33965ea2581eff647c9d7b6bb67bd0e653178f002e476d711a5d3f8dc9d195e68a110cd82e8f9e6ab143f039548db83d47105d35d504b53d0ebf25f236469bb0d201e508d97f8d64c72438c044ced98d6f89ab62902631c1035f4feccaea3ca850b5d11fd2058cbdb7236691cc44bcba9b60224a55ed4993cfa00e75197748ad2564cdf92c2c3c60e145bd2b4f8c4e52e79a686e559ea76dc43db47029cca408315f95dafb17e6a97d111341901f05f9ee76b6de10d056cbf5d0777ab75dd9ea8d3480dc9b8bffc7d4c461fbec9a868dbcce85505f99d0bf6b845acfa9d90d6714428fe9560808bdc9e526dd1a841847f56c129c0f315b689a0d98e4ae1dcb5dce74e5a90ac0e1f5dd238ac1cabdd341a4f163e8c4ba15738ff3717215ccd2a9e25be1fe319a75a5a4378db96a71ddc67d9a672f52c874a54c72783924d28bc982f1189d4edab66c4b913780baafcf89dd5305488261d3ff3b705c55664bc2c9979b97693203feb4f09031fecad86f7c15ef2bbaa1cc6c4609555e8268b8b8e77e75c4e4826294c912d7fe1da9ca552fccb1ac5dad3de3a6d501c7e268f5ee415e84cd79072150c367453258116559272da03cd1ea516266cfb3002e086bd72ab15ece6f664b92dcefbc8a6a3002e0fa0427ccddac38648ca5372b738d19cd0d4c4ba83471af7ee2c5cb30df80ad", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1615161600, - "not_after": 1931472000 - }, - "subject_key_identifier": "0x0d352d90ef3c5df0085efc48b634fdd7689fc3b5c1dabb74f66f9d34c2d1f403", - "private_key_usage_period": { - "not_before": 1615161600, - "not_after": 1772928000 - }, - "tags": ["UN"] - }, - { - "country": "PER", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "EC", - "curve": "brainpoolP384r1", - "key_size": 384, - "public_key_x": "0x827de5cb9db946d16576053a1fe9742a66cf7adb130df7b53372ddc90c9c70d6b7dba7b03216207b4a304bcb9a3a9a59", - "public_key_y": "0x58117a59405c738ecf09c1e3b9fbc3102361dcf30f29970cabc031535c96858a36b2842283a9f038a3d879aafe6ef86c" - }, - "validity": { - "not_before": 1455667200, - "not_after": 1936742400 - }, - "authority_key_identifier": "0xf4aa24e5accb3b9c0f174e913de43fde6c9a7bd8", - "subject_key_identifier": "0xf4aa24e5accb3b9c0f174e913de43fde6c9a7bd8", - "private_key_usage_period": { - "not_before": 1455667200, - "not_after": 1613520000 - }, - "tags": ["ES", "UN"] - }, - { - "country": "PHL", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xd07a3d51e2b19257e19222baf6fcbe7a04bf93db66f9e62306e53a0093ecff8dae48a48dd05cce2d13109b5c9f521b91eb11e3f8888913bdfe68ba34b222b66119fb77657ee822a0afe1360c5f22778a0173eff809da996eb2bfe348ecf2f13ffef1f3243a9cb1259356b985a8977edb634847befca395c7a3ee68f49e0c06ba39516873d76fb7215fcba2b2cc420cdc48a4693b91295d8e2aa3f09849b1171feafdfb31646411c5a84766b9e13e33aef57f27d34b4a36cd55829e1556415bb493093bf5a5ae8b11bed91a245e2c1700ab8dd72b4e4ec8635551d2387d1b8f0afe4cda3e194ae27a4c83a556ff12938908b84fa7482d776b5351ebf2b40f83c11bc53a354d2caee968ef2c4ca7a2a145ed1fe93e0a65c16cd571419490a99e0d6174c3dfce596ca6d9a058c5b471af7db8a22992f07560c07366671cb2ff29b831c8a13ecb432e8b0ee5098e1edcdb2ce9ef5f33d2def1230bed6d850e6b32e0516fd62c576e2f0976b9c5b4de419541fbf4285e8b31f643f3f62c8e5d4633eb298236388857c5ccd820e56e1237e7cc25249a3ad30e695c48474c7b31d7d8a5fec42f258b8a0c69413878419ded805f109ec8bc165aad76829beea726c1bd3e68b041dfde8957ba318c2970ebc8bf5614e0fb4218f920c78cc9f916fff8c74e04145ca9ba14df966c97da84ff69a022368c8ad8c51fe419e547236624920607", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1454428800, - "not_after": 1770134399 - }, - "authority_key_identifier": "0x930ffb1bf7705579971b202a66f0321b4c2b2e4a", - "subject_key_identifier": "0x930ffb1bf7705579971b202a66f0321b4c2b2e4a", - "tags": ["UN"] - }, - { - "country": "PHL", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xcda5dd31a8bfbcad0388c92fe230293e1588e53364f36baee28893ddf38c68e6f482f7ae46b78ec7c01352a388fa014b874ef9cfd788ccd4184cdc1967fe452797dad46abb912be1268c0f43633d03041d31f93235425a34059d0492556064544cad3f5005e2fc4ce955dc4e511470cc9546401ac34b3d2c6b9144b2fc28397f056b1c86379be40f02baedf374a100158e50a774d63c4f651de59fd4b9a0978698574a27dec00e55f350e4ec1d06ffadd55a49c397cb85180ed79ccb8d85322eef67c1c41237303ef90998edcc36aca97af1725677305c94ecefba68ac999669643beec811d2ab673fae3b6b222c3557debd78f8daf008fa54c751ae5c9aee0885ca940eac8282a2bde4730b0d0cf87bab8532c5aee46a6c7a34ec361cf47e59c55359ad7657d771f4a63d1be8601a453a708ac7fa0e9925705a78b0c321c232d79c346dc25d6596d6d3d58f51dec8b0bfca75300ee63f1bb3ea8cc6e8da7473cff85bdebf4e2aebf27603738b9741d90ea904499ebcc870101d4ae7902fdf8c94e264c0c3c619834e19af0f369d0104103a4073f7c81cc1924f39a758e5b8ac8a37d612fce7282232e6b44b23c04aae892efa4d5b2fd6846b32815b9b0e08852f532750ecf8a13342664affce974dda8ddd6873ddc0d647edec2a1de530c884b26305e1d135e1f48f5010e297dfbca05dd861e9c6b2f195128c8abb60deb685", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1560787200, - "not_after": 1972310399 - }, - "authority_key_identifier": "0xe565e5d20737598e3d938fc3581660804399b4e7", - "subject_key_identifier": "0xe565e5d20737598e3d938fc3581660804399b4e7", - "private_key_usage_period": { - "not_before": 1560787200, - "not_after": 1656691199 - }, - "tags": ["ES", "UN"] - }, - { - "country": "PHL", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xd24081be6cc14fe3fb4b35ab6df1a7f28f373017ef15a26b67ff2dd04773a3ef8942b7ba5f2f91aea469fe757e2e3362a907610b441f3610f528b1f39739a132c4bebc26c37d25b6d12481336fecddfc6bdcd011be4f2912ff0663cb70d9938280813dd3f32f2e6fef184881f784bbd2fd2d165b169d8594c45d832dbaebfdcb532d6542b57413825df5164b577dcdc248dfc4a8b071eb0bef021128e9172b77a18a5a6b00ebc0e07af0a9df6592684805a4ba0db00dddaabf793641ec0da51aecc6160acd56a0194d1161271b8feaaf0ae851ae65f1464c79607bbb237de3dbd0a299e9cda846c362976108d10555b57866a56c87c6a5d92d1888d6260fa90459afb14688b8a53921d2d477d1677518956412e01eb2592b27ad62a3d3a50777c4bee3f348b4788bb7bbd38d6bd902968a7b3640d75f98b78824ee9462e1b2d405b8c1ce7d7dbef479c2979553790b7d7fa8a6f05dad4cf95b92a218b410eb5b9df712d099b6952a07f122d21e95b934e9a765e758397b191fd01c0c4ae669039a0d7003308ab78d03809752bb7b676c3f3bbd9ac4b8cf0162efb50e01c52e3a97fed31d1e73f12b3da7b4df87fd7e93f70f92dc154d0bcef5a39c9631b2b50c7c7b91f4a63d4e3d487c37fc63bbdf87b71cad5581409661d15f77ff738a4d53d23424d999490607ebfd8293b2fb5c269cd8a19477ca88f6f7cb1abe00fb16c9", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1656000000, - "not_after": 2066918399 - }, - "authority_key_identifier": "0xa1436db84f1c134e49b387da56cee801102d4f73", - "subject_key_identifier": "0xa1436db84f1c134e49b387da56cee801102d4f73", - "private_key_usage_period": { - "not_before": 1656000000, - "not_after": 1751385599 - }, - "tags": ["UN"] - }, - { - "country": "PRY", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xeec067e8c196c72c94425aca24dfe40b6026871a8d1e656c3aa2d7e971517e6e59c75d1bf86ed72be033e35d79d104a7646b1b20acccc81f23e93a4529fdfb155761a63849b6c0be3630ae19e298e99de388ede1805a9584c4bea2a0d8eed9976864268ed928326a4f70594980650ed04c703f759c6748b1fb430e4f2f6ef483300fc6658c9a30b5e6e9b433085cfda979c7cdcd07dc226cbad0e8c53f6c54e322f5b2a041b5df7576069f953659bebd5506a2fc1b1dc9ccb3646b9d34a0c30986dcf291f3e50e63892853a3af24177c1dae312b4de02d5b7e120d8a222c5bb45e7fbe8f28a91299c75a2ce09d6a2f1ce919b77b85e6fe13b6a813c53983985a989b851334cb086a3f1b1fc0992667b8849b7bd5338930487376997923f40313e49a4cceff8c2acf4f012f41b3b9085afb68b82092b387112e6e59695e57606de8a81d418798b3656a924df8e676d5edd9aadd77ed173efdabf60dc34cb7d055a0ca2786cf4e6bc369f4c0ce67341eef91cf3224ffc80f45fe18e244dddb1557f4a1dbd47434fd248dfa4f1266b4395aff700c82461394e8c06826a14e3c3ba68517fd2377910cf2cb61c0f17a6d9f7783756aa0b5e9bfaa9dbcf2a2a1b199ce8a6bd0f2ac8442bc3d4a05d684001b8f537a1ada048f4c96a72b3a8d8b2e88af1877413888f9e386c0d6c5ddcf4c9350a201dd389bad76f35019f4e3b0a8dd37", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1636689600, - "not_after": 1952308799 - }, - "authority_key_identifier": "0x490ca0810e531e67c1c7dbf28e0a65d0e2b0215c", - "subject_key_identifier": "0x490ca0810e531e67c1c7dbf28e0a65d0e2b0215c", - "tags": [] - }, - { - "country": "QAT", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xaf1be02978ad9b51fda5089f0c3f5fbea2a5c86ef77a57e7ec36a3a004d997185e5ce4d6c70d40df09ed843dc41c01f6f6b48ae53c01bfbc8f035d30ec05d53df8e5d2ed17ca1a5f38a3238197f026e62f0e4bff6e22c7e2a73005b5b806abf1972ed93ee3b482ca8f96299e80e718642b10be85a3868c6bde255c027112db317fc090e9cc29cef709760f097654b36ff0cebc75796dd6f902d4d1b2302dc5843c5bfbe9b0402410d26dbadd6c95de6b6be7aa42fecae69c74f9db6c6a83f8d476452ffc278a5ace0cc44beaecdecf60ee74214caf13397af3a95f8a7bcb771f5c65221d0b0bbf47f3317b293c9f04252ff74ae63889dc56618d40b0f7b903e62fb04a52a03e4a2cd16d3771f53743756642288c769df3fd8945c3d7d610ea372c4ca8b8d21ea993473bef4b0104b9cdc300128fe1584a73ea88cafe04ffc1f29d7b196ddf127f64dcd54daa050ec8dc27e961e88138d76515124aedb26cc6cfe10b0e5363d6ec069d06d6a68d47901eea70eeaf94e00294cef3af0d776f199d031bd5f6f10d03c6ee3bb64f450b4f9ac5c3c6f85a22bb622dc7c93b11bc04696dfb6b22478a16575d02d876ead73fe12ee60d3e3241cd816ced4f68feba2baf34b764837e43ce209cfbcb37c75a50905e9244a5d6d2980fa396539b5819608ca603bf49e03c185d446ba41f97b9a47e81de876b7c4abb34dac418da1ffb7bc5", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1528156800, - "not_after": 1785888000 - }, - "authority_key_identifier": "0xbc91c6fdf6ea52624c5f3bd1e398532cc9436aff", - "subject_key_identifier": "0xbc91c6fdf6ea52624c5f3bd1e398532cc9436aff", - "private_key_usage_period": { - "not_before": 1528156800, - "not_after": 1622851200 - }, - "tags": ["UN"] - }, - { - "country": "ROU", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-1", - "public_key": { - "type": "RSA", - "modulus": "0xdd754db8a2a519a4570f0326ad61113c0613e6d5477be7240aa7b6fe5f86cf6d047cf1293ca47f95dc263057508fad437b0e5add33bb54926a4b3635327821c68d26dd8c7bd8af4d67ee9e6b35926aeee5789d5fc03e0995e1644a04b50ed333f3ed61fa0c9fea953bba346a1b1928faa84069b25c9accd27d7e5674fa966e12846369f9e6e17565b8a4cf3e123730fc19857f279c755af92c7003903af2f5c41dbaa4dd883fb3cfbc52fee137fcad9fa085c5c6eb1027025d2de494613284bc5df329765adea5bc6020b851b44f6ba3d740e9fbfc51e8d80a6bc6c5bed5a2f8918878363713ed2bdfe0ca4f08dd70820b99397df884e94d1eb33868b3374bb3e75a3a11638e737b73fc173458c6196716d0e8d323fff408ea5ae52b09d8b646acea150055c09171582ae1cda25af34d4f12a33f62d6c7b14ad0f8af34029b05cf18015859125c80e4d5670438c23c73bd26e70ca5eb6d47fdb3f0d741ac44f0ae837b7c4333142de822d17aa2853b323dcf6cbf08c50989d2748db55ff94c9d8032b0df1fd4a3dac4dd9e8a2b21cbe9773c8cbeef000378016d5d57f262e74e0b416662b7952ade815dc99e0b316214195b860fa846cb5089268ccba9da8691a1403508d08ba94e8622a55e269edceb272e01475530b9a4456de0fabfd9ecc204a9dd2722ae3e3b7a44338cbfe46d18bc6ea5b6a3c7d3e076b265ddabaec63d", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1322484440, - "not_after": 1795871840 - }, - "authority_key_identifier": "0x4a24ee04b51f6023", - "subject_key_identifier": "0x4a24ee04b51f6023", - "private_key_usage_period": { - "not_before": 1322484440, - "not_after": 1440832640 - }, - "tags": ["ES", "UN"] - }, - { - "country": "ROU", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-1", - "public_key": { - "type": "RSA", - "modulus": "0xb696536bc2ff08ef1bd0654f7a611dc7b49e3b1361712b63e4cead906f3d4e0c781decce6d9bda337e85b4924f919d52767b29d0441c50336a070a01bb13ab87c2797e2e59174b1c5e86a8e8c05e5d80faa4ddc8460660ffc8866789abbc37f77728be37fde385b0f2ae97f521eb0f4bdf2843893cfb128d15b071b6dd1b91a8617a456f9d5f67b567090c9d43dcfed2b17a3333e036529369194feabe82dca571a2880e81164ea57e2fa1cb50e701e31626b02a70c2f002e12fb510278e8ded673f30ddf6a3f568c4d53d1ba133c48e118355c70091e0734c0eeb1f65d3584b7d5236eaddcf135c3deedaaae80fe2884c581de8fcde1c235cac8678bf3473d991f6b0e10a241eba2c84665c158554e205b7875f3c4ef9168ba0d937ddbc3abd0ed4cae2388dcf74ef5e8110eb4191448e64af301e15ccb6239ae7dcefe231e69ae54aa20b3af2b671e1c30862f2e7d9cb3301b043c3842fc05d5bd1539a83f5ffde398828c2ee24adaeec6e628a116ced56247ba780430f7b57f8e055fcd49a6aed7d0013010e0448bda3f1ff3c7fe6582ca6a5d1f621a2a5ad468eb8ec47b042a32fef5a6b27a78283f19c701d8dbf53dea6b553c9aab29549dae6712b5201b445698381c981a6d1e725d9f18bc0b3f3bf0f84adf49f888208b46740abc614fa6732c8c0724cbb568da5c73af3c41c2877507b072469f47b49a256ddcc229d", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1409571845, - "not_after": 1882959245 - }, - "authority_key_identifier": "0x4433ca981a316f70", - "subject_key_identifier": "0x4433ca981a316f70", - "private_key_usage_period": { - "not_before": 1409571845, - "not_after": 1527920045 - }, - "tags": ["UN"] - }, - { - "country": "ROU", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xbd39c853b8535c95d57914ce8a1c610403b482a4090c65e2e9be68eb609d15b25cdd4ade73fe9d8a9c75f37fb89d15b0cbc346504d67660b05ab44c045207bc948d6d4a61bee5f4d9552e88f34e921980ab7d9ae3bfa1eb12cd047a29c89714e946c39cda3ac0c3c0b64b61a6e2e60bf8244ed2609d5397c0889d7daba26da70e661c9cdee11fed1cad739cf80eaafb12ef330f43289d60c19e330bc70cd33b7bfeb6c60510a4adf9af68136ad29420f2a5252fc246d0f57d133d491c0bd86d6835816192b4b0adfd2a29f9992edaf6330fce4dfe89df16760000b930ae4106f957762c2b0ff9d89c700843858d898717255f5acb8f5bda86a4f1d25f23c9ca9fc98df63dbca0284fedc35d6237a0f9a9cd457463ceb2dd30a189d070caa9e92ef29e664ccee55f674374dba9a1ab11a4bc84b67290bc67f7883f3feb225c4933ef0aa57eb3e4a5bb98165b4aa4c094c5463b26da241ef1d740b5a95e43e4ea9c7c46209cdd86fb9654419880babc252aad1f1d0eee7c0ecb8cfdf2f03f9bda0d6d6c8e1cb6d3e8eb5059688aa8e09110b77a49b52ddb0b3b9d9b225935b3a3bc3034b1fb6c376a1a1d396cb4a84ae45fade2b74c5a2c1d917efdd651526057cf24f6a9c327dea6a911decaf91d4b8405fd8535263f96a19c565fbfcc9bec23edeb98da693d4a02b88e3dceac6ead604423e67b11e03b93aa1087ba5681bf1d9", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1495708515, - "not_after": 1969095915 - }, - "authority_key_identifier": "0x4d30a32a4642e10e", - "subject_key_identifier": "0x4d30a32a4642e10e", - "private_key_usage_period": { - "not_before": 1495708515, - "not_after": 1614056715 - }, - "tags": ["UN"] - }, - { - "country": "ROU", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xc73d0a9aa62f5e273571a3c52b0819b32406c13590120f07380a40a8726cc45442e6a2c4a1b729b1a0d6921b56b4e83b5db9091e2c49f9d071608d0e1b1e6c348efdb98d2cc32a3f75e620f5a470e549247b8c01eb85f65de1cb13af8c72ee0592a3ec5ffce21b98abca48d034df5312a2a6ee505a31623a0ae212fd181bec416d2fb3208db4955d78278e02ac2894bdd19aeae92531f3a4c04fcc7abb85dbb4fba0a47ff0d672481f4c8bdc98747bdf6ae4f83a7357c0165781e33e99b87aa5cd76a5aca163a9bc675561099e029bfe4663fbee3c7081250f4e1c071865a6467407ec14b5f3c84b20c05689265a8798fc306f825d5e7439a930cca80f5c8955d029099d7a500c3fd7658f257044f726c5b0e596244f37a0669df5854808c1e1d2baa68b38d8b8f354f0801f0a03de3353a33ec719744ff608a204a104a1f054c75b3da27009a26610bc1caea20ee4677913d3b8889e3fe0ff62fd5dcb97c5698407cc8dd027eefd9d0e6b8a0775bbcd1af11fb7e3b81b480337eeac74f44cbb465bb31279cbdceae981603f49e2f53148de37fb92f9af94b689bc4c3709e75fd7e57840f1cc818f9c608023c76a68fa985b1a8a5225a8ac71ea6afed83d05b7f58ad85ac16f9f7832e7f278afa95ebf3d2eb07b5dba7e1dbae7d9fee3fb2e294913782c5b7d4419a7c30de08428679e4bfd3372048fe337d9243447404cd153", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1575629878, - "not_after": 2067334078 - }, - "authority_key_identifier": "0x481c443520132cf6", - "subject_key_identifier": "0x481c443520132cf6", - "private_key_usage_period": { - "not_before": 1575629878, - "not_after": 1733418978 - }, - "tags": ["ES", "UN"] - }, - { - "country": "ROU", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xb1ee9723c7c85b1443d6df7590d538cbba3aa27ba91dec9060cf1def35c4334eed9888b4921cbd8430b525ac351e971de85f09752124c9bd63b694209d4174275c3d179605b9160cc47073d59fdba892b259cf0b42ed135ba0644d061fb73dafb1fdae5dd6da546f96bf9f89afe8d4d849f2f0ac67dc58d6c8f419ddf4a2aaf3513ebc93c692f85b567cf36810a3a16849b37ec9d0c876c14ab36487e1c694b168cfd267b1de3fcbcd8f77aa25b38810a240f20442e55b9b2d572932185bbaeacf768a8eb7a9780f51ef2f3aa35bc2abe18e0500588e11be4a1bf6025b918b6093b35b9ed75fa0ed7701479de3849a141707a6f30a2a50608be6882cb663c5362508757563e249ce80fd989840795ed523794f6f967a7c920a710c276a6ccfaa831ac944332929bd76287c07c53c571c6b48d6be5f7e84a7883ef743a0e8274cd7db9c63217baa8c82a7edef774e6cec458f2ba5877af11dbe06f478835a3a1ad17c79e791e44c383fa9419ab181482cf0ad6ef703010577727ed3210efb5692a6a494a03728dd56559cddd9a93be94fee44bd1861d084b64ecc128962b93e575dd925e1ccf7b61a134300375ca62ff481d6949a4f7f890469ec10629e06c5205a766d03f69076be6c9ccad1ad333824bf925e1f02e940219e7b37909f7e8010444ea9e923ad55fca02b2419d1bdb0b3433e776565ad6947bc1b41a32518b385", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1691576272, - "not_after": 2183280472 - }, - "authority_key_identifier": "0x4a6ec9306f03ee63", - "subject_key_identifier": "0x4a6ec9306f03ee63", - "private_key_usage_period": { - "not_before": 1691576272, - "not_after": 1849365372 - }, - "tags": ["UN"] - }, - { - "country": "RUS", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-1", - "public_key": { - "type": "EC", - "curve": "P-256", - "key_size": 256, - "public_key_x": "0x58176df8ca510846d785c81cb969b1e22a62e812c1e56b8105a76db7ef9465fa", - "public_key_y": "0xa5c06b2ccfc9a037003a2e1696420b246194e3dc9b549fbcdc1fefaf84d20277" - }, - "validity": { - "not_before": 1265358705, - "not_after": 1959150705 - }, - "authority_key_identifier": "0x56599989a1cc1c13d39fbcb0c87700385033a533", - "subject_key_identifier": "0x56599989a1cc1c13d39fbcb0c87700385033a533", - "tags": ["ES", "UN"] - }, - { - "country": "RUS", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-1", - "public_key": { - "type": "EC", - "curve": "P-256", - "key_size": 256, - "public_key_x": "0x1293dccf04ccfd54a9f5958e221a31962b21a414a44a3488936c335c87da299b", - "public_key_y": "0x3fa8808a0d2f4b32c2ba2f688eee849df1372dd4f65a3567f7550429880def70" - }, - "validity": { - "not_before": 1416398957, - "not_after": 2110190957 - }, - "authority_key_identifier": "0xa01e87502745922760e2d03140375e147c46c002", - "subject_key_identifier": "0xa01e87502745922760e2d03140375e147c46c002", - "tags": ["UN"] - }, - { - "country": "RUS", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-1", - "public_key": { - "type": "EC", - "curve": "P-256", - "key_size": 256, - "public_key_x": "0x534aab29c078ee859689bcb82945c51ed123908f673d6a7b2060bb404dfec70f", - "public_key_y": "0xf9648cb96ca03792962105176797c77d14b4b887f3d6a953f84a4bd91f7de9ae" - }, - "validity": { - "not_before": 1570788637, - "not_after": 2075364637 - }, - "authority_key_identifier": "0xa01e87502745922760e2d03140375e147c46c002", - "subject_key_identifier": "0x850c53f7160e5def64a5677cf7c1849205d2b29c", - "tags": ["UN"] - }, - { - "country": "RWA", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "EC", - "curve": "P-256", - "key_size": 256, - "public_key_x": "0xaaf4e144155905948c43d1a739cb47bec068978699fad1978d2b71debf76b71c", - "public_key_y": "0xbf83390ad3d52c716bec5186c01c98cef5960a51c5a5434c6e48537d139df7db" - }, - "validity": { - "not_before": 1560333481, - "not_after": 2052210481 - }, - "authority_key_identifier": "0xbb1c63a9837cebb01e34df5a45a4a52f61d3106f", - "subject_key_identifier": "0xbb1c63a9837cebb01e34df5a45a4a52f61d3106f", - "private_key_usage_period": { - "not_before": 1560333481, - "not_after": 1718178032 - }, - "tags": ["ES", "UN"] - }, - { - "country": "RWA", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "EC", - "curve": "P-256", - "key_size": 256, - "public_key_x": "0xf8dffd4543d7fc68758d26e5dc5900327092ee964c24e324c856b12efc2c3c61", - "public_key_y": "0x6c6aae4e15ca3ddf6de720889ba96916ae1dd287563fb0e41ce79f24f65ac8ab" - }, - "validity": { - "not_before": 1716971427, - "not_after": 2208762027 - }, - "authority_key_identifier": "0xdc472e9413a8354b8a68bf0636849ce481639252", - "subject_key_identifier": "0xdc472e9413a8354b8a68bf0636849ce481639252", - "private_key_usage_period": { - "not_before": 1716971427, - "not_after": 1874788252 - }, - "tags": ["UN"] - }, - { - "country": "SAU", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "EC", - "curve": "P-256", - "key_size": 256, - "public_key_x": "0xb9f7b75e6c52912868fa14f5eb88dea018842642ffa851796b6111dd9e4d36fb", - "public_key_y": "0x135ea7598a5bc193f2c17dc510400211b325b0159d6b46c6d87135b39ec8526e" - }, - "validity": { - "not_before": 1606459578, - "not_after": 2098163778 - }, - "authority_key_identifier": "0x9031b490c86ddf6b67eb9fbc90ba755b3dc59e3c", - "subject_key_identifier": "0x9031b490c86ddf6b67eb9fbc90ba755b3dc59e3c", - "private_key_usage_period": { - "not_before": 1606459578, - "not_after": 1764248678 - }, - "tags": ["UN"] - }, - { - "country": "SGP", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xc2cb67d748d484174d49c9b3339c78da09958cfa53380597755ccb86edb7e22f17c63ced4a1ecaee04a387b011e531106b2e76dac34a08098d35b60a6b8112912ac657fc50799b103063e4fcb65d5fe1bf586c1404f743230b9a151b33ab9ae94cdb84ed8a60083558d064791c7a58742d8cd6bde56b3a4295bfa28138f2f2f57bb7a733c17e565c9c640e1b0ad68a9f772ece460f7258d0333c26896ff2035e2edb6344d7deb46d257ea816878c113c2908b9580a1b4f72b5800b44ccc60fe45de7e39ff4305509f42adfad5fa64afbf763331def6ba17a15487dea7a7a0725e6cc1f8dbe6bd41f8c2fcb570cfa4cf93ebd90252b95e3cf3e2a98cbb6bfa2fbd1177dbd8d1b3035df24426dc3e2e370c71ce4053dfc1f765fc91ae8ecd8ccd6659fe3236b0b47da013ffbae2a4a5ccd90a53e385ad2661ed8a16c07b3f37bed31f9a831384bab1598af56a07493320625c37625dd5f15cf1cca1eb4c5f4cd1ef6572e5e2f0e633d4ed38f09643f864d0e85f19d132a8c0175da83cb368f99d13416e20dd45f1c9828c0962f8fc6625dfe12ed2cb5a534184550f286c26c62b2d17178decd3f402066145a8309fb36e72679275fbb6fbbc6197d968fb713f435e40bb6961e1b5cf55ad8e3c49cc1d6e2075da706426b37eaf9749c4e73c37643f5dec0aed250621517d5450bac54a9aec4b5fcfa28c53f59c9942e54d76834af", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1297751270, - "not_after": 1786777070 - }, - "authority_key_identifier": "0x8afbe5d9d8fc6cd12e15a8cb1fed205ffc2dac35", - "subject_key_identifier": "0x8afbe5d9d8fc6cd12e15a8cb1fed205ffc2dac35", - "private_key_usage_period": { - "not_before": 1297751270, - "not_after": 1786777070 - }, - "tags": ["ES", "UN"] - }, - { - "country": "SGP", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xd343042eb4f144e83e31ae7af01870ec3d38b3a48625921796aee3d1d69d123064a8d325f963ee01f12a9cd175478269fdec892c46ad6e329efb0eee468fc054a9f9443ee875195ad2b79b45a34104ea254ddbedde35259c5bb51d59a65d3c852cd975b452a19c5eb93ee7d209019976efa587f0a474763ab79da67c716c09a2f7a5ace2080070b62f5b49db62fbd1ee02b0db84278ef338ba3ab3ca4b9215aee0116082c9d777b11ff37e1a1393d3a0267db2f612500763f4b97d2d0a704aad8b0b272fc503b10fe108a1fa356be0857f14af52f050af2d9b73476033de788a066c436fe767487c97260f1c3f543887bbb074678c55a59a344109430e2829eac7a5e356c0679ef1e4a55451e400cf19a762860ac45b7b786a9f16ef0b952912d4eb2ae0d5245ee377be43b4499785738f59ef629c9613bee13fad0f88933b08698eee0b271cbc7c6a5f78b739433c136fc90a697530af56aab6a7f3f41c3ee5ad7a3c67cc98402f4e67b37f2b3f3f1d900758bf1bae6d29c7c4ae3cdab427eab5e771b3afe59dae57d1d756389ad6cde1721f6d179b10526aa43b98609052e7714f025270afdd178fef12b42ebae39c78ee81599c55209b87c26d12693f9c09123cb56f2806c5df30d30c38875da17e53437218d8fa05101d0cb91d5928a137b65a90138e2f482d25720ae350e86b7f260aaa1f1137c71c31a6b51d19403805", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1453793464, - "not_after": 1927180864 - }, - "authority_key_identifier": "0x32b2241e7442df02964b07bcefa099f82820ec91", - "subject_key_identifier": "0x32b2241e7442df02964b07bcefa099f82820ec91", - "private_key_usage_period": { - "not_before": 1453793464, - "not_after": 1628946064 - }, - "tags": ["ES", "UN"] - }, - { - "country": "SGP", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x920cc062319f782cc4d09ce256f369e867f97dc4625de13a0a807960780f6ce4a0d06b960801cf2494601bc56c94c094bf75e02b056d58e35eeab931b7c900e8afe304ec686b403905813a9c10dba4e73072ab6ef0ad3bc33b8ca384de14d6a4fdeadbb7d2e9307028546ac6e130a65e8c03573f53d97181ce4716e348623cc1031c6f33f983a0a750e675066542e7e377cb77df5224003647e2592c391053522af5dba45617a740d84f72b2d103b41666c69bc365c417316d1c84912c6c581a3c07b44f3c7dc7ec81cecb78ef0513f3981eae76a468febbf0d12c18c621d03ce2410afb85413786b405fd4e283c103003db974b1d947b5e9cfb51d74564e7521148b56faa79a09d0eeba8afc4fc57ff9ca3c239e542cdbb848f9e2ca614cf432fc539a1190b99e89ffa09a2f73c14a22a651f84710d4dd36647b66498c79e105f60b2f79aff6a4d44036b2b7f28956a8ad60e62126b7a83a28e4092e8ef352f1feeb7aed7c57405a150ccb92cd4b0298d000362897a7e0c5ba166cfbcb4176a7eb8a3833aff35635700c1bd9114fd39bc2f81add7d3efee7f25d4e83fee2cf0b84a3e7ab7d355b96974ec01c6165ffa1016edd0636014a6119f9315dcf0319bccc5e3b1b83c3bb8e437fb241aa7bbf74f8282009fbd8179ac0291e770cd27c3568c4a0af9e2dee3cdd45ee166585b994cbe99b288f0e720698c894615a218a3", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1491900916, - "not_after": 1965288316 - }, - "authority_key_identifier": "0x3a4d8de8fe2407a702bb9f7a320313098a2d4a8d", - "subject_key_identifier": "0x3a4d8de8fe2407a702bb9f7a320313098a2d4a8d", - "private_key_usage_period": { - "not_before": 1491900916, - "not_after": 1667053516 - }, - "tags": ["ES", "UN"] - }, - { - "country": "SGP", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xb687b2fa93ffce2c110051857a65fd68ce3960a260c462af3e9bfa6f269f5ab8965d38cb22ba7f35471ca4b33e7904e183c594d4b9e84c74c04821cf528c3fa83bb6a3f4c0c317e4c95a5acc5339b4c4dd9db8eceb64db29fb88f96525ebde38e48ebe40ffa95b842f16a721e5bae8327d9545e9dc0bd143df441f6f4ed672b1711c6b20e0d266a9866c50eb172ac5dd4530969038d955a7b87bc7656395ddd670c1392672eba4f05e9dc36b563ab3fba1bad9de0ff2df8b1deb562c0ccfe88579d7318e2a6342e6dba73b716c32c830a1f7476b36f80b2dad1f0ce27c9a00610cf4d7f213f35796fc6b26c336fef1db2143dc196c02fde859239dee0bdd459aacd0481ffef9eb1a6d9f52699d570289e3fd2da753195836b2fe51a827ff8ea497059faa496b36831e5554f8f306e835b086e0b7ad30afc1e55d6a15fc1036cf6b54042320747ab7d6d5fc86113937297227758c7cebf21f3827acce909026ceb4ab4d16e065e3bd82dab7ee40abaab58085c96c5f1d19bc16a94b23bf8c0572b7d88b8a4a21a0ae77a231b0bbdaf40d5205e33161a4d8b8722c308d6a565f34f38b50ff84bda8f9ee9f0e584ceac279aa337fbddb9c9b1069a7304955422da53ae35dd72ea2d7827864a698c0980a322b59ba6a4a00dbd115a2f663fafd89413b02f416130875c6bc8e3da4b8bb49c1b6ecfefc1fa2d965fc9e38abd4754203", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1607302661, - "not_after": 2080603661 - }, - "authority_key_identifier": "0x84cd5d8a477755058d4ec97e0d4992322be1c545", - "subject_key_identifier": "0x84cd5d8a477755058d4ec97e0d4992322be1c545", - "private_key_usage_period": { - "not_before": 1607302661, - "not_after": 1782425165 - }, - "tags": ["ES", "UN"] - }, - { - "country": "SRB", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "RSA", - "modulus": "0x945bb6190adaa77bb565f3b07feecd5482843b3a332440046c31dcad63281e932488b4f73b8f947fa7b6c87bc78435fe0c0a7c94d48ce0310c315d8fc61bec45ff54fa8819a9492cd1f767d9be297a9ea943bd11996da8d7a51eed6d2dbc80b3234f9d96d6e8bc2f14d8cbda518c2dbbb9f02c532a7e8e1eb288fa818cd3678af379826077895833dafc4bdf10172ef4b5224de0525a438ff5d0e0753b0fc699fb3ff8cf7c411eb89260dd8746dd3770499265ef444fff8bca37fe5ef7213f8ef422edfc5d22a116a5457c4ac853942a616bd5e316d90341506a992c9f5c803a8936532d576a0769ebb1ecc07c2ed9fe7ef294fa2487fbade4df03e415a3ed13fd0435cd4eb901e29502281c7b8c2b29c6674097f824dc7ae518a79f661bbaf2a52eb357df27c22b93aacd54ed79a93b02e6b2ddc75efb63fb235f75f725cc143b823deead743742a1a5af12d5efaa841e4797860216a774548f21294b5dc8939b612aed0e1ecc9f1482cb335a59f4cf75e354060e4dd61c916e450dff82d9cd", - "exponent": 65537, - "key_size": 3072 - }, - "validity": { - "not_before": 1383130800, - "not_after": 1864465200 - }, - "subject_key_identifier": "0x3a15a77624205540c6373482f4798330e9821c33", - "tags": ["ES", "UN"] - }, - { - "country": "SRB", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "RSA", - "modulus": "0xb8e541afae1e30134c47d2fa0a4169beeb57fdabd572730c7ce9035ec42c14a8cd790863975e2ee1fdf191bcaac6bb6e341791bb1da9813e2a7a60a165075d0bcf4c8c5ecd8770f13c98d168f192f7118e947e63ec10ad7cede5eecc0757bf02ac35dab9bde4b24fd0e0aa30e5412740bf028ebcab9942c34e22ae5b3648f1469f5c89ca07f7ae0569c1a4f260296f75d5be0abbe12a8014032d5d1afbda35e98a0a2a29f864bea0407f896580ade2ef49e8019852c327b51fbbed4ae4b74c7529a9d3566941dbe9e4b955e42e73a1c24a1ea83548a89dd728b42bd1ed9a10e2eb99a6afcbabc1f8ac2b1d52e29f1a27a1bdbcac664f7221351e78fbabefb856d2bddc246a3d2142af1b51f25826dae10de2336c68dda9dbda0768186aff28db455a97374d4112407a683929cc6e03852979c82e4714ef95bfd32098bff3da310c22cfc88e45afe304ed50f83cca4276ac004e0b2eea33d7a322053fae81ecb49c87e6b2307ef9102185e068190833d0264f830892ca107c946726e083c2f935", - "exponent": 65537, - "key_size": 3072 - }, - "validity": { - "not_before": 1540551600, - "not_after": 2021886000 - }, - "subject_key_identifier": "0x2a08e6f99bd2fa283a1eb33ab4818811c52b5001", - "tags": ["UN"] - }, - { - "country": "SRB", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "RSA", - "modulus": "0x9772145c5227a445ca7d1847a8f8d04f49e499ba926675e0db4279b78a52c0501ad767dcd33cb62a7cdbb9354f0ede3f0198f03bf85b5a378d4a20e6bf96118884c515754638ced89af01e905cf14e6b6d635d7864f712d9496634c571117baaeadac8acdb5b6d9fd373ad6a5587117fdc1331d09c5974212fe0cc49c892e62199ac3a69aadff750d953057bb804b2284a131b1d345056d7f077c46b1971c9c02d05137631b5109d58ce5b7dc6395ccd63b5599a227164c4bad531022df33909303cd5312c89fc7aa7b2926a0e84701926335502bb68c80ac5cbb9b35c63d3b0b38b3a4fa2ec2d60bd971f8a34355466fee6424449f6cb1b58a74e04eac93637314b4266cd91fc6dc0429251ad8475a41539fc2c37e88a945ce1496775d905c0f8c0bcfe0db33678cdfe67cf53e7af65c073d7830ed46a94b044685872b771c1000add9776d2e2898fd81ace26f07a82cb97ab95e3c31e65099b050996e338b5ffde899d126fbf2fc62088e3da6656d549709e51f5ae463580b5abca1465bb23", - "exponent": 65537, - "key_size": 3072 - }, - "validity": { - "not_before": 1698210000, - "not_after": 2179544400 - }, - "subject_key_identifier": "0xafde85a271f82240a501aac77aba913ee938796e", - "tags": ["UN"] - }, - { - "country": "SRB", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-384", - "public_key": { - "type": "RSA", - "modulus": "0xbc87a0087e92fe8dfae585d92106c775e59c45f8febe5ee433d26c75eb28161f8ace4cd6f1a0a492a686ed4854c0e5bae36be01b27d67838794b32b8434bee16b0bd7ed69273c04a1b7be370e12075f9f680a40474155341f0be9b90b668974420e3f366cbcf70384595d15a3ff00043ce88e6093c69ad0a47e589daad40ab3bb7509dd70d9eaf57a7fdb6e8fcc0a4bf33341f5fb856eaedf8e1ce69d1ae07f103b2d8f53a62c1772a41269b982f1664b9611e523b1ebf6e8f9175e4a8672f882de77beb7495b3692676083c4a97dd55799642ba26186a8742a8169dd4669d024ecf358cc6615a8124b230e89977b37810d4690e0d2936289feacebb92c4d4281e3a8576aa9ea05c24ab4f59820972ac85b87e8d791bd7f1901da8b0f8ef0e05cc23825e152a696e452cff2d07e792d64f458a618e79c17d26d696f30e1804b042e365cb562d3e8f51fb5b8129c8ec2f01da713955af7ba5afb83ae9a096678d8ecfe238c78173ba1cb7286560b5e949d08dbdca83f1021483870ba222ee8629", - "exponent": 65537, - "key_size": 3072 - }, - "validity": { - "not_before": 1705906800, - "not_after": 2186982000 - }, - "authority_key_identifier": "0xae027ba426064a831cda2f3c6e7cc9bfefe1ba9b", - "subject_key_identifier": "0xae027ba426064a831cda2f3c6e7cc9bfefe1ba9b", - "private_key_usage_period": { - "not_before": 1705906800, - "not_after": 1863759600 - }, - "tags": ["UN"] - }, - { - "country": "SVK", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x9925d4225652020236f9e50fb60f21beee0ee90403940bb9b2cd10e6850b96ce0860edd0d5f3120cc9e48ca32757ba5834a791553e70c7045ac1e194597de699cc728c41708e36bf035a252ead1705fd23e1e56d43d69b43089fd931a841c211d6f3c079c38c3d44950e71a64312ee29e376ed8ae305d346ea70357bca31c52f0e51ef3198bbf3ef366e95c80431f1c720ba4bf4ad5209cf4216ef72b7337792435514f5395418c2397fa6dea1b2fef3e664fce457b4e3ec6e7c129df09626e4eaf24e5ab604886a514b3364d1447ba594ed7182c31303f8e9279d7323ada11fe63be10bcb09d71a1cda7db9cbdf0e707fa07861345e9045a27d5ff81d6137d6b7f9ec8283c1ef05fd506dba1645b2f2ada61966d3dfba5f25a70baa9b75e025a6990519f23c3873d9b76c9afca9d380fcb0aafa8e9ae18530f02abcef3372a36637fff7dae0ffeefac71332f0e101c6a5e7cf0dae3bf5d30b9a09c895982704344ff5fb14121029ebf02ec8a38583cd358599dda88de99c6f492105e9693f4c8f7f5ccbf8deb7e55e6bb44b74cdf03d9bd82524b0939f22024dcc52289472ae31ff1d25b6ce93c5623c795dc9fb644977fc3ab4aea086ed8b1854053b523e4351ccac70625939c3ac6850123419bef34e06bf4370f2bcc8d5e497300d1b7b7304aeb57e92b3eec56f3c2838cd59c0729d7aa4c4b3b0a15bcb16e99a8f7c7b67", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1350547868, - "not_after": 1831881785 - }, - "subject_key_identifier": "0x10adbb34402ee32674fc5b1662a292855dfe0594", - "tags": ["ES", "UN"] - }, - { - "country": "SVK", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xbfe00c6b994197998e07347d8bf68cd9a18798ecb6cdfb1524735494564a33c237ce3668060ac38cac51527662567441005eafe86d24d8a822653e70c6d3c38fc9d2440b21a6e04e9ebc45ce7441263cae8dcb44eba7d36a1fa6520596335f304fed10d90012f6774f9ab441fe2072131e31db131441fdeeffa4cad9c0116f76a2db9a89ffdc214a82fd50f4d339cde533f2ae3f096a902f3f3255a285de55808d46054dd60c1ea7e99a2381d5bfddb69156325a61cc055febbfedce5652d82ec6f54d02ff8b456a2af27d160698d676bbbc2f63bedaa8e2b630378f33c5c10c5c4c796dcc83c966d7eca7abe8194097d3d184469410e6e6e4ee630777120d8f891cf5774ed02cbfb5eab3d79e156f67044c0e0290508bb81eb0e4e7c527a4e8d23c2cde31cec8742b5f41dff4c01f0e71a88bdde6fe388fbf59675377daada8a4d9e95dec9367bf86a4abaee2319748c6f925414ac22af8798033117650ee41273d0e2d3315b35334cbf0814c7f5311350eab20424e89e579c7aee7edf26fececf2351f4e300c866b207a7e2dbf945ab35d684f56aeecaa6e483dc769dd40b8a1c254028c37a397fd36e852022ed96282559f3ed942099a14e2621a3eb280975cd1a6506666f3a16671071612c154c362970e9ed8c126a5193a580148466613f97f4bd440120d956fd7494791d4a3b74b95bc705fd73ec7e561367abc721cf1", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1507623696, - "not_after": 1989129511 - }, - "subject_key_identifier": "0xfe00b80da02261b93879d97c22233928d8df8520", - "tags": ["UN"] - }, - { - "country": "SVK", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xaf02a6ffc5f7e1485e5143fde5b97a8892578939559e5ffad0d33f69eb58746f807a9b0c6bd9be78c2e5fd273e1a88759b5af58be4c5583f56119742e29a40d43eaec3d5803e50875e20d5e0f73c3da65d2e7d4b27558137b09cb0df033b2b6205e6582e72ddf7c8bc1a9811be8e48c0c014b6ddaf47ca4a180cb072c9fb2e140ddd709cefe3db53bc5a562aaf776b7cae0c2d30e007af5e2a4ef51f8fe33e68750f206384b808007f7cdd07f4ff0dc82ff98382ddf5485b0701f37dc1b10247c613ff58dc0980f27421ab699726aaf9bbd084b243aa9d5b331ebd2b4effcca9025e19b7d4b3d9317eca90b65014567b4b5668ee19b632216c6e09f4ed7083a5b1a0bfa5164386b0a61b19196555ef33a35dab1da1bdeb835eec22145df50f3b32c0066384450c85b8d207256003058e0147417452934308c2cf777b941747d4be48744768dc27495a3e4c112a0b7428dde489aa37ab24479791eceb502a42d7411eccc337db0a012c501fe4ebd1fd3c614358aa2f8064abfc67ee61e99cc6d0b1df3941de279a415f017cf19bde0e2459cc19fd3db2e2d4141b76b8f3c0128f1489f4029d0e5c619d455a51e2eee7830fe8b49e46e6a2510da114f58e9831046ee6ed9b5caddf7ba4b5fbecfe9ce9670b5d25c0069bbaf8673c171e5e8d3bf6bf0a28551aa7316dd1422bcce49e23f9fc1bb31faddbcfa56834a4c89ec92e59", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1665135337, - "not_after": 2146642537 - }, - "subject_key_identifier": "0xe06dad29fdbc07f0e82a61586c4f2a9d48844339", - "tags": ["UN"] - }, - { - "country": "SVK", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xb5500b5891105c1d31cc3b3e39bb29bd94ed72399015855ae286bfb700cdf87bb0fa4a3c0c4e34ea3249a0ca9f77a6bb43dcc6c6e0482850987a9c6792aa13a3cc3054bdc0508f650e0f3402958b391496a73bbdb2b30b2b58099dc9d779da1d24743fa4f7651bafd56dd794d9c3c6c48ad671f4ba2017a406b0500624ec2dd18744a507d9732269cecc26e1775c99a2bebc664480f1c5b2e066be373fae4e429265351691c38d2f8029f12c3ef2a4316f0d87d2f6b955c31399b65d67db74d44d8f33277b478d3b0172bd2cb16bc74e32dc8e13c40ceefd535a9b2f6698b4e1d578465faccb214340dee18f23a1f633f4db2b92705707ba1dbd52545caec9893ee290f1347e0d070675ddb0a0b4c4a487e46b74bc4e71f65481934d341629fde268993448051920de7d9ace8e9a2e7fc02d3ecf4bec87fbc1ec6d72d95ee5a9a34bc88983efb4ea455acf308b141f42d7e8390bc0f3c4c41deabd882117e5f61e600b40d022cf18dfc7eb1365c65491d7b566db3a45430c603a3be859d5988673494c99580aa110bb1e493db935e91f6cf065208c2654782327bed13ad9a7851de7aba57a735f4f7073f82f3f08b66ef9b9dd4a9b50067a60548910a751c4ef4369fdccf5ac09cc9b73c9ef82bee35ac2e8d807265dbdf5033266a0e89f41912c6d2bb36e7374fede4d479bf03da814ecec7799ed29a472b9adde544d35c9f5", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1695713605, - "not_after": 2177048005 - }, - "subject_key_identifier": "0x060d63c74b7eb0a5651dc33894fba6ece0ca9c92", - "private_key_usage_period": { - "not_before": 1695713605, - "not_after": 1853625599 - }, - "tags": ["UN"] - }, - { - "country": "SVN", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xcb1254efc5cc9443ece79edac1f02d9db7166fc524429ca047083c496901c61c70735c8d605b073a359b2aabdab5a485c4cd8392043aa08e304c5517ff0afcd45c4c3789fa97ceaf50e049a6885d425fcb317e6ea5b39d2e22924b07904313b8c5b2b60c43638d6a164c3106bcd753a884378aab87f02705b76c9ce640959f60cb5d9a28d767f9c72ea29eca8adeed484a92cab35d69d02ff00605bfe5144413218cea70e9c11db8bf604bb136e91542e8dd926b8c22d3162014de6412fb45617a7ce5ad2a517060ea8326ee55e33eae35b28eed27c71c3272fbc7526a06c615079f9f7f2c5a56d76966097168860585ffd47a9e5185c01b5bf4a86e9f2d5793f351971cf4ca98bb2dd8e2300f7088db00427f47a2fd526427db10da803e2be625543f67af45334e2231b71487b6b8710fc90a0be32d75f5aafcce96d538d008ef3e2b3239a2308802a769e85e932daae1e0c3c8112f438fcc02eeb0e309e3ff4a56a0bbf0689ee23f0150024901040c3baa8a71619ad1cc9b7f9d4cba10bfd9b8c27fd7f2fd63c3452a83e94c83e11280b77fb0226bf2f9e5ec68e78effa4382a274d4827499b7b3d7db8f8c817370d788f94973f0633f09d4afe478ef9173aee9f5396d0e9a4a77197dcbfecaaed2cdb57792ef2fa02524769e7939b9b37853044ef83c329db1dfeeef1d37d4b1609b54bf4dd76a3e30f79d5d8627d5bf127", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1288164782, - "not_after": 1761552182 - }, - "authority_key_identifier": "0x45c02458be10add3", - "subject_key_identifier": "0x45c02458be10add3", - "private_key_usage_period": { - "not_before": 1288164782, - "not_after": 1430179382 - }, - "tags": ["ES"] - }, - { - "country": "SVN", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xca9018437ce17984fea89225e726822ecba705312e0ba5cb4caf2f23f8e8be79b45fb10d26b89ea15e36b04f2a77ef19463e8455b3c8553c53d4053e9d2df54e6342a7c363319859d18ee8b4b6cf7abde61337067c02738b612edd266f0737e35778cecf682657ec56c508ed5f7f556f660edd73dac0a7102fe4b234792f5606a463ffd14084432560008a639b66d6313d8258c2974b121fa7e22599fc4ea007c80c8442f8af9eb5b60e956dd94348e5aa421666ddc4c17fcc38a7b360b4318bf32a416bb89d1b526b0c13ea457da71655ea5bd2576d6232136658b9164eb0e4ee0527b5bb0bd6a07d6c2dc2d12bf8e7f1a40b5d89011717022a892441c29784e0fbae7c1aeab623682c93f3c742e029580d153eebada63d4d4ebcf8603c6d8a2f4477d6ca771519e036468b3a846272633985ed3cf2e4d01954f91e60b040ae6ab5a902c2069b0914a25ea6f429fe2851b8ecebf2476319d2cda4d6dc72098af9d21f46a070bbec3d667c43e65c4c260c5734eb20c112aeca8f6c799d4c9de7d9ee8c9b40bea0693052a1ddf3004e5eafeb4b93fbc6ed6c7bda273425d1df860f40c95761e3ad2fa9c17f4c791d7f78c49dc11c1de9833873d30098b294877a1ed9ad2c591b698f86b71cfb0e936cdaf211f783a44ced7b08d1b2356c16806746e2dd7d09ca13992d6caec33e8dab7de430a2e8b0f26be2fbc39a6cdb92422f", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1571385705, - "not_after": 2063089905 - }, - "authority_key_identifier": "0x4ad472215d5e8744", - "subject_key_identifier": "0x4ad472215d5e8744", - "private_key_usage_period": { - "not_before": 1571385705, - "not_after": 1729174805 - }, - "tags": ["ES"] - }, - { - "country": "SWE", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xdffc985c0a16dd0512c26e4f7479a15e66311f27bca78f2112b4906f3e29b8d21237b45f54d9cd4f4aa1f1a0d60241375129e9f16dcf8f34d6a1685d6fb15b1c66f353303f2e97438ca61d8160e6a20c7033d2f2432c0c4576cdfe9dd2e8d53b4e4c7446060c4d79f6ffacd6406aa1925715d9306539e250cebd01b17c2d54fb8cac75c93eb43072e9233b0b82bec22f2f4c0c0d48f855b657b779214d3fd0edfa3fa8c57094b9a0aef77d935ab78d193169f1423cb9ad351b32665ba4ae7c0de52c04ac213133592a7a004cffb5577c6f2d76d10ad541efcf15e87707688d149953c987c0467315d8ac7716654f69d2d4330665aa74d04b4cb8fd63ff61b3b5bed2ed35a37e24713193d0f525832db5a4e980a95935ef6329ed93a0075fe84defe5f2e3f4b0aabc5482bab04a24c5e592bdd33e0f5c6b7898c2282de593b7f5dc261cbe7c5acd963c9e1e118cd0cd6320c8644bfdcf242a2fd09c84574231081a460f59844766cb87e2a81ed9b88d8f900bcfaa505106e0f39c1e10679a92614d20bb124091205b6f6ac79020234c617fccf3eb53822ab2e2eb178c8894f91773dc39e9e5a05f5abea8bb8648cdbf167b393a7f608aa518c6df02c083d1109658acc0a9baf51620149a2524ca21a2dc3ad9dd5182603a06162883c480f44b108376f6e6bf98203925127f1b10f552d988e519b86239e09c429edbc83e68fab3", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1517228145, - "not_after": 1958732145 - }, - "authority_key_identifier": "0xe02a80f72fe36d0bddf237e167d685e5e5b22289", - "subject_key_identifier": "0xe02a80f72fe36d0bddf237e167d685e5e5b22289", - "private_key_usage_period": { - "not_before": 1517228145, - "not_after": 1643372145 - }, - "tags": ["UN"] - }, - { - "country": "SWE", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x9f22813e720a53a9fc5dab63a05fcb544024a30d22c012debb1f6430249b9091b5fc92b5b7848ccbfeed6ec111b879a0c830faaff74b794f42e159ff12deeea0bcb60bd2158b6f36d11ba449d6b3e65972c021caab9e11ee1647b94410a88b8bf7f121ff5affe4158519331cce1b8e34e8ed7e42d12eb7b1bb88d41754f4ac8e17eb21f88205402dbefa467fb1b53815bee93b0cb41d6b95e594fe56c700a182ee62c33ba5099fe86e09e3f376b55b07297c6a00fd049edba110d365b6082f3d6365438951bdd4f2ffbf145a9b7d5f8731eaf9c86e74b6c425fdc05fc2872ecab6dfa867e4dfcb12f948f18022912c4e8093f81bfaa8337a3fe34deadf833c2e8354db3845f276441fd91fc9d58d1069fde9c6ec9b0d60619439beb8f6118a041e698745c6ec9926cd2c8d623aa2934d7fa9a83ddb95bee377adcddb125cbb220b842ddec69f55df5fead479fe75b840ff6e92e712aabb9c35586dcba82ba4578e22665e52f09b5643a37a144d149a2fa6f7f902f1c2c01d9ded1963264f730144f1cd2175fe74ce82c6c9293386b34b1454c032a7d72e78e79ee092bbe7abd850d51dfe09617adaa28253db9fec4a3ccab5c49671f9f86fe88dc945779e4c9329685fd0501771692c67c69ecab06444820a34f0f88aa54dcb5fb51a3bd2d49111c729b23eff07c47f8f990f8112b5a18c747937401424db8edd45e4d93bebf3", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1631618459, - "not_after": 2073122458 - }, - "authority_key_identifier": "0x371203cf3cc45a3037fd0ba6da01bd47669240ef", - "subject_key_identifier": "0x371203cf3cc45a3037fd0ba6da01bd47669240ef", - "private_key_usage_period": { - "not_before": 1631618459, - "not_after": 1757762459 - }, - "tags": ["ES", "UN"] - }, - { - "country": "SWE", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-512", - "public_key": { - "type": "EC", - "curve": "brainpoolP512r1", - "key_size": 512, - "public_key_x": "0x300f0f5aab3b898992f95f2eda7b67fb38d34d63ea15b0aa90f06f671718304e5b95689d65d4cb5fc90c6fb4838650815d7b9b08564ae92c5068e56346f5b97d", - "public_key_y": "0x1c096a30266a608d5a807c1999ff0cddbd105621d9699818359b25cf3b42073c198745453edb4e4916597da0dee9cbfb9405feb3f96bc40ef11831a1db8bc53a" - }, - "validity": { - "not_before": 1730797106, - "not_after": 2172301105 - }, - "authority_key_identifier": "0xefbc1248be5cae80f964c8b204c9d033bbd99653", - "subject_key_identifier": "0xefbc1248be5cae80f964c8b204c9d033bbd99653", - "private_key_usage_period": { - "not_before": 1730797106, - "not_after": 1856941106 - }, - "tags": ["UN"] - }, - { - "country": "SYC", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "EC", - "curve": "P-384", - "key_size": 384, - "public_key_x": "0x3e979f90ed5cbe5a766bc3bce1031105065a59b30159e765c318caeecec88d7791e282eca517a547a2ed5a3fae07397a", - "public_key_y": "0x864f47d3a362aa85eef50f3751beec29243046402c665d32887d9b0680e1d2a50d983328271fb6fb0ae80fb72353fef5" - }, - "validity": { - "not_before": 1668426554, - "not_after": 2086602554 - }, - "authority_key_identifier": "0x15ecacc9b836120e8f25a42657f51db8522c715d", - "subject_key_identifier": "0x15ecacc9b836120e8f25a42657f51db8522c715d", - "private_key_usage_period": { - "not_before": 1668426554, - "not_after": 1763120954 - }, - "tags": ["UN"] - }, - { - "country": "THA", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xb33d14aed2622cb8286b79374009b7efed42de4d3d1eddda422c253c6d49d8ce02789a67539dcdf63eb532586562539275ca1752927751a4ae4a41d798469e169f9ae2ea10e8fd2f848d8c37d64d1e94e87e178fb07f1d19e2f2d01193470fa27ec3957e2b5e11253bed6c83aec9eb8b6a7e1ad0ec54238022ef986b8bbfe5a3a2442490083baa21399d0a31c01a2cc679ab065a787fc94bd73dbb7e58fa430d635fa1663bcf71be301dcc0f2f04a2aed95f995297b213b7ec3d5720952e86d74b98eab91b15d2cdae9aaefb9a4e97f0b788a6e28286613286bf6eca7bd58e5a7ba3321ba03e10b38ed15dec618e3c24e0e4381ccaa0cee4c9f2aac57f2ec664c75c2fa955e97cee03dbad021ba96951f8bcdecb9bcf7cd0a57e5668c6672ecd51c46b51b1bfaace61940a5af5c71c3f0e6ccfe660430d2a348261bfd29bcf133086f0bcb3f037563f3dbb83afe85d68c382f7281a5c81a02717e75ca7b6f353bfa700273152a17c122f716aa936b158174bbfeb6e1558a4086e80feead4c9a94608ff192cef09c3648953dce31831cbff565dd792cb815a51d431283433af49f569d02dc6430845bab6b27360113d1f74cc33b2095ddb0eda82c0d21ccd595827628b323914bee9c86f7cbc678d4cb6aa6ebd427af9cad6342d90b7f8bb0a1aa41e39228814393428269412063ac16b7960cfa633147ee7ca761213fcf63cf3", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1513133984, - "not_after": 1860290984 - }, - "authority_key_identifier": "0x8a8e62e2510b7b5c809685ec71ee8205596ea6a9", - "subject_key_identifier": "0x8a8e62e2510b7b5c809685ec71ee8205596ea6a9", - "private_key_usage_period": { - "not_before": 1513133984, - "not_after": 1860290984 - }, - "tags": ["UN"] - }, - { - "country": "THA", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "EC", - "curve": "brainpoolP384r1", - "key_size": 384, - "public_key_x": "0x29c68370a65beb46f8834c00e3f8c0d33130840f56293524fd9b57240df2581f064f8ea57c1464b17fc8865f14080bd5", - "public_key_y": "0x3583f8a750066e4659df17aa185a41d565cf04c4a4cc49aea3f4f5136e5589457e87aefa4f8f65de008fc9f01e6a0dce" - }, - "validity": { - "not_before": 1584500813, - "not_after": 2057800013 - }, - "authority_key_identifier": "0x505d4c506aff95d2210780b15abdd1a4bcd6a97b", - "subject_key_identifier": "0x505d4c506aff95d2210780b15abdd1a4bcd6a97b", - "private_key_usage_period": { - "not_before": 1584500813, - "not_after": 1723950413 - }, - "tags": ["ES", "UN"] - }, - { - "country": "THA", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "EC", - "curve": "brainpoolP384r1", - "key_size": 384, - "public_key_x": "0x73b16117ca5003a71ac6bd9dded5a5b61fe88e5fc5d08cad064a7e3864571c9ea1ca0726c9fb92c0a13d7d7b4e28f529", - "public_key_y": "0x832035d1e5e51ba3b4245816bae195ad2c73e42c9b034fe79ada231744e2bcbb0629b2ab7cc55176056bb40f60d2b234" - }, - "validity": { - "not_before": 1722572791, - "not_after": 2195871991 - }, - "authority_key_identifier": "0x0951bd7741da230614be2d2702746527f672441d", - "subject_key_identifier": "0x0951bd7741da230614be2d2702746527f672441d", - "private_key_usage_period": { - "not_before": 1722572791, - "not_after": 1862022391 - }, - "tags": ["UN"] - }, - { - "country": "TKM", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xc644a9dca09e0fef79c7eb29cbb8688ec947e6d415fe67345a7d3eb51147c243ae0145622f99f093bffebb478b0a380d86c449e9fa232f50f585105f42f46dc02486ac0d3e257a42656da88646da65de65765421803ccfa3462b95b99e1fe083818553669f6d31c1dc982618d2d030d4c48db1cd8ac13dcc534ad03a2a5428905add98df72f64b160b8784a660a248510b9df1ad8e0c1260d23b8b5384a97daeb669c3ee6855a47925dd33f4e8e33ab3577fc6d7407da3721c30c79c358f7f8277d3c9ad65c487819dbd151df4ef2bdeafac91d99bc6ee7dc661a9fc60fe47330a3b5f62a6c3b88fb5a7aca27a85e4d323baafcd00a0a3533bbcacb8196a0feeb3770ace266cd6140e44fad6d4a2b733edc70478661f4f1cc5082911c88835d9aa8e4dcd9cf30cedc47f214c8e07ae1a38f0069c4562fcbf9849fbfb364268e057c5a10eef5aa147a0db47528ec4539510f1ce73919c70c1fc50882d140bca1a68b8b14da9fa400bec29941e99f2a90f15def7537738739553029c01be0bdfc32d22c97fbe3729de17ee7fe626b4d549320736767c2d5760b00ab63c736a0a93c7abec512f354ee420d01c9bb959c8ecd85ce33ff90340bb3d6fb6084f6da8adb1af3bd56d126ad92c458f7ae8cadbe81bcced286d17ef10d6f09bbb957211496e77722a4dd34131aa982f1e406b34ee79cc766f6be2fcb67b80958343187a6f", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1213695224, - "not_after": 1844847673 - }, - "subject_key_identifier": "0xfdefda092b6276900d24e57e32f2d7c2a2ebd4e8", - "tags": ["UN"] - }, - { - "country": "TKM", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xcaaf4398b0cbb0e5d997df0adb7887046ef57805d2474e04439a4ae93918154c97cae849d22ca761c6f3af47d8cbd3269d8a81e37bcd04d4c67c1c8db0bac320cff99985717d45792a56f495cc5fb9ee04e0c0f16e69697c5fa78e8e939b864e45d897c86179dda11c2a02596572025c0d1b8b14d09f83db4943a24e7e42fe4e4ca9a4672f314829f7d79ed539105c739d7a5bf0962a1344cb303d4416bcbe33bb7cc837ce85a9c371f840c8ee4829e1cf4e425ba0f9aa7310397190093ce77f8dd11b249fe83b2c6c7810b66726523cd476e1344144f370a148ce19a4898d5d4a943a4adb652fa9c02eba44337838ab5ce62e33fd59a7df7d8bf2bfe3f314844a2b2387f3e5a486def5e3b91a0dc797ccadc51d09822b7316d98c34678f83efe5f2632610275a6a528a35d6045d787ecd5b8b397a2cbdbf7884dcb358b214df9515eced8dd60633e6bdea65b70ca017b6cf462387fd271c19942fb5850decd6fbe270427b3ce489aac332bbb11a434c90c2e6b9f0bee498a81656b8282f3d208c514534c82f07c9e6c99b7e8278fe5849753441c4db1b4599210cb5b721c18ca926ba8a5473b0d0de68ed4c8a28d25ba7f36f57a0aa49574d218b254ebb237bfa5ded3ecf3e4b329ae526f5ca8211975410c9dfd2940cdb7b97da51c9e7104053f79297ce4fb7305c8a2a51ff5927bc86b228f0bf489be7e3fdca39b71c6fcd", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1518561312, - "not_after": 1834094667 - }, - "subject_key_identifier": "0xed0aebcfc914d722c6a24460a0288a458ce4e93d", - "private_key_usage_period": { - "not_before": 1518436800, - "not_after": 1620691200 - }, - "tags": ["ES", "UN"] - }, - { - "country": "TKM", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xaf6ec4012a7a9c5879049e178ba87d42f73bec8ffdfe7d8eb060b88e931d76120efce10ef100166b15fa74ee2f4d3f101e065468be7dfa01a16087dd15538710d3e13bfb0380b97792b9e7905d784dcc27e5b8283e7a854e8ece9988350690e6245d75a1b6dde178c420c8a584a415cd99fc213852d9e317f1db97df930670796e9cc596934aa13d9b7beea567b1844728a34779acfd178d8c61ef35ce2b9fd713e8be9e313f1a89bcd973574b8532cbc7e149c4d6ec38b05d7c8b8902a07f41d1d853ae80fcf6f2293ee2db7d0f47c6007ab65475d46ea3bd901d8ebc255c1c23449d21409b006a29df61ccbb9dfa7e0500cee32a84d26b13f2409e0aec44d8a89da904a6064fa98e3ee5f15e0e69da95d1dea8a5937fb37bc6c0458b5f543c7341660af6ccf2a4f90b4f96b2783c3eedca44ec0b331bbb5fbca576315e932a63511003ca3a73ffd07961e26a26afea98afd977df34bd82676e1db0ee1c3089d440ee921bb07bb381baf59bfee0e69854d37c91fca8716b667b9eab9a9106ddb9ef155b959c73bd969833fc3e68370aa8d28eeaa7bf0715c596be02f099e0696ccfc4324ab4885e711a07989b04d62b1a9a853e2143d0a718077ecfa465f71ebe642d8e43b89b32d7d72c1a12561cc81832f1304903ba3e301284d89384c44109e28a803cea78f4b1623a622232dbd94223d3abc75b7f3adbecedb9564c50b9", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1620131742, - "not_after": 1935665142 - }, - "subject_key_identifier": "0x6e73f4210346e675578387677ac09acefd10ecd1", - "private_key_usage_period": { - "not_before": 1620086400, - "not_after": 1714780800 - }, - "tags": ["ES", "UN"] - }, - { - "country": "TKM", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x8fdff55e84a3f95554443c844fac0515e037721130003e8b7559b509d02c72cd75a11ebf18bd80c3ff97fda10d4092c54de47db1420e0e3af61419980e9dbb0afe006a811d35d9910d68c7fb3bfbc8167ff7eee817811fc40f523c7174cb5f98b10edee17088a3b08c5f508f7801c05135b96e8fc72baf7df235d4758e1881589c754b0c3b2366ff08ca3aaefb5533a092fca4c99d0480557d90e0439832e94f76bc1db9b8edf055fe9767c6ed249045df0b90eb4fdc7b10bd327154c1736143bf4dbc345fa41a253b4627c2b73c4d656f364e5b1e9f035277db97f2e9afa27f49659e6a6fd645f784a02b9f3298a6109dc31a6a82c5caa68d6a024c9a422cdec82651372fcc4823750517fa623740fda53ad689db6bdeb93f49b2d6696070058c1d471641fd4127cffc8969a4f51b2f850be54ee7051f6b34be1937c94dfa985e76db71870104d2c241c072ab32e12cab45c103b7fbcafe72c01ed20ef7b0c235a193ef031bb239bf2a595c3e89c73347b3c9cd8b0d53b9a99d815d2c9ccb422145a3ad905b76e59c2fe333a36a62b4d110b4210b3176428ddff2e5842c71f335a623b798fa7d1052584976d48ac3d1dc8b53b64bd9656f732b21052f42ad7015d3bf910f193bbfcb850241ad9b97eeb9068df4be9f3e726e9984fab7122c427fd317df6a924b4ce3d0e30387d4d96e5cdb15c2db60edb368f47307addfda05", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1707085067, - "not_after": 2338237667 - }, - "subject_key_identifier": "0xcdd2ca2ce1fda2ec9a7ae92c0353709110a91b49", - "private_key_usage_period": { - "not_before": 1707091200, - "not_after": 1801785600 - }, - "tags": ["UN"] - }, - { - "country": "TUR", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xe8f0a2fa94571529c4df03730aa3c8ff9368187462a5cd7d47afc214a5e9714fb5c122945bd9ff482cddcfa799e72c61d2e15fc10cf0a07206f856cb275f34e568ae2e2733b78db05d62934cc95f9ffd3b8c0c96c289bc9d0464563a2e8bf42b27e5530f6ac68790db98364c9cde0a1d559633b1fc419465ba0fa9ba09c27efa258b62a3c30a5e27e8ec5743952e7c3d59f0995986d7bfadaee7f9975603ac87e5cb4f0c7204823a3864fc127466c2e232353afe20acf5196e10f126b4c3d6eca5c96863cdda5f716ed71e3bc9c0c5d0eed384643d8fae6e540e05106a9edd08088444aeb7093160094048c331940411803cd4bc1209dd581d93bd850ad3c25ad312f40de947a4edb2f4dbf2657c42a1baaba50c08c3a2a3e6e25e111e9519fc0c1de4bd6577e3e7d7659c03128934386d0459750ec5cf2bb22253fd1307a2db4f0024e0d59f6e7faa3516dd2e10b1ef156f4f98dc7a2e72169dc6d2547409103528892206a91d96d9ac0d4af7a7bae132bfac65bc20727374e10a01d25d91ecf45cc77c9354bedc76b1a4c51385cc075c1522d121ff09105c1417ffd3517a40d61b6aefecc4aa905ac0bb3efbdf14c311edf43295395ba4c4c8ae3f04907ace1e579b874d9866383102a6d427a6dac089f72b3af058082dc48089012ee3d40778e63939570c987bae6dbedbfb61ec2e01020a87e0b2f42bad0559fdb3399c19", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1369742631, - "not_after": 1785240231 - }, - "authority_key_identifier": "0x3f38d115cbf5b2016609c464fb6375d812f15acd", - "subject_key_identifier": "0x3f38d115cbf5b2016609c464fb6375d812f15acd", - "private_key_usage_period": { - "not_before": 1369742031, - "not_after": 1464436431 - }, - "tags": ["ES", "UN"] - }, - { - "country": "TUR", - "signature_algorithm": "RSA", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xdf935d9f05363c87dfc8fd7330ecf65541bc9a0df170bff03907d64333aa44b045c08a8ffb6eef7713bda9d494692bf2d81a270f47bf0263f345b1615afa013b25d5854235fbaf73628222b59d87a50418df459febc2948905fc0368ac5f3886a010ce9bd96b6dc3d314f1d179ed6f86a2924566cb2aaf90ff966c981f60edbd61c1cc07f1acee33b603a12880e7eddc574c62fea65dcadc6d35e2c0dfdcb627f206d640be42cb4700c1cdbb795c4e82447200c6b2e1d5fd5a68c2bee0beb9187657733a2ac3041dd452d419de84862854832cf3ea0210dab4a3ca678be7db3efda172637ead744dea96186e3a0ac59aa2f59da8716cb71690a9a8ddb4e0f7b5a8e300a3aa6197952c3958beefd18ff605311234ad520c8678fc474f2756a48b3252b67c9a503fb2476419d4c0d8e5317b74909fe7405e8fd4a812b72fe76d11469ad446de282984ec43875b27358e59afdfe96ca25b7134aff05d3d058d39c954f3699a85977da50208763f077e55e84cda80f064d547a2ac82c9a08e96900f240ce2c6b235cb3c53c4b5dfccc406b8b1aec8c577adc299996cbdb14d4f90be7b53da4536381271032e233cfba0e86e06e89eab7314ae6bdcf82a0040c6a15fb0a57841827ea1aaf3ecae0f8c6558ef64f6ef8ca2b83bf8312f6997b65ea3f5b7e0ea9177a908f56acfd46a326d2ca808bb1a1499c2b3dfbb56a2f1ea6f2c9f", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1464709927, - "not_after": 1880207527 - }, - "authority_key_identifier": "0x64389d154eba8000091857847f6f3238ea621bc4", - "subject_key_identifier": "0x64389d154eba8000091857847f6f3238ea621bc4", - "private_key_usage_period": { - "not_before": 1464709327, - "not_after": 1559403727 - }, - "tags": ["ES", "UN"] - }, - { - "country": "TUR", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-512", - "public_key": { - "type": "EC", - "curve": "P-521", - "key_size": 521, - "public_key_x": "0x01038fdb2767be2cdd998661c4d0ab00df62ddb733661b2a229cbb9cff24127291058772c5db2bad85ee4e2b450a5a399b27e5e2f6e1432eac5e47653c8b9582cc3a", - "public_key_y": "0x006cbf86e163943d0e95fea3deea5c5b4a9b01e8fe94214596322c7a1a29a85b12de8a7aada50652b0ba60b2574e59f8b5aa2c11eadc587b1b4ff661106aed0828e6" - }, - "validity": { - "not_before": 1520602703, - "not_after": 1938778703 - }, - "authority_key_identifier": "0x6f9bbbc69eecdad9bc31e950e11ed0ca00220596", - "subject_key_identifier": "0x6f9bbbc69eecdad9bc31e950e11ed0ca00220596", - "private_key_usage_period": { - "not_before": 1520602703, - "not_after": 1615210703 - }, - "tags": ["ES", "UN"] - }, - { - "country": "TUR", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-512", - "public_key": { - "type": "EC", - "curve": "P-521", - "key_size": 521, - "public_key_x": "0x00cfb4d942f3a45da9b6b86604db8504f2c7d6c99511695be3605419ce7bc51d61fe953bec8d485bedc654c773acf7f1259cd36b6b851c0485e4d82726864c05511a", - "public_key_y": "0x010ae584e606fd2ba698a615bf2c9f526c616cfcae7c7489ee44b44354f6de34f69e796ce41a7385ca6ca95b721ddb0dd8fdc1f2efcc28f8c3e97083869e526c4d5a" - }, - "validity": { - "not_before": 1614931637, - "not_after": 2033107637 - }, - "authority_key_identifier": "0x871f66bee258f190df1b52db3cd0e3c58d450def", - "subject_key_identifier": "0x871f66bee258f190df1b52db3cd0e3c58d450def", - "private_key_usage_period": { - "not_before": 1614931637, - "not_after": 1709539637 - }, - "tags": ["ES", "UN"] - }, - { - "country": "TUR", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-512", - "public_key": { - "type": "EC", - "curve": "P-521", - "key_size": 521, - "public_key_x": "0x00f3c8958a0baaff0869dbba428701037831383822ea65d014d8a6969c28418b616b5c95a5bb894416ab1d773b53444c3ae96dad696b22e53067ce472caf5fdbb54f", - "public_key_y": "0x00b9b45039ddb921e33faaf3fa46a4ab76f313da8cf7f8b88b81dc2d1c3f0b3b7b0e77836200efbfa6f23996407be13875980027b0c50f24667e6e764a535afd72e7" - }, - "validity": { - "not_before": 1709625758, - "not_after": 2127801758 - }, - "authority_key_identifier": "0x7ce974a8510321722d50f4e90bd3f5ca3ecf822a", - "subject_key_identifier": "0x7ce974a8510321722d50f4e90bd3f5ca3ecf822a", - "private_key_usage_period": { - "not_before": 1709625758, - "not_after": 1804233758 - }, - "tags": ["UN"] - }, - { - "country": "TZA", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0x923679e7d36586335dd2995d68c263d9c2c22b4ae6f33d2c966675b00660331a40d8e894b3d5ff575c11599f36db158165cbe5ab1ecd2f99fa4b48054f102d5b7e27e1401f204d67ae39793f446357d1003f5cff34e0d94aa820152ebde6c0b7a846cbec4976278baecf71c55b7965696f519b3b97e23a91900ff81e5bfc6c09d1393a23735fc77824f793fd59134df0ffb97aa58698b10e41fd20d477f8ab650b98e96a89a2f658f49c47951d0b1eba6ce83500718ba6ed58068392bb5fa016d1781a18e43e23f24f8d8c8ea21f09143b47553ed47fff80786d941c55456a5a5436f1b8310a8ba5e2bbd63da13c2a4eb10b16cfae7b351e95e891acd3fc46bebc241336d57eea0a07a53e1959673d7c3800b20a68a2d719923b5f49ece56e8a2df0cbdb1a85c2a4403bcdcbddf7b0e6ba7ae861d9c5015c3393c3b663ceb64c4444c8806199fa0172de19462f210837784e478fb8d9f40a4e8553e5c381cf453b307f496dda84a779ec18348f329fc204dabdbe087aa2df5284c31b43457536e245e441b7ba52ba15d0e6a2673fecd1ee1116be633d19d1dd256c9c04b42cd7eb62114c92bd5b44a408b5cc4aa8d8740f6017b35c4a2dd41b017e6999be2c0f4dbe70576a0562db6cc93865e516b3f2669432b5f39d3c51481a3922276a265530b0305babf4e848b5d25e6c36a05ce15a270b46abeb097c04ab547dbb8fd15b", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1517086800, - "not_after": 1903899599 - }, - "authority_key_identifier": "0x029e1ef48a391c6bf033f3ee84bfe741bee3f77e", - "subject_key_identifier": "0x029e1ef48a391c6bf033f3ee84bfe741bee3f77e", - "tags": ["UN"] - }, - { - "country": "TZA", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xb23460d8d6ab603eea289b61c4da608a6ea302190b2fae8f3cd07eafebebbaedbf61f77736f48f265b01617f138b77815c22030d588a038bfacb2dd712c26a7788790bcdf8c624b0be0b54af85f00a9deccdc993b4805ffae7784cac42c63f5c102cd596a4b9ff9548ff5d0219bfc01a6b49f8d9cd5793fcf0f595e543f2b692022303dec9f7bc9715f5362ebb7cb2e0b20811e9b080aaa9d6b3b248b705bc73ceb82fa78457c6f104d2f6f69728c5ab862628d7b208f77f2a387867d0e3f24aa0f58747dda1138e97bbcf5f6e581078a09e8e33f6662eb0fe507f104e49ed9fba3040276beecc23831afa45d96e6ae272a9ce505e645e0e56e971370244596bdd94271c410c9ac8e8e9a7a0489ba8ecd3ea83377fc6ef4a6f1fe5ddea6d6fd3d806e0f5c65aa591d1235d8866597477c1b1188ac06a13e73e1fad536e1d3efb1438447fb404d6c97fe89278ffe672cd30a859fb9b68b86fee2fd4b8ae3d4b8f08376a8f8bcf1831942d201f517ddfaf74f0cba51d4cda13090150c91f1888e49237b07f00e92764dad9a0e1c53fa1b23019901ceb753e3473e2a6ba1118d17bb51c8bcc4d8ad2a1370f2c40a703eb3b06a418788273f57b14bf4be4a4b8e57cde385dba6b733e031fa3f84d014886edd4572f8148d0f913f1523bc55788fe5a297d9522a193a6d18458ce890e412a2fab1f6183ce535bd990f7edaeef966867", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1569445200, - "not_after": 1988225999 - }, - "authority_key_identifier": "0x90f7d1721c031f48269637def1ccd194f587acfb", - "subject_key_identifier": "0x90f7d1721c031f48269637def1ccd194f587acfb", - "private_key_usage_period": { - "not_before": 1569445200, - "not_after": 1664657999 - }, - "tags": ["ES", "UN"] - }, - { - "country": "TZA", - "signature_algorithm": "RSA-PSS", - "hash_algorithm": "SHA-256", - "public_key": { - "type": "RSA", - "modulus": "0xaeebdf59664b1db9f715142e1f8b674933b89b611d685bc6673c97901b6fa00e525688ebad981a1ec86159c6070b298fd3d77eea6487aea885236cb9a3c26210fafa4b07c3be64e00580b7b29797cee6ecc4caa03ed4018cdf2a5b2ae26081de4d07a98c07be37d47305424b55b92202b68514abfdd198d83fa225b7df4bc4024fe3b6de310a59ec64850eee1f1ba87ec75093b0d849cc618deb114fd457e04ed6ba559f90d058479ba623513389b62bb6fc113c7a80bbf24fb88558270567ae96bdfa98ddb0700518b9c806f5c5a78616b691b06ce60d7ffa9718fb11894d6ba7955f7249f190109121748fef6ea1ca7e7de5874da5ff2eb4c127ad89bcca15d594b3319b38e751e7925ba96d66ccd7650d26df97df3ca99c9217c1db33cc0b88e01d0e0c981aca2797edf8e58379d4aa606e3c218085fa2807ed92e7335ddca4d589db28eeb02527fd264f00c5f27a8761755e09799b181539fa1d73600fbec9975d06b0bd0e3e7fe49679e8e4bb22dd0d7ac1e25a35fd9bba8a0d445ac98de9305cd55567e7cfaa9d7edbe460daf9102df5bdccbdd26e2dcdfc2927466742264faf24bd8dbdd6957410488106d3542468438d31a0f78d18cb898a0e7da97740847c2515f4a5d3c8e01722b0ab9624bc1069f840b0b18cc3d1f4c3445bc226fab77e266a1f060caec16ce553516d9f9625452255fec3637a3aef2aa80874ab", - "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1663707600, - "not_after": 2082833999 - }, - "authority_key_identifier": "0x610f1c9e11f5b4bdc1a2999c163fae2bdfeccc38", - "subject_key_identifier": "0x610f1c9e11f5b4bdc1a2999c163fae2bdfeccc38", - "private_key_usage_period": { - "not_before": 1663707600, - "not_after": 1759352399 - }, - "tags": ["UN"] + "validity": { "not_before": 1507198631, "not_after": 1796465831 }, + "private_key_usage_period": { "not_before": 1507198631, "not_after": 1633429031 }, + "authority_key_identifier": "0xf5a8f9b1e7a992a0865408db2a471c04a215f4d7", + "subject_key_identifier": "0xf5a8f9b1e7a992a0865408db2a471c04a215f4d7", + "fingerprint": "0x109141f99baa5abcf790ee60daab9a7138e975114fb7676c06897b9185cd2330", + "tags": ["CA", "CH", "DE", "HU", "IN", "IT", "NL", "NO", "SE", "UN"] }, { - "country": "UGA", + "country": "ARG", "signature_algorithm": "RSA", "hash_algorithm": "SHA-256", "public_key": { "type": "RSA", - "modulus": "0x8d4a3584c4a8846a9f5428809dba9633d6dab6999d1e772a9eedaf08c1fb12ea22c5f00cf544beedea689361e44d66d8ba9a908e40e074d6d0f5a4f57c5a1243bef1e9a16e1bb6bd36374d8a299a3d8ae8db6421a4fcfbce9683f75b73d7e659a8e502bd4c4d95e8fd23006e73ec9281081af02b84219abfaf9f022d19d16f34aaf3ccec20f3228603bebfb29cbe234398b3b130c5db039899c3d2cb5b50313f9053a1b7556c4dce3bb6cb6ec84478a906cf7547d88d745b8bf527776b51382d0b1e1b8baa4408baf124a5ae13a2b4402a9c4bfe97b9d7743e37119e0aa250a6cb43066ad9df94473a25272f9fad73f2c1c49ae84c2aa22b40b93417f938058699b5858990add3ee372547766eee02a6f2e982eac8e233726002244acd3c73974247e0c8666c70c2bcca2650073c9c5652d7e28593656c08d47b893f87843788347a42f7e251a01c1e0f6397fcd37bd16cedae97e1ee946ba481f8449e18fdd8c04ecc013f0e0888eeabb1539de8b16c5366532e711caba07c230395deaad85153c0733cd2b3215ba0a3e1afd0ac262b9b2f9af4ce40403b86bef38f3249c3d1bde8fdec448a234925558270436c408641f6a944bac026a32fee1f184b0bf6a07b48d19eb3264f867a242aebec05b9f78afab5ab66fdea95b77c500a84d9833abd34c9e8e66a17aeb5248510ecbbacb5e3635df9eaced20f421c03f507595b9f", + "modulus": "0xc9a6105edffbf21e91ce42dc29b024ca8fb2c0c28ba8fcc0710d8275943a058494cb785caa1735f72d23364e1c5580501fbaea283458c47363fcdf475b9f86db803c812d87921142c38eb199b4787a0957368e8d454794c16ca182431e373ab853e5f21d7766b86614e300d4853329aa1bf88082d10f5c095bcf2fc60b371f2a8f37e1bbc84cefd98926b7f499914dd5af7977b9a1113afeb89bf46d1162bf5bf7aa9a47c5a9b22979c1fafd9de434395cef7e46ea13603da949582713e9347df8e151079c108860854486ab31a51186eed42caaf63be699452e113cd5865917f71c0fd352faf2f6cf69b28a395102ad0e471828e08276413efd47017d1bc512b4b557b4fb0386881542c8ef4f75cfd4ac787ff345c886027d54ca0d23894ffcf9cc218ce7e0026e1b304c038b1ab12052e9ef217d3a020ec85141e0948a97d7b87b901edb46a8f6d27b7c52c2eaa27bb5ca32df9affd73bba4134c2d9c64d41e1cef44b5d35f69db5e31df0c871386adff87b934b5923adf5ebcb469140c49d", "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1543844185, - "not_after": 1985693785 - }, - "subject_key_identifier": "0xf02db21492dc8d6738c46eb3c586987779f02f2b", - "private_key_usage_period": { - "not_before": 1543795200, - "not_after": 1638489600 + "key_size": 3072 }, - "tags": ["ES", "UN"] + "validity": { "not_before": 1328895527, "not_after": 1842793369 }, + "private_key_usage_period": { "not_before": 1369405969, "not_after": 1525622569 }, + "authority_key_identifier": "0xc1c334543aa6bc5f3db2a8795d865ab96e7bf6fe", + "subject_key_identifier": "0xc1c334543aa6bc5f3db2a8795d865ab96e7bf6fe", + "fingerprint": "0x08e65793d7173129fe5027633ec9791ba76f5f697803e3da6aa7c267dc3a3d28", + "tags": ["CH", "DE", "ES", "HU", "IN", "IT", "NL", "NO", "SE", "UN"] }, { - "country": "UGA", - "signature_algorithm": "RSA", + "country": "ARG", + "signature_algorithm": "RSA-PSS", "hash_algorithm": "SHA-256", "public_key": { "type": "RSA", - "modulus": "0xabde62f6b46547c39ec42fc7309eed50bb41bc7407960c37fcfb2f10e2812f83e3957dd675228cdf71f76320fde03da7bd31103dc603353b058f185686ceff2e7b064cfc1882c9b2f8129a26f3008a05e540239a85f2d68d19da07c8b24b1156fe24e9164928b5575de4704814a8012a2d6d4dd7c7610dd9de30d8d6d69600e41605f59592fd13c3ebae9beee06530b428f5872805d78bb18548b1fef0f3a8349444dc1be4036134a147fb7f796ba951038ca41b3a992a84c69dac51b412181d7c8ffa162862a78d68ded4beb5812d4bc825547b07986ca318f5e886a540f66abbc87adf419d532f89cb54ea7c48e7dda17ace39ade168713683eb9470880e54dbf898dd3dcfa297eaf7b8ae211afec95dd2a54edafe92fb34af41184070bbd15f5e869356659187757e7291ba76364a840e467d09ecb98fd46fac6336ec93da698e63ecc5a2d2678c1358cdca88b50dde3e4a2e3479236c0af0dbdb31dd232619612d948557e39e6832abd00a08a6a5053b0f1c091d7612bddf40636c43bd4005bb38277d7700b79e300d46439ecc0d9bf3a947a11a0de0271ded429e618f222a78b016efac480bd21038fe78ab83a69e282318c11a96340225382832bc695aff38cbdddeaa39ffe8833c934fa236782244c9490fa553403aeb264e7fccdd914858bc8deec442ed121810eae75a085719551562795831d1a65dd9fa3959c68f", + "modulus": "0x92d437fd733a6cbf1c80a88fdd08da140fe3257ede9e427dc4421f57cec4d3770fdae4025ec1d87c8b929f0bcb5a7f9509b6de1065726aa9cbbd8f4ce6bbfaa9a9fe475ab1f9f934e26ba0ef5935928d4a948ea25e36947c8f8f49fdcf47be5323240ae86513f4f4301786d7abec68b1018434c810b195d8acf953f6f6b9a4ae27d88846b544056e4f379b5fac9d93ba271f40ae2e63a582e7c54dbeeaeb62ae69594819ce7a78a879ed7b2762dca3434cc9a6c43d93440af52f06a78ad2cc01348e4e5356e7a1d3b2a195beec44c685ae6c12ba01f2262f44d3012f8f3f7f8aaafa86f994da556d322f32d259cfe2e9ae58c3d605c0f25a338b30b7d6760a393a2d0696ca299e1447ece4b5b0f6a9977f833f1db8930e6c0f51ae4acbbefe8a3845eae83645c9a083b05a14c27856945322d8956597ab235acbbcc4899ff1ed193d79e6693f371628af4e98885cdef7afba08e2cd8b89d12ec7f06b5d0a000a0ba6589a44c0a0551d59094ca62a2de6662c43c067a0f8c808d4d873dd1ed4e5f8e57865758b9e191a88eafab0aa4032ea80c9d08c89c38c133d11c1649217059091b3f6efa1d2772b98bb7bedd310c7d873cea76041b18e0e635826b6e5635b64c08d9456da8f4930c03e5fac01c98cd2439a5cb22460003fc81ace45bc49b6cb4431eb7dc2024aacbb64051069bc2a05a7b5e9359cc2410ae402f4a54c2a4d", "exponent": 65537, "key_size": 4096 }, - "validity": { - "not_before": 1637948726, - "not_after": 2079712526 - }, - "subject_key_identifier": "0x5c69dd9511fd9c02576da3359a9330304b5fb660", - "private_key_usage_period": { - "not_before": 1637884800, - "not_after": 1732579200 - }, - "tags": ["ES", "UN"] + "validity": { "not_before": 1724641200, "not_after": 2205975599 }, + "private_key_usage_period": { "not_before": 1724641200, "not_after": 1882493999 }, + "authority_key_identifier": "0x6d49b37052b10c5a424aca90e6803a7f66df6300", + "subject_key_identifier": "0x6d49b37052b10c5a424aca90e6803a7f66df6300", + "fingerprint": "0x083ebca1c8109f3fe3795c21836ff7f7b001ab71bc4f1209698113b0d2217381", + "tags": ["CA", "DE", "HU", "IN", "IT", "NL", "NO", "SE", "UN"] }, { - "country": "UGA", + "country": "AUS", "signature_algorithm": "RSA", "hash_algorithm": "SHA-256", "public_key": { "type": "RSA", - "modulus": "0xd10c2616014382c527f80b8726486e3613f5beaff3761a606274c53fc64ae23adabb88a96ac8bfb042fbd53ba99910af69641967723254fe880c2f43051f477926265b122480f57758459db2c4bac18ec057d8d5f596704d5d4ce98c5e66ce212ab7be353d38b2e30b5942da15f9852bdc54bf53b41a46eff28304f8dadb9903c4c5b2e26f80a7af0d3ee7b403425eedc3a3f93eb798584555198b8ff699532d70c89fca9c363a24f0e958d596699525f2813e88c2dfd4f98e06edf20767b87afd12c97f8998776bc6aeba980e4f58220746e444962a036ed99aeabb96c6355078828928160cfd161611db0de6e0363424db77473ddffe02ca4e43d6494e01d2021117bb4e6ff65a571140552dff739ea7040022bf0d4c9c8f4b6dc16342956c44613d73a058ce7c72584ea2a2e12fe43fa1faba98a84a53146299143e32830c631254db5448dbf0385325e5f5f23814ba043d020c8205512c79adfcb7987dca54563e6637fac7366178bf9290cfa01aaf641a1732b266a2909c4c1094bca991a87b9073d77d229d185297cb912d614f3c61a7bb1131cac075674b6fb53c00c1a6a5629268b3a04886883c496b177dc883f77d3b78008201817ee633ac80361497f7e7ce84fdf1b0d58c114e43a0a52427686b94bab4e6caeedb54750b7a618068d65e55405a63c9fd85089e25fc57413eaa172e3b146c9c4b512c68fdd174d3", + "modulus": "0x9fc356d37179e527f8b6f40c93628df420ec32d781ade2611e67e3e501f84635860f0c7e5e2b069990ccc6e92509f0950a06ca955f69625ac7da788003d29d726ff9f00a97ffd562d24b3c9c491463583e09bde83f4959651d10295ad2c83ec2d7dd5df7f7800235eb62095950af9cab67f5cd7a8a70f72536190ea686fd7b6f5094b3cee4d9667e4e9924a554839f9ec50bd2188de40c84ba89ee1c3b5f1c2cbd2b55d1bc279d1642e1caf39762fcffd4bd68d73197ce10f4548afee8c0a6794b3f6764263cc879457020da8f0674d0bd8e79731b8c37defd62d2b318cf44b72f0ca3540fb09ee412738fe120337cf604c20236121fb22e91e5e9b1bb73d682e257adf9fa615b26a24b10d7178a7651aef9ec448b9f07beac7c58916cc92064cf4b3feddd6b7fc151aa1975deabf81b6bf439f0b52ed1bd2f7b8e151d19c235a068b34cabadfdd10decd22e178b3cac93c68e376523b6ba99792a29240a2cf44e3e4c6b3e4a9db53ea89e11e62d103b933771723bc87a8e58ecc8439d4dc99b014206a452b2d64ee8afc284799912bb6a8e0f9cc936628c7af7b2b4f9809c20b8c1101461408b6eac5e0519d6c6bd5bed931761e34c0da2b909e87d3034c1ea40a95026fddc7ddcb155f586ec514e04a5413f7d52fc08f4063bd69cc673ad5d3ef5ad4750a7542ae31b576baebd27c43453daf7895312bb95dfc3ded41d06b5", "exponent": 65537, "key_size": 4096 }, - "validity": { - "not_before": 1738749983, - "not_after": 2180513783 - }, - "subject_key_identifier": "0xfb85b3300334fd74bc621fbeed94fca6de979c8e", - "private_key_usage_period": { - "not_before": 1738627200, - "not_after": 1833235200 - }, - "tags": ["UN"] + "validity": { "not_before": 1298848960, "not_after": 1772234090 }, + "private_key_usage_period": { "not_before": 1298848488, "not_after": 1393542888 }, + "authority_key_identifier": "0x2b0f99a34be9d5ae00933a7868cbcd21a6cf47e5", + "subject_key_identifier": "0x2b0f99a34be9d5ae00933a7868cbcd21a6cf47e5", + "fingerprint": "0x024deb5be505413ac1ab660f86b728c80647b9ad22044191de66e9fe47745b2d", + "tags": ["CA", "CH", "DE", "ES", "HU", "IN", "IT", "NL", "NO", "SE", "UN"] }, { - "country": "UKR", + "country": "AUT", "signature_algorithm": "RSA", "hash_algorithm": "SHA-256", "public_key": { "type": "RSA", - "modulus": "0xc7f23e114fd9d77958762c60712729d46ac79b099944ced3e728057928017e95c3c3075a65d10750fb1d2f1e40a03e770e6e5a71ee49a030a65ec4fcc47f525d0e3e6397697402f3f023a8e3790359f5eaff522ae69d7593dc5e693fc0910b80b8b714ba79ee73781dde2960753fcfa6de70ca507bc18a93d66035c098c444be36eb465a89023a18b4d9431e6f37b1ebd3265fd8ca6ec2bb64e41f668b51fed6a93a0b9894fa80c577c5426bd44695b147082c2e003a65504b662206df0de90b4571b0ddedd6471ce377dfb558f0367933b542203ad1791a2c80d7edca18ca1c715ae28180ca3cd829d3c212ce6caa743796003d76989f3e7fd2f054e6e69718e8ea24790eea7a91a2b9ce2e5259a15e3efa886e55825708e22a1d0a9e7975c89cc87a4648714053400ca0d56514f20af95a2a3aa986209b3a7c33f1fa976397faeb3caa9eda330b8c68d480ea90149a621d4a6c8be2bdcf254ffb1cc7d0d2a18be13f573e81e8cbb31c2f3a6f1dcd296855e2c8712fad85a4dc554699dd3f7236591c494424d76ea0e8ab1838e61465b90dad668bb8d4cabc1bc83cc462ede1efdb45cb963342c54e27ed69ec656b09282d82789c0bf2a307ebe95bcef7ce12af04732e7dfb7228d09e6ecd701dbf02f81ed4bb8c46f57e56d51af76c4b971ff6d31404f289a87025f3adee7845ca1cb8d8a4ff4d880f894f7624f7c413e5a3", - "exponent": 65537, + "modulus": "0xd213d1480459a827534f0126d9f17ffabcf5b29ca183031e1f4d9866d5d278b541a5a83c190ea07a5dff6be9c25fca7330ee3dfe12f9655d6c642426325548f436ff7eb979d72138f493e3d5631e1409fdde6da70e7cf4e9c3669905a48a23562487d45e8a3601a4a962396459a533deaa03ee296cb3d27d0dd397ace597f7dbceb9c0c3dacc6de020d3d4f9c1c220cda74e3d9e9c5ac0a7072b44ccfc8b07c6fb44930dc43db99d5fdfca0f3d007fdde292bdf892e99eb730e652432d5e64d7297e47c311f7917b14f60e31c1528855c9a9d027246edaaaa053e516b598a374659d759f79a4f8b7316b3fc9b51a95f71dd2b9559ddcbb6e696d62f38e09ab625c2c87884e1bd89b4bba7f46b8d0e49c38d142584a04bd883bf96ec813f4561b758fa14d1f31360f3e1230ac0e58e081d6fbda98b11245790f0f0117ee1662de32c00f8e3cef6aaba413c9dd4833e9345209dc843f38d464cd78a81ff867496893971f8cc406e9a152900417fc23283b86b298055b8c0ae1274681599876dd90bba8fae1cd3f026bbdffecc657e385a70c223ebf678ce209b4e7de7b4e8eab4e0626d89fc4b6ed16bf161cb4e16fbcbb65514419cd570b1499b00ec924396c782c98c75438b8573005def8d84817cd72ba0fcb39cd668d56b61d1c2c0148f38dec46b969a8e506f9df2545efe38b870d5ea3d310b69f2232bcb98daae41da39f", + "exponent": 38129, "key_size": 4096 }, - "validity": { - "not_before": 1427201860, - "not_after": 1908536260 - }, - "authority_key_identifier": "0x6034ffd638e602e30aefd89c7138deccd06d20f4", - "subject_key_identifier": "0x6034ffd638e602e30aefd89c7138deccd06d20f4", - "private_key_usage_period": { - "not_before": 1427201860, - "not_after": 1585054660 + "validity": { "not_before": 1302857444, "not_after": 1784451044 }, + "authority_key_identifier": "0x1fe1572e9b35121363a50fee3e2ce2c1d187a8dd", + "subject_key_identifier": "0x1fe1572e9b35121363a50fee3e2ce2c1d187a8dd", + "fingerprint": "0x25026c77297190d8fd02249621cdbf14a34aa2be3a7620c9cb7bd1bff3f5199c", + "tags": ["AT", "CA", "CH", "DE", "ES", "FR", "HU", "IN", "IT", "NL", "NO", "RO", "SE", "UN"] + }, + { + "country": "BRA", + "signature_algorithm": "ECDSA", + "hash_algorithm": "SHA-512", + "public_key": { + "type": "EC", + "curve": "brainpoolP512r1", + "key_size": 512, + "public_key_x": "0x12363cc8d50c67ca72ec54793827131a2060162d471c9d790e9f0c02bb014d202b7c76ff63ecc3793357f0265270a89e516481e2ae29516d8d44abf6ceb73371", + "public_key_y": "0x372662ce0c54285cbea98e079d99e04cee097e9272e714e0eca2d878551ce3d695eaee58bcab13ba69350bbfe11dbe714758e76819c45954d4f4a128bad7ed52" }, - "tags": ["UN"] + "validity": { "not_before": 1429816758, "not_after": 2060968758 }, + "authority_key_identifier": "0xfc4ce0f76b6557a4d9edc8ca72ad0535517b674c", + "subject_key_identifier": "0xfc4ce0f76b6557a4d9edc8ca72ad0535517b674c", + "fingerprint": "0x0ecc40ca6d6546a0061a2c7a04f0220efc08877b763339573c14a60b8b920626", + "tags": ["CA", "CH", "DE", "HU", "IN", "IT", "NL", "NO", "SE", "UN"] }, { - "country": "UKR", - "signature_algorithm": "RSA", + "country": "CHN", + "signature_algorithm": "RSA-PSS", "hash_algorithm": "SHA-256", "public_key": { "type": "RSA", - "modulus": "0xb6fc5ebd4d20b43e92ca6ffb1fca1097921a138b652592c0f94330f10baaa35feb55e889d353a93035bdb5a9cb8517fc3cda58bae757113714f09b74674955558f2fa4ac1351b04c203833f17f74b237621ae9cd31f970daac56e827352a8c89675e9aebf3459936f25e1efa3ae353e029448b54c690723df961551e6b6c7c4753accc80a3becc336aa58a502146cadcff0b7b549abe502bc9b0c27c210bd904ee8557a9f6a59dbc54016142288bd4611b97a35c248e3cce5f7a06f910cdd93e10121746bcb813f011e40723101d04498f8142baeb5bfa1ca33d56ebbb4bf951a99eeef4bb17d7136b1e8624e0db9b7af9e81ff571b4fd7d0fc1bb02f8722d511d3396238af1f39e7908155b24c532564f9b16cae228aa863286427d1d7dc8e3ef14d3ced507dd7d89b3eec3fa2ba25ac3047d56cc6a55227341ca196ab2219fddf45a52f5d47a2f5d6ea4944562e416aa77e37708ce2c8541834b3f0af5438482faf1992d9d9fdfba1fb3ea4a8e07a9663b4aa329d365c48c05f3900ff4e7337a9c7709a075b5a0d4efd4d6e4f03d23cf1ccfbb0c0ec2ca8769cf6dcc0e65ea672d586f91df90611087a197b2978f6a76e727697210f1916e0ed6e862aa7dd5cf6674fd620a6c4e57d1ecefe75f1fc7a1cdd235e6c75e8b7313088e73b2e2467aae7c510093e24509f5ca9450a863ef3c5fd2c804d99702e3cd4d9bf4886783", - "exponent": 65537, + "modulus": "0x88665f13e2c105b86b3983d10ab145456f902ce9bce4fe3ce95f9dc2ea152fb4afee319a5407ce5b938541f9318c257977dc444f52934a97ca523d27c38df5311dbdd48b7c9a248263f2067a46a6c2c7c9ec631953c2ae008dbde933d1864127587decbd43e659b21e7c1d938165cad18ab44ed4ed9e8a4a36091477169572e75b4102097d03258e0acf580a7b080db03718a627fe94dc3f8c245088ac7a696f3939e02fe29e3f4ce7f40c677a7045b32dc26793513a1a2ae798e47adc4d77520c26354ba48a6580efa79adcd2db7d488f83008f0f7301f9c889cb50329ff8abcc6ff3dc2d4272e3b006960d1161451af7f675493a3a22a63d751dea5081eaf77d9f86cb9a4c7d8988f1dc1de4264320dca34c6f044a66058314ff65e8c1cdae5ce5f947fe7a1f3294e19bc91de2bdb4dafc38522144a76f0e6bb07da62a750075c6f5b02aff05d2d2d507591b63fcc27f9bd412612337d5c0f993a373821cfd04af91b1cdc754501d7fb9641ee45b0413c00207e2a8833c732122d0b4811d1fb8aae780c4dfd868cc9ffb456ccbb680d9de8bcd4cf7d1ceb53577d029bea807c6907f2dbcbafa407e899eb578d257ea456582586cb6c8c266e2f0e16f72bce3a9d45c84a5486d9840f23ca126ab534b7055f3a3ea878bc191a6fb0a9fbf01a14e5fa7c2726c075201b86e3008a46d2ec77eaaff1f7c54bac3bd2ec3ca5a8011", + "exponent": 3, "key_size": 4096 }, - "validity": { - "not_before": 1584446862, - "not_after": 2065694862 - }, - "authority_key_identifier": "0xf4ce2f8ca64b63b3f1d0ea751fabef7ef452358d", - "subject_key_identifier": "0xf4ce2f8ca64b63b3f1d0ea751fabef7ef452358d", - "private_key_usage_period": { - "not_before": 1584446862, - "not_after": 1750162062 - }, - "tags": ["UN"] + "validity": { "not_before": 1231776001, "not_after": 1862928001 }, + "subject_key_identifier": "0x84435319dec4b5236eeac6720e82c2250050d6be", + "fingerprint": "0x2491e377d5007ff2f051c09ba73c7ceb9e9c011eba45bace732ae67872cb8f40", + "tags": ["ES", "HU", "IN", "IT", "NL", "SE", "UN"] }, { - "country": "UKR", - "signature_algorithm": "RSA", + "country": "CZE", + "signature_algorithm": "RSA-PSS", "hash_algorithm": "SHA-256", "public_key": { "type": "RSA", - "modulus": "0xb0063182ddf457802f31b24ef4a13c9cf96eceec8e6032d82686a99bf9f43b915ad02b12cee6d9900ed3099a0afe1bb457d9209cc02afaee2847072a38e72a857068b664011cfb4bdc99bd11f99162a137aae0f578653e99551129b4a3eabf30dc32d2f8e56d5bbdaa9de7f75efd01d0428a8c48ce2fe991b4d6d466a7025c30e1a79056f1ea7fd85f230385041a845a65e96932c716be35fb11e7dafdcd721f52b45d8e138adde69dea4fd36a1b89d5554c56a25613f61c1ae3fc46f6730a10c69f37b5d8e5eedd4650b3e1aca046b965c0f67bceea2f801e75ca7d7e4182ece03433403acf50f0f0410d3ed9159d21dd9c536111a3396e7cc67e6ea6f1472d7b8817db032cd81c6224f18203c0969202f352a1558cd94f2902b4f7129ca5652495651461d4ee66c67790d6d40f6afa48766e502e3fdc9c6a23ebc2e688b3f8b6fb91d1c8814cf789878d4e51d3368a8e52808e36e1744cfe12b2ba9562ffbb79203648df2012a93306c2999944ad122c80b76cd79bce198563ae556bba76a5a9051d38da34f9e486d21682f3331fb91b4471a7c742543cde3f167295099fbb73c749de4a97ccdec285ca229b6eaacece0a81ecd513ee70c2df1357d3bdc9a8193fb26de9980ae7889b25d2c5d72eed83c1202550c7da4d1aa34f2c8ea9ef85020a4dd199cafe52ec13f0942869c8b62c7d716aab01664b35c350ad3ae6505f", + "modulus": "0x9d161abe49c4177a9000d24a7423017f9c4bfe31ddd6c78d58e96449913555c94e8214f96faff17a5cb197fc82c9b4cf102fdec28288c35506c471c37152c67eca3b41e27e76b6d5982c13799e4b4992c3f668154cbb57eaa324ea06169fd09b64a508d628d54961b507936a5793319427e6071b4e2338460828d72563cd9fd47a3559dedd8b8819d4b081453cc853d2553c430e65d98bc75a902273967fc75e6781a6923e54ab35edeef19017f4db21e76199f9dbba5bf21cddd4103319815833905d9f20e681c2ee6c91fa3c7b4f3f275e79859209b548d793f9a82c5f14ff8113a3ba84475124a09f4a21122fa0fc0f93640023824fd0777a1a050c12ccf47664f128770964059770368a7304eb1bbff184f4c07df74e6674e73a96103dc2a68d4be882a63cdfd5509b0632a3eb39d6d56b0087b661c74784874163948b3a11ec0cd69da51ac16086bcbf3520b5f507e74512edd66ec14bba59b52242ee6f9838ef18451aec5e9e7a10827fdc5791b3c966813adedfcd258bc74856b5c037", "exponent": 65537, - "key_size": 4096 - }, - "validity": { - "not_before": 1729750223, - "not_after": 2211001823 - }, - "authority_key_identifier": "0x5af58c7fd9ce7e85d0971b4fc2c0f059a00d329c", - "subject_key_identifier": "0x5af58c7fd9ce7e85d0971b4fc2c0f059a00d329c", - "private_key_usage_period": { - "not_before": 1729750223, - "not_after": 1887516623 + "key_size": 3072 }, - "tags": ["UN"] + "validity": { "not_before": 1301011200, "not_after": 1782345600 }, + "subject_key_identifier": "0xeba14f8f3c698adab6109b123528ced4654a0859", + "fingerprint": "0x2e2c217c4adba66c9ba76fec82f16f1511a3dcc7309ee6b99cca13b7380da98b", + "tags": ["CA", "CH", "DE", "ES", "FR", "HU", "IN", "IT", "NL", "NO", "RO", "SE", "UN"] }, { - "country": "URY", + "country": "EGY", "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-256", + "hash_algorithm": "SHA-512", "public_key": { "type": "EC", - "curve": "brainpoolP384r1", - "key_size": 384, - "public_key_x": "0x32a78cb338f4036108bfbf240d297df591f02ee088e3134cdf2f47e2c0e7ab15ecfa7abbd848899dbaedbdd796d88986", - "public_key_y": "0x4b0ee65236f7abdef6c58bb004f25252f5dbbd147242498c1a7524931d880d441ceca4680ab10c74df95d8db144042ea" - }, - "validity": { - "not_before": 1444176000, - "not_after": 1925510400 - }, - "authority_key_identifier": "0x46ab533469753bb7d23568aac7423b4116283d27", - "subject_key_identifier": "0x46ab533469753bb7d23568aac7423b4116283d27", - "private_key_usage_period": { - "not_before": 1444176000, - "not_after": 1602028800 + "curve": "P-521", + "key_size": 521, + "public_key_x": "0x016540d39344053ad69c6258bdba2cf00e48192fac8c9280a6dd328201f2322054ccbb01212abaf5c4d255492077e0646d2f228058a4f069e0b43c9edfbf0181f5c7", + "public_key_y": "0x008a5a7efc565a535a40c64ce22f55c477be8312c319270b17d60b522bd60a8f7609015fe0be7e857f483eb1addd639de784cb65fcd8c3ec8a828d9160d17bcb9d39" }, - "tags": ["ES"] + "validity": { "not_before": 1741088365, "not_after": 2245664364 }, + "private_key_usage_period": { "not_after": 1898768365 }, + "authority_key_identifier": "0x4898ecbea905a068e997955a4ac0ee0b08771842", + "subject_key_identifier": "0x4898ecbea905a068e997955a4ac0ee0b08771842", + "fingerprint": "0x02d362863ae43968b3ace2e0904badb029e6e0840c48a9d46c653e5a0055e6f3", + "tags": ["UN"] }, { - "country": "USA", + "country": "FRA", "signature_algorithm": "RSA", "hash_algorithm": "SHA-256", "public_key": { "type": "RSA", - "modulus": "0xbdbc15fb397fbc1ccb58069daed4d2a42f65ff338ecc040a6f08555c218f28ad127ce8e2a8825255f6e843e4efcfaec58316fc2c3854273a144b11e387b3ef3bc358c065cc850af0d09cc00118cfa9b194493dea5cefc37c4c008a514ac7536f9a5af1660012eb8888a948e5ec81b0600a402c4d4e9398e412f6034c4d7ab827b9450cf4beea9a29c822aeb870216e82e2bdb0c7d1b5c6beffa62208edfa3dec3ee1e72d36d3a3b0b210a51c0990d29e0b48af8dc5ec69eac59a0ec6ff13b8ca8cb73191c2892ec6b2185e7c79d5b87e723dd81b88de90213d226932608899d37c2ef177da8d239d89983ec44594bb23dbe5040271f5ddbb35a92d3bbef467c7709798f6131a5e9a9a56e678f68c0e0578a9633c7bbd5d755823d63c9900d833c787c34fd07cd80f3e230d7764ea54feb056f4e677464d9a48e9850baf55ab5d9c6d8adf5e86dcdc65f243f85be32322ded7cd4b69ea79eb1bd9ae7f1abc4a87038888dac9702967cd396aadd7231077596025d3e2447ac296c601036bb9ec3f05622e5ab1ae8173c1f1a87c7fcb6d2deb463b9e6431a3c36e4f995d8e839438c32f39eeac5d1b13366235c466510f29daba53a11aa61ff5e7b44d0e81ab06cc199c257e6830d0beef3bc42c125c73d6333088175fb479565239fc6be79e7e31ea59a28a8e4559bde4b0c7353166133766e6939b72c8ac6f43a678ad9771fb55", + "modulus": "0xf0a362d5dd579a816dad303dd1f6d8c34be29548b3c23d46fcee097b2c5a00ccedf81d5aeee96ababaf60af6c2ab5451520116e83a2e77ec5ebc51e0a66c32ad8f9045f5809ae5d4a604ca66153abd227a3fc57e5a4bf8e5cfbcc0300f5a1ac9899dc676afc40663633812894a6501ec3f916f198fc842a78ec29252c03597b468ac2f8193f6c4c746290020733c5cb77e9bf4016c96e356f14f57b84508569a851e6a738ffb2436d4b6b29476aa2a8d32aafd4248e903f03c61ab05e86e9d2f705077c36b6d358b9ded234991a8e27cc6a30a6a1f900f504accea31aeb4cd4bd51afcd285ffd3a539ac09fe09ac1db8a6fc42341cdc69b7d3ee48148d2aeb941feda86957c6929a0c5609d49203e869e412a79dbd138f916f00873c8592496cf6ada235c2862c50da327ebb8aac460c248631ee86469db7b2381496d01af1f8c45471d34a40870f971b25025fa261275c8e8d36789028aa82a6fb51e5a55b249363b9f4ed05343ad321ff1931b2464f72ac1ae140b11a9eeea6a03ca799c842d94d808ff4176b21f2070c4b0f0a9c2470b50808db511484cd94f7c258d8f97e73ebcacfdd701d34bc2c691494b7ed07f78b4fb85b2685839c74e50b8595090d8c26a6412a3ac540dbe91cdcc3fc0b6a8b9674471938b73e907a948bf737730e9b95b25266ab973627ee3e82fad89fd48b969e25b89f3e1a028fae889894c47d", "exponent": 65537, "key_size": 4096 }, - "validity": { - "not_before": 1262966787, - "not_after": 1912437387 - }, - "subject_key_identifier": "0xb11a1df823a296948ee7ea49a8cc8772c6fade9a", - "tags": ["ES", "UN"] + "validity": { "not_before": 1291852800, "not_after": 1773014400 }, + "private_key_usage_period": { "not_before": 1291852800, "not_after": 1449619200 }, + "authority_key_identifier": "0x22f38320a573422caf46ab8c3dee764dbbe5c502", + "subject_key_identifier": "0x22f38320a573422caf46ab8c3dee764dbbe5c502", + "fingerprint": "0x0dbee2be1ef49bdbe573b08123fdf1308d2654e435cf9d19bda1254442990084", + "tags": ["CA", "CH", "DE", "ES", "FR", "HU", "IN", "IT", "NL", "NO", "RO", "SE", "UN"] }, { - "country": "USA", + "country": "FRA", "signature_algorithm": "RSA", "hash_algorithm": "SHA-256", "public_key": { "type": "RSA", - "modulus": "0xc385461e7af78ec23ffdbbf87ca0661982dcadd70006440d995afcc649a54bbc719031100a8867cca4a4f2fd13f8bd32a7787e59cb4ed59c2c6897d4d070dd328803984bf749ea0d2263aeaa2a1fce40cb747ebf21603f25f1300580f3fb5727effadb1ee142c28fdd90f34991e13b3ab2c677d83ab6c8fc6226cc66b07c37b9c856011af503848aa5e651457828d28a45924bbbf45a5b364636af89aa55e000d2af4b0296556f9a20d6fce147e404875b3df22412ae8931da24f98210c877a610fea7c671c0550c0e6119201e2770f581d7659907821ef979f8b1328032dcb431be8927102ae5a59831a88a5dba9f80c2c116f21a0965ba5ddc3c5e6f6ec0005dd197d2c118f8b5b6177503841bfc08d50ed23241a53ad9c1e8edf106716e64560fc12c684a1fe44928ea846681bc6fcd17d23bff67654d36d0d4ffc7e570a1bd0e40fe77e9208cc400c8f08e8c2d9a7210dc2b965cd50f3fb6ad13db9c7a1a84636f169da91e8c2ab01868ff0a38b0ab2f4309b23bdc7c3dccfa177225724f37fed3782c8a6caf9d06f54293d05e3e2ea504a9a9ea51078f2cb276034107364fad335fe65eb43a1f5e5a9688a131dc993a12eb32957df15bfdd5a79024c5d4106ecb556024d788b299fc9f53e1639436deabd5f2af90d536b55f74c51a4bc06f54971a23d05b81ddd89ac5244068f0087c9e7f2b40a5fdf7d3cb23e027d5a7", + "modulus": "0xaa55588329ece95c591d5e7aaa621e78ac78b484f2f23e442e97689f9e0c5c42917be63cd3be01ed00532dacfe009461353571e713e69e0dfd4e78e35e9ccbc3370480fe4bcab3520a0460e73adad7f33da4586eaefea4649282360594af16d7ef51745f94cbe4d645d27a5e7054707aaeae588efb99a33405f41717d54d035353f4cb8bd80b809dbc27bf73503900779b678c824cdaa9f3b66085eaa0023c61bc0a71a51c0785d34930bf0a789db0598d560b83750f7b8be18b3e1d766e575fc28902975976e40898fcce8749fa198d2197fc2e22e8fac342096c24e61eb0dae5d73a521602499fb80c0c85996924fde12f4c0362fcfcc2b7e2c59459ea6ebd703db41721387a9600cff5a9aecd33e2e8fa384bc2d6db4f5e4801aabea76392cee78a223781bf90c3ed91db9b28f79383d5caed39b107a4b68ea44572c8307f3083ba11e8773ae8f56b9d4ab63ac714267fc806b7b2fe252260a8071fe106a278c710845cf2efce6ddc9f65e32bb97306e132d308037d5d3803af23e52799aace90d58dbb8735eeb2dcf0f4bd5506bc0f4ac77238baa5640afe6172a16e4767aebc84d1e9f98464faa37a8bc0b7005668bc9ca7ab947991690f8537c12ec2fb46621ffb33c2c20b20475fa09f7a8a531bb8e6010fcc8fb4ee967e54d765d948bb71b8343f157c5df1df4665f0f05eda1c577f7216fa0743aca0dee37cc0a0eb", "exponent": 65537, "key_size": 4096 }, - "validity": { - "not_before": 1418919661, - "not_after": 2068390261 - }, - "subject_key_identifier": "0xe62d6516f615a86ae789ee813cbf3e1dc2a080f4", - "tags": ["UN"] + "validity": { "not_before": 1441324800, "not_after": 1922572800 }, + "private_key_usage_period": { "not_before": 1441324800, "not_after": 1599177600 }, + "authority_key_identifier": "0x0fcc3251e4e92a50658caf6a6871bc9e8fc86d59", + "subject_key_identifier": "0x0fcc3251e4e92a50658caf6a6871bc9e8fc86d59", + "fingerprint": "0x08571453f7030c9b1363ba4f0b3a69575296989e9380df513e1bdc1e78a54c87", + "tags": ["CA", "CH", "DE", "ES", "FR", "HU", "IN", "IT", "NL", "NO", "RO", "SE", "UN"] }, { - "country": "USA", + "country": "FRA", "signature_algorithm": "RSA", "hash_algorithm": "SHA-256", "public_key": { "type": "RSA", - "modulus": "0xa3320e36162a5de2d64e2dab8439be5f6657d4e314aff8fb0d981ceb35d9ed5cec61507ee8046221ba24efb4b13ed93d65e508aae8e35b9f49c9bf8452223a8222193aef7363b040f8d41f8597b2c33af55ca5e17d139de669948afdcdcf9ba430117006809a38751c868ab09a5df994293e5fb2b734e4bef8759b9f1bd1405a8e22db1371a320da3a7d045faf987af49dbb9cb22e3303707350a5acadbbdc574e4ce07ff2a32aeeff9baaf0992d4b16f10b32b788a5d5ca2e92c1190e8897a46f3b552a8b842d095586584669c50e43cb9bf8f4dae204562951ed87af189985b9935dbfd81e760abcc09ddc4219ec1f3792af0f2e70a101035c7709f8ef6ce77962623645354e5c78bf91e3c8d4a172d53ee0a65c540aaa8d4dfedfbe95647a89c5b2f2d9651d91acaf5183557d3e118fb48095142d1f923f3b00aade48802ab406543f8b3e222d44bc7c0a07b38e80537bbfc873516a906edd73aa2b00a6407d87354b9f519c83e7a71568807313420b58ac18ec768470fdbccb40fffbe3a9a8fcf8e1cf188702dc49da0860920e6f7173055b2afb5076dd57aa4d9f08c690e4238c2e9812f0252f9e275dfa5c151e80bd61410bf9051adc37f5e027dc320b8dd037e77c2df056519428772ee42970b42adadab601f0c1acc277197c3d1de9d1a7976ef79405b266c91412dbb8c3ca49dcad852bce41bc5915a1ad6d2d511d", + "modulus": "0xc0160f9d4dd49a2f80a0e4b0d7f55a70ac36f645af9400cf84da3413e9b4c3d4a72e62cf32819c57ddc282a35c979ee1fcbd5816c599f30a5d8a47cd8a72df8f1b0431d5c251705ba136e9779378dbc66d0e0a873cacb1c79d88fd7652550726834618030b89db1dd019154984f55733512f4b853954447bb1c6d9b54b56c551990b6f1faea7c31af5b4aa56f391fe3d718ff1350989fbd879065ad14699f77cd24ae82b0c48ab3ba52017f7ec99052a35bbfc0e1db2a0f70e721d246905c3ae56f2d2e10c1c05a36dc6bf7d2587db79bdf5347ad3b59aabfda10b820c4690c9f7579111b7c66ad7a40c7fd8edfd3c4725502866b53aa61e0cc6047bb82fd4b644ba993d2c7739732f6299c7befe94aa020db44934dcec04ed2fdafa9bfaadb09bd7cbfe0d55b149d281fcb1496dd4013fb2f69d585af9a69e446302bc3949c2acb5b82621b282915b403d405655eb77473e5ffb9e51f8893d059a3f89f20304f7c51976024ae3468a9c8b47e784d334c288a44322a035e86dbbbc724100cffb1da2eeca9c28beaa5b1c63fff84134e1efde2519d6364fd5f2d4a988e6db642ba6fef94f916e1870620278416817e41080a8179a97db48e7efe2d64180749005ac2b8102feb4eb5eba6e16bd1b774155aa65c4304134103b39505ef36ff62606efaceb98be5e67b278f7dc3537f86d92fa6b23f68380e661062e6305ad72a763", "exponent": 65537, "key_size": 4096 }, - "validity": { - "not_before": 1573749432, - "not_after": 2220628032 - }, - "subject_key_identifier": "0xf18a8bfb6a44a3468334d2d592158158824a4cfb", - "private_key_usage_period": { - "not_before": 1573749432, - "not_after": 1747303749 - }, - "tags": ["UN"] + "validity": { "not_before": 1590451200, "not_after": 2071699200 }, + "private_key_usage_period": { "not_before": 1590451200, "not_after": 1748217600 }, + "authority_key_identifier": "0xbe8a2ed6c9f9204e3a270308974decfdd97dc5e6", + "subject_key_identifier": "0xbe8a2ed6c9f9204e3a270308974decfdd97dc5e6", + "fingerprint": "0x134b59fcbbd379f27cb0984bf0a7fffcfbee94da58e06f600d6ac114ea2f9a62", + "tags": ["CA", "CH", "DE", "ES", "HU", "IN", "IT", "NL", "NO", "RO", "SE", "UN"] }, { - "country": "USA", + "country": "FRA", "signature_algorithm": "RSA", "hash_algorithm": "SHA-256", "public_key": { "type": "RSA", - "modulus": "0xe3219d24a43b0f80c20cf1ac78074e302e83823f176bdd685e01e03ed80b5bbcb79069b6678bbdc972dc88c79b442a2ae79c1f3b865c1affa69cc1e992fedf9c55929c6fbca4fd4145410a09885701b7964b0c3e0a930511a8333fb9a23d98354ec13840a1611b24407cc74916e1b5686413b447638005a46aded8a2f4d2034a42ed5fcfc0c95a8196704eccfc38e88ed30d1e4bdb881c624aca583c822f5149067f1e6dabe28398bf1dc6dc8a9ae0e94d5cefca283f66c1dd7df81163b89d5c76a7f37187a384c3e8b61caf95481b59e6987a4dd97d7baacfd5e3601177ae769c54a13dc38c9d9dc4695293ab495fea4b0c59038e9006e2801b1092de43948e0126023ef8fdd2c8f086aa1e161f4b072141d893ec585043e61910d9112391a6e100d52eb4f4d6994c2b9cad5fb9a8e05f371dbd6e13e5868234e4f550c429f66c111b1c0a202b47ba14a11599cae1fcd5a31270c5730d5a45c6f3a0e8c77bad693993c851c0bef99d9b6416296c36721518cb6e40fec3486d3170a2771194faf58b111f4a0401ae2c7dae5f9b8fd7fd655f90d979d6d23bd4f998be7cdc3ba515b78da9806880246a32e5899d84a2a65c1823d1a566cc547177ff89c764a0c9c70b7a220803acb96e7e9abff2ae501db08bd34b3db173d0ec6f74a62ab5fa8d2fe13a5a6a5e1c78a22860ab51eb35e5dedfb3feb9402bda995edf1419fcfa57", + "modulus": "0xb8bffce6f30f3b501280fbec7ad212dad81f6aee4345078b539f4c631bf82cadcf4d9afe70a86c762c60a710df7de90c545218903719cd9ed172e240dba309300842597eb03dc8e0744c75b1279dfccbf0af1ae30d0c95a5333e61d2f938f3cc802591913c49730baa84e0a6c72c1667bd261c741c8cf7edd6987ffca6f6e722ada5a9a5a7ee39687f0e67415040cfa1044d7d9cc91ee12c9ffd1081740e0aba98aa5054f1b81cd8fa50742c38b71122d6814f84889f487a33103ef4c20a4777b50697297583734afffd636127bb8c1e90760b06df2ea072e45d0a254d683eda50d39dd8ce2bd822d6d0fbf04215fe9a2bf485609ede4573b798b0b815504a2b78e39b3ecdbc3f07135a22e714db4e54372980a1007b938699b87c91e01f6e1f41849fd51dfc1fbc469cd566864b09915911dea49033951a444d319ca5b7e3fb8752611fb487d9fa803f0f4040f4f2c165fff1bf9f7981756f6660c9749c3398fd9ec80690a82adbd4b6184c722c78ec648f80f39d3528106e84db5a10c0cd2b63417c6ecab4419926e2653dfef5d0b46897ef7f08fc4dd0ee2015b59a5f9a002d545e6bb8b5636a215a3255df68babbe0675301c2623ac971860b24a468dc836a06ed4a06838e34fb6473dab4bbf423bbcee82611dd5cfb1c86efc1c91ed21603bda88e553e39e8b29892587bfb2db3ff2943caa46816dddfadfa84b74ebcbb", "exponent": 65537, "key_size": 4096 }, - "validity": { - "not_before": 1727714300, - "not_after": 2374506500 - }, - "subject_key_identifier": "0x54649478d4e61d10d04e90b0d9d5c73521abdbf9", - "private_key_usage_period": { - "not_before": 1727714300, - "not_after": 1901245436 - }, - "tags": ["UN"] + "validity": { "not_before": 1739923200, "not_after": 2220998400 }, + "private_key_usage_period": { "not_before": 1739923200, "not_after": 1897689600 }, + "authority_key_identifier": "0x8319511c9de1eeb87891003537c958b76f207742", + "subject_key_identifier": "0x8319511c9de1eeb87891003537c958b76f207742", + "fingerprint": "0x063c281f37c5429f2a21887a2edb4b088f8965273808a2735bc379fd35ca4261", + "tags": ["CA", "CH", "DE", "HU", "IN", "IT", "NL", "NO", "SE", "UN"] }, { - "country": "UZB", + "country": "IDN", "signature_algorithm": "RSA", "hash_algorithm": "SHA-256", "public_key": { "type": "RSA", - "modulus": "0xc6478805c606f7118042be38ccc8eee978650ae58b531bfe5e72cd87d63585164d84f290909f455ec51054f8421433a1c745686ee698ac1ab2433a7bc67bbceebfc7f65afa2c209fa390c1453425efc9b5edd0a8207bba7e4c4dc08736e25e27e0fde41fc4ed36d814e6a87c3d9a3dc01492d58b209fea09a97127a7dbb3cde3df7b7da7b1418b879027b756760d414a54547505f526f8a9d5a620bd672bcec146c69f1a56cc955e402b9db812cf3dc467033c699a7a88ffd4f182138c38cd4fe9ec5a4a4e931f3a300b8d369d28277ed5eb67f67b232587298ce88132cd017b43ad5d3470edf8e714eda67dcca4f646422e1298087ef1bc3b9af218a723f58d1a4e527489fbcce054ce5a7a91aaf28db73b9030e469335f5d85999b3f5124e1fdae81ce891919b4a7f429e6d40eac663f28453c8ee9abc09466f8c8563d41b8cdac12b660574f240cad859052732eddcbeae494776950fa89226cdbf4f61b6146a5f9698694230d8585b16e3e764a7bcf44ec8906398c94abfff343b5d2b3b058580dff6d6a9ad3b51cb80ea4a412630f3c6296f9255ef9ad0e306ed28379d9cb6d85d8bfd67b7a23ace158d242ce0562023b9feccaaafddec389a8109bbc2186b317bb35b6eec99deac6ba3dd325f3db05488903543cefbf8441253aa9c21139b4851585a2f434c6706e7a6e553f4d71a95a35e156b8d6fbf2e9effa75890d", + "modulus": "0xf16b4df06b9d880572deb5b0835c937bf7c2756c47b9446cd89e9e96f44b574cf912580d568d762e7fa6cfccd2da0288d02ba4f737abdd5f9443451015707e5143789b73628933c376db5f1b7614f768fecfb9b980ee21485217891727f584ae03d5e39f46078abfdabdeb72cc5c42e9a164712fdbe2781cc9a3881f958119470d7614651426847e26d6ac78b642e9338034206daaae0a2ec032002cc5afac1561e9501f075c755d5a2cff921211a22c43ccd1d48002e28b0c5e1e67d54c9bc59745f1e1d5b1891eb39086b68917789f6cb6210879e93bd48c08b61ca316352ed1184a80c45da98ee6eb87c71e3fce7c5967dacf3c0f8cf9fe523985b66348086996019088b85901f03f3afbfc9883c072773be8155a3e76babd1406c01a2f111f7333ad2a38eb89a7bdec7826b8b42a438710e3a2bc73d01f96b811558bc91972918e8dd2a56d993963342303e337c6906ba40ba6269fc9415bdd0499643e159d561f14e9b3a0be8104f6b11c7d7842ec750bc04f3ed7d80bb1c152f5c1630e4bb7e77a0336e470ec278498ae5c306dbb2fa3d3031122c4574967aba533473e74d155fb674c86452fd8c65e90a6eccf85fd9c7cc7bbea0d7d388a76a09c5a243bc3c266a8ba0063f209062b5738d65b0c5d691688f47e77f1b0a68a629a71efc8c5215f99d284e43d5e9b6fbe0818968012b0a44e8603d49e37ebbdef618f0d", "exponent": 65537, "key_size": 4096 }, - "validity": { - "not_before": 1398146634, - "not_after": 1816149834 - }, - "authority_key_identifier": "0xd93b3c4442e51760c33144b4f87338c5aa775091", - "subject_key_identifier": "0xd93b3c4442e51760c33144b4f87338c5aa775091", - "tags": ["ES", "UN"] + "validity": { "not_before": 1545128030, "not_after": 1812968030 }, + "private_key_usage_period": { "not_before": 1545128030, "not_after": 1639846799 }, + "subject_key_identifier": "0x2fdb3a5d60999ac5d7695f5327987b5bab29c94d", + "fingerprint": "0x2e3fc14457f4757a54ec1bd757269caac7632f0474a03186a8780fae1388dd38", + "tags": ["CA", "IN", "IT", "NL", "NO", "SE", "UN"] }, { - "country": "UZB", + "country": "IDN", "signature_algorithm": "RSA", "hash_algorithm": "SHA-256", "public_key": { "type": "RSA", - "modulus": "0xb27eeaf4af3abcf48b7dffcf58111317294e554c78053f389e1b42d92ae8666e4eb5ec02138704b4c37d40f5b33e59657554312551f2541e78be3cc83f9ec0a4909ca7f51b2f77357335d9250e8fa9dcc0d7a5cc0b4f4c0697f11e27f41db8fe9256eb008c584d903f1350fd738a72bc14b951ac0d40c507fd72b9c6a7a5e1de44291b72e456e8f88935143e1775923a56223da5fad121f92769010cf7f1c0e5b025e1a83d3099e3913e6c91a966041c95fd05591e133a99ebb103735281a702c6319c3c5d099f234b01c6a306758e6b889c009a17bd4cefac4195f6abc44e254bcf05496c6663e7a07edfc16c071f6330b0deced75d2c988f471546d77cbe9f27934d6a5b8dc507d5613bcaaa68b4436e1b6cf294a980f6ad7f1aae880279ba7de00552bcd0fb37d3af51132cc09a931e2d7d92e166451a9a2d437f6be3001d8924e635567830e4ac1bfde1ba5bbd45c7e6d92cc32201ea10cf49a38243b804511da614685e979239271393506bffc45818b3a53e5474e24f816942c74d4a21e571f20a4b619c9e19d6bc6071368db372fd1e20f37ec91573bb1bd5fa8240042720df3a33c258ebbc599dc0dd646ab383614d1f1072446336384c5b137aa78e103a25a4a858b0cac08b7e32bdf65c6faa2a735f5f0fefdf41046039739d44aece3a427dafba65251785b119c7558fc31043d569259c077f009a5867b184c229", + "modulus": "0xf1604076670afbc36fcf2abce6ecaaecb71491123e90bc1f5815d825c947abb8eb1dfda6a1f2977d80e727921c838bcb763dfd7bcd79b86140ca1d2ff971f0321060be36bd2c4b11cb10bb41a1fce507fcd67f31932e46b67dc9e085618d3b013f2cfe0fa91aff71b06e9d2f6c974deb8e507b097aee864882cee82e8716ddd8a6ff1470d2c88b10d7bb977f48a5215d726a4c48db95f8b188c2208285a2de9f9de947f99fd1cdc5577aadf1bdb6ee8f2f0e7985ec43b333dc25dc5f3223bce806fe94a2da514e5315857df56494fb52387811a16a7110713be517ee4150a7803775d8f74e1e0aaa911802f1bb59f88f2aa12e8524b9b53018445d6f7761c4bd29ea84790e38fb09a995e3b1aa0435819f938e707699af4be57b39370592257aaa303b24516d88f10b800148f765a9df54701917c7bae99a4fb2bf39d970f3029d5f4e83000dc7309facb51bd0adbd691bfade059d0eb418714cefc19e62ae6b2c2f29201adfd8192d44e4fdd7624d13f35de3d5132f6d00e5edaae37328ddf9a0dda6011eb129e679a80f5be12966953abf05a728540b1e279752818a95c17e19f2aff901cdcfb7ac67f240cd9d430506bea150a50071efaa19a77292a32a93c11c7d3fe75939ca8c202e9b0acbfdd7e86645c2278ecca42ccb01d0ee76ef3efe714bab062bba432f8753d4b0ec16999cc58066c88c94604c8de5c22edcb9ab", "exponent": 65537, "key_size": 4096 }, - "validity": { - "not_before": 1490868041, - "not_after": 1908871241 - }, - "authority_key_identifier": "0x4bdc36babd3836e66a3bc5d990d69f25f14c40f1", - "subject_key_identifier": "0x4bdc36babd3836e66a3bc5d990d69f25f14c40f1", - "tags": ["UN"] + "validity": { "not_before": 1638949445, "not_after": 1906789445 }, + "private_key_usage_period": { "not_before": 1638949445, "not_after": 1733677199 }, + "subject_key_identifier": "0x77623b37d09cd6fb9d2ca570a73ee88e77d60459", + "fingerprint": "0x269ca5562c1e9def6c1430f0c03e7da32e90eabfbb337e6326987a80fd764b5c", + "tags": ["CA", "HU", "IN", "IT", "NL", "NO", "SE", "UN"] }, { - "country": "UZB", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-384", + "country": "IDN", + "signature_algorithm": "RSA", + "hash_algorithm": "SHA-256", "public_key": { - "type": "EC", - "curve": "brainpoolP384r1", - "key_size": 384, - "public_key_x": "0x23e2771e2e93dbe8690eae1a96c68ac5677fc7241cdcb3341617707e7010d66368458c22822f51428b59ca37b228da64", - "public_key_y": "0x06aa2b07868f7f928442da46714c19eee7e479c43ebb1936ce2d8d31ae014dc4af6e10f9fd9ed7dfdebd8bce093099d7" - }, - "validity": { - "not_before": 1557381540, - "not_after": 1975125540 - }, - "authority_key_identifier": "0x51467674f4f2f4626840ea002c121f886e071f47", - "subject_key_identifier": "0x51467674f4f2f4626840ea002c121f886e071f47", - "private_key_usage_period": { - "not_before": 1557381540, - "not_after": 1651989540 + "type": "RSA", + "modulus": "0xd127294368b771bb8496e204cbe5df4992518a618e75bd283c85111d307cc47d281925e9147db393e4d2d042ef84a95a4e0481a90e9cce8184152766cf557ebb76961836438fc0e3571aa6379a70c660201f3a1df3a8e19c9bb38f9ef8d588711ca35d73afab4f561a0373bb1d36c9e0ff873527afce568d904c5215a5c839912ea3f613ec1eb958ec6ca04f69cc74e883aef29f7392b0804304fb2b56a1366d33106c7932a99e805cb5a0d9050b1b2e30bb89ed9ead37e1274b2dc27a369d312dee082da031dbb772f9af7034dcdcedf7b92ebac28b60958eb54f596a7b6c32dafb3d72cdddc6f6abaec10a71321539debc1f1c9662b9fd4e9df599a7c6983425b5043f68fb20842ffda9d8f78d2985909c4fe9e16171807c9aad31b019c12b52105cd25cad0e1fdbfc9bdea90787626ed0be8b5ad3e3278c5df170705740c54069cff1b9176d3e945e568103ad94089217e70bbeb69edabbdfa83f3d526199d606254074cf0e11c5299a14e525abe5029d982612f03b6cf3231b5fca896eeb6f4dd3f2f7d56eafe098eca7572cf56d989736bed3b61e32d416e6e00bf8b243501f4b68206d52c1157395bd790dedfb89574d5517d02dfbfdbf88e81d333296166bcd421da49a64d89eca5cb1ffe43a9bbeb2c77cf8f8fe194a21cc5b7564a17aae8cab54bc2f3c3f0563078d369e5cf6f2f2ff5f331e5dd10986cb93ac5edd", + "exponent": 65537, + "key_size": 4096 }, - "tags": ["ES", "UN"] + "validity": { "not_before": 1665975434, "not_after": 2146877834 }, + "private_key_usage_period": { "not_before": 1665975434, "not_after": 1823705999 }, + "subject_key_identifier": "0x331edd10ce8012b5418852081ad0cf36e87ae89e", + "fingerprint": "0x1fa4211688e9e6d1d4492695567442713a28c26cdf990f25e2de61e554ec7fa7", + "tags": ["CA", "IN", "IT", "NL", "NO", "SE", "UN"] }, { - "country": "UZB", + "country": "IND", "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-384", + "hash_algorithm": "SHA-256", "public_key": { "type": "EC", - "curve": "brainpoolP384r1", - "key_size": 384, - "public_key_x": "0x28cf6b41467f71ce093a7ffe003393b13c6f773a6e35bfc86a17bde5160685dd07a7348d4283520249c64bbbfb09f975", - "public_key_y": "0x156461e46e4c48ac873eccd2de14056cdac4de5a0514b7677ad88f24f3f04827c4ad9992b45f6d65909fb2b25d04d6f8" - }, - "validity": { - "not_before": 1583324384, - "not_after": 2001500384 - }, - "authority_key_identifier": "0xb90f6a1f82f3b55803cf9b318b883a8954c47f17", - "subject_key_identifier": "0xb90f6a1f82f3b55803cf9b318b883a8954c47f17", - "private_key_usage_period": { - "not_before": 1583324384, - "not_after": 1677932384 + "curve": "P-256", + "key_size": 256, + "public_key_x": "0x1785af2b0065914a14946f62fab23bf0868819632dda451d4cea841739230bf4", + "public_key_y": "0xef82f8788ca8fdafe119acb4a81f45c14aded9b47a82b76ba20e57882b36fd2a" }, - "tags": ["UN"] + "validity": { "not_before": 1689765040, "not_after": 2181728440 }, + "private_key_usage_period": { "not_before": 1689765040, "not_after": 1847637317 }, + "authority_key_identifier": "0xc757d59fbee8f19afb606005f6b7c92763efff37", + "subject_key_identifier": "0xc757d59fbee8f19afb606005f6b7c92763efff37", + "fingerprint": "0x1841dfba623cd9edd57a7fe54eb1890ee66ac64de7ac9bdc4db914128558c4b2", + "tags": ["IT"] }, { - "country": "UZB", + "country": "IND", "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-384", + "hash_algorithm": "SHA-256", "public_key": { "type": "EC", - "curve": "brainpoolP384r1", - "key_size": 384, - "public_key_x": "0x016d2486ed78f4f85a4d89891379fae174943b3677fd2a52a4f68ec68e234125a00aea697d6bd61430715aafd0725484", - "public_key_y": "0x67984f474b72103ef1ad11191c65b3d0c899bd8a92c4d9d32af4016951d4dab0c9a575242cea5bfaf0db69a9b5676e4a" - }, - "validity": { - "not_before": 1676884230, - "not_after": 2118388230 - }, - "authority_key_identifier": "0xd65f5cf42ad3a4c10ada3d3274bc63911de4872a", - "subject_key_identifier": "0xd65f5cf42ad3a4c10ada3d3274bc63911de4872a", - "private_key_usage_period": { - "not_before": 1676884230, - "not_after": 1771492230 + "curve": "P-256", + "key_size": 256, + "public_key_x": "0x5520ece5eb8ab0c41016b211585a88d0c80acc109917ec2830a1265d31c6d441", + "public_key_y": "0xc6c40248aad4baeb6093ef04d6ca1d5233837a330e6e391c8de4d47313df4c0a" }, - "tags": ["UN"] + "validity": { "not_before": 1690365644, "not_after": 2182329044 }, + "private_key_usage_period": { "not_before": 1690365644, "not_after": 1848237921 }, + "authority_key_identifier": "0x7d79684a30a5b811acbef68ebb26068dc9307875", + "subject_key_identifier": "0x7d79684a30a5b811acbef68ebb26068dc9307875", + "fingerprint": "0x1e900def7899256307969ceae8dcebc794c583edf3271349712bf285f360607b", + "tags": ["CA", "DE", "HU", "IN", "IT", "NL", "SE", "UN"] }, { - "country": "VCT", - "signature_algorithm": "RSA-PSS", + "country": "IND", + "signature_algorithm": "RSA", "hash_algorithm": "SHA-256", "public_key": { "type": "RSA", - "modulus": "0xc5b6fdbc40d37ecf17cb07512f37077e2e83d75e953ada49e1e3fe9b5ecb6438918492e3c7ed84d91ed14720a6106c81dfdf4c5f45387a3a53010502cc9419555e681894d59ea328878bf3a59f1fd57c49ad87de508e3babde00e8f2970bcb570bab41ae9593d8bc6eb8838317222b78a989cf10c5e47c2d73472c7699ccd943805aed7666b8040d59d0c74bae4a699a612209df751c377cf3ef05d522d6284b6c15cd399d78177a1cd8600e5cf78685a177278b44ab8ee2bdad22a09c6848c5540d9689fc9250d7c8c0dab9909622e7ee3fe1b7f042e8e7eceb26a701a1ac2ab1d89eef4ca8d206e4cef63d91e6bfbebacc63272014860b57b4ce872c2ad19c1479a8904686070f7ae77f796cd4807121ec331e6f0e2ee6c8d09afe5d0afdf61910694c41dcf954402e778d005191eef9c62893110b71987b35fb2be6fafeee05286d356f87c08a46accbf119c5bf7fdc941c558e8681d82c4b28b5e8a21be3f14b47370828eaa967563cfc5b319b889a4760b27fbd45b9fc952067e758b26ca9f0b84ae81d07a1e7e108ee464ef640b423c359b61b90856f13f7ac6bb065c215d358382b571f2988c5b8bda52c1c2e013d11492b48b0ad6f04a50378679ea6b5aa901596ab30cca30bf8f55e2bb6699588b3ddc4e0acb933fd82963cc2e9ffd672389d2c475dd2abeed95db812ed633c4c19324e2c5e11eb210e80b4829d63", + "modulus": "0xa9455265eeb4e84373d551203a7f13111069cada447af4804b3674f489bad96400492bbccf5fb90d8ae5c5a7a016704cf58286f3d0f3214cd0d24b85d2614afc563c7ccba5c7d0573bbdd98e73320ad364cd3654de9a4bc6c0724cd06d1e0d638e2edd2239d4d14c37bad537166b32bdd16f97768ef6e28474c4cc9b7b12af38f2f44b8edbbf8acfe55715ddae8dbce5ebb9f7d09e2f12835212417e76d28008bfbbf0e7b94ce271f3503c6de33bee7476098fffaca555ec7a7642ca1b7f8cd83797babe83b83cd3dd371b82f011bc65a72bc6271aa1508d33db0133254ae64228219d904c803497941533bf22b82ecb459d616258a182b907f3dd9cd0d09640a6bff2c1c376882c03b5bd38e87fd4c76d238ba47e6c6a4704d04ddc9adaf5a38aee554d74473a6d102574241d53c1001a5ec6b2c7f92613a3fd5c8580cc52ad4b393507fc55da1e54e9ddb2ac667e795f08e3465ee4086b4d512034c2be8d587521da810b8e68437f8d96aac9f9da44304d9199de40f32d561a410478c42ca708e50208b7736a7edfdaa20dad4efb0692b20c7f9e8d06e03d9a3513925d7cd582b6926b8161ef0e1762b8a986c23ac3135361f7d824e56329fad969c2c8339aa1efdff9e32d588ba91a828da0a60586fa762b2b565f4202729fa0dcbfbd060d75af358b7e6e297c92b816b040be8ddc8b8d7c15c58c37ed9c9ccb27821ad81f", "exponent": 65537, "key_size": 4096 }, - "validity": { - "not_before": 1385576234, - "not_after": 1874602034 - }, - "authority_key_identifier": "0x57ff282e66b7d4e1ab6de31b330098dbcd4f278d", - "subject_key_identifier": "0x57ff282e66b7d4e1ab6de31b330098dbcd4f278d", - "private_key_usage_period": { - "not_before": 1385576234, - "not_after": 1542062834 - }, - "tags": ["ES"] + "validity": { "not_before": 1692782529, "not_after": 2103097929 }, + "private_key_usage_period": { "not_before": 1692782529, "not_after": 1803253059 }, + "authority_key_identifier": "0x8dfd77428ca9931b4fd873199040907509a57751", + "subject_key_identifier": "0x8dfd77428ca9931b4fd873199040907509a57751", + "fingerprint": "0x0e630e604d417408bfee77d58f8c57c48bf462f1bbd4253472325e92a613d97b", + "tags": ["IN", "IT"] }, { - "country": "VNM", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-512", + "country": "IRN", + "signature_algorithm": "RSA", + "hash_algorithm": "SHA-256", "public_key": { - "type": "EC", - "curve": "brainpoolP512r1", - "key_size": 512, - "public_key_x": "0x009786843d27bef9e05594742e234db4bbca63edade63dc158b49bb89bc5e1f72ec66aa5918bd6448b2dc19da2bc38c99a074dcaa1b330563f79c7d06bb7c959", - "public_key_y": "0x595cc0f2def141c3d70c85746157d9a55ad2fe2d2c9b70982f33da37a4d95a85b17256b6bbadf8dd45c1e442cc7b0dd334f484a958554c274dca40a1f3f6880a" - }, - "validity": { - "not_before": 1656466627, - "not_after": 2137973826 - }, - "authority_key_identifier": "0x88918f5a25ece37a3e04c52d38a4f2b5123c85c7", - "subject_key_identifier": "0x88918f5a25ece37a3e04c52d38a4f2b5123c85c7", - "private_key_usage_period": { - "not_before": 1656466627, - "not_after": 1814405827 + "type": "RSA", + "modulus": "0xe766bc2e10937a3b61db4979e21807c25c4a3b3af7fd4bcf541721b3a49d13337f5b1ae448d58c3b637afa2280f4b07e983818a8c86e6d041cb94b968c02ee87478514cb6f8fa98af08dd3f82962d49ca4de1ce479d5daf70a2dd146bfa38d3f1afadf3a994d773d76d6caaf22024533744df53e1a2ef4e4d3bc34169230e60966cdfd7f1579398e1be64e258e6a108d82f9758dd6f32dda641dcf4c309ceaec952a159d07fff9d08bce511dd033e33b6fca895accb440df31e15af8ec65804843b28a9daa5513b26860c9da7384cdac37a6205812c1aae1e06582266cf08a18dec2c2727a525bbadd2f5e781db10a2863a1add70a22ab18bf9a385480765a811d8b446d05685f238e653215a97b18bb5374d42ce491178e5d175b7b3855c4c8b3476408666610e8d7445ce56886f66b3e0fc9fb60d5d86be1ceccac3eee6965b39ee29403354dfe794dfea3f7f87330b4805a7940930d991f91229577f5d67de4eccbca5a1d688d06e9ee8a3d484e2016788685822220848eba4491c932e4f4abe33fe27c16807aa7cdce6694d89d7a7d9f712cc18dbb733517ac75b236fdc725b14b5c44499aa305afa580e6325ff42dfa1fa1f8879f701039a26678b9b536cf8fce57cab7efeb4ede16ce76c1466d79f73b3ddab3669fb49ec342345c28c31d08b59cb164d1db6e545678e0b986c9b7b3cfb3760d32f8781fe5b4deb4e23b", + "exponent": 56611, + "key_size": 4096 }, - "tags": ["UN"] + "validity": { "not_before": 1502797523, "not_after": 1889527523 }, + "private_key_usage_period": { "not_before": 1502797523, "not_after": 1723722323 }, + "subject_key_identifier": "0x49892e694d1c968aace1b64043dcf4cc318276b8", + "fingerprint": "0x18414027eb492c9dc40b7ed18a4948a944ec4e9d1aff407321c44ac8d2a9a75a", + "tags": ["HU", "IN", "IT", "NL", "NO", "SE", "UN"] }, { - "country": "XKX", + "country": "ISL", "signature_algorithm": "RSA", "hash_algorithm": "SHA-256", "public_key": { "type": "RSA", - "modulus": "0xb6888300bc41bc9494b139bb7d0685750f7c661d2ef1130a09dba9e32baee37451ad106922403fecb8d7843cd9e6b7b4d33bf3f2d37e6eae880bedba03375def3f212feb6fa05203f634089eff452db15564d01ccb4e1ece931a1f94bbe182dd91cdc2b2a45f6118f0ef4fbae2eec8ec7257f91e6fba10069b07f69e9d98b6cecb903f7cf308c06144c4fba5795205a65cadb8f5385810179ef909972fc14a82ce92a76535e243438bf6bc724f762444db20e6ac3e734b16d769a5258981d8014e309a61181fd056a6bd48ba533069f3ed98611af6410549952a554ee41c362c1dea1b89392c5ca1dff1bd66f06d5c8cf3bf41c90ac8e9c283e103e9de012fca505a192ea8d4200d1d744220dffc745d92c5fb2d4ae771762dc609ab260b1544424c07c4ec5c5e8361f8bb29e4793bfa8ca4f65f3649075cf16d631bb349623dc21131b4c1e379bb4c49af4822164c5d16d270969e86e652c5e8b0121be8f4407e1782c50c333d732657d89cbf8162b33ca5d2969430625b4e1b3332ca62d5d99546bac72de67eddbe67eb5f3f376a400589bc7d69a0622b288ce3d2f2aedcc447d78dfe1575385c7d3a45987d6bc529ed28c722899b7ddb32e4619323ec9a2e7504a9d0e62c3acc4b414db749bee9819c4c56bb6696abae161b3af385b8301525db2e903e3cb50bc897cc60efd0754ec8bf1dbd0618a11a0f13db550c59f345", + "modulus": "0xb016c5ae5c183f07848d01dc01ae19b89a104a59310bde16997eb44571e1fd46cd8dcd1142265defcce35a899b087d24028bda45f606d03a7a7780e3994f768bca6de76c962b73b53ea5b4c3b919593e3cce76de0cd3519a945ab3c091aac12e94fa44f6b4979a92483d05eb1ab342f19c5a10aaa1bebdd1e1e10a904cffdc5e9adf5c702c2e6aaa33814d8944fc240beae9316620a376ab0dd531388999d53dd82f1758cc0fbc57af4d173c52de79bb0f1f45b6df13e3c85437ea1dbb5bf184e65a63c0f5a23e9e3a6b7fed16a05510898fec6ff16a50ca92c772b634ffaf12de1e925a628f43faddc2824c8b15f65d784c54dffc8fa6dd6034f36d6c9d7707", "exponent": 65537, - "key_size": 4096 + "key_size": 2048 }, - "validity": { - "not_before": 1319932800, - "not_after": 1801270800 + "validity": { "not_before": 1359590400, "not_after": 1990742399 }, + "authority_key_identifier": "0x857ff56a53b6c4d8336005d9ab5e80206773c74e", + "subject_key_identifier": "0x857ff56a53b6c4d8336005d9ab5e80206773c74e", + "fingerprint": "0x11e7307acb2163325c251b2e35a11c8609aa31aa5f6314327dc7ddaf71e6c290", + "tags": ["CA", "CH", "DE", "ES", "FR", "HU", "IN", "IT", "NL", "NO", "RO", "SE", "UN"] + }, + { + "country": "KOR", + "signature_algorithm": "RSA-PSS", + "hash_algorithm": "SHA-256", + "public_key": { + "type": "RSA", + "modulus": "0xc7fe759c6acf9ea74c6bdce1a0605834cf4973892b3344811f04f566e4c5d3e08fbacd1a6db4fd6b4fe6ce412c89c3a71e1064c33559826c428a10db0b5cc0673f024f45408db5352838b4c0c77c9d2f06e3caee0ec4c9135e5dcb9e1c05664c7e68d9a69855d78a4fca8b26c42bad1b74acef0457df01433027875689db78b6c02c0cca73a9b22c917feb513937d041eefa8c5055f8c0f13dc4ff063616d970ec731027e1e9b7e612e85488331a2fd2638e4ee0122d01f4c8d453f1a2ab7912f92e2eed218c09d22ca61075ace99007365472255ae4865ce66413261f49f9f658ddebc7bb459b5e6dc17edbf8fcd9a60d1b541875ecb7a48611df6591ec4be997a755773043499b897ef5d4e6a3bb87232b91bf801b6f4c51950632c430400870db2fe61b296f1f7996cce8ed46a5de2cb7c073591dc2b5425aa468fc72660328746d131342ae2a6d97f9f4172de2d5c4f37fa9aaa5a79c987b97c4c6979510f19f5d7166aa88e4a0bba617aca69b4f14ebe9c129d0a48b15263cf70315608f", + "exponent": 3, + "key_size": 3072 }, - "authority_key_identifier": "0x7119151e546c4ac76e3758d875fc1501ba7daa90", - "subject_key_identifier": "0x7119151e546c4ac76e3758d875fc1501ba7daa90", - "private_key_usage_period": { - "not_before": 1319932800, - "not_after": 1477789200 + "validity": { "not_before": 1369989716, "not_after": 1851346799 }, + "private_key_usage_period": { "not_before": 1370022060, "not_after": 1527811140 }, + "subject_key_identifier": "0x7c06261ae37de33ffad61470e5abbf6d147d27f0", + "fingerprint": "0x1bcdbbba14abde122c0eecde54d53295f6cbc4563b54c25177c0e2858fb63b38", + "tags": ["CA", "CH", "DE", "ES", "HU", "IN", "IT", "NL", "NO", "SE", "UN"] + }, + { + "country": "MDA", + "signature_algorithm": "RSA", + "hash_algorithm": "SHA-1", + "public_key": { + "type": "RSA", + "modulus": "0xc57311ca1c839534e98afe81610940324542b0998aee67118225530229a864da4fae392ff514109240bbc0133928c73375289b1fdd8f764e1dda2603d2536f2d47753daacf6be3d5e6a962c445f84ad584df4461f64c239f627392fce4702528fd40c01914abb3680f09117cff7f82b2a459e13324486c91b86d894f1d33bf139c80d80cc36458d364fa5256d939a95f482c055d128f056e9226a8efa1e70446e138c75689990cad0974e3cfe3f1d907fcee8a155d6a84186db3a43f57336aa67583a4f1514c5e8178cb2d6abca85fa962b0f3e637d521cf8cca8def6508e9940e6fa3e7af9cb0c3c9ee4fc68990238e3a9a3d6d8ec3a6ff7ecd77377d76b161047085af2d10717aa0bf0f05f2740c41220807424b426ffe55cb00f35001aecf95225ab62dd25141e2532395a58e597f0423c75ef1f844a6e11d6f60e4f61b119b0d3a675d6aa05a69abe872f61cf4d6a06769925c8831dee634be59afa19626ce4c51a637379f6b13117421f4fb79c4f007dcbbe1c33246d7db13be7f8afec7b7b74baa3ccacc6cc104150cafd312e3795b5333c1cb3e907d62ce36cd161b8f775d4bed140f0afb046d27689a713b775ff043cc85fe50e03eb4c97be9b0e1650cefead0f1cf7e5410ceaa9e1867c5bebdbbc05522a1fd68b870658b484e09f8be4be2a3d44dc02ec32db88894b53835afd95aba18ec76beebba7401b9a7b507029231ffc40cb5e3df3eca806b9d8a61a8f962d9b3ad1f634eedc5a63b39480a525f1f848437331a25ca359bba15d4ce1f0d743f7106289fd6bdb593bfbffe67f24f2bda6fec5cb9dfabf36a4b5a76d63a7eb3730d77e07e190d128ee904a4f6ef43b892e54b9d3d9d257f64b81386280197cc055350ab6ac3be2c01b84248d8f18fa6ae378e585ef7aa3bce26afc5dafbebfbd9011dc218ed7c7b2fb7765d0e52f6ae74c0fc6d8be630f3b696ccd1f7757307ca7ba0f08ea39f725f6e5bf9a598f5d83bfebff1fc08f8fc06a627cd15a3fc5a080cc8e99b61b864a88b67664fa7f6f49d5f2ffc92eb509b7b61e66ec52357ad70ff71b5e8fc036ece79b6cca7", + "exponent": 65537, + "key_size": 6144 }, - "tags": ["ES"] + "validity": { "not_before": 1299074708, "not_after": 1772460308 }, + "subject_key_identifier": "0xc59dd59ee7e15cbc2f103d5299ef319f3ef910f6", + "fingerprint": "0x2fa3697919f75c9d397ebb35ab1483a34e7547e8ac019d332d19573e3e595d42", + "tags": ["CH", "DE", "HU", "IN", "IT", "NL", "RO", "SE", "UN"] }, { - "country": "XKX", + "country": "NGA", "signature_algorithm": "RSA", "hash_algorithm": "SHA-256", "public_key": { "type": "RSA", - "modulus": "0xac75d6fc01e6eb6b1cb7731562f8d843a82f15f5b0f434bfe6b641ebc3d176db7397cdff0c97c6acd5b65c6aeef541a6a642d17e5fcd577aeaae346a68357231bc74ae350446f2e9937804e18045020ec9aa86985aa4aad71521a3d663f69aacb1e9349d3f3f885a1e8e70f0723e48ed0f628cb3fca8842c54161502092b28f87de38ce86e91766be6faf8cd5a7971337d00ca59f95225510f840e41aafa66c6361de685426b64fb958d3f9c1e4a23813a4fdcb20f150e2f6bf4d69f56e0414c6a1e93a2b0b66ec7fc4843dbf7d14afcbb8bc07fdd2051c4bf75ef131aa9b890e4f3b03c7b4622d328271ad415b11e7ae7cde7bb1db0550fbe23f1a5f6de3d994cdc2b318023ebb7bf67306090530a19bdef77c62b73764194f185371e0e63a43d6796a681e6798d6b7305132547e37cac04bb2e013a4f1a8f52c536c4a18b48191063c6eb84b1ed722a4d5790b2fbb0a6658a0c102fdfbe59b14c72d8c85e8300fac3fccccf546317c4bbbc3e3317c5a1552e590488245d5eeb9893c39312259ed816f45c734d640ac03ec6ea6eebc48502fc8aa133c95de49818014cf8dd64e367aab82e034a561f6b9521d46b1d89fd1ec7d494bb7ddb052cf95486069cb220ff3edbafd0504a3164d2b96db9ee8f77d8ea901288dcd8ddba973a66bbb654514914a948ca4355cfe597314bf2968cdab599848db13ef14226f2541d6fe76f", - "exponent": 65537, + "modulus": "0xcc7fbcb9331cef9f4be115468b095f622bb84a295af93770388c672f63e3d83a0fecf58520810758b53d03ed6ee7aa9d41c165ccb7bd5cfdb7a7d4bc71b14d2dedc73da6d12ea1abef9dbf1f54ce39f25609d600c33da26e21954a30042aefb96b6ad479f617e587ec07c95fe0b7b99a578355ec1252475866d283de2126b6ebb6ff81778f714c5f452715723bd80be8e46965a933194e749317d321f377b2a240524ea7f025f503a1e1464caefac60194df68755548891c8afd9844f17fc5d5712333764052ac41ead4ec0878938adafb193672f38052d4932307636df5453373ee1b8a4f274e66d33ad4f247033d35ab310a504da71ddc4d2429aca9bef17fd2fa4f90980618f16a1e08c936e4983d849c47d77e338a3ab5aa681c932d11c5b106cb8c7002e65c2a00abeee01dc284b78672a167d4dd8321e12db4d43ba74845819b5cac6c1050aca71637ec0d156a7c88caba9ac5ab22b2b5e43039e44cf742a327d5ff06faa4b2e4688dda1c8d25de5ac661e41a2a55f0162e443c0f757c92eea0dbb126859b1fea614289a37b34a7cb1eeb2886d9ad147a2a4b4484603f21f48985d9c418354e6c236b3131f09f100a2a658a4376e2a24a9c2c58f1c9395a84d06b4662ea9fdc17fddd9c962a1aae61e59b46e50bc96026fa3573580ed051948f29744f3dd01b024eff8d8bb1e5e636becd0feae9afd5cfe3e7634063e3", + "exponent": 107903, "key_size": 4096 }, - "validity": { - "not_before": 1477481968, - "not_after": 1958643568 - }, - "authority_key_identifier": "0x1658caa4c0053cbe6c188c93794d87a377f233ca", - "subject_key_identifier": "0x1658caa4c0053cbe6c188c93794d87a377f233ca", - "private_key_usage_period": { - "not_before": 1477481968, - "not_after": 1635248368 - }, - "tags": ["ES"] + "validity": { "not_before": 1495027148, "not_after": 1810646348 }, + "private_key_usage_period": { "not_before": 1495027148, "not_after": 1589721548 }, + "authority_key_identifier": "0xaf3cfa7356b2257be9b19df390723726be7c8dfc", + "subject_key_identifier": "0xaf3cfa7356b2257be9b19df390723726be7c8dfc", + "fingerprint": "0x27b1e6bac2778c95e42005be427e6da9db26fc9ba2b3c38062878f18fe94b105", + "tags": ["CH", "HU", "IN", "IT", "NL", "SE"] }, { - "country": "XKX", + "country": "NGA", "signature_algorithm": "RSA", "hash_algorithm": "SHA-256", "public_key": { "type": "RSA", - "modulus": "0x896a754950def92cd4c648d40ce6caae7a6babfec9f7b2802489174839728dee78a1242411e067250b4f09ed7b1c92545046ea71529cc964b2384d8ede190f028f4779e9015efde9c19e18c3acf6b4193fd78963c1345ee2cf4b0ec8bcf37aa4f876f64103da0b0fcc21d0827abbe62a28c167c4cfac2d3c80295bf2406be80b9b40560dccef45561e1a7245e4eb2a2ead3dcc2307776994c3c75852decec81be7c04b3bd4c959acb999208bc5e3ba0b4176fdd99e19353b8e24c2a65bf98d2e7474e6bb4fe02e45b97465816ac9885f0e83d0bc7a3e0bd15775ea04282d70c3bdb63acf8f689f541fec2bf2fe7822339670f5110af95b72495a7df0d1a639c2b4ead513b40579d96e0ea2c1a82fb0ca86fe1afb48ef146d043404195ede4aba52c57938964c2374865cf39db48554a0f813a39a35097bc5eb5f7c13e9db59b47cc9000de21fff03fd9ed72b703c9cf5c79d13844505231136bf90d94cd063c23b9710e8e11a1abca3a98edcb2a297d46c5125b0a89c89aa3e87b5aac78916a56c86b7a67b920535a015889c0566cade38cc7a2c36709c6a8dc576dfe2aed5641db0723c7825e2481f67bd2ce269ee73c0d71aed06a133937722e59b444559a922a3e554b79ff0b10dc6e672290e234781b214c285e4684503e00ee88e350a8f33ce662758dcbf36279e0570cd4c91284008e69c160c4a1eef380234a7f80b63", - "exponent": 65537, + "modulus": "0xa9241d920e67b58b1662f038a97766ae956d6972b7985641d7509e143135e5ce56025c5579847e0eb901e27806c9deb45f1215b54a066aa67f022b4f14082f68b9b2b7651a69799c47431331ba4e2300b263b58c34e185aae16dafb43217fc1f443abbc3808cd65c44b68107ea50771f65745ff0bfb2ad9b47bdc8438342d61b8a25a313a495585c87ad034886a5224768a1656ac8bcb0f5dc900c226d0341b08d34fc7e1706f1c9ae367f3a920e6d9a22a85256227c8f2aebfc499a22476b031bb00fd62c487b3bb7883fc4653c93d030c3b4898914c6cde3da44366dde9ebe30c4cca77f516899f6085304716e655b91df5de69df1d3c84c3d3b3fc24afdd2f0a180bba6c502e9b77295d0a6903bd35cfa87ac0078ac65d74c18cda0dc369a8adac15847a2e008f7730b0808e585122ad05fd5dbb87b2be890404c3175157a399b5ee83fec12e5d02d5d52d4f153c31e22aab93c56836e2718f6f52df890a4f96d0ee6bd733bf6c43d908f869584e102fee51f0bebfabe437b017a44941ab8b9e97b6fb12b58e56be72fcd5e080890edc98c156f400a0438f2103874f7703c7021e887904f3f920fbf02b1aa5e71ca3496ad8247a1742053624d20dbb758e6e3c3085b7dde5e1c01ed81290d43f31249dbe713470fc169f7f67945b0e1378661b227be591b5fe681002eee7202b3e72267a45736d945266ee88b38f64c619d", + "exponent": 122125, "key_size": 4096 }, - "validity": { - "not_before": 1627371942, - "not_after": 2108533542 - }, - "authority_key_identifier": "0xbfc125b6634b6ac166209270f7d7445bc63857eb", - "subject_key_identifier": "0xbfc125b6634b6ac166209270f7d7445bc63857eb", - "private_key_usage_period": { - "not_before": 1627371942, - "not_after": 1785138342 - }, - "tags": ["ES"] + "validity": { "not_before": 1554105074, "not_after": 2027490674 }, + "private_key_usage_period": { "not_before": 1554105074, "not_after": 1648799474 }, + "authority_key_identifier": "0x26cb4edc2f52e7d51937344e53dc579f4ff85136", + "subject_key_identifier": "0x26cb4edc2f52e7d51937344e53dc579f4ff85136", + "fingerprint": "0x2e4fc1f8e14f31e3b853838f4488476d3649efeb74245eeb48bfa72d7d40edcf", + "tags": ["CH", "IN", "IT", "SE"] }, { - "country": "YEM", + "country": "NGA", "signature_algorithm": "RSA", "hash_algorithm": "SHA-256", "public_key": { "type": "RSA", - "modulus": "0x8df01ada4dd12bf5c44a55ffadefd3e73282197e17ba191be4e85884720a5520d120a1eb7b0ac713e99c4474844de9c877afd044b89f6b859070a581b8bef70e3278873be8859b3f3b2606b74b949ce8a935232f880ce4df9aed7cf3fed606cdb2c34217e2f7805d1215086c6c9f8eb4b53bdd2b955bf7fe304dab239986fae5bac414133c282c21d9a15d81196d0e915481c8ebf4e35797bf520263cb9100fc85cd272a345afde86cdb10266d460a77032fe038ef8aaac66ee5ff57b19a4f3432b0cc0215324fc00ca9a89d8eab7fda3dccb4fb26b81625c9a0dc76171abafeb6b055994da6ec2ec271dc1ef586462a8f194973a3d47819026310625500f1bd7625617d98f6babe79d3fb5fbea148f6239e97843d7bd00e405c838f988fd5357d3abde7612c71bd3672d0e7cb2a4401a80b7d6c7764280458c0bd9e916bb561751353be05ec9ef5f7f69bf49bd8117e406d028a40ef71758ae7316b9dfad10e32126174b36890d49d1f46950c42b42a337d0a8debd42f3542a06fd7aa9a288f", - "exponent": 65537, - "key_size": 3072 - }, - "validity": { - "not_before": 1701258105, - "not_after": 2183370105 - }, - "authority_key_identifier": "0xa67446d57ad6e9cca96220b83d8bb3c5c267f888", - "subject_key_identifier": "0xa67446d57ad6e9cca96220b83d8bb3c5c267f888", - "private_key_usage_period": { - "not_before": 1701258105, - "not_after": 1858938105 + "modulus": "0xbe80fd3db2787979bd79e40e3fdaf351cd08ca23cd0d97daff2e8781fe94df15e94bea233c4a0d857da78eeae10f639fbded32cfc6dccd0b7a97e3cd4ca68f57d767ff160aa8cc765456e00901ebdfaa110ed0dee189fef6b34bcaa4ac2cf3b8764f7489605f037351c725cabaa9e6e8e605ec5f8e581c0679a5fe40c0f6bc2289317a6ad336e83ee1e65b8e7727b7dfe2e640d65f12196a526082df89095501d3759982707b1d2cef9c37e0baf0c12b7c392bbc7724420a24402da71ffd3b163f662c589576e87c8e6ca80f68e0c79ce246c199095c8cee125036312751cf66f8dd49f9641ea49e20dc64bfaf5df46ee5b0cf02b7f540fd08a2ef85b538fdc7624c4a0138502fba4314930ce8328039be103e199bddfa4ae870bad2d8a380efdd453352b9b0de9a2a620dbe24b8e6f8959cd4ba9b04b22d3f6bc6d46612c507d5da0b19feb1fd77835dd6ab6d826606c94ee0cb1d3707ef02419a9d1598d8039857e67d93963d08cf6b627fec7b1937cd1c1f74837b9cbf7489a1f76a3bc2e5b2322b3f185306a707cf61c5a7aa488627a045f3106426fac7d66f4c0dad7773f612018e18057016b9530d01fecb2de865dc7974aeef0f3bfdca0f5aeaa6b82970b08e89adf8eb262d5a950086e766acb192ea8dfe24847764fa46e8db66115a571fc993e8f19320be08468a4857fb4853e0469767b133dfcb051cd3a8255df9", + "exponent": 130689, + "key_size": 4096 }, - "tags": ["UN"] + "validity": { "not_before": 1647941034, "not_after": 2121326634 }, + "private_key_usage_period": { "not_before": 1647941034, "not_after": 1742635434 }, + "authority_key_identifier": "0x5681341660d52733f509ff23defdba3cea612650", + "subject_key_identifier": "0x5681341660d52733f509ff23defdba3cea612650", + "fingerprint": "0x054e4f56ed970041554d73203271ba65f06a4dbbf54ba8bb6566461b43577ecc", + "tags": ["CH", "IN", "IT", "SE"] }, { - "country": "ZKR", + "country": "SEN", "signature_algorithm": "RSA", "hash_algorithm": "SHA-256", "public_key": { "type": "RSA", - "modulus": "0xf831f53186404eb32fb2527e13e5d198eda7ecf6567722bfd36f704140319b51b62cd524600b15987d5762a899ebd25b3c34b81b25fbcce614964ce8c50ea7e44743f07d24a0f766ad32125313806b95d9654b4937c006a9e2ec2d3d2dd8e764e03c7f141dd88b315af0564a8a1e6b882c954d9d64e2798932fe5bb3d32e8a2e94bc1f69c05d67b731b3992b02152d42f0d28b4016bc7474ca963574aaa06770575feb6edf9bb49ada97c6a0d21b88ec075c4b8bac34c204b6625fbfd8faa6eece3c91eb05e428cd7776808d10aed2e874b61a501dc0b88b73fa5373af6035052d9993c059c1ad0f8afa4582ddb4b6afd4541163b8dd03b62b405749daea4d57", - "exponent": 65537, - "key_size": 2048 - }, - "validity": { - "not_before": 1745849141, - "not_after": 2061209141 + "modulus": "0xda66c33d84cb462d4438c5a5de08633bd55b169638dde20c936a561a08391d64d87aa82c91e3b0facb6deb364ef7fa7fe2ea8f424a9cf7b893ddef3ebee5c35eb815cf047ac765b9d5c3cd90e0d5465cd9f6877ce8213488e443941aeafcbb901d84a4e7b1c1a7b865cd76b251c074ce10bbffa73d0fb0741a761f5a07d383ebb306fb43c388cbb635d0f040f2323f9d322ed8c80150481793da0094069c593b7064775341952b300af600196b2fe0e1029a62f54f6eb7abda45fbaa99265245ecd7ee5b1ecdabf82c32b2562c86f56c0f4e5e89cc00c98b01db99335ff4ef388626a16840ae01d93ad4b4f8751ef9e7749525d5aba6be874e0d4488f3bcd349d0ffda88874bd8b37c9d7e9880af32e6a83d7517009c31238d464f9ad64837004da348148d99c54e61fcb1b1112bb3034cbc7566d46c4657428c6c713549a573ed00aab6a3b2c39a29fdf58ef67726e637bf6c10dce0b6f03328def7b83bc6ebc8dd4f3c7cc3a96ae8d7b000b4a7c684c3692f74086aa58290a8b640dd6b7fc2fe0bba6318a4c696af1197e761b54f93927a5651a8aed94ace167ff72af783e4ae53140b7984a1ea6640deeaf2d2f876f3d2febbf1d2175688ca0b73411814fc435ea79b73470fdfa171ca4adb65aaf6de939a038d86aaac25cb038b476269546c291962c76e8e349bd3353b7d81d15c1c391f948f09fe69952e7bc7d687be27", + "exponent": 109729, + "key_size": 4096 }, - "authority_key_identifier": "0x5406f94b10ad7e7f6f96efd19434574c7235153e559d7eeddef6a69efba6efb0", - "subject_key_identifier": "0x5406f94b10ad7e7f6f96efd19434574c7235153e559d7eeddef6a69efba6efb0", - "tags": [] + "validity": { "not_before": 1474339122, "not_after": 1947638322 }, + "private_key_usage_period": { "not_before": 1474339122, "not_after": 1569033522 }, + "authority_key_identifier": "0x245ac54ddd920d5065be705c237ee684f7184d51", + "subject_key_identifier": "0x245ac54ddd920d5065be705c237ee684f7184d51", + "fingerprint": "0x083669a5a225869aabaeb8cca947d0a7c6b7e92aa3e47cd85d351259d375908e", + "tags": ["CH", "IN", "IT", "SE"] }, { - "country": "ZKR", - "signature_algorithm": "ECDSA", + "country": "USA", + "signature_algorithm": "RSA", "hash_algorithm": "SHA-256", "public_key": { - "type": "EC", - "curve": "P-256", - "key_size": 256, - "public_key_x": "0x6443032bb8d0d4071cfcc2f141bfa3d730338a4c8f45a3e01c59da4d6f4d91dc", - "public_key_y": "0xae545f1897a365aa173eeb55d90c8789178159a0089a977f16375dc591daffa3" - }, - "validity": { - "not_before": 1745849142, - "not_after": 2061209142 + "type": "RSA", + "modulus": "0xbdbc15fb397fbc1ccb58069daed4d2a42f65ff338ecc040a6f08555c218f28ad127ce8e2a8825255f6e843e4efcfaec58316fc2c3854273a144b11e387b3ef3bc358c065cc850af0d09cc00118cfa9b194493dea5cefc37c4c008a514ac7536f9a5af1660012eb8888a948e5ec81b0600a402c4d4e9398e412f6034c4d7ab827b9450cf4beea9a29c822aeb870216e82e2bdb0c7d1b5c6beffa62208edfa3dec3ee1e72d36d3a3b0b210a51c0990d29e0b48af8dc5ec69eac59a0ec6ff13b8ca8cb73191c2892ec6b2185e7c79d5b87e723dd81b88de90213d226932608899d37c2ef177da8d239d89983ec44594bb23dbe5040271f5ddbb35a92d3bbef467c7709798f6131a5e9a9a56e678f68c0e0578a9633c7bbd5d755823d63c9900d833c787c34fd07cd80f3e230d7764ea54feb056f4e677464d9a48e9850baf55ab5d9c6d8adf5e86dcdc65f243f85be32322ded7cd4b69ea79eb1bd9ae7f1abc4a87038888dac9702967cd396aadd7231077596025d3e2447ac296c601036bb9ec3f05622e5ab1ae8173c1f1a87c7fcb6d2deb463b9e6431a3c36e4f995d8e839438c32f39eeac5d1b13366235c466510f29daba53a11aa61ff5e7b44d0e81ab06cc199c257e6830d0beef3bc42c125c73d6333088175fb479565239fc6be79e7e31ea59a28a8e4559bde4b0c7353166133766e6939b72c8ac6f43a678ad9771fb55", + "exponent": 65537, + "key_size": 4096 }, - "authority_key_identifier": "0x9026156f3c7bf9dca5db7c551e9de87a91a52925a92a229163074698beaa9da4", - "subject_key_identifier": "0x9026156f3c7bf9dca5db7c551e9de87a91a52925a92a229163074698beaa9da4", - "tags": [] + "validity": { "not_before": 1262966787, "not_after": 1912437387 }, + "subject_key_identifier": "0xb11a1df823a296948ee7ea49a8cc8772c6fade9a", + "fingerprint": "0x0f98dcf949037c4f3f46093bd1107a6766292bbc5e862cc47255aa9202dbbd17", + "tags": ["CA", "CH", "DE", "ES", "FR", "HU", "IN", "IT", "NL", "NO", "RO", "SE", "UN"] }, { - "country": "ZWE", - "signature_algorithm": "ECDSA", - "hash_algorithm": "SHA-512", + "country": "VAT", + "signature_algorithm": "RSA", + "hash_algorithm": "SHA-1", "public_key": { - "type": "EC", - "curve": "P-521", - "key_size": 521, - "public_key_x": "0x009312b9ee3bc1147f8eb6d2a4b31c7937326cf0a7c941744a20203049fe70ba77fd9fb41c1fd81138c4be1b10e3e58ab0f7c8c76ec31c0981f83ec7171d4009dc20", - "public_key_y": "0x00bbc3a2a7b267baac0a58479aebed9043f47e85c5994540b4dfae4a75d75e12edb64537e72509343116c02029136cd67f6d2a44eea3923c345d69ced1e17b07f481" - }, - "validity": { - "not_before": 1638963947, - "not_after": 2064483946 - }, - "authority_key_identifier": "0x82ff193b7d62743a07e393502bb116e72a77ef7e", - "subject_key_identifier": "0x82ff193b7d62743a07e393502bb116e72a77ef7e", - "private_key_usage_period": { - "not_before": 1638963947, - "not_after": 1749123947 + "type": "RSA", + "modulus": "0x9c4ff9a2006df7f763f75a40bb2f3cb8b69b39dcd0bb01d6567768e403ff74082b7d7a2cc78805b3bb499d59364f422801598fe1af453cf6282a3176b79c6a9962d30c610ac6d80f71a6f590567dcc00de837e314c09558a0f71786eea107d3ec78fc32fd4738a5da1ba81f146d1ae83ab7f5e260fd0fde255055c6ba18b1f5498d3eb2830e1a58af6e15ba7fa1f9de52c73ebb5c4d323e328e5726dec237bc86be5e0b24d49852fa6e1bcc0d240ad8649430fa4b9cf4b566675e5583c919855c896dcd58fd8ba3b0fb7f0570a57d40af5f4c4c93c0efaade0027664a53117ca49be316504e8a6b43346f0ef41a9d5250b3bb54939bcc7a5dee31d9056dda8ca690aca4113455296e0d4bd7c76b68185a59b587f502478b7e21e8803eeafaf6bd8151d2a9e013e00de486f47cdb2e12c24d58bc9aead347e84b2eb3c81bc671a4dc8573be867bc7de9ddb67788dfdb4c45b1aeb93436bc4134af4dff572dc8439201e60f8c0ea710922014208e7a6f286126b6b42e873d3154943db2de0aeb795d9b54db655f83a9f2823c639f6627578ae88eee7b44c49b0659e45ef11e870ab8527c3ecf5461786de1f2b3261588baf3c759a2cf53bab91c0b388e1358960662e332cd0a2561a61d51acce8d36c4d5417cc778fc3a151c0afe115471755ea0107472fc0ea8b4257876b47486a0927daf0c05035bf617af9a08d84aacf61c9f", + "exponent": 3, + "key_size": 4096 }, - "tags": ["UN"] + "validity": { "not_before": 1203589065, "not_after": 1834309065 }, + "subject_key_identifier": "0xada907a455abc131269722b5bb502103db28b6fd", + "fingerprint": "0x2301430bfde5e9484d27fb4c8fe04ef634b0f3f16883856f173ef08c3cad8d6c", + "tags": ["CH", "DE", "HU", "IT", "NL", "SE"] } ], "serialised": [ [ - "0x002f458b6d52c74f3d3f67f3e02a6e0e5ddeedc540ebe8c869d56a33caeea144", - "0x004b5357c3b3d059f7356e29e1fe766239a44c1ae06b77226872347adbbf29ff", - "0x00690f75b45ef0feaa60d123401c9be9c8d6c4fe08bb072de39a556640869abd", - "0x006990822a2a1c586aea4cd5738acc474d6c055f85e4d62e0547cfbf378bf139", - "0x00784ef5466faacf6931cc8755dbc7b24d76d2c0856d4658bbf7691e91fe2b35", - "0x009ab6f45513cbe9ea7c4f33752af9489d684ad854bd0928d0d05dc8e945780e", - "0x00b2ea93260840874a929dafa8c2cb0ead55db5adeddddeaa4a77e43395d5056", - "0x00e80a293e01214fafdd19537c50556f1072f115ee161bca0b52e90b38b1410c", - "0x00ed501ce5b41f41e51e8b0f34a6dd5df850c576aabc8f3ad00da6dfa6272c4c", - "0x00f9e75b9e43b652b3d7cb2a6b028fe2cf44a73b50088e69076370acd7a8764c", - "0x0155fd4f3adb6da2791b25c321a9f90ccdbf9c13998d8e23d1137bd55b040a0c", - "0x0163e1c4e4dc955b09e6c77fa93d3246db94901d3a9bb5c5bbd06b1b78872084", - "0x018c74993d2c94815bf11d36b24ab9306b688ec773d1a497ed604674dfa37f8f", - "0x019c270f7aa93cf637da52aad38b9629d9aa9d972968296a7a4540a82c3a5e98", - "0x01c08dc670a2e8bee189b5989f3d886e4abdb6ab0c206de1a5b2f06b7c7069be", - "0x021b6357b397474f51017b96fdb7047ceed3cdaff66f241860a8b65fa6df1d03", - "0x025a150bc714c1b7af50578e218e9f6946a1da0152f0fe5c5afd495e3c9c3324", - "0x028c94df12eab8ff1ab4bbd050f2909ddf0df879075ba380aa96dcc6bea4c0f3", - "0x02a091027a81a055aad881d5480ae9850041ac789fe9166a4cb5c503fd62176d", - "0x03225c9eab37ed112666ae6a31e0916a89fff1ef0662b4be29e163addf38fbc0", - "0x034c1e61c7d52d7916f67068601821c37e57031c3274aa64c14470429d6487a3", - "0x036968efb813391278008c61ec8098f710257fda421c1924c4f110e04565dae5", - "0x0371e91b4fb45eb46d86176b05b920cf0ddd97840eabd9599fb5d7719d98f64f", - "0x0377faacc461744292854886efd21a181822422bd07a66c0c2f189661e726f19", - "0x037dc276fea557060ff8a679f18554e8738be51a1f2bbc9ef2d9840f603fd244", - "0x0387cc8280ca904239fcfae37983e29ce678f64767c04462fb10d1383a1351b3", - "0x038860266a94ae2e8e75440aeb9fc84c76f955ccd2f8c36fb2ed877b987b5264", - "0x0389d45402b958ff02321a67072bd061f496e17e0671d769000825a4d7619f47", - "0x03a83e369645c44c29ea2376b455bcf25383326c20d0de3402745df7cf9692cc", - "0x03a92979cf2df3ba87dd23021aa649c1d5a924d9a71a2dc1f579010e1d668eb3", - "0x03bfb70b1da71d662ec63a60c4c3fbbbda33657538d17a2ef0e47c0f9ddc0c97", - "0x03c1b62f38a62b342665cafd5abf9d4818bfbf28ff36be9303479966c036bf10", - "0x03cb9d518d787316955085796b032674851897d716da11c66cf8e4c1a4868b72", - "0x04297115fe4f2ec34291822dc1d7d5f29e775eba20444ea41c2ef1bb50f686e9", - "0x0436036ce605ea0d621311dbe2e90fdf40191036a4e5a5579a010b3a196e7aa4", - "0x0468ae270b51041e396ae243ef42bd37ae4bab9f0f8fddbe0cbf8a12fa6df272", - "0x04784231a0cebfc828fe39ab1d5aa4fa0d377514bba76ba2e507d5056787f48c", - "0x04901f3f755fb741a54cebb5977c8843f57b9246762054ff7b373766a8087ee4", - "0x049b7b3d14271a116f6852a6112143f382d8dea239ba0002068ea8fb0e1bf4f3", - "0x04b1f76c2f23a26b1dec46c2e852989f4da2c5ce887b81bd7b21f87ed8de08c6", - "0x04c7c2b4da951ef057b618e36d3f6f54c06f2b1bc584a9e7d9c438507eba296b", - "0x04d2008376be3e18a8a998e43c01050d3a642aebefc15b47b7b620e2fc0d25c6", - "0x050b60d03f4ab259f6f415ddba1ebe3f9e2d3ecb3d723d2efd72c33408c170a6", - "0x0544d2765448f2f09b24970b0b79f3a210ce8a6ee3b2c567bfe98dfaae45ee8a", - "0x05777d0ba9bd892ed4ee829c38f8eefcfde96aa07eba759c8acdbd7ad16e59dc", - "0x05b66c9c249858bcaefbc79524ee575ae5849497c51fda5429a722d34b37eac4", - "0x05df76af4ec8bb7907c86db2dade1d7e6a9541f0873682b73e1bc77a8b8738bc", - "0x05f4ed3483a52a7798d84667fab89c41ea0c842bcd9d9ac39e396e4d5f70c97b", - "0x0606c2ad7558d869b48a376d3dabfd0ed22dbc0f5290684cc3269efe3f0a8625", - "0x0619ef278226e341602e68bd2418fd7a8c11d13fd56f1f05ac6f06fb89b06719", - "0x0627ed3074cc3b9249fae391ba8f3c8909b81bed18a8704142b3866558721b5f", - "0x0646a9867146372dc306b3827a4758ac3b5f112db722121b8483fb483b74d03f", - "0x066c88e74b4707e57d8fc237609238270b8f21018a73afd7dda6efc2ac0ce000", - "0x067eeca14d7c8dab6ad0d5e252c1212f00f0c7fd345154963c54d6b3e2ef411a", - "0x06a92cf187ad8fdc429bf43de15091d576524ddc8d79c24e538636d5e8af3fff", - "0x074e4a884a14a1f5e271970e21f502fab6a1de49add4a5ce08717bf35a87c258", - "0x07f9aa58aa4a99034bd21e8bf0dad443ac517dd7b1a74a3a71a1e311f8c3bb82", - "0x0801f1259e99e073354bf15351e91054974451a4d2a2344c36d738af11cf64c1", - "0x0830bedd94211e48c396dec7daff6345a215e8be867bc29d96962a8803a7c40b", - "0x083baf6671c35dec8f73a01dd815b9d69e0e94484939e0d3d187a8738a4f99c2", - "0x085d277ddb8e8b4061fe7100a622c2265fd2bc7d122c7eec42b45d59da5f2bf2", - "0x087c1bf4ba230d051d07fd208fa926d0a496b8b12de07730bd076f3d764dee59", - "0x0897eebd18056f1ce1bfa0c85eca43b2f384b9fd41b571af137097e764872730", - "0x08a198657d9a7ace3acde9a9bce19c94db3c55d44391e30ed1bc8be2a3d712e6", - "0x08b6f0881a59fecf56b8cc4692d1686c4c662315a05ceb4c42c11dc884008560", - "0x093bbc8de3e267b41bc36abbd6fa089270909d3df1764dbed7b1c871bc867e24", - "0x094fc2fcb32a9bfc543114e6dd44472a069b4e5d1d1029e94f4134094e88a9f2", - "0x0950b01e8249f74ffffd9cee4ce3a00542e65c350daaf8e49ff2f42d6ffb5222", - "0x09d8d387963a135471686abf8d057cca5822b313900c2fcfa2e21d1ebfde98ae", - "0x09e98c5d748fb2499b8dc8ff021218d4d81ad4356630e6353fc728e08387d9d3", - "0x09fe21c3d119d135bc9656b1a74be66db5709b87fbac414b440c3e54bb6a60a8", - "0x0a2db758a4686d01fba6fcfeaf3eed61a760ba5a9a94fa4880dccf71179ad364", - "0x0a4613d93d8a00cc49679dcbcd349430420c03551c0cec2499ef809927e82239", - "0x0aa1343fae573d35522d0c35cb4c92192611432705f2c2bbbac7bd2aa625cc92", - "0x0aad140f12e57ef07cca439b4b36bc97773c6db3bd54c389000b07d75fbf06ba", - "0x0ac5eeddda5b071b0db1bef4d85f164afd7bc83d6e219dd16244365d7896e125", - "0x0b29c1c77c3e7d6a91c1beea25281cb6f34678531a0c9498542a74b40ec88b82", - "0x0b29c7e4d6f3b241448e2af09544ae50b5072be96c5c11ee72be9787fc612b49", - "0x0b2e2171747c35696b09b1645ae5dc3545e256c969f649f6cb9d086371c7d83f", - "0x0b48a0f78835866d3e31a20f19acbd61410609466d03c0cc2efb7d16c6d9f934", - "0x0b6fb248a552f978fb92baf652543389172418ac5b720ad742d70fa9b423bd3f", - "0x0b8949ff32f011ce123b5bad2b8ea685fecfb396733e33200ac2e01d9b0d319b", - "0x0c5e986dae1db9aa8919d05a225922522d83c9f44c51ac341fd35aa2705c8322", - "0x0c63839330da4a4ce84b58ef07bfbd945d346a5237ec401b78f7bb548d20308e", - "0x0c65a0c0eb9dea2722b45ab430d8b825effca607d400a971e52b477a908f9ca7", - "0x0c799e7b1ae92dc11bb3de9fd3ab64291c2136f630141beb26b5f14a97f39f7f", - "0x0cdf803a7e8599639cddc73b631962043d0cabcce6c40bab060b72853c0b958f", - "0x0cf3d87e9dd1be01539745539bf1806781f38f98aab0a1a3362ccb520b3fff2f", - "0x0d4c5e3fd094eab9ddecd03b623d66060ba48a649a95c8df6a99610748dd9c71", - "0x0d6f958359221ed81da79adb52ae760187ccc91b6846ce856c87876a967dda26", - "0x0d7e74060e0491d806d03c03951d0abe2ba5a19e23603fd1d5b840eced8f610b", - "0x0d882c5332a96642c3c4fcf2dc94e5110d3665660d48acb405da2e6cec086541", - "0x0d890469fc1a8bf4f777ece5c79d330c72de4ff8a015878376672fbf7e82dc4d", - "0x0e5bc1d7aab18b32da9853f1c8ce91ebca9f499714c0698f63056c9d84647d82", - "0x0e67a854ed332483e1f1cc02520d9584e114ace081536b8699c9d1bc0b33f4a0", - "0x0e8715aa4fad2cacf69808d945ca6f061b7f225bf9ca1f0468d266e4736775a3", - "0x0e8edbbfd5316d44ca75246346653016a7b4400f7f83cbd6ba12de491cd5ef77", - "0x0ec2d910532630a170d77d1e4387036ecc9e8d8b59f1e2a352134dcb9247c8a4", - "0x0ec99c7aa5cd14605f65582ea1b2741bbaad4f52131bfced720c6b80ae0db367", - "0x0ec9d71d11a1d10b31101484d1390dfa9d4edf992cf235c01c6b11604d760b20", - "0x0ed9163e7e15900723b2fdf2b8b112f608af86513758c36dd3490d73632f0ed1", - "0x0ee103b37c2df922a3febd219f9ff499098df9ca44038c2630b623a68da7f5e8", - "0x0f5b5c3ce1ce19ea0b3c8f7cbdafbfcbfb5ab43b8dc61a8a222092f93d20fec9", - "0x0f6a6bdf2e6e33c231aa68d5a4923d9ca136c810145ac6f66c1a78eb526903de", - "0x0fd1b6df037a833fbabf48584cceb5a8ab58f83397046971f971cad833850c94", - "0x0ff5c81c2e94b184d9ac2e7c87d0e9e571952d962a6b4b7f11f6f0dbe116ae8f", - "0x0ffcca443ce8b37baf50153c84108ab76f0a03c19b1335f3ec632db1a76b8374", - "0x1026180a163c558008f56b17f30856807abb01f869905fa85585cb701a1f683c", - "0x102e43721f4d95652feb6987cb1034e839ea971b481dc73959bccc2a3303616d", - "0x103abe175d35c8fd206abb4d2345595c313650b89760da8ecd5824e85d2b51ed", - "0x104b520ea23a1cf6d846c163e422605abf2c903ef664ab915f79872a1d4b5c9c", - "0x1076fb45a75de3bcf8572a068edc53d1bc329ba5718cd61f2fa3c3a1d5ef276e", - "0x109006dec24e846480311c4ffe9a7842d0a722266c9391c0d2107469efa818ca", - "0x10a663f944745f5648cd03422284541469af30c8081965ac1679cde1bf6f072f", - "0x10bbfb0bc45be1b2febdfbf34daf533fc7d3ec0e75e9210c2cb74be4b47f5021", - "0x10c63348e5e8e6e69704ddcf00a96201b20212d727de6e525faa88ea27233455", - "0x118fc9481a0402eb5f6e3190a23df84ac565d4dd2698d005ef3b4c16894f0cd2", - "0x11b55db2437406b0daf9c0f053e1671e9e57b8e7d88e36c7c5fde6b3b5ba6b8e", - "0x11baaf2968f152dbcfbd1235e3db1e9981b6ca36f626cbf178bc1d18635f4029", - "0x11c5adf91e87673b9039dfef3a791b15ca85e5fb0789ad41c6f92b3d3de1dbe5", - "0x12166e47def641cda0c589f1ebe874d17b1b3c0ca961f1b73ea0ad3d6613893a", - "0x1237b52df3975d96a91471c11ea85614c4bef7a0fd3e297fde08fbbe9b58927b", - "0x1259b44eb14cec05e326ca390b4a9f9507181fbe9a9d48c27f87e07c261e5610", - "0x12a854d214da5fa2212cb664a2b3717a024493abbce91b942a0f902901a69ced", - "0x12a8907d5a645af81c57bfd8a2ce76e97724a677b2d00386164fdc6c7d594db1", - "0x12e199679ee9d313c8db42316bfc3d8f405837f2f16fc2cb05dc389fa27bba19", - "0x1329d5b42d5a89f156e0ab62fb110438046ff09838887e6f1bd7c7466679ce81", - "0x134dae7bbb16c161b854c8095e712b95d0b1475d6ea81ea3a2c46db38b9091a8", - "0x1442b32bdde45a703b4e570adddb7116eabc8896b2f61a1b0a04c41293d4db48", - "0x1460f9f0fde41c8a3546c5f8246f52d1e1f393deb3e031e5b6f8d9b3026dc755", - "0x146a1dd78ac71b096ead2f9dff9ee0cac1e7edb9433ff4493b3600794e7e1832", - "0x14926b296e67d9b078cfa51234174ae0308567f421309d54e4ad52f32e7b8076", - "0x14a33978ba83e0e64a683a3c74932393bf48f47fd02fbc6894d8f904e7be371a", - "0x153387d23aa240e8542ed5a1cb6a1c0467342c2c6bd731427dfc52e52bc64768", - "0x1533b171c3ead6aed8e6f874d4e0b692e0a1928bca4aae489be77dff5ae53409", - "0x15403051cd7ab9c4d966b7368da5f78e67127c36275faf6a2bc0e6e35362962b", - "0x155fb1304508e45be00e5b079bfea6a853332016e6f7006891a79ff00ee2438f", - "0x1560109c81f0a98da947911238b8db768dbe16ee8ff56445356ab6ec09132db2", - "0x156d97de40f6052934e8b06a88d875e21674eade783e437201b2a004981021e1", - "0x15bb016b7d7e767688e815502a4263269881684e35b15c148b77add53e3b1b36", - "0x15c23324505cf1daf4016059d6cdc23fbd3fc231c10f995b1b25bced18674981", - "0x15cc59ad9c2cf8fd79fd2fdbc1f613b437e524edb834db978131756e4c7f3a63", - "0x15dca753e56bee3f48e13e02c3834b061a7e116aac2bac7f20e12fb322f9138e", - "0x1644a46e0bea220eb251793442addb3e3703f56e8ec0fc7ea8a50a1b644813f1", - "0x1646355f0c2793eb7e2429cbee9009a0e68bd5788cb5a23646ba6b6869522854", - "0x166ed5bc69e50fafb364695674e762b54375d4eea3fb24fbe4a0ac447df48e98", - "0x16719b65dedc057b6dab370247dedebc18d0179a4a69b152decc6f3a41d22317", - "0x16c3dd6b05456ac8d4c9c329b0d8efebec9725949c945988303d243688320afb", - "0x16c860ce2cea3afd9d360d35e34d428be40ac7e17578ab0cecbb6d0f23372d2d", - "0x16d937d1ffded604489cbdd9c505ca499f7f9053cf170b090ee2323e176e55cd", - "0x170f520a327e5264789c5f2ae4d3ae4a5da7b69e2c1dcc034c92417ccfc67463", - "0x171d783b23eed72f7e8d59765ba90cf6802a8d59d166e09192bc4497ad338421", - "0x173611116ef33b1fc3c819be0ecbba4a45a4b65cd2851adadc70d1cef770b128", - "0x17e1f14afdbc1d3b01cc97a8e7a4a995f4c36fc284a8c192d6e5137ac1043379", - "0x180caf260040b13d78600010eb3eef7f91736f41ce191cebf54aecc72688e3b2", - "0x18152ddf6b130585351d7589f496493905dfac9db1c44fa260d4adf323d9482f", - "0x1821586987ba34650da7061eebd0ae9c91097cb4ec456f979f3eeb05c39eab5b", - "0x18318abb2867f19b4b018e8737fa7df31f08389b8e47b5d1ac31aacb81b83a53", - "0x1885c7fb9a40da641c4289ea9f37797a2034a88feb043429bcb667329f771227", - "0x188b9f499f0b2fa4ddf6e3eacc05a358867ab57ddcf283501fa66a082faa1ee5", - "0x1896adb9d21659a2e311b468ea3feed8bbf179b93373e4c9bbcbfb76342ab3b4", - "0x18b9c0e291019d55c2566e2ceaaa86fd6933b76e51fcdb1fc0e29f07fa09e85c", - "0x18e3a1988e172279fd2c27f639051d5a838e301fc8bc93fe14899eb2f54bb470", - "0x190d778182477bda236732ce466cf356e627dfb65d656c2b08aab5e7984acba4", - "0x1939ca8dab45e884bd8f39a4ad65cede9bb6ad79769ad9c5555e49c6e2d6e3bd", - "0x1951130aacd8550a89a8da7770e21cd79db911a5fe1682281851cc03346ffbe1", - "0x1988033d18f3ad41c234b9e15239136453f5d0c80d01ac0f3a13322b0fdc98ff", - "0x19a4e64ec3f98e94bcc8a7ecbc353b772794553e8d8f326ff9c53fac06f85813", - "0x19ab26359481524ae3e5088cf8b4e92c1d025a6723a8dabfe20dde30ff1014dd", - "0x19c23b37d9396821cb31d9693bfe3650fb68eaa54f89f29973c2895d64649aec", - "0x19ed6c3c815995d3f7a6bdd0399f90fd15c63c3499fb1cf30adec0f6daae6e54", - "0x19fbe5ef6b8df1bb6e35269fe0af09c3a2b47fa6fbb31f33ed8230384fdc767c", - "0x1a8381d54205e5bc259ad4f7f9355640885919bbcf63a795319f17381d302cce", - "0x1a8ffb82dc8f64dd6d423cad63d20afcee2a66550b6eb234bf0db4627f721342", - "0x1aac3d64bfc93e51a97fd7f375b9045e6820cc2d0ffd648858b27a82779c51de", - "0x1ab0967f99a85382d296b4a54814643d468187a0c1726fd759d4ea842ae58ed7", - "0x1b1d39ed8b96577cab7ac7df44dd0895e85378aba2dca260bd64ad6d01704f8b", - "0x1b2069023a452a6aff26de1e2be677ac992a7a52208b9da9794fb524f2b03e16", - "0x1b47dcd0a41e7e5069f13d2117f86f9ad81e37c4a296b0ac6be5bd0a88ecd1c3", - "0x1b58cc6b2f0219a124f6b64a4727fefb39d6d2c345fee2dab1801667c0acb3ef", - "0x1b88d150b41c9eb45fb772e4c84d565186646ae5b8724c4db51f47e31c7e2211", - "0x1b8c10e1a696b97045a94e3360eb496fc01a1f871a81510ef8a17a6b996d3640", - "0x1b97f883da56cced19f6ac4e428395e37b0f4b96d464aa10e76bcff9a83f5148", - "0x1c46937d0697e539028d18c8fbb5bc77effa4415cd775b844bab00188a557beb", - "0x1c4cb34852bf8284993368056456c6c88682ef2b5c629328edaeac5fd724638d", - "0x1c5793f2f4ab8b4133a1044bcc7560756dc890a918d14f3d68a3fc34e5e3bfe1", - "0x1c62cfc63f7e0660911b977d709c594604b6dbfafce07af0f2d2f4f1815dfb2e", - "0x1c739011cc97fde4383e30a3f30214bc5a4af91546933d13702cc742c6e6eef5", - "0x1c82e07ad944c67ca3b861598828793d88857d6f94975fe6d2492a88905ffa1b", - "0x1c8db507b3486210f75aab95f2bfc2d86c47728b3baa9d9d7073b9e0746e8a5d", - "0x1cfcd4d35608fa15e6439c849537a4c31973e4ecda82f9d6621cd048ad44f540", - "0x1d065c4a5180165a8881a365fb52a4eabefe30168a0362f4f8a27e002b80c2bc", - "0x1d5d0e89777546c0fd7b636991a111592a8c1536fb58ef2981d32b73f8824028", - "0x1da8ef7b572efe875b5b18df81fb976141b15ceedf3e913897cadf3fb2512d76", - "0x1dd2b986fd15dec9d0ea8178894cb09b75124f6502dbf48790a7edb4ce136796", - "0x1e5d44e8c276a0eac80d6c33cfcf3b6530d582a1380ba6870c0230a698e5a11e", - "0x1e687bbc9e60101f2790e2675ac20157ef9e9b7364282fefaa71e7afadc8df83", - "0x1e6bf44f3dae7e5ad1bd72f23bd52eabef9da0d8221129249b43db23ec7e4633", - "0x1e7e082b5a3b72ad1d8b24e108ba564c164f8a7292c4c94b1a7b9c2a2165063b", - "0x1ecea2d6f442561cd1a83cdfa0753ac0fa67a93a137452a795b82c7817553683", - "0x1ee70d3fd871fb02062a8cc88de0cad40aaf64d84a5979c823cd01eef3461938", - "0x1f212a1bd4cb615405c6cdb8a8b1b6a8f814b87f04246eaf4e0d3599bb687756", - "0x1f4c706afb725a75f52c6689fd2ab7fd8b1ecf92c1fe053ac85105c8bddd7376", - "0x1f64f659acbfbd2d9ba57af8fecf5524813d58fddfeedd61ff2a85504b6c42df", - "0x1f7a91061de5fc1dbedbcae7bae16ecb2ffc8fc7db5a0bf443972ef456c05d48", - "0x1f9d6e9ca1035d039ab17af3e7a02adeff5db1da61a4405ee78e13e8ab357e25", - "0x1fbd401ffa5e7aad665e4c52ef3f300125615e3da0b1a1194b8f7c05a2d5d79b", - "0x1fe281acb32230d13cc75c81d06ca87615c30c8de43da671817ec53779b13e40", - "0x20979cb7cb0ed985da0fe996d8ef2b41ba7096088124917d6d18b03c496bdca2", - "0x20c99e592caeedbee8393a71c99dccebd6a98cad7ff56d56e717570760bfbc74", - "0x215f5b23241a64d90aeb3a64161d3317585adce9a3c9cffa6d2afbb23046b757", - "0x2189e1d976eb8cf25acaba94bf334db7fce8ebb9a53cbcffb871c98b49dec6e7", - "0x2199a19b49ca867a4df24e5e330ad567779ebac9bfe2924c1a43dcb4a1977fca", - "0x219c041146fbfc3356f6d96ee47870efdbe036f00acb72edcc3824f16e01a7ad", - "0x21a23c84c252971769fdb965778888758f6c283cdd9f81500f596fa07a32c075", - "0x21e86f7e92f96255a56ca5dc7be4b0bccb2dfb63623ede052a57e8227d9ba311", - "0x221a30162335e02ff5da234a80a08cba7fdd5162a941bbb3829511bd82e06e2c", - "0x2230b34ad9475b913f86a5b2b5dc1b77b41b93ed2fb72010fd6c5238ab8912b7", - "0x224b460c8e799f43fb91c5e1d174d8764df15bf0c4b1b58e890045dfeb792db8", - "0x2336f82b98a15f588ebf7894cd337e81c9ed218af82afe6f5af00b55e2ecc6e6", - "0x23371f0090a937a64cbe7776effa0e99f898d75b8701319ab36469b55d876f91", - "0x234195c929b803517a14aa2d974d4e6cbc79726ff3c25dab6859c359edb8a186", - "0x2378db17a378d5ac3068e3d0b6eeae3762c4de4e773f97bef1a35f8875d36587", - "0x239b75415c6c8a93617007dbd81387f7b8b3f7887ed9c177f4f40e789e130cbc", - "0x2425ac3277779a7a0a56228020d5f771190aa97251755138a21c4a0f0c0aa81e", - "0x243ab50a1f7aa1fbc2466372f5c2d756939022a726c6ae6a91f27e1abb646894", - "0x24448ab125882aac4b00c5154f4a06dc416d13f8caaeb814b0f3fb9dffb350ad", - "0x244731eadbe50e1bd61450aa926c50919620dd9fa9ec16f94ebf8dd5d70555bd", - "0x2453321978c09ec82001b4b144572b4bc56ed3b577ef8f6e69c3221f1ad62ac4", - "0x247677bfcc32a86edcff87a260fe2059885972cb95fee7cee39a4aea24be0d7a", - "0x249e71a11178aaaea35035566f72903b22e39bcb2b985035ef63036e31dfb914", - "0x24c3a5bdf0c2a9c82dc3f645d416a0d2a3a8f3aeb92c7eb55b6edea220ab26f5", - "0x24c9c27e7432dfba98e3a017eb087a94f58e71be1bb619dc2598d95d2dd485fe", - "0x25578645b34c93b97d718901adc5c00162217776b333197c348c848902ae828a", - "0x255cb7ea58ea4f0b91e467c59eaf8f42b691530317845df86aeecaf6d4c197e9", - "0x256b4e921270d2b7bb2bb48d3337e369e7717c3884223b91f5c9c78b8e35d8d1", - "0x25a54f7f718140ab791815e6ff3e22c7c11c1577189a74b8dbcaf6197a8bec1f", - "0x25cd7009a520c5c7549abe326969116dfabaddb2d90ae94a58fbd0bf40707e06", - "0x25faf12eade49dbb056b1aad6e01d85d89626392c687629eb4ff6c95dee2ee8d", - "0x26145d83e2e8fadbe3b6d26301d387f5968522cc55f304a657ef782e1b3a6ef5", - "0x26623c072fcbc0d01a2a0248649a2cd08b3d359af211f4309e9b80b3348f1f75", - "0x26828933daf77d2a260f352442712180c905a42f864d0da97faff50d87330a02", - "0x2698664acbafdd6d947bafe355b960d4da1cab3b0deb8410968200ccf04a5377", - "0x2722ef65e003dc74f51e258d3cf46e7999e19df59f1f89ba8e5a9198ad9c9479", - "0x274a30d9a1e3e6fd4d63e673e1ad0d390d970dc5ec19fa14add17f51e84af6a2", - "0x276875b2a57f03d9067861b2618c7a274a7ad44d8b9c8578cfd365066d457bdc", - "0x2773ee462a3d6ba12d3e7ed6cdd75604ea18848f28504ee9987ae70e03546ce5", - "0x277485d4dcc05006a98d92b4fdf80f36edbb6e69648c080717e92f36e7772678", - "0x2789b50328f811b80a992fb02a2a9f35ac268902bde54713a089c25cba6b1a9d", - "0x27990bae6215e632e7b4b267e568e85efce40b7f18f4a52b331b368cab4f5f12", - "0x27cc7172843e096a51ad26f8105763a2322817cbacc6e4fe9092934fedc918c9", - "0x2818c693395c93f67e2b9a29dfe6929e47da8617b4cebbbcd1cf7d15c4eba03c", - "0x28527bd79c6ff967f55a3b2d9ea65b017d15a7d637afe2de188cf16617febdd8", - "0x288070e08a431d17d54fd2438ac4e15b89cb80f491675a938d7db5176578b929", - "0x28848a09679b56898fbbd4e8b1199a6bde0e4ecfa1c7e00bc0d422eeb58d97e3", - "0x2893b48f842a4896cb3447e92ad509b4eeb256bf2c887f8333c8e3ffa99aee02", - "0x28b1b1d102873b8b97bc60c4574868d19e62a69d70d6ed298b0e21b801a1fabf", - "0x28b5607cc8d5c3203681478c5423a0fc326b7b6e1d269a2892ed2cf9c6bb7e6a", - "0x28b743105852687b11e43f8ddf5b622bd5ed84393771a1b836f1ce4a36e26125", - "0x28bc8c4b60b919bd130afc00437c4f8a8a917b57dcc5295f57e998d996f33e9c", - "0x28e3403f0fa6d07bad7d306092a047b7a0fa89917c395fdb3d62683101edda1e", - "0x28fd714a9595da57f2af7e765c98481a18f88c9de9a9d9133c9e103794d1844e", - "0x2905a20b3c9e340e5879b309be0fc8bee227e4e62df121d2a4b4eeb6663ee8cb", - "0x290e5b8d9077a166021683044903547e099d380e1154b1dad47bed0afb81b3ab", - "0x2a0cf797c52911534b3cf36a55d9cdaa8d9c068e3ec34e12836a7845412f5711", - "0x2a13d0115847d8e2f0e257d8c44b5aaca4f4ff5bbaa4bf7dfbef54663e0b0d78", - "0x2a49340bc474d0025f26412d358738f08c0df18e76ad33e56e5fa6775161f8d8", - "0x2a8b9cf5173be4774a075d518bca8cc66a8fa53f3350625d6095ef99630f6b10", - "0x2a980c58aecb7b54582c453ab9f1d76db854c3489ddb23633af8ea831d7166e1", - "0x2ac080592df59a6e6b49373cde0c022e092ea002812a054e02749dc85fb391a5", - "0x2acd966cfd83e6b5b00d646a4058f568e27326098e8997b95e0574879d42f206", - "0x2b36a4fe0afa5c5e7ea15351b8a20cc9b3421e52efac5e3e3fc6245f770a5559", - "0x2b5319ede3d62f9a481b35326f5c39c4700565d9542096e0a868f93c52e24409", - "0x2baae4b809293fb544a411ff63065377f735df0ce3bc4920296f5b64d6f899ff", - "0x2c36c39bafbcfdf1d62693946ac3a7d39f31dfe9084ca6fbf3b2eb4aa0a1058a", - "0x2c666f42c05714d41378577fcb59336a23fda96a720e67cad49f5c14e2c2c0b0", - "0x2cb259b4590b437f745c108ce9cdf3d284f02daad0c2c2336339201197772b22", - "0x2cd13fce7ed7e2f370ec5831bb0b0d85cdd645818479a7d4dfae4d39ba7b2768", - "0x2cdeffeab433276cd7c0884ad904daae0bedb6203b87b31a5985e5741b3eb982", - "0x2cfa51f3691879753728688c5f13ae1d19e7d6c3400e467b1045d7092a4ed2d8", - "0x2d2dbcdc58b58df846496c248740d1ed1e6955fd5e4754713611b0279c5c3012", - "0x2dd0f2c4e5d19a092de3c4413648e86cc6ee47a441bce9f340fc0c7a5e3e2819", - "0x2dda21bfeb60764cbb152268e375f81fe3b91a496fb838cf792b80909c0edb51", - "0x2dfb5229e7264a22a0aff613b889de4446f0ab693d877ae02250182cafb8be81", - "0x2e0666f347800818b10562b812431ba70a0502cfe23c2bd3ac13f8595490a963", - "0x2e467236654cfbcea4a87fb47837e04ff92c47c75be98072e71db29ff1ba10f3", - "0x2f160bf0629277cfea914349456b68f1ea355b29d939209d0496541f62071e24", - "0x2f4a548d0c1c102301b4c202a6ff96ec229c37621da0bf0c4f60c381507429f3", - "0x2f6059192a0ae46fb02cac012322f7ea3f2d2b22e3e0e967a6f9c6dbe9ea4202", - "0x2f90b2e3a791fe8247f7a987479c20f8823ab403418f67deedebea0cac92bd9a", - "0x2f9e8fd09efb455f68caa41c67ac090d37425b652099bc60ae82db3b23a4bab6", - "0x2faf08b47930ee45c51b2d492c65a05c53f738e6c55acf618c658a96eeb3a96f", - "0x2fb11ece4282080d718a9180eaa0e5cc0c42b27c4b063471fc11809c988511c4", - "0x2fb70c18b7a1485682403567ff6191acbf87ed7de2d72f6f0f1b4f8f16f49c88", - "0x2fc1fc3024f9176290d412886af3b232c3f141de4d2d566d1ce7e87e6354d229", - "0x3011213f7141899c0c2c3beb6f01972c0a4dafc59eae373e35b3eae889e52c2d", - "0x3030420589935c0b625fae7e8ca9d7c4bf9f28777b46759ebbcda9901fad3ef9", - "0x304a78212028269eee2ec7035c410bf47e19f8622f81664203234767d23a28ef" - ], - [ - "0x257d97e64e5edd4a77e3439ea2cfd50cf5a560d7d5c53a0f32da13497ec2c00f", - "0x01c8bff050992e0b0071a91f0293227dfa1a4d3d7bb0b45296f7e69975bef179", - "0x03aaf815625362956d0ba8648788c29b1dcf1bcccdd7fdd923dfb88a310d6f5a", - "0x2a7d6a78233bf6c6f94b93ae484ee0f2dd2dd24b79c0919917d1ab9ab7bb05ab", - "0x2619426df90318706b31fcd850b33a8b6aa86494bea612cdb5c3c01807fcb63b", - "0x2592b42fa4c455a206cec24d0a1ebee36102fedeaff1fa6d808ccbe7bdf82d09", - "0x226319ef6ee33329ca0d633a2a838fb9de55eb3aa9129575010e53fb255d9931", - "0x0e36cd03956bbc04b4902061e279db1e05e5604d06b1dc81413b711970a16036", - "0x2f1a7a259db946c9e6d3dadbe3aacc790fe9103f561eff53d1cd90846b52e615", - "0x0e48b6804d24562b00ab4d59ae6ee0f7e1f93010ad5c5a4003c43a91e1ecfb99", - "0x140ba665f7f33f66aa6758b98b43934b091a7110f5fd664ff3021a8f07f45dda", - "0x240bd27839bb6509920cc3cba38a0d96201b5ee7a31c97e785154fdaadaa8256", - "0x068bbd63fce0a679241e6043fbb81175af121a815ac5b3a60d509bc59359fdc8", - "0x2e7e5938846851d8ea7aef5bfb2bb0734271d2806061dd019afdb4379ebe9df7", - "0x0fe4efc144b9b14444b081d4547d83e3bf42153d8f142bddb9642bccd1529bbd", - "0x2eb96cd9fafd6844a358896703a8048cd3d5e992b9f2d9814b65451b75d3ea0b", - "0x1b86b12bc4ba9d0d3c2456b3934098f3a77ab2d489b886e8a9e3e86a0b6528fa", - "0x0a5e82ba9a6c9e7bc34f8d1a38529ef335fcbaf782d4bb8681bc2c5a99eb6a5e", - "0x2d421a075ef713257e8062fa771b2aeb2fe6006615fd27a6c4acde55aa142670", - "0x27caf99e13bb0c59d600ac540dde6dce64646d01f64b32c346f6f6926d8f6105", - "0x284c1d01195c5e3114e7223aa5f52323e664a9aa61fc54cb79a7fe479f3b0a3d", - "0x295ccf9e9c1c298c8cbed3ce78576b19d7642492f4dea5762ae4156a84429869", - "0x0e6024f4a8c0d4ec4703638f87cec6aebc50d0ae778d3771c02b5b0743332b64", - "0x052361f5a505653c4f8343ab4b6ae77b6d8935d5c699b6864a0484544ae0d982", - "0x27624b4f1c06776e57519b4079cae5af85ae4ac343e14b5eebf3fd581dcc753f", - "0x0e2b37279c1ab371ae956dee71e656794066eccd631403ee97b2598d98fc6d62", - "0x0edb6cd5fb962bea8ee1da33abbea8c5f2f4d8d0fec776d280deba739a4ba058", - "0x056945f773fcc3169cf459b8bdb140b3bc113d4d195a2d84bc2e3c619d743ed1", - "0x129ffc0a424e1fd4987201e3252267c9e261803147dc904d965bd0ba5c288ecf", - "0x05417fcd38204131850f47355d1fba6b3e3707868d051c402bfc54933ba327cb", - "0x2d19793f4561730fa660c4cfcd64fcb0132043e5ed958cb2efad0aaf24c6f7df", - "0x1814d6e77bfcab6bbb4d2f635f857f5771999bfe0d3cc1365869cfb18e9e4765", - "0x2014915f78b221d89f8fb431a58c0ed0ee7c7632d2dd4f8139b72dda254e7aba", - "0x0252dcd5b6bb361ad8e9dbd693212f6840482aca1b3c41afe859cb66a8a3f390", - "0x0ca1919e26c15cdcb7309da52a1a9673780f2173ee3962925c0262af500d4f49", - "0x09e995d067ccb3830af932e446ae54e0e0677460426250590ad277bb5b82ec88", - "0x103f0c92a81b514757dcd8cf289b1262121b2618b4174036a5b7731ad01a8040", - "0x2151a775ff8c05b8da9ed9ede45efc3129386e5e388fc8e93defe7158da9035a", - "0x2006d6368c7e3be356975594b54ffaa073f7cd99af9b8a0af57738828fa0ec4a", - "0x051dea3179f82cb74f3d3a07569cc9ebb8fd0dbd9989d6585ef5a05c98c27a15", - "0x09ebfa778d6ad1793b5d36e077922bc84bc3e5729e1c661034107e11c4d8d363", - "0x223e72d73b664aa9f336270800f9fcdbf3b2059d979439735c4be742ce5c1a5c", - "0x2a948f33f587f7c5fdcc0d05b1dfccbeffe8bfc8034ee736a3356fde4ad09929", - "0x1e3c16d3c2fb492b6d7dc9778e6c1971ea60f15827205de566cc227436ff0f74", - "0x0ea270f2a28aa802b1d4b3dee0358631ec0bdf09d8a42738b970c4c478a032da", - "0x08bae91ed0aa8df78ba6f22e48c1f6f4dddbb023cac183001f410cd10a800fa4", - "0x14a20a73a711754d25d9e17d1396bc0fdde66d9b72c72194377da2926a0a6e97", - "0x04ea8e7e30233f85330a7f0cb873567178e66212faf98c1053804136bd79470e", - "0x12a7e72ada6f837befb2dc3d15c19f470fab87343000fb6568691ae8e8b6fbba", - "0x08bf22c906fc1bb89ba14811cd0418b172f7517f3ab7f17d89b88094d8d50c9b", - "0x143bf7dc259af41c69e859a45e771f076f93e5d17d9e9f7dd56d18bbdfeb8c9a", - "0x3010f335d6a877e1eedc0c306bbd73815d8ef0f4db3e04c704baf9d28b9d2381", - "0x0adbf3a01221cb0661c8cf79cfc4bcfd6dea179ec41960a6d2387279451fe50b", - "0x0daa6200e6c6053acfda66ee132c2ba108c6e5679abbcd2c8a71cfd8a8f5c027", - "0x082f55b41c0ba8b075767c46c28801a012e8a23064191613e2baf8bea2e4825a", - "0x18f7cc9c9eaded645326d2bc77c8f9cc3c4ac49a655059052e2461c5ce7fe6e4", - "0x1e968094ef55392b6e606a7569d78cefea1ea3100253b0448f38ec5c1c719826", - "0x06cf59af18b2ef30418bd8444b486a10a1a357d049f059205c5b9f292bd6245c", - "0x1241c403ebe0dbd6462e5f58d6f9edab87ffd96c8a3a2e44c17df1dab1f5c3bf", - "0x27def4d2085a4629531585a8a69868743de5d807f6e895c8b03c93e5a9f23037", - "0x0606873cdadffd5aaa2edf3544c2a634fb64af3d5221694d13202b07c00cfbad", - "0x253e61e4a7e2bd5932d368871210a6c1cf73de8e94f9a36c7cd7bb1d24ee47b8", - "0x19f1028cd4bb0adb584830c38771fb4182c4a79cf0448e833179c7f6b338dda0", - "0x0ab0ae8627324bd9f77a58f9ac76989e2eb581bd32eafdbca74b9eb94749973d", - "0x1cb282f77a8e88d061ad0097816215ec212b201b7b7d756c124d0d60156c6426", - "0x13851ff93d7610cad505c0506d6d5f0dc4a3cb8139f4d596f0654e7213200d25", - "0x18c02f166dfb4f36d00601ed75a99697d303d2c6efb3c8e08f65a931b68efb3e", - "0x27981cb83eb63665ea407ea6c8d8d0a3bf1d52fb9fda6907913837c1c7ab2120", - "0x1b187bde4e609104337c5c31bbf6e543f9bfdedea549d92f07f1e7738cacb6fa", - "0x14bf8ae0a754fa400c84e4bc7bfa6badb73ca4305b5a0a55667e7e8d5ece41fa", - "0x268733b6c47adcdb0ccad37b5e6152f6e54878105039e8b6520d69753c9a07ef", - "0x0621333e76e59f904ea5fd99fe338b0c71e0ce2d61a5c9a72eb635dad671bd6e", - "0x242e41ba177ae7023f5a8ae0a297b1c0546128d816bc9ef5d11f05c90089696b", - "0x1f26636e63a5a4aab708a0e187a47d4fca145a11f6c858a8155d5996537c7235", - "0x1e53793c2c9acfc8028869deab7f4879e524542c9f160050bc8c2a3880fa4a7a", - "0x09406ed1e0750d18bdbc30eae2da7c0fe29132fc710d621733080fdb8f511537", - "0x2cb2b5ec249b725240ded32a9df998d578b2528f4b08b46d9f70346cf9500515", - "0x124d640c41fe6738b11aa6faeefe13d366d72bbe8e3b943d2bbdaad2404991c0", - "0x04d1a630f8c212079d1d907765a96a89bca0e159b5529a6b847ebd9980b3e52e", - "0x101e9228ca777149b044a2ab107afc7601531a6c8535f1ccd070e240f03241e0", - "0x2f920cbda0ffd017db91ff707fce394708793baaca78399faa19ab7c486d6c3c", - "0x2b0125b3c59b6f78cb1100be4778c7005e75a390797333af59be136550bdc3c2", - "0x2a6fa39fb05204e4ed96bdc488f0a7ecc15dc7bf94856bf6981c8e4f07982086", - "0x2f8f9f79b61b132c1d3df4adfc5488d9c2a8454cd23ac00c4e46d158e9b6eab6", - "0x1d3548832d326712f2e8fb201d38ab5f78c56c3a5573025eb7f369e45214995f", - "0x1d1a7843f179d8563442a7f2ac36b8865e7a4f2b968816e541cac872d73a3d16", - "0x135e58912675e1eb1a13b1c281612d7b103f0ef1e7907f6cb5ced1ef7ce2df1f", - "0x086e4bec5f032dd90b10dbb9f8e21bde283283f67ec812d00c259d4fe3379b47", - "0x2bf7971c8324c8c089fea5f1c19d7984a40a6ea7b6c516140ce9f2ba50634ac8", - "0x04134b73e13c03dc7f0637de18b43acc925597aedc07c7629f70a57fe06cd8fe", - "0x1360f21c6af69c74385836eadd93e194751831fa657d95fb46d85ca0ea040c96", - "0x210c426b81fef67fa92aecd6b2c966f229b68404337d22bf888861b495855247", - "0x247e6c35e196931d7a8b7d57d1afb6fb9222c6d4781d40292eb4de143edcd919", - "0x2610246698ce7aa9cc4c4487f62ee6093954bce2ed25e327eae33bfb7ee0d91d", - "0x08b63436aaf60085d1979b0cc3f92664caaa428cd51b6f8540b5074c0a6a5af8", - "0x2606c3c979ae64dcbfc6d3ec16f4ba6ebc0da5256d7f0bd06bd98b69f86b41b1", - "0x107db1355fde3bb5de5d68b62a0abac21450c9125d5d9e1d8b3e8c53f94b2b4e", - "0x2f32f329e23fc1fb20d31cd29bd21b4432d7b2e8f4712d31d0d483e6d140e615", - "0x133ab6f4048f18e01facc126e2086f2335fa823077bc19eac2d2ead8b93d82dc", - "0x0a6ecdd6411ea5d9059ff08001840d8b4fa6fa86792a9e1154176c4d8357a7c2", - "0x10a7c7e2520dfe8e716dfed5a2c556fede02c2b6e1be96cb505ab8c10f499d79", - "0x227ac32880d1a61537405270fe0a379db503e9cb22d7dbafe9a171b69cf7ff63", - "0x1aa81e93dd061de664c211904351e79e4af17af497b3890d10b2242a0710b5ac", - "0x2019bc6048ceaf0a421af4f6cd20bb621bb490682c634887006013364b2519c7", - "0x2d0c4f370e59b81f1159e1eef3e0b51733fc2b40d04c6f93594322bfd9dacc37", - "0x168371cdb3a53c69991f3a4efe17d32c61f86d5772ebdf42365c2f8dc62ab4be", - "0x1442680258cc5f25b5413f093c5c32fc8fe052a0c7dc8984faf547892366811f", - "0x25f11da0cb2eeb9c7ec4b90ed37980e988c4c8e33b6434ead008ef24343aa14c", - "0x2d96c47d21206d97a7526c45d64efdc09607c691b4ee1aaa330fd210de56002d", - "0x0a1edef3d7deb0299278351b24491abc71d2da102752704dda82a0260cc69489", - "0x0d884fa67c1dbe298f1a2f8587a8e0422dae806d49211cfd9538588ee8bcff9a", - "0x04255babb2be9c1bea498d445aaa88d54b3cbd62145140f54abcb559da0617e3", - "0x2e3161f58346a1fdcf4b6de1f6bc87e4cf0bdc7ae71e3d381852c9390408f859", - "0x2d08df6eb5ae9e36f803b30d4f0d92c88b5d90bb14873d9848a49bb09f2b5d94", - "0x064063fa66ae4522642d1b7415a8a8dd85f77364b68c78af6d16865b87aeb3ed", - "0x1699728194dd1532acf16d1a21721cd577e88c8d33a4891524efea860a23278e", - "0x162137813ba42a3fe04744e69e4c55e7d350b8894340426b007273914bd97ba9", - "0x1d17c84e2b8467e2adf2c23cc902d4caf51665b90d70f3ce08d8addd60863cef", - "0x2fecd57f15f992e3fe31d3a845a67a14675a03ed5dfddf16e7ec010bf1876d90", - "0x2dd8a92eb51fa058ccf4f0a370e1124a47b33501d072d425e48938783b6fd01d", - "0x200cd18c8c96e646a3f09eaa58009a4df18a4355ed8d62036616d140a11c5c11", - "0x23ec30a53d72379c7a6f9ce515a522e0e2bd265aab09fe07aa08d05cec3bcb5f", - "0x19b9d124caeb9ce7e0a31a4bf095079edf47fe8e91966dfa681e334ee6349098", - "0x1e0140d49fba888dedd95efdac7e3673856733a1cab51ae025ad1b81b2d68bfe", - "0x2ffbc1cae43293556acd8fcc3a4164781ffb3ddf22d3934455eea03d286f8173", - "0x22731266b39d49d3e63eb1e647fd31af5e9856a72e13197b5b226981684ea4c9", - "0x28ca7cd317648100780b9efa48f4c4eb7ff751211f5bf133462629c0b2bcf9ae", - "0x2d34f95f12366d968b9048304f22e9b072a712767ece4b6522a944b17c4cbe8c", - "0x2ce2c072aaef1bda6e712999d0a93efcdbb601b0e30000be0757d090654c36d1", - "0x29cedb05f00a7c7a2a87af99e23028983e7392918b7f56ddb6c044ab2e501e5c", - "0x0d8a623b25ac76db51b642c936370503d962fa7c12662610ab8a003f65a988a7", - "0x2d1f5fcaeb7b091a2516a604f3c2cd438967a70e2e5d7a33005e6fe4d244056a", - "0x2c65e364fdac2a9e19912d6519f9943b6d3baf0537fdfb158d1a844b0a8b9b12", - "0x26d0fa1b7703f5023ea4e0658301678596e555d65e90cd914d3c68f75e28d762", - "0x27eea69c9579a9ee3fc000c46f4a10b12a3df5a72fa2790cb548eccf01b08272", - "0x15474e4ffb01a79d7bd94cc37e50303cdbbc2895e024aa04374c7af94b5c05ef", - "0x07fb2dfd12c1b61791cb1818693b8cf2ccd5688ea2debe38847331b0eb422500", - "0x216e40390a116dffaf2c7efa00b01a95a74246da0cf9fbd4a3843042eba80944", - "0x16af36ea6f3d04304e71fbfa641416afd11a13cda4be55e2877dcc6bcb956994", - "0x118fc2201fa8653c6e8b56512e3a97a4339f122003f46f08418177cda46b8de7", - "0x2478a2b27d54aa054bcdf5b3149464c91b899555121c8fd18e6445aea5f58a60", - "0x1a9fc26d5c14c5cccffe1b54eedae20bc8ae9b79648efa0109567c40c09fa132", - "0x0cdc5454dfca367b22ede8c5825972a8d6de7e4dc91d40f12c646f88c9fa573e", - "0x05ad61a7dddef7e6d8b90009dbbf76489633e89b412015eb42cbd6ab7c3d85a1", - "0x0b872b6130441acd7b3b9f5618cbd1afb81594302c3b62609f5066c10ab93eb8", - "0x2abc3a7d29277cf86c68b3c27731f6d4bc850c7bc297b4048d925bdaed5c4553", - "0x07d77d750a0b3f7f883a693018f39825868880754717bb4588822fe83279ea74", - "0x22338f9af6ba415f12c0b038e64c1059486cfdfea708f5c712b79512d461703e", - "0x09567877eb700b7b74c4528461466b86efc54c7e209cd9912be06008629a35a4" - ], - [ - "0x15bf7ae7745cbedb4e82a22e5db009bbc90b58074135428192d08faa40f3e97e", - "0x26f7ccf26b6b3ee8477454742c05ad29e7b08936d4fb0f455ae32d613fa9f181", - "0x1589325b48ecd0897b51794d213486d8ce15e3470b10ef1b5e1f6876af91ee5b", - "0x21584be8ec47014451b7cd90cc28a5f0104b3b8ae7f610ef5bf982f640168b94", - "0x013101c27ffd70e136af9065de604bcea4c3eb76e488816deffe49d8a97af246", - "0x2425e6638d65bdb25dc61e7a4e7bd77492aafba203dba77afc0f4b38cc84268e", - "0x1b1b30e0dd90f6451946f443bf5a1e2b43027e5231b7f10e595f23bc04bd33f3", - "0x2bc71ccf3c260ac168b6570b48557bc1a525b112d363c301a9f4f077438be7c8", - "0x13d450ae0ace468e50fc1146ec77e0ed74d2898f52f401583b8cad024c6e382d", - "0x2c27957c332dcf6329d819ea9ac2a2de86795c8acd1de6dfdbd62d4f58978153", - "0x2729ebc736e8b797aff730d5973caf5b8027189d6108269247db1b9e71de254a", - "0x15a037370361a78f464a4a815805e095a52cfe8ac9f2d801c93d959620fc67fb", - "0x0cc0338ee5cc8041a02ab6986c8588762aedc9240ccf0cf5d895fda50743040a", - "0x206d0a297a1a42d092f36e91c151dc38b597c76f99a5b4bae7fabd1639c677ac", - "0x2b5b0e261f54f08016a8c43d527b7b4fcf5db2842848b6e6d1a7cbcbd6c3f586", - "0x29e15cd9e1fc3a6f0683d07ed983f39c7185290400a02e822f5d7add6ef662c8", - "0x1ff64f13f11d7ca607b319b18a98e0e1f846e0176c5d8ad7bc29a35ec76aacc4", - "0x0cba6bd335b8996b8c349edb8733a2924867e8849bfe00036a09b37825a36555", - "0x1e19f90d0b6e4f9fdd8cfc0f7e13212004573e03d4d4705d9a823c43ecfbf4f6", - "0x11315a7426407df69ab6f81d8675d4ce3d1c527cc52c6dd33f33d700cd1fd94f", - "0x0b3eb43ff3b274e181567a8b61c465f96f6825d4969248db6b3a741a73969e77", - "0x20ca4e55ccee2b70197b5b4fc20406a72a331f7532232e7d03c18d0259f86848", - "0x131e1b9791830f0c6b5f95f94bdb09ea51cfa2d6bf00b9f1ef5c2b3776ad5794", - "0x30108113ca2aac7944111e8005b71a6d4864d17cb190da89ec9c742681cedf24", - "0x0f9582308f2f771094ec45b0d7e8883383cf239e2c4bf23eaa7e1537be4594f7", - "0x1330a3dcd62d3dcffaeeb0c9fe68b70dd51831b66da215a6f4a92219944b1707", - "0x251cc1afcdc3cd382964f1a5f052cf75686b1582ae582b03cceb0dcedc2faca6", - "0x17363df18cd36d5075e1873ab0461355afc7c971912394f7691af1f4c5aace3a", - "0x2c748555d676e07d264de91cd80ea9e8764cd8e8cedfdc76c0172f3a65bd617e", - "0x00f7fd191d3c2d2e269e60001daab26176bfe296bdc88f095fdfbbbcb6daaa6c", - "0x159397b8586c6f2f2271bf88debfc7777549ade946bec016d68f8db91ce42dbf", - "0x15ff0dbf0adccc0cfe6881cabf4e465f4274436c4ea61a8b5515f9de79bc4780", - "0x2dec7a4739d31bfcae59efbc257395d0bc8826cf91353a0f7f2c169ca3caf17a", - "0x15c4717a636e5dfb6171d2efd91da5bc12a5875775eb2d9da18aee8ae45f4f75", - "0x03a8a61d4f4c6c904dd45188cc771678be2681eb1d953e37dc94d96940318ba1", - "0x06849bd934e53a357d6ec8fc83fb658ffe4d92020d7c23bc9ef22007b1029742", - "0x0523a11dbad1a887370ea629cd2b993673a8cf20905e15610267b9754d4cd0f4", - "0x24d377eb73eb1a3e95b89416bb2d5e94ad6c2d5ca513fe8f7e7c18a5f175787a", - "0x276354f94e14103d7b74ce46634cc654d7201a1e96f584a3fc5629bd1730153e", - "0x0f2d90511023fc582ccb3f8e55f6d06f5c2589c6f7895cce39d6a7a14e51fab0", - "0x21c4fa244b54e66cf0031dfabd16f53874071e9bfabbf671f5c1d7886dd8b9fa", - "0x14e6be13a234cd0baacef6826ef96aabd77477f8a9772ced820fb92d61761d18", - "0x1a8bd7b327301f983d3ba23f6594a03958f4b47252c086d0fcf49e319d311282", - "0x2ae342f71107d44025ed9203c3198d11e08a17d0b1668b4dfb5f5723338f8fc6", - "0x2a3a1d7042ccd32eb9fede216154bdf98bccc68e16d4b8ad7db51409404498ce", - "0x101590395a38c920289dab7acb63d5570610fb18af7e7249e9fc407663bab158", - "0x0b3a2fbaf28fdf13cfe2274d51037cea60319e4d0d714d7f1ec0017e1aa74401", - "0x23ac5611dedbf9d4919e86e8a48003fe68e7f180449b5602db753030dfe57e73", - "0x232b4d8ae38c1c1cd38f93467ce4ebe51feb1f5124441c1d61ba8d58a839befb", - "0x1759eb5aa8734081ea2cac0aeb1b418a7337045b9d269b16455c9afb2281454d", - "0x04da6e21f670ca3f8465262d8b768bfc4ed1cb449bbbbac25bdf0fdcc4b7b878", - "0x0ebb8f3c3090e90f5b1eae205a43c3bd4972d328c7ed94221cda04452f6853c4", - "0x0eea3d81aa5ee89527a6d85f73dbdd06bd112ffdebfa66c7318f263b85501348", - "0x268d2703431ea12ba8cf1eebe9f9a053224432698b011e7335e46d301a15e018", - "0x25253886118f147931f0a995728159eaa713f469c45aa352309c945a83d3caee", - "0x28eceb389bfd34ac52c3f3eab11dabaa30e9c5d6477e0c693eb615994a75e6de", - "0x2527c47ffccc917a501edcf51eb368e00058cf6503d3a0f473fe5f6092343500", - "0x239f965713e2d399707ed1eca36af28eb9c0102d1dc2668ffcbd9dfc308db835", - "0x230cb389665bf3b58a70c30bd6e7a588ad3c27554853629ec9519dadbf13a1da", - "0x1f56939086522d22210d8b85a67e84c79bef3d07571c43efa27595ba4271cc86", - "0x0909df7a9293cee92fc9b2bb482d08acb73b43ea343346dec1b21b383f43bf87", - "0x27736bd1e905b03239cf6f00dacce3b1b51901a4d3c13981ff0a86d4c586f38a", - "0x2343957687e7e830c51284694fe135a28e9ba1dd6a57053ce9587dc85ebbb408", - "0x219f16d4e52e5225637e8a9fd4c4c0ce35dfb63dff0140744ed12f065f4cbf96", - "0x0f8dac8f390b0c0ec79e1bebc94bed62e48f2f0e53b4784e8c9d7780e9a7e983", - "0x2e737e2ec5e27499761da0c64234ee82e15e72c609f0137ed880619599973a5c", - "0x0526d7f7d83b778cfe4ae4cd50a336714d94e2784031e68caf588d4bba9a8558", - "0x0e4644094bca1e1255a56e36f5ca498c2a68e0ca66d85a8491e0892bbbd2e478", - "0x17179197bda194d934af55a3bf21b941b4a07c20208d6fd0a44b0331a9c7a4b2", - "0x01167de3b58401d41ce8c39ddc5056b1491c5a352d4005fdb62312d538eb0195", - "0x1f4a3b638c821743304a9d383346dd86dd8019fd72ec4d8168f39950b096dedb", - "0x2d6823bc6b5ec51c74e6cfb2e7a93b8a57ae8300846892920a04dff4baa118ed", - "0x01693a50818646f58b2655e987b8e32e99cc1c9b9a2277f73453124d8bc363d8", - "0x0bfdcf01ac6904b770fb0af4317ff19048186aaf031384d022edddfde8a51286", - "0x02702dd9d33726dad48198ab780f0e8d24cef192fcac68a821e425bfb30369d6" - ], - [ - "0x2b257d89bbb92588de0dab61ce5cf91d45c596ae3a0b863f1efb550160974b73", - "0x01917b8265f70561ca54d384cee48c579facbed028f044ab00702964fedff3df", - "0x27224886a5904396ae237f3c0e72ef355b852fdf99f651ac6dc0d1291cdea397", - "0x27693873311f17c8647df37bb72b1fef10daa54a4903db01258d2d1b38f84773", - "0x0670def7de94834c501b55e1964648898cee5188de5e7f30b877a218cc13078d", - "0x277533c89e71e86032c17dbcde3808f31b80a8b543ae30d97c5ae604aefa84d7", - "0x28ec198f2cb27df9d28037ae29a06c33367bc16477dab6c7e76453958d6dd42c", - "0x0cf6c95d654c3903ae5daac520261f7a795ff89b5a3fa9610f029c9b168c501f", - "0x128fd3e613e4dde936130736af7c541b4750097b2efef0860b4de1939eff773b", - "0x22a0365f84072af5eba7ee2b7000f39918dd6c14a3d44a25544aa39e48859d8e", - "0x1541afb16b7f8db88c960ca299c4d0675f109ed8c540e1df167271f20665f5f0", - "0x08e209152b3c813dd84ecc0a0f3ed07629c4e22db7b7dc043d38306e8a13d81b", - "0x120d026faa9b137422059371ca21f727ef350f1573e7bfb9a9791c3822c95fc9", - "0x194850c2f92d1c98eeb524492241f34c7c81345d92a5068cbde6d9e14d858ded", - "0x2f5c9dd73f23be3d178ca97277085cbef9774ad53a5769631d3a78951822399c", - "0x233f72bd401ed2a6d5e56b43ae0bd91cf4936a8a7efd244e672ad1d886f4add1", - "0x0e13c5126d60c611870fba9c20c7d4abe0f889b1b81bbc6cd98749d5aa8de02f", - "0x04b8cd3a70a4e42324d6b8e4ae239e4084e92c016c1f865f0244eb3b6d4b50fd", - "0x2e1c6d8d30a5d8be4216aa11cc8ba7026b5466cb93e06756a3702f7caa7787fe", - "0x13ed975614cf9a17c2cd3bf1a3c184832b01ca9d39fb98e448f5cc649ebd9f01", - "0x2a41b2319d4280467ef9bc4b84aa8da0d5c3b8138ed05d75f260ed2aa30e7ec5", - "0x1f4b32c90e76a632311eea371a0ad78a2418e6af6cc54eeaf163c3e1b44d45d7", - "0x0fb3462a5cb007e26b4582cd7a2e36ad4feefcda4058cace2d42ef5904e1137d", - "0x25c9f6806f141ca9f74ee54c8c9fa9fef07af91de8541595aab8d08db2fdd16b", - "0x0d31722f854dcd834fb44f9dcef44add081e64e607b3ca09861b0415e6912d40", - "0x2839121168aac502c4f738c89d1f77d0d9d83cb862d0e3157241a05048367b61", - "0x0e9d1be3811e67362bba206ac761d9ad7cd8006f3324b4a8b65ddb9436156993", - "0x0e56087ef846a20e944b9e462b39d19ad3e441597f2c7351e215fe056295de75", - "0x274eadd9269418670740e7333fae6f988447e83fbb701e0265718ab108d488f1", - "0x2b1a04979090188fd04449e58daaa019303c1da7abba3a629d57542cb6847151", - "0x042084903408cdaeff0b4acb55d8b57ffebbf92588a7f28ec9f09087e05647c3", - "0x10f951c5dafe58815d83fa1ce0aaf75f4423c3173d38ea74664206408d4f0161", - "0x1d6157199f806e58c418fd623afae5b76b8342f398e97e65e0ef154df7bb94e1", - "0x10ca1baaecad377d89f157b4534d71a420a3af09af7d029312a1ff3e7f7fc359", - "0x2d0e3877b158d2e4017c6b2369eae96a8ac03475b08063d6330146d23ce53424", - "0x1a7c70d69f5fdad303cabcafcf99eb87d9721a17d9f8ca354167ba51c2a814c5", - "0x08841517e57f454d808f2a55e3e750a3f38168dc257d5f4df12bdaac35a235f4", - "0x2b2fa9a37c2a4b58edef8deaaa5d137667e141b37e0653bfe18166cb887062fc" - ], - [ - "0x22018039fc6e653e9bb060764b5bf8aafc15649eed23da280877f2e7ce0f6135", - "0x24bdfcdd36fc824878b9177830aab83d296c9100a99b193e552a9959cfa1b9dc", - "0x097d0a15dc96a04d941f6f266131ef86074db799a5aa8e2915c9943eb1eb3955", - "0x1218f0b3ffb957d1cbfee708e367bf6e740615925cfedfe6343ccec5646db356", - "0x13210f7088d26665ed8f1f8a28585ebea5659d13f043dd7b20804129334197e2", - "0x09a80245983bda75e163b0544c50385e49582ea04c5758bf7ffa915aee6de4c1", - "0x2652feddb25e8ed2cc6ec113cfb6978282c84e85f36e19da8a6e3cbb35c2c672", - "0x0cf4e63b2cb59292d49d367e1577cc3e1fbe4323f6187bfdd3c91d22e9f2b176", - "0x2e0b638d846a91fbca4ac77458825063746c09ee8f7fdbfbad449e2a853e738c", - "0x0ed241aa1822b6e2b6fe839cc105b91bb382d1ccf32cd9c219f87a507102d6c9", - "0x0f9266b9718a346796e1778c0ec3b73ad56ca3d8bb5df67a526ddac1a424f373", - "0x1544a163b3fa99e385dd4365f5b2b6ae6e3c0e1a43af4fc3f9fa87640fc89cb6", - "0x05787ee6955e2d54d6e972fe8fac6ad58a658b851df12662290399eb948d6ae3", - "0x01aacacce5cb52baae237c5dd7c04743d2e22a056d7a3caf6501bb3a705dc975", - "0x1507f8f7f30192f35f0b356070002a5e834b1e0a188db45a6fb1c56543286c0c", - "0x0fc44b3e4cdb1052c8ee6489000047aa536140d4932eae69158d992109e02f91", - "0x013f1609f5f8c73a4cc2ddd0b1625adc29a531cea2b554f94d2ce1748aeb0306", - "0x303bf1f60e83fe4759f3c18f8e3e62c9a58bd58dcfffac39e39373e53e7eb661", - "0x1586a9fc035ae377fd1caa91ee32ac327ea06d731f88178ffd8030be147ca6ee" + "0x009951263933be5c915c2003e4c76123e3a2705c9dfa83fcb01161f23275302a", + "0x05dabae8bc4f735bc246b56e974edddc93c7d70293b880a7b40e13851a9e0fb6", + "0x05e1befbf6cedf1a3b3a644f2d7ece2b00eeec4ce6305f1cd02d4332e220752a", + "0x06473907073af634d13b4eb1e0db3f861236540034bc42aaeebee5237cede35e", + "0x065ef9aec10187678cb8de43b3c5abcfd78bd3d983077265513b9894ae6623a7", + "0x06b662ce912277d3b54795a9523f46bc65c9eb4bc6389e9d7bf3978630ac3eac", + "0x06bf4583b421cbdb980291feb9f3f734ad2ede171fc9a5d0e08d0d632d405a25", + "0x06df1990857376eafcf474130e3cd5c31aed510d5d97ca0bec4db470ea5e8615", + "0x081dc87be7d62ed6843b524fdc3e7fef85795c7d1801b7c3045bf253af82eabf", + "0x0a171c49d513cc80d9d3eb3677e2c64cf855e284451da39c1705ac0f65b59628", + "0x0a7facb88360fcab665c1542c849916836220da436027d8944696e663ea54959", + "0x0a85f6e604851e8f1d56bd0c0aa3ea3dc7d6a95d32db53678e6cfd5b9b8cb533", + "0x0b33e4b01c71940518ebb786276f27376fc3ce19c7bc7dfe8498ebd37cc6a784", + "0x0e2e194a645a331ed93205e7312cdcde2e661f3122499896d00722eebd12d346", + "0x1153ac1e235eae079c5c79f76b1d73d7be7dccdcefadf3622f78441cf56e7c47", + "0x131adb9404e1eda178c13032ce036bd78bd8ab5546bce9924a9c8059641f1613", + "0x19746aa8d1ecbccecaf1d157e83374baf5d3a8130cdca756ede57fdefb8df1d3", + "0x19f55fc7c3407b80974e24c19bdb4b6397751a5f5a933b86d188f1c273c6eef1", + "0x1cd1a1ecd34419905a86f4ab665851c64603dbb8948fc187cfdde7e25f20a8c9", + "0x1d73c848fca0012ebcd4c8ed9b34682a15ebcf0a80760d8bcdb25ee68454d866", + "0x21a84fc3db64055d0864d9e1c4539e832e5b6f0793c7e1218368c2f8738b7616", + "0x241d64849c570f43e94bd3d5a40eb844345d32ef120f131ea857f7cb3e2e23b0", + "0x2606e150db719e05da89dbb8eedab35a407852a428286662ff74cc1d565bac86", + "0x2637c4e91cf82c80ff0c4dd0e69c359fc40f39a182d860c46423b078743be7f5", + "0x2693b16a914ec3e02fc4fea8ebffa2efc461cd60ed28264962043f68b166c814", + "0x2695edd82c5b286a836911b8b8043bf4bc0a6b8a074e664f86326d1ff3aff93e", + "0x26fce086c7f09ca38344f2149f40bac7bba53a32bd66c2a57a54d0c0c7277f71", + "0x27bf676c61d67aa66ef1a4a6077969373e98e42cb23271984610fb5e4868d352", + "0x292b3fecef4582da59fd32fc432b6513036cda9c3f8eac0f1e37653a3c7ed5d0", + "0x29b23a6715831c797a1b46842649eabea43c1c69b2b44991a3c7db349591a001", + "0x2ac4c0d76bd9e410c139bb72e97a698674f07783628b295f841836da3f5ac5ba" ], [ - "0x0ffb3432f4618cf00f8a68a95b7db3ed5a0e997c0ae99e4ea4d1fd3c531f6961", - "0x280dc086c7c4b7a0afb3d548d50c5146ade59af1427fbfea637c73545fdee3b4", - "0x2fde01f352b66a026093e1e065091b55ff1cd449c6073351eb3433f18389e77e", - "0x09553327adaedd7e95164cf6f6bc505e6ac5beb7caa85eae3a33cda73df882bc", - "0x0f392b82897aaf428bed14a8202f29f84c7e411b769953b2be9627f8c257860d", - "0x05df0f77e4d0e5d525ad9e0b9fc6329c7bd4dbd902ec4e890169bc1ee00f1809", - "0x28ba8dacf5a7278429ff8b8e423712432bb6c42048fb017da79974a3bf9b2f18", - "0x0a5b6a4cc5f7baa0becb617d9552ca0b4c0e53bd6d482b4b2555908e88ce1320", - "0x2dd22b0e03616dc4ba7ad4dfb5609fffc59ec876c39a9df03d5cace23d26f03b", - "0x082870b2cf8641796d129e068db3da5e6b9ba679b8f13a4a53b5d788f8468ecc" + "0x1caa5b74aadf98936fcf23d751d2a0735e456d7d4ed97a15ed77ffa22508021a", + "0x0d5046541b06608fd9a8d2fa8f8112d1a119fc1d64e9b420d065bad93905984c", + "0x0476c0bc2dc701ae2f8da24e803bfdc60690064d15a54b6d7fbaa2b6c64025a9", + "0x1295027eae6483795f7d2f159d8b5f71fde0b221a50b07cc8026185046c88c14", + "0x1036e1ca6285b01ddb3ed582f98bb938f0745784ac115701982589ee98e2cfd4", + "0x1f492d438fd04b1a13d62f862b5dc099636436e288692e4a053bfded81e20572", + "0x2add8de4b53399f80c483eded21becb19c129aa05207d0fb6ed9f626fd3f894b", + "0x27d580197e1fb168d14728b3ef2c3fe06b36e5043e3fe517ad991adfbec5adc5", + "0x0ec3481cb494d791494a706e8ac064ccdb033fdea1bb82f33e98862f99bb204f", + "0x236a70c625821149674aef66c73f22b58178d6df6a6974be5324a09ccd02d97a", + "0x1e5e211ff849b77308c00df36288810d1edf0a334636548cb2e5c8b313548ccb", + "0x231b67bd00b6e8393b93d1534c80ba0309cdab4e4195df115cb378821986e923", + "0x1a5c2a871d3e483c4488ab8f0db75731150aa6fe90bef0687f693ab563638d62", + "0x2629adc243192d19e8c041810f9ecb719739c7b056ee2415a46cce5090bbdaec", + "0x14343ba82f7145fd65a49737294bde1b711d4975bb8886f1e1d8aa0cf2ff48c5", + "0x2d4f545d6e3bd03ac76fde4b9aee808ddec7acc57ef2b40a68530452b32e3764" ], [ - "0x21743d76419b30e0117be14c6151f6251f19a3da8810c16ff9e455a50f6eb9ff", - "0x16a5bcee967bab146942c7fa1162f57d68dee31c0c4fb2bf95072420c6ee3cec", - "0x05352e1e0eb4171012bc6802c77b44ae18a820a2740ed7c596625c047e15258d", - "0x0855239c415de5443be5e75d236073e91c2d66781b0dad94e1d7225c7d57bb3f", - "0x2e8e54da70207c6c649c4ad564d61b244e510ab27b1c5dc5435541cb641896bf" + "0x194d10ce0cae595532e9d34849734288149827ae9103fbcaf60c73d19fe4ccca", + "0x1dbdca1da8f4b8d7ae0641f5d4fdf738082eb3401c6514d842936c669b837b04", + "0x1ad930021aa05d93a47e527e0149f6b7d076e396c19c92330c5bb6b60214ea4a", + "0x1969e517fcb3acbb1e927b30279c025b619a2bb481ef8750d9e18e921f35394c", + "0x055cc563691634b97a07e26ffc755765a6492b94c8a830153ab2510de3eb3757", + "0x2fad5bd27d59f3e2af06a1f007f84dcb7435d6ecc979e33859191da54e6e0f8a", + "0x11873f8d9c6807a67d4e3f864dfd88c62f64ff2a1991e5c6e9c5975fa5a7d6a8", + "0x088410d4247d6ce398d13c4235b499127163df3eec6ebd0556e47cea24318bd1" ], [ - "0x0e9e53f115382a661fb45bfeb7ae965cb3da442947d96d3e358c501d5d89aace", - "0x154589905ec323398c4807a142b7e1cb3da7ceebd5a2d3f66b664a45195cccc4", - "0x14a184d679b268b359953137d108679aead34e73d40682d160e670af7a238e01" + "0x1961cbc7648444703e79da69eabd79d18eba2099a3ed92cc032b9d98870672ca", + "0x02973dbd78ae2054a6ec06cc83f522f77071492d70f5a40a16bb9f7af2a93401", + "0x14ec2b60dc0392c55ecefdacc41fcc2c98a661390c009df34766dfd9c7c146e7", + "0x212f5bfc453a37aebb422c73065b3f70713cbd6200e4b4c72df482f2c8a56653" ], [ - "0x24e1fdbff4c4928ea658a446dd5c069bc97354be11b8de098de61adb6bc8405f", - "0x293253daf30e54c4d3217ff258fa39e2d402839c3a62fdaac641b70012a8dba1" + "0x114a11f24590604c791ca41284e90da30235ee57d2f96494a571b59aed8969df", + "0x1d88f79d351d018a91a5bc911f4563bebbfbf73fef77cd04dc56799557193128" ], - ["0x0dd8b5172509300c32365cd7ce2bb2b18967b7d438b8fddf500e8cedf531827b"], - ["0x15c14f9f5654bc2905c22dfbb2f53e6cb22f6e89569c91d7b8167c61e6e763c7"], - ["0x2a45af08d77968fc833afe2ea7e596b252e471a44b6360a6177ffb9a4023c12a"], - ["0x2b7ff824c4335ddd4d49a12f82f9997b6b2e80fdfd798c267349fb6bf81f96e5"], - ["0x1dc57df7cd0ee0c9b9d0abb1f351fc18b6b9ce5c2f97f9ce7062789b11666857"], - ["0x098ca1e2f7b4f848481fd847ab48f23454eef75f61dc62222fcdecd60bcaab5a"], - ["0x18d258fb662f1b84e7f21cd1ab3208d7c11d6474276b0fbaaca145c232145f5c"], - ["0x03c239fdfafd89a568efac9175c32b998e208c4ab453d3615a31c83e65c90686"] + ["0x0bfe40eade1843d2799445e5ac79f580256e19d022054fe1945c342f7d378958"], + ["0x0ad93c1d1ce7c7d6e7fa3a0fdff77f7effa64e5a557160fc46ff8b9a0867cc30"], + ["0x0f171ad94081a499ef1f772ae8496708daf1cf7003b33e2c35888a1ead5c0fd2"], + ["0x1459741471a054f3ccc7d382eb49fdb573fbae4154b196281781e92915117e53"], + ["0x0324581d07dbac0fc58c2df353a71696969cc051d72ca6244652e86b886a2a6e"], + ["0x29c78d48c2ce79016efdfc20073b6c5b5bbf78c0bba4a48b55994c91c5801f71"], + ["0x2e01c937bc777a3f4e2969264964097334a342104940a2faa8a5a5957fef07ef"], + ["0x25e2d511c49e6b67411cbe3f3a251a9ec386f58dc2fac7592454d6cb19b932ff"], + ["0x198db6fbcb241b12468c2b1c43bafc4c5b9d78263ec37e30d4a424857cd49a5f"], + ["0x0196ec7df4a917b2e88155becbfbc38dd6e44c1bfa4d2179d31a7f2a90a97231"], + ["0x2abef2ad091c7390907eb674e704c63ffa187987d9c6204490886fdf282433be"], + ["0x2b49d7ddaec2fa540efec3311af6223cfd19d3a9e9314e10039f9fae0747f062"] ] } diff --git a/packages/registry-sdk/tests/registry-client.test.ts b/packages/registry-sdk/tests/registry-client.test.ts index 78a8160db..4a32e8e23 100644 --- a/packages/registry-sdk/tests/registry-client.test.ts +++ b/packages/registry-sdk/tests/registry-client.test.ts @@ -1,6 +1,7 @@ import { describe, beforeAll, afterAll, it, expect, setDefaultTimeout } from "bun:test" import { strip0x } from "@zkpassport/utils" -import { CircuitManifest, PackagedCircuit, PackagedCertificatesFile } from "@zkpassport/utils/types" +import { CircuitManifest, PackagedCircuit } from "@zkpassport/utils/types" +import type { PackagedCertificatesFile } from "@zkpassport/utils/types" import path from "path" import { RegistryClient } from "../src/client" import { DocumentSupport } from "../src/types" @@ -158,7 +159,7 @@ describe("Registry", () => { const latestRoot = await registry.getLatestCertificateRoot() expect(latestRoot).toBe(CERTIFICATE_FIXTURES_ROOT) const packagedCerts = await registry.getCertificates(latestRoot) - const valid = await registry.validateCertificates(packagedCerts.certificates, latestRoot) + const valid = await registry.validateCertificates(packagedCerts, latestRoot) expect(valid).toBe(true) }) @@ -166,7 +167,7 @@ describe("Registry", () => { const latestRoot = await registry.getLatestCertificateRoot() expect(latestRoot).toBe(CERTIFICATE_FIXTURES_ROOT) const packagedCerts = await registry.getCertificates(latestRoot) - const valid = await registry.validateCertificates(packagedCerts.certificates, INVALID_HASH) + const valid = await registry.validateCertificates(packagedCerts, INVALID_HASH) expect(valid).toBe(false) }) diff --git a/packages/registry-sdk/tests/retry.test.ts b/packages/registry-sdk/tests/retry.test.ts index 594f5fba0..1aa78ebde 100644 --- a/packages/registry-sdk/tests/retry.test.ts +++ b/packages/registry-sdk/tests/retry.test.ts @@ -1,5 +1,5 @@ import { RegistryClient } from "../src/client" -import { PackagedCertificatesFile } from "@zkpassport/utils/types" +import type { PackagedCertificatesFile } from "@zkpassport/utils/types" import FakeTimers from "@sinonjs/fake-timers" import type { InstalledClock } from "@sinonjs/fake-timers" diff --git a/packages/registry-sdk/tests/utils/constants.ts b/packages/registry-sdk/tests/utils/constants.ts index 5bde67c52..eab08374b 100644 --- a/packages/registry-sdk/tests/utils/constants.ts +++ b/packages/registry-sdk/tests/utils/constants.ts @@ -1,6 +1,6 @@ // The root hash of the packaged certificates fixture: tests/fixtures/certificates.json export const CERTIFICATE_FIXTURES_ROOT = - "0x03c239fdfafd89a568efac9175c32b998e208c4ab453d3615a31c83e65c90686" + "0x2b49d7ddaec2fa540efec3311af6223cfd19d3a9e9314e10039f9fae0747f062" // The CIDv0 of the packaged certificates fixture: tests/fixtures/certificates.json export const CERTIFICATE_FIXTURES_CID = "QmRYkZEm7ueX8XT82QuYTdL6iivv3gryoi2jJsPzvsdu6H" diff --git a/packages/registry-sdk/tests/utils/helpers.ts b/packages/registry-sdk/tests/utils/helpers.ts index f8f989b75..ae171ccba 100644 --- a/packages/registry-sdk/tests/utils/helpers.ts +++ b/packages/registry-sdk/tests/utils/helpers.ts @@ -3,6 +3,7 @@ import { ChildProcess, execSync, spawn } from "child_process" import fs from "fs" import keccak256 from "keccak256" import path from "path" +import { PackagedCertificatesFile } from "@zkpassport/utils/types" // Configuration export const CHAIN_ID = 31337 diff --git a/packages/zkpassport-utils/package.json b/packages/zkpassport-utils/package.json index ccb2b4ba6..fb689c474 100644 --- a/packages/zkpassport-utils/package.json +++ b/packages/zkpassport-utils/package.json @@ -1,6 +1,6 @@ { "name": "@zkpassport/utils", - "version": "0.33.2", + "version": "0.33.3", "repository": { "type": "git", "url": "https://github.com/zkpassport/zkpassport-packages", diff --git a/packages/zkpassport-utils/src/circuit-matcher.ts b/packages/zkpassport-utils/src/circuit-matcher.ts index a06ad7051..6b1415701 100644 --- a/packages/zkpassport-utils/src/circuit-matcher.ts +++ b/packages/zkpassport-utils/src/circuit-matcher.ts @@ -40,7 +40,12 @@ import { getCertificateLeafHashes, tagsArrayToBitsFlag, } from "./registry" -import type { HashAlgorithm, IntegrityToDisclosureSalts, PackagedCertificate } from "./types" +import type { + HashAlgorithm, + IntegrityToDisclosureSalts, + PackagedCertificate, + PackagedCertificatesFile, +} from "./types" import { ECDSADSCDataInputs, IDCredential, @@ -495,7 +500,7 @@ export function getDSCSignatureAlgorithmHashAlgorithm(passport: PassportViewMode export async function getDSCCircuitInputs( passport: PassportViewModel, salt: bigint, - certificates: PackagedCertificate[], + packagedCerts: PackagedCertificatesFile, overrideCertLeaves?: bigint[], overrideMerkleProof?: { root: string | HexString @@ -504,11 +509,13 @@ export async function getDSCCircuitInputs( }, ) { // Get the CSCA for this passport's DSC using the async version with signature verification fallback - const csca = await getCscaForPassportAsync(passport.sod.certificate, certificates) + const csca = await getCscaForPassportAsync(passport.sod.certificate, packagedCerts.certificates) if (!csca) throw new Error("Could not find CSCA for DSC") // Generate the certificate registry merkle proof const cscaLeaf = await getCertificateLeafHash(csca) - const leaves = overrideCertLeaves ?? (await getCertificateLeafHashes(certificates)) + const leaves = + overrideCertLeaves ?? + (await getCertificateLeafHashes(packagedCerts.certificates, packagedCerts?.version || 0)) const index = leaves.findIndex((leaf) => leaf === cscaLeaf) const tags = tagsArrayToBitsFlag(csca.tags ?? []) const merkleProof = diff --git a/packages/zkpassport-utils/src/registry/index.ts b/packages/zkpassport-utils/src/registry/index.ts index 09ee49fd3..54e7eb67d 100644 --- a/packages/zkpassport-utils/src/registry/index.ts +++ b/packages/zkpassport-utils/src/registry/index.ts @@ -4,6 +4,7 @@ import { CircuitManifest, ECPublicKey, PackagedCertificate, + PackagedCertificatesFile, PackagedCircuit, RSAPublicKey, TwoLetterCode, @@ -174,36 +175,78 @@ export function publicKeyToBytes(publicKey: ECPublicKey | RSAPublicKey): Uint8Ar */ export async function getCertificateLeafHash( cert: PackagedCertificate, - options?: { tags?: TwoLetterCode[]; type?: number }, + options?: { tags?: TwoLetterCode[]; type?: number; version?: number }, ): Promise { + // Leaf node hash calculation based on Packaged Certificates file format version + const version = options?.version ?? 0 + assert(version === 0 || version === 1, `Unsupported Packaged Certificates version: ${version}`) // Convert tags to byte flags const tags = options?.tags ? tagsArrayToBitsFlag(options.tags) : cert?.tags ? tagsArrayToBitsFlag(cert.tags) : [0n, 0n, 0n] + // Tags must be exactly 3 fields + assert(tags.length === 3, `Tags must be exactly 3 fields`) // Certificate type const type = options?.type ?? CERT_TYPE_CSCA assert(type >= 0 && type <= 255, `Certificate type must fit in a single byte: ${type}`) // Ensure country code is 3 characters assert(cert?.country?.length === 3, `Country code must be 3 characters: ${cert?.country}`) const publicKeyBytes = publicKeyToBytes(cert.public_key) - // Return the canonical leaf hash of the certificate - return poseidon2HashAsync([ - ...tags, - BigInt( - packBeBytesIntoFields( - new Uint8Array([ - type, - cert.country.charCodeAt(0), - cert.country.charCodeAt(1), - cert.country.charCodeAt(2), - ]), - 31, - )[0], - ), - ...packBeBytesIntoFields(publicKeyBytes, 31).map((hex) => BigInt(hex)), - ]) + + // Version 0 leaf hash calculation + if (version === 0) { + // Return the version 0 canonical leaf hash of the certificate + return poseidon2HashAsync([ + ...tags, + BigInt( + packBeBytesIntoFields( + new Uint8Array([ + type, + cert.country.charCodeAt(0), + cert.country.charCodeAt(1), + cert.country.charCodeAt(2), + ]), + 31, + )[0], + ), + ...packBeBytesIntoFields(publicKeyBytes, 31).map((hex) => BigInt(hex)), + ]) + } + + // Version 1 leaf hash calculation + else if (version === 1) { + // Fingerprint (Poseidon2 hash of certificate DER bytes) + assert(cert.fingerprint !== undefined, `Certificate fingerprint required`) + const fingerprint = BigInt(cert.fingerprint!) + // Certificate expiry (validity.not_after timestamp represented as 4 bytes / 32 bits) + const expiry = new Uint8Array(4) + expiry[0] = (cert.validity.not_after >> 24) & 0xff + expiry[1] = (cert.validity.not_after >> 16) & 0xff + expiry[2] = (cert.validity.not_after >> 8) & 0xff + expiry[3] = cert.validity.not_after & 0xff + // Return the version 1 canonical leaf hash of the certificate + return poseidon2HashAsync([ + ...tags, + BigInt( + packBeBytesIntoFields( + new Uint8Array([ + type, + cert.country.charCodeAt(0), + cert.country.charCodeAt(1), + cert.country.charCodeAt(2), + ...expiry, + ]), + 31, + )[0], + ), + fingerprint, + ...packBeBytesIntoFields(publicKeyBytes, 31).map((hex) => BigInt(hex)), + ]) + } else { + throw new Error(`Unsupported Packaged Certificates version: ${version}`) + } } /** @@ -211,8 +254,11 @@ export async function getCertificateLeafHash( * @param certs Array of packaged certificates * @returns Array of leaf hashes as bigints */ -export async function getCertificateLeafHashes(certs: PackagedCertificate[]): Promise { - const leaves = await Promise.all(certs.map((c) => getCertificateLeafHash(c))) +export async function getCertificateLeafHashes( + certs: PackagedCertificate[], + version: number = 0, +): Promise { + const leaves = await Promise.all(certs.map((c) => getCertificateLeafHash(c, { version }))) leaves.sort((a, b) => (a > b ? 1 : a < b ? -1 : 0)) return leaves } @@ -224,8 +270,9 @@ export async function getCertificateLeafHashes(certs: PackagedCertificate[]): Pr */ export async function buildMerkleTreeFromCerts( certs: PackagedCertificate[], + version: number = 0, ): Promise { - const leaves = await getCertificateLeafHashes(certs) + const leaves = await getCertificateLeafHashes(certs, version) const tree = new AsyncMerkleTree(CERTIFICATE_REGISTRY_HEIGHT, 2) await tree.initialize(0n, leaves) return tree @@ -234,10 +281,21 @@ export async function buildMerkleTreeFromCerts( /** * Calculate the canonical certificate root from packaged certificates * @param certs Array of packaged certificates + * @param version Version of the packaged certificates file format (defaults to 0 if not specified) + * @returns Certificate root used in the Certificate Registry + */ +export async function calculateCertificateRoot(certs: PackagedCertificate[], version: number = 0) { + const tree = await buildMerkleTreeFromCerts(certs, version) + return tree.root +} + +/** + * Calculate the canonical certificate root from a packaged certificates file + * @param packagedCerts Packaged certificates file * @returns Certificate root used in the Certificate Registry */ -export async function calculateCertificateRoot(certs: PackagedCertificate[]) { - const tree = await buildMerkleTreeFromCerts(certs) +export async function calculatePackagedCertificatesRoot(packagedCerts: PackagedCertificatesFile) { + const tree = await buildMerkleTreeFromCerts(packagedCerts.certificates, packagedCerts.version) return tree.root } diff --git a/packages/zkpassport-utils/src/types/registry.ts b/packages/zkpassport-utils/src/types/registry.ts index a2732a9be..f0c91ceb0 100644 --- a/packages/zkpassport-utils/src/types/registry.ts +++ b/packages/zkpassport-utils/src/types/registry.ts @@ -64,6 +64,20 @@ export type CurveName = NISTCurveName | BrainpoolCurveName export type SignatureAlgorithmType = "RSA" | "RSA-PSS" | "ECDSA" +export type PackagedCertificatesFile = { + // Version of the packaged certificates format (defaults to 0 if not set) + version: number + // Timestamp when the package was created and the certificates were validated + timestamp: number + // Merkle root of the certificates tree + root: string + // Array of packaged certificates + certificates: PackagedCertificate[] + // The serialised ordered Merkle tree of certificates + // Each row represents a level of the tree, with each entry being a node + serialised?: string[][] +} + export type PackagedCertificate = { country: string signature_algorithm: SignatureAlgorithmType @@ -79,24 +93,11 @@ export type PackagedCertificate = { } subject_key_identifier?: string authority_key_identifier?: string + fingerprint?: string tags?: TwoLetterCode[] type?: string } -/** - * Structure of the packaged certificates file output - */ -export type PackagedCertificatesFile = { - /** Version of the packaged certificates file format */ - version: number - /** Unix timestamp of when the certificates were packaged (used for certificate expiry checks) */ - timestamp: number - /** Array of packaged certificates */ - certificates: PackagedCertificate[] - /** Serialized merkle tree data */ - serialised: Record -} - export type CircuitManifestEntry = { hash: string; size: number } export type CircuitManifest = { diff --git a/packages/zkpassport-utils/tests/circuit-matcher.test.ts b/packages/zkpassport-utils/tests/circuit-matcher.test.ts index 08187a603..bb0d64f1c 100644 --- a/packages/zkpassport-utils/tests/circuit-matcher.test.ts +++ b/packages/zkpassport-utils/tests/circuit-matcher.test.ts @@ -19,7 +19,13 @@ import { isIDSupported, } from "../src/circuit-matcher" import { getCountryWeightedSum } from "../src/circuits/country" -import { HashAlgorithm, PackagedCertificate, Query, SaltedValue } from "../src/types" +import { + HashAlgorithm, + PackagedCertificate, + PackagedCertificatesFile, + Query, + SaltedValue, +} from "../src/types" import { getNowTimestamp, getUnixTimestamp, @@ -214,11 +220,11 @@ describe("Circuit Matcher - RSA", () => { ) }) - it("should get the correct DSC circuit inputs", async () => { + it("should get the correct DSC circuit inputs (version 0)", async () => { const result = await getDSCCircuitInputs( PASSPORTS.john, 1n, - rootCerts.certificates as PackagedCertificate[], + rootCerts as PackagedCertificatesFile, ) expect(result).toEqual({ certificate_registry_root: @@ -728,11 +734,11 @@ describe("Circuit Matcher - ECDSA", () => { ) }) - it("should get the correct DSC circuit inputs", async () => { + it("should get the correct DSC circuit inputs (version 0)", async () => { const result = await getDSCCircuitInputs( PASSPORTS.mary, 1n, - rootCerts.certificates as PackagedCertificate[], + rootCerts as PackagedCertificatesFile, ) expect(result).toEqual({ certificate_registry_root: diff --git a/packages/zkpassport-utils/tests/fixtures/root-certs-v1.json b/packages/zkpassport-utils/tests/fixtures/root-certs-v1.json new file mode 100644 index 000000000..f83a24c9c --- /dev/null +++ b/packages/zkpassport-utils/tests/fixtures/root-certs-v1.json @@ -0,0 +1,605 @@ +{ + "version": 1, + "timestamp": 1768823285, + "root": "0x2b49d7ddaec2fa540efec3311af6223cfd19d3a9e9314e10039f9fae0747f062", + "certificates": [ + { + "country": "AGO", + "signature_algorithm": "ECDSA", + "hash_algorithm": "SHA-384", + "public_key": { + "type": "EC", + "curve": "brainpoolP384r1", + "key_size": 384, + "public_key_x": "0x5bb488bbd2774ce7ced40dc8034ec3048f3782f4018bd59e7f30b2ed588c57611ab7483965b8456f45b8167a2d41ab21", + "public_key_y": "0x59ad32299013af2a01f5515dd77de5abafab16f24bd9ea3415d5447ec863e1705a67bff2aa773ee38bfdfe12e16db90f" + }, + "validity": { "not_before": 1760537584, "not_after": 2241871984 }, + "private_key_usage_period": { "not_before": 1760537578, "not_after": 1918303978 }, + "authority_key_identifier": "0xaf444982ebf06fb9ff67caf451aa4515e9e23fa9", + "subject_key_identifier": "0xaf444982ebf06fb9ff67caf451aa4515e9e23fa9", + "fingerprint": "0x111a08ff123a169cf2a0830649262c875eaa9544d707a9bd0ba2a92e9dfe1eba", + "tags": ["UN"] + }, + { + "country": "ALB", + "signature_algorithm": "RSA", + "hash_algorithm": "SHA-256", + "public_key": { + "type": "RSA", + "modulus": "0xc84e0ffc3df9bd995c6ab6e8abb30751a8ff3b659c9cebbc9f38ad82b89271070aef6d42ffe9052ad60507946d772d1c83f3a525e24f5ad1cd859f49cffadda27c1b164b7d304ff7d68dc86891c41beb96b0064edc1fbe91895ba0142ecbf5f65a1cd1344b75809d4c9caf72a2ba379fba632351d6f2ff0a8bdc369ed5182e08db70cf8ad2c152a7485ba154c836488ceb22a97803555011dcf8d944983863aa9e977134e07e595de4163995658a17405173aefd90f1a04f442c400963573b3ca6faf6a23dba7c5d07fdfdc88885475af6908e0aad52143c1703f54501e51a256ee3e9eeb57a4dc8525b08f540b96500f61aba0d3307829530ea744c067300beefde05928b1273098f9a9f4b4f9798bea099ee2e3d8f32a6805ff9b45e088ca725b92ee554e304619ab2404d4a740a081dbfd75a6a9d7342116a134464a2792efdc5971ebf4f28cb802e4e4ff23d9b9dfd50baa736553c72411432f7bcd78da57f550d69202ed7959a8c39b8ffac45da09686352b548fb9238f2bbe83615bdac3ad5a6b55c8dc51c1c1fb20f892a5f2c88d99486f64737b95c967180a5455b6b859a0ca0053d57131659fd8aa606a647a1bf49f2e3bf01502256299596b8ede3997bcf8102bf41bf30215d740b4a732b06a7a37b39729e0e77862f1a3422145648f5fd7c92e94f09009ba72f0661a5f9d63d1fc51667525f3c349dd180f59d3f", + "exponent": 65537, + "key_size": 4096 + }, + "validity": { "not_before": 1392854400, "not_after": 1874275200 }, + "subject_key_identifier": "0x382f55bb2a3f84b250b0ad6a27d5e4221db3e7551e0cee4e5b2724971c13f94c", + "fingerprint": "0x2215b0e6cb4d3e69e722c6895caa0ed7285a12a109a055b0c80902200267460b", + "tags": ["CH", "DE", "IN", "IT", "NL", "NO", "SE", "UN"] + }, + { + "country": "ARE", + "signature_algorithm": "ECDSA", + "hash_algorithm": "SHA-256", + "public_key": { + "type": "EC", + "curve": "brainpoolP256r1", + "key_size": 256, + "public_key_x": "0x078c9dda9dcc89c01c0c484baa17859db71ee6db32915d2dcba0d734ce0c6f4e", + "public_key_y": "0x606a3d7f445bc0321990adfa3a87479a94cf31d6a6bfecc961e4bb6046d72bb2" + }, + "validity": { "not_before": 1507198631, "not_after": 1796465831 }, + "private_key_usage_period": { "not_before": 1507198631, "not_after": 1633429031 }, + "authority_key_identifier": "0xf5a8f9b1e7a992a0865408db2a471c04a215f4d7", + "subject_key_identifier": "0xf5a8f9b1e7a992a0865408db2a471c04a215f4d7", + "fingerprint": "0x109141f99baa5abcf790ee60daab9a7138e975114fb7676c06897b9185cd2330", + "tags": ["CA", "CH", "DE", "HU", "IN", "IT", "NL", "NO", "SE", "UN"] + }, + { + "country": "ARG", + "signature_algorithm": "RSA", + "hash_algorithm": "SHA-256", + "public_key": { + "type": "RSA", + "modulus": "0xc9a6105edffbf21e91ce42dc29b024ca8fb2c0c28ba8fcc0710d8275943a058494cb785caa1735f72d23364e1c5580501fbaea283458c47363fcdf475b9f86db803c812d87921142c38eb199b4787a0957368e8d454794c16ca182431e373ab853e5f21d7766b86614e300d4853329aa1bf88082d10f5c095bcf2fc60b371f2a8f37e1bbc84cefd98926b7f499914dd5af7977b9a1113afeb89bf46d1162bf5bf7aa9a47c5a9b22979c1fafd9de434395cef7e46ea13603da949582713e9347df8e151079c108860854486ab31a51186eed42caaf63be699452e113cd5865917f71c0fd352faf2f6cf69b28a395102ad0e471828e08276413efd47017d1bc512b4b557b4fb0386881542c8ef4f75cfd4ac787ff345c886027d54ca0d23894ffcf9cc218ce7e0026e1b304c038b1ab12052e9ef217d3a020ec85141e0948a97d7b87b901edb46a8f6d27b7c52c2eaa27bb5ca32df9affd73bba4134c2d9c64d41e1cef44b5d35f69db5e31df0c871386adff87b934b5923adf5ebcb469140c49d", + "exponent": 65537, + "key_size": 3072 + }, + "validity": { "not_before": 1328895527, "not_after": 1842793369 }, + "private_key_usage_period": { "not_before": 1369405969, "not_after": 1525622569 }, + "authority_key_identifier": "0xc1c334543aa6bc5f3db2a8795d865ab96e7bf6fe", + "subject_key_identifier": "0xc1c334543aa6bc5f3db2a8795d865ab96e7bf6fe", + "fingerprint": "0x08e65793d7173129fe5027633ec9791ba76f5f697803e3da6aa7c267dc3a3d28", + "tags": ["CH", "DE", "ES", "HU", "IN", "IT", "NL", "NO", "SE", "UN"] + }, + { + "country": "ARG", + "signature_algorithm": "RSA-PSS", + "hash_algorithm": "SHA-256", + "public_key": { + "type": "RSA", + "modulus": "0x92d437fd733a6cbf1c80a88fdd08da140fe3257ede9e427dc4421f57cec4d3770fdae4025ec1d87c8b929f0bcb5a7f9509b6de1065726aa9cbbd8f4ce6bbfaa9a9fe475ab1f9f934e26ba0ef5935928d4a948ea25e36947c8f8f49fdcf47be5323240ae86513f4f4301786d7abec68b1018434c810b195d8acf953f6f6b9a4ae27d88846b544056e4f379b5fac9d93ba271f40ae2e63a582e7c54dbeeaeb62ae69594819ce7a78a879ed7b2762dca3434cc9a6c43d93440af52f06a78ad2cc01348e4e5356e7a1d3b2a195beec44c685ae6c12ba01f2262f44d3012f8f3f7f8aaafa86f994da556d322f32d259cfe2e9ae58c3d605c0f25a338b30b7d6760a393a2d0696ca299e1447ece4b5b0f6a9977f833f1db8930e6c0f51ae4acbbefe8a3845eae83645c9a083b05a14c27856945322d8956597ab235acbbcc4899ff1ed193d79e6693f371628af4e98885cdef7afba08e2cd8b89d12ec7f06b5d0a000a0ba6589a44c0a0551d59094ca62a2de6662c43c067a0f8c808d4d873dd1ed4e5f8e57865758b9e191a88eafab0aa4032ea80c9d08c89c38c133d11c1649217059091b3f6efa1d2772b98bb7bedd310c7d873cea76041b18e0e635826b6e5635b64c08d9456da8f4930c03e5fac01c98cd2439a5cb22460003fc81ace45bc49b6cb4431eb7dc2024aacbb64051069bc2a05a7b5e9359cc2410ae402f4a54c2a4d", + "exponent": 65537, + "key_size": 4096 + }, + "validity": { "not_before": 1724641200, "not_after": 2205975599 }, + "private_key_usage_period": { "not_before": 1724641200, "not_after": 1882493999 }, + "authority_key_identifier": "0x6d49b37052b10c5a424aca90e6803a7f66df6300", + "subject_key_identifier": "0x6d49b37052b10c5a424aca90e6803a7f66df6300", + "fingerprint": "0x083ebca1c8109f3fe3795c21836ff7f7b001ab71bc4f1209698113b0d2217381", + "tags": ["CA", "DE", "HU", "IN", "IT", "NL", "NO", "SE", "UN"] + }, + { + "country": "AUS", + "signature_algorithm": "RSA", + "hash_algorithm": "SHA-256", + "public_key": { + "type": "RSA", + "modulus": "0x9fc356d37179e527f8b6f40c93628df420ec32d781ade2611e67e3e501f84635860f0c7e5e2b069990ccc6e92509f0950a06ca955f69625ac7da788003d29d726ff9f00a97ffd562d24b3c9c491463583e09bde83f4959651d10295ad2c83ec2d7dd5df7f7800235eb62095950af9cab67f5cd7a8a70f72536190ea686fd7b6f5094b3cee4d9667e4e9924a554839f9ec50bd2188de40c84ba89ee1c3b5f1c2cbd2b55d1bc279d1642e1caf39762fcffd4bd68d73197ce10f4548afee8c0a6794b3f6764263cc879457020da8f0674d0bd8e79731b8c37defd62d2b318cf44b72f0ca3540fb09ee412738fe120337cf604c20236121fb22e91e5e9b1bb73d682e257adf9fa615b26a24b10d7178a7651aef9ec448b9f07beac7c58916cc92064cf4b3feddd6b7fc151aa1975deabf81b6bf439f0b52ed1bd2f7b8e151d19c235a068b34cabadfdd10decd22e178b3cac93c68e376523b6ba99792a29240a2cf44e3e4c6b3e4a9db53ea89e11e62d103b933771723bc87a8e58ecc8439d4dc99b014206a452b2d64ee8afc284799912bb6a8e0f9cc936628c7af7b2b4f9809c20b8c1101461408b6eac5e0519d6c6bd5bed931761e34c0da2b909e87d3034c1ea40a95026fddc7ddcb155f586ec514e04a5413f7d52fc08f4063bd69cc673ad5d3ef5ad4750a7542ae31b576baebd27c43453daf7895312bb95dfc3ded41d06b5", + "exponent": 65537, + "key_size": 4096 + }, + "validity": { "not_before": 1298848960, "not_after": 1772234090 }, + "private_key_usage_period": { "not_before": 1298848488, "not_after": 1393542888 }, + "authority_key_identifier": "0x2b0f99a34be9d5ae00933a7868cbcd21a6cf47e5", + "subject_key_identifier": "0x2b0f99a34be9d5ae00933a7868cbcd21a6cf47e5", + "fingerprint": "0x024deb5be505413ac1ab660f86b728c80647b9ad22044191de66e9fe47745b2d", + "tags": ["CA", "CH", "DE", "ES", "HU", "IN", "IT", "NL", "NO", "SE", "UN"] + }, + { + "country": "AUT", + "signature_algorithm": "RSA", + "hash_algorithm": "SHA-256", + "public_key": { + "type": "RSA", + "modulus": "0xd213d1480459a827534f0126d9f17ffabcf5b29ca183031e1f4d9866d5d278b541a5a83c190ea07a5dff6be9c25fca7330ee3dfe12f9655d6c642426325548f436ff7eb979d72138f493e3d5631e1409fdde6da70e7cf4e9c3669905a48a23562487d45e8a3601a4a962396459a533deaa03ee296cb3d27d0dd397ace597f7dbceb9c0c3dacc6de020d3d4f9c1c220cda74e3d9e9c5ac0a7072b44ccfc8b07c6fb44930dc43db99d5fdfca0f3d007fdde292bdf892e99eb730e652432d5e64d7297e47c311f7917b14f60e31c1528855c9a9d027246edaaaa053e516b598a374659d759f79a4f8b7316b3fc9b51a95f71dd2b9559ddcbb6e696d62f38e09ab625c2c87884e1bd89b4bba7f46b8d0e49c38d142584a04bd883bf96ec813f4561b758fa14d1f31360f3e1230ac0e58e081d6fbda98b11245790f0f0117ee1662de32c00f8e3cef6aaba413c9dd4833e9345209dc843f38d464cd78a81ff867496893971f8cc406e9a152900417fc23283b86b298055b8c0ae1274681599876dd90bba8fae1cd3f026bbdffecc657e385a70c223ebf678ce209b4e7de7b4e8eab4e0626d89fc4b6ed16bf161cb4e16fbcbb65514419cd570b1499b00ec924396c782c98c75438b8573005def8d84817cd72ba0fcb39cd668d56b61d1c2c0148f38dec46b969a8e506f9df2545efe38b870d5ea3d310b69f2232bcb98daae41da39f", + "exponent": 38129, + "key_size": 4096 + }, + "validity": { "not_before": 1302857444, "not_after": 1784451044 }, + "authority_key_identifier": "0x1fe1572e9b35121363a50fee3e2ce2c1d187a8dd", + "subject_key_identifier": "0x1fe1572e9b35121363a50fee3e2ce2c1d187a8dd", + "fingerprint": "0x25026c77297190d8fd02249621cdbf14a34aa2be3a7620c9cb7bd1bff3f5199c", + "tags": ["AT", "CA", "CH", "DE", "ES", "FR", "HU", "IN", "IT", "NL", "NO", "RO", "SE", "UN"] + }, + { + "country": "BRA", + "signature_algorithm": "ECDSA", + "hash_algorithm": "SHA-512", + "public_key": { + "type": "EC", + "curve": "brainpoolP512r1", + "key_size": 512, + "public_key_x": "0x12363cc8d50c67ca72ec54793827131a2060162d471c9d790e9f0c02bb014d202b7c76ff63ecc3793357f0265270a89e516481e2ae29516d8d44abf6ceb73371", + "public_key_y": "0x372662ce0c54285cbea98e079d99e04cee097e9272e714e0eca2d878551ce3d695eaee58bcab13ba69350bbfe11dbe714758e76819c45954d4f4a128bad7ed52" + }, + "validity": { "not_before": 1429816758, "not_after": 2060968758 }, + "authority_key_identifier": "0xfc4ce0f76b6557a4d9edc8ca72ad0535517b674c", + "subject_key_identifier": "0xfc4ce0f76b6557a4d9edc8ca72ad0535517b674c", + "fingerprint": "0x0ecc40ca6d6546a0061a2c7a04f0220efc08877b763339573c14a60b8b920626", + "tags": ["CA", "CH", "DE", "HU", "IN", "IT", "NL", "NO", "SE", "UN"] + }, + { + "country": "CHN", + "signature_algorithm": "RSA-PSS", + "hash_algorithm": "SHA-256", + "public_key": { + "type": "RSA", + "modulus": "0x88665f13e2c105b86b3983d10ab145456f902ce9bce4fe3ce95f9dc2ea152fb4afee319a5407ce5b938541f9318c257977dc444f52934a97ca523d27c38df5311dbdd48b7c9a248263f2067a46a6c2c7c9ec631953c2ae008dbde933d1864127587decbd43e659b21e7c1d938165cad18ab44ed4ed9e8a4a36091477169572e75b4102097d03258e0acf580a7b080db03718a627fe94dc3f8c245088ac7a696f3939e02fe29e3f4ce7f40c677a7045b32dc26793513a1a2ae798e47adc4d77520c26354ba48a6580efa79adcd2db7d488f83008f0f7301f9c889cb50329ff8abcc6ff3dc2d4272e3b006960d1161451af7f675493a3a22a63d751dea5081eaf77d9f86cb9a4c7d8988f1dc1de4264320dca34c6f044a66058314ff65e8c1cdae5ce5f947fe7a1f3294e19bc91de2bdb4dafc38522144a76f0e6bb07da62a750075c6f5b02aff05d2d2d507591b63fcc27f9bd412612337d5c0f993a373821cfd04af91b1cdc754501d7fb9641ee45b0413c00207e2a8833c732122d0b4811d1fb8aae780c4dfd868cc9ffb456ccbb680d9de8bcd4cf7d1ceb53577d029bea807c6907f2dbcbafa407e899eb578d257ea456582586cb6c8c266e2f0e16f72bce3a9d45c84a5486d9840f23ca126ab534b7055f3a3ea878bc191a6fb0a9fbf01a14e5fa7c2726c075201b86e3008a46d2ec77eaaff1f7c54bac3bd2ec3ca5a8011", + "exponent": 3, + "key_size": 4096 + }, + "validity": { "not_before": 1231776001, "not_after": 1862928001 }, + "subject_key_identifier": "0x84435319dec4b5236eeac6720e82c2250050d6be", + "fingerprint": "0x2491e377d5007ff2f051c09ba73c7ceb9e9c011eba45bace732ae67872cb8f40", + "tags": ["ES", "HU", "IN", "IT", "NL", "SE", "UN"] + }, + { + "country": "CZE", + "signature_algorithm": "RSA-PSS", + "hash_algorithm": "SHA-256", + "public_key": { + "type": "RSA", + "modulus": "0x9d161abe49c4177a9000d24a7423017f9c4bfe31ddd6c78d58e96449913555c94e8214f96faff17a5cb197fc82c9b4cf102fdec28288c35506c471c37152c67eca3b41e27e76b6d5982c13799e4b4992c3f668154cbb57eaa324ea06169fd09b64a508d628d54961b507936a5793319427e6071b4e2338460828d72563cd9fd47a3559dedd8b8819d4b081453cc853d2553c430e65d98bc75a902273967fc75e6781a6923e54ab35edeef19017f4db21e76199f9dbba5bf21cddd4103319815833905d9f20e681c2ee6c91fa3c7b4f3f275e79859209b548d793f9a82c5f14ff8113a3ba84475124a09f4a21122fa0fc0f93640023824fd0777a1a050c12ccf47664f128770964059770368a7304eb1bbff184f4c07df74e6674e73a96103dc2a68d4be882a63cdfd5509b0632a3eb39d6d56b0087b661c74784874163948b3a11ec0cd69da51ac16086bcbf3520b5f507e74512edd66ec14bba59b52242ee6f9838ef18451aec5e9e7a10827fdc5791b3c966813adedfcd258bc74856b5c037", + "exponent": 65537, + "key_size": 3072 + }, + "validity": { "not_before": 1301011200, "not_after": 1782345600 }, + "subject_key_identifier": "0xeba14f8f3c698adab6109b123528ced4654a0859", + "fingerprint": "0x2e2c217c4adba66c9ba76fec82f16f1511a3dcc7309ee6b99cca13b7380da98b", + "tags": ["CA", "CH", "DE", "ES", "FR", "HU", "IN", "IT", "NL", "NO", "RO", "SE", "UN"] + }, + { + "country": "EGY", + "signature_algorithm": "ECDSA", + "hash_algorithm": "SHA-512", + "public_key": { + "type": "EC", + "curve": "P-521", + "key_size": 521, + "public_key_x": "0x016540d39344053ad69c6258bdba2cf00e48192fac8c9280a6dd328201f2322054ccbb01212abaf5c4d255492077e0646d2f228058a4f069e0b43c9edfbf0181f5c7", + "public_key_y": "0x008a5a7efc565a535a40c64ce22f55c477be8312c319270b17d60b522bd60a8f7609015fe0be7e857f483eb1addd639de784cb65fcd8c3ec8a828d9160d17bcb9d39" + }, + "validity": { "not_before": 1741088365, "not_after": 2245664364 }, + "private_key_usage_period": { "not_after": 1898768365 }, + "authority_key_identifier": "0x4898ecbea905a068e997955a4ac0ee0b08771842", + "subject_key_identifier": "0x4898ecbea905a068e997955a4ac0ee0b08771842", + "fingerprint": "0x02d362863ae43968b3ace2e0904badb029e6e0840c48a9d46c653e5a0055e6f3", + "tags": ["UN"] + }, + { + "country": "FRA", + "signature_algorithm": "RSA", + "hash_algorithm": "SHA-256", + "public_key": { + "type": "RSA", + "modulus": "0xf0a362d5dd579a816dad303dd1f6d8c34be29548b3c23d46fcee097b2c5a00ccedf81d5aeee96ababaf60af6c2ab5451520116e83a2e77ec5ebc51e0a66c32ad8f9045f5809ae5d4a604ca66153abd227a3fc57e5a4bf8e5cfbcc0300f5a1ac9899dc676afc40663633812894a6501ec3f916f198fc842a78ec29252c03597b468ac2f8193f6c4c746290020733c5cb77e9bf4016c96e356f14f57b84508569a851e6a738ffb2436d4b6b29476aa2a8d32aafd4248e903f03c61ab05e86e9d2f705077c36b6d358b9ded234991a8e27cc6a30a6a1f900f504accea31aeb4cd4bd51afcd285ffd3a539ac09fe09ac1db8a6fc42341cdc69b7d3ee48148d2aeb941feda86957c6929a0c5609d49203e869e412a79dbd138f916f00873c8592496cf6ada235c2862c50da327ebb8aac460c248631ee86469db7b2381496d01af1f8c45471d34a40870f971b25025fa261275c8e8d36789028aa82a6fb51e5a55b249363b9f4ed05343ad321ff1931b2464f72ac1ae140b11a9eeea6a03ca799c842d94d808ff4176b21f2070c4b0f0a9c2470b50808db511484cd94f7c258d8f97e73ebcacfdd701d34bc2c691494b7ed07f78b4fb85b2685839c74e50b8595090d8c26a6412a3ac540dbe91cdcc3fc0b6a8b9674471938b73e907a948bf737730e9b95b25266ab973627ee3e82fad89fd48b969e25b89f3e1a028fae889894c47d", + "exponent": 65537, + "key_size": 4096 + }, + "validity": { "not_before": 1291852800, "not_after": 1773014400 }, + "private_key_usage_period": { "not_before": 1291852800, "not_after": 1449619200 }, + "authority_key_identifier": "0x22f38320a573422caf46ab8c3dee764dbbe5c502", + "subject_key_identifier": "0x22f38320a573422caf46ab8c3dee764dbbe5c502", + "fingerprint": "0x0dbee2be1ef49bdbe573b08123fdf1308d2654e435cf9d19bda1254442990084", + "tags": ["CA", "CH", "DE", "ES", "FR", "HU", "IN", "IT", "NL", "NO", "RO", "SE", "UN"] + }, + { + "country": "FRA", + "signature_algorithm": "RSA", + "hash_algorithm": "SHA-256", + "public_key": { + "type": "RSA", + "modulus": "0xaa55588329ece95c591d5e7aaa621e78ac78b484f2f23e442e97689f9e0c5c42917be63cd3be01ed00532dacfe009461353571e713e69e0dfd4e78e35e9ccbc3370480fe4bcab3520a0460e73adad7f33da4586eaefea4649282360594af16d7ef51745f94cbe4d645d27a5e7054707aaeae588efb99a33405f41717d54d035353f4cb8bd80b809dbc27bf73503900779b678c824cdaa9f3b66085eaa0023c61bc0a71a51c0785d34930bf0a789db0598d560b83750f7b8be18b3e1d766e575fc28902975976e40898fcce8749fa198d2197fc2e22e8fac342096c24e61eb0dae5d73a521602499fb80c0c85996924fde12f4c0362fcfcc2b7e2c59459ea6ebd703db41721387a9600cff5a9aecd33e2e8fa384bc2d6db4f5e4801aabea76392cee78a223781bf90c3ed91db9b28f79383d5caed39b107a4b68ea44572c8307f3083ba11e8773ae8f56b9d4ab63ac714267fc806b7b2fe252260a8071fe106a278c710845cf2efce6ddc9f65e32bb97306e132d308037d5d3803af23e52799aace90d58dbb8735eeb2dcf0f4bd5506bc0f4ac77238baa5640afe6172a16e4767aebc84d1e9f98464faa37a8bc0b7005668bc9ca7ab947991690f8537c12ec2fb46621ffb33c2c20b20475fa09f7a8a531bb8e6010fcc8fb4ee967e54d765d948bb71b8343f157c5df1df4665f0f05eda1c577f7216fa0743aca0dee37cc0a0eb", + "exponent": 65537, + "key_size": 4096 + }, + "validity": { "not_before": 1441324800, "not_after": 1922572800 }, + "private_key_usage_period": { "not_before": 1441324800, "not_after": 1599177600 }, + "authority_key_identifier": "0x0fcc3251e4e92a50658caf6a6871bc9e8fc86d59", + "subject_key_identifier": "0x0fcc3251e4e92a50658caf6a6871bc9e8fc86d59", + "fingerprint": "0x08571453f7030c9b1363ba4f0b3a69575296989e9380df513e1bdc1e78a54c87", + "tags": ["CA", "CH", "DE", "ES", "FR", "HU", "IN", "IT", "NL", "NO", "RO", "SE", "UN"] + }, + { + "country": "FRA", + "signature_algorithm": "RSA", + "hash_algorithm": "SHA-256", + "public_key": { + "type": "RSA", + "modulus": "0xc0160f9d4dd49a2f80a0e4b0d7f55a70ac36f645af9400cf84da3413e9b4c3d4a72e62cf32819c57ddc282a35c979ee1fcbd5816c599f30a5d8a47cd8a72df8f1b0431d5c251705ba136e9779378dbc66d0e0a873cacb1c79d88fd7652550726834618030b89db1dd019154984f55733512f4b853954447bb1c6d9b54b56c551990b6f1faea7c31af5b4aa56f391fe3d718ff1350989fbd879065ad14699f77cd24ae82b0c48ab3ba52017f7ec99052a35bbfc0e1db2a0f70e721d246905c3ae56f2d2e10c1c05a36dc6bf7d2587db79bdf5347ad3b59aabfda10b820c4690c9f7579111b7c66ad7a40c7fd8edfd3c4725502866b53aa61e0cc6047bb82fd4b644ba993d2c7739732f6299c7befe94aa020db44934dcec04ed2fdafa9bfaadb09bd7cbfe0d55b149d281fcb1496dd4013fb2f69d585af9a69e446302bc3949c2acb5b82621b282915b403d405655eb77473e5ffb9e51f8893d059a3f89f20304f7c51976024ae3468a9c8b47e784d334c288a44322a035e86dbbbc724100cffb1da2eeca9c28beaa5b1c63fff84134e1efde2519d6364fd5f2d4a988e6db642ba6fef94f916e1870620278416817e41080a8179a97db48e7efe2d64180749005ac2b8102feb4eb5eba6e16bd1b774155aa65c4304134103b39505ef36ff62606efaceb98be5e67b278f7dc3537f86d92fa6b23f68380e661062e6305ad72a763", + "exponent": 65537, + "key_size": 4096 + }, + "validity": { "not_before": 1590451200, "not_after": 2071699200 }, + "private_key_usage_period": { "not_before": 1590451200, "not_after": 1748217600 }, + "authority_key_identifier": "0xbe8a2ed6c9f9204e3a270308974decfdd97dc5e6", + "subject_key_identifier": "0xbe8a2ed6c9f9204e3a270308974decfdd97dc5e6", + "fingerprint": "0x134b59fcbbd379f27cb0984bf0a7fffcfbee94da58e06f600d6ac114ea2f9a62", + "tags": ["CA", "CH", "DE", "ES", "HU", "IN", "IT", "NL", "NO", "RO", "SE", "UN"] + }, + { + "country": "FRA", + "signature_algorithm": "RSA", + "hash_algorithm": "SHA-256", + "public_key": { + "type": "RSA", + "modulus": "0xb8bffce6f30f3b501280fbec7ad212dad81f6aee4345078b539f4c631bf82cadcf4d9afe70a86c762c60a710df7de90c545218903719cd9ed172e240dba309300842597eb03dc8e0744c75b1279dfccbf0af1ae30d0c95a5333e61d2f938f3cc802591913c49730baa84e0a6c72c1667bd261c741c8cf7edd6987ffca6f6e722ada5a9a5a7ee39687f0e67415040cfa1044d7d9cc91ee12c9ffd1081740e0aba98aa5054f1b81cd8fa50742c38b71122d6814f84889f487a33103ef4c20a4777b50697297583734afffd636127bb8c1e90760b06df2ea072e45d0a254d683eda50d39dd8ce2bd822d6d0fbf04215fe9a2bf485609ede4573b798b0b815504a2b78e39b3ecdbc3f07135a22e714db4e54372980a1007b938699b87c91e01f6e1f41849fd51dfc1fbc469cd566864b09915911dea49033951a444d319ca5b7e3fb8752611fb487d9fa803f0f4040f4f2c165fff1bf9f7981756f6660c9749c3398fd9ec80690a82adbd4b6184c722c78ec648f80f39d3528106e84db5a10c0cd2b63417c6ecab4419926e2653dfef5d0b46897ef7f08fc4dd0ee2015b59a5f9a002d545e6bb8b5636a215a3255df68babbe0675301c2623ac971860b24a468dc836a06ed4a06838e34fb6473dab4bbf423bbcee82611dd5cfb1c86efc1c91ed21603bda88e553e39e8b29892587bfb2db3ff2943caa46816dddfadfa84b74ebcbb", + "exponent": 65537, + "key_size": 4096 + }, + "validity": { "not_before": 1739923200, "not_after": 2220998400 }, + "private_key_usage_period": { "not_before": 1739923200, "not_after": 1897689600 }, + "authority_key_identifier": "0x8319511c9de1eeb87891003537c958b76f207742", + "subject_key_identifier": "0x8319511c9de1eeb87891003537c958b76f207742", + "fingerprint": "0x063c281f37c5429f2a21887a2edb4b088f8965273808a2735bc379fd35ca4261", + "tags": ["CA", "CH", "DE", "HU", "IN", "IT", "NL", "NO", "SE", "UN"] + }, + { + "country": "IDN", + "signature_algorithm": "RSA", + "hash_algorithm": "SHA-256", + "public_key": { + "type": "RSA", + "modulus": "0xf16b4df06b9d880572deb5b0835c937bf7c2756c47b9446cd89e9e96f44b574cf912580d568d762e7fa6cfccd2da0288d02ba4f737abdd5f9443451015707e5143789b73628933c376db5f1b7614f768fecfb9b980ee21485217891727f584ae03d5e39f46078abfdabdeb72cc5c42e9a164712fdbe2781cc9a3881f958119470d7614651426847e26d6ac78b642e9338034206daaae0a2ec032002cc5afac1561e9501f075c755d5a2cff921211a22c43ccd1d48002e28b0c5e1e67d54c9bc59745f1e1d5b1891eb39086b68917789f6cb6210879e93bd48c08b61ca316352ed1184a80c45da98ee6eb87c71e3fce7c5967dacf3c0f8cf9fe523985b66348086996019088b85901f03f3afbfc9883c072773be8155a3e76babd1406c01a2f111f7333ad2a38eb89a7bdec7826b8b42a438710e3a2bc73d01f96b811558bc91972918e8dd2a56d993963342303e337c6906ba40ba6269fc9415bdd0499643e159d561f14e9b3a0be8104f6b11c7d7842ec750bc04f3ed7d80bb1c152f5c1630e4bb7e77a0336e470ec278498ae5c306dbb2fa3d3031122c4574967aba533473e74d155fb674c86452fd8c65e90a6eccf85fd9c7cc7bbea0d7d388a76a09c5a243bc3c266a8ba0063f209062b5738d65b0c5d691688f47e77f1b0a68a629a71efc8c5215f99d284e43d5e9b6fbe0818968012b0a44e8603d49e37ebbdef618f0d", + "exponent": 65537, + "key_size": 4096 + }, + "validity": { "not_before": 1545128030, "not_after": 1812968030 }, + "private_key_usage_period": { "not_before": 1545128030, "not_after": 1639846799 }, + "subject_key_identifier": "0x2fdb3a5d60999ac5d7695f5327987b5bab29c94d", + "fingerprint": "0x2e3fc14457f4757a54ec1bd757269caac7632f0474a03186a8780fae1388dd38", + "tags": ["CA", "IN", "IT", "NL", "NO", "SE", "UN"] + }, + { + "country": "IDN", + "signature_algorithm": "RSA", + "hash_algorithm": "SHA-256", + "public_key": { + "type": "RSA", + "modulus": "0xf1604076670afbc36fcf2abce6ecaaecb71491123e90bc1f5815d825c947abb8eb1dfda6a1f2977d80e727921c838bcb763dfd7bcd79b86140ca1d2ff971f0321060be36bd2c4b11cb10bb41a1fce507fcd67f31932e46b67dc9e085618d3b013f2cfe0fa91aff71b06e9d2f6c974deb8e507b097aee864882cee82e8716ddd8a6ff1470d2c88b10d7bb977f48a5215d726a4c48db95f8b188c2208285a2de9f9de947f99fd1cdc5577aadf1bdb6ee8f2f0e7985ec43b333dc25dc5f3223bce806fe94a2da514e5315857df56494fb52387811a16a7110713be517ee4150a7803775d8f74e1e0aaa911802f1bb59f88f2aa12e8524b9b53018445d6f7761c4bd29ea84790e38fb09a995e3b1aa0435819f938e707699af4be57b39370592257aaa303b24516d88f10b800148f765a9df54701917c7bae99a4fb2bf39d970f3029d5f4e83000dc7309facb51bd0adbd691bfade059d0eb418714cefc19e62ae6b2c2f29201adfd8192d44e4fdd7624d13f35de3d5132f6d00e5edaae37328ddf9a0dda6011eb129e679a80f5be12966953abf05a728540b1e279752818a95c17e19f2aff901cdcfb7ac67f240cd9d430506bea150a50071efaa19a77292a32a93c11c7d3fe75939ca8c202e9b0acbfdd7e86645c2278ecca42ccb01d0ee76ef3efe714bab062bba432f8753d4b0ec16999cc58066c88c94604c8de5c22edcb9ab", + "exponent": 65537, + "key_size": 4096 + }, + "validity": { "not_before": 1638949445, "not_after": 1906789445 }, + "private_key_usage_period": { "not_before": 1638949445, "not_after": 1733677199 }, + "subject_key_identifier": "0x77623b37d09cd6fb9d2ca570a73ee88e77d60459", + "fingerprint": "0x269ca5562c1e9def6c1430f0c03e7da32e90eabfbb337e6326987a80fd764b5c", + "tags": ["CA", "HU", "IN", "IT", "NL", "NO", "SE", "UN"] + }, + { + "country": "IDN", + "signature_algorithm": "RSA", + "hash_algorithm": "SHA-256", + "public_key": { + "type": "RSA", + "modulus": "0xd127294368b771bb8496e204cbe5df4992518a618e75bd283c85111d307cc47d281925e9147db393e4d2d042ef84a95a4e0481a90e9cce8184152766cf557ebb76961836438fc0e3571aa6379a70c660201f3a1df3a8e19c9bb38f9ef8d588711ca35d73afab4f561a0373bb1d36c9e0ff873527afce568d904c5215a5c839912ea3f613ec1eb958ec6ca04f69cc74e883aef29f7392b0804304fb2b56a1366d33106c7932a99e805cb5a0d9050b1b2e30bb89ed9ead37e1274b2dc27a369d312dee082da031dbb772f9af7034dcdcedf7b92ebac28b60958eb54f596a7b6c32dafb3d72cdddc6f6abaec10a71321539debc1f1c9662b9fd4e9df599a7c6983425b5043f68fb20842ffda9d8f78d2985909c4fe9e16171807c9aad31b019c12b52105cd25cad0e1fdbfc9bdea90787626ed0be8b5ad3e3278c5df170705740c54069cff1b9176d3e945e568103ad94089217e70bbeb69edabbdfa83f3d526199d606254074cf0e11c5299a14e525abe5029d982612f03b6cf3231b5fca896eeb6f4dd3f2f7d56eafe098eca7572cf56d989736bed3b61e32d416e6e00bf8b243501f4b68206d52c1157395bd790dedfb89574d5517d02dfbfdbf88e81d333296166bcd421da49a64d89eca5cb1ffe43a9bbeb2c77cf8f8fe194a21cc5b7564a17aae8cab54bc2f3c3f0563078d369e5cf6f2f2ff5f331e5dd10986cb93ac5edd", + "exponent": 65537, + "key_size": 4096 + }, + "validity": { "not_before": 1665975434, "not_after": 2146877834 }, + "private_key_usage_period": { "not_before": 1665975434, "not_after": 1823705999 }, + "subject_key_identifier": "0x331edd10ce8012b5418852081ad0cf36e87ae89e", + "fingerprint": "0x1fa4211688e9e6d1d4492695567442713a28c26cdf990f25e2de61e554ec7fa7", + "tags": ["CA", "IN", "IT", "NL", "NO", "SE", "UN"] + }, + { + "country": "IND", + "signature_algorithm": "ECDSA", + "hash_algorithm": "SHA-256", + "public_key": { + "type": "EC", + "curve": "P-256", + "key_size": 256, + "public_key_x": "0x1785af2b0065914a14946f62fab23bf0868819632dda451d4cea841739230bf4", + "public_key_y": "0xef82f8788ca8fdafe119acb4a81f45c14aded9b47a82b76ba20e57882b36fd2a" + }, + "validity": { "not_before": 1689765040, "not_after": 2181728440 }, + "private_key_usage_period": { "not_before": 1689765040, "not_after": 1847637317 }, + "authority_key_identifier": "0xc757d59fbee8f19afb606005f6b7c92763efff37", + "subject_key_identifier": "0xc757d59fbee8f19afb606005f6b7c92763efff37", + "fingerprint": "0x1841dfba623cd9edd57a7fe54eb1890ee66ac64de7ac9bdc4db914128558c4b2", + "tags": ["IT"] + }, + { + "country": "IND", + "signature_algorithm": "ECDSA", + "hash_algorithm": "SHA-256", + "public_key": { + "type": "EC", + "curve": "P-256", + "key_size": 256, + "public_key_x": "0x5520ece5eb8ab0c41016b211585a88d0c80acc109917ec2830a1265d31c6d441", + "public_key_y": "0xc6c40248aad4baeb6093ef04d6ca1d5233837a330e6e391c8de4d47313df4c0a" + }, + "validity": { "not_before": 1690365644, "not_after": 2182329044 }, + "private_key_usage_period": { "not_before": 1690365644, "not_after": 1848237921 }, + "authority_key_identifier": "0x7d79684a30a5b811acbef68ebb26068dc9307875", + "subject_key_identifier": "0x7d79684a30a5b811acbef68ebb26068dc9307875", + "fingerprint": "0x1e900def7899256307969ceae8dcebc794c583edf3271349712bf285f360607b", + "tags": ["CA", "DE", "HU", "IN", "IT", "NL", "SE", "UN"] + }, + { + "country": "IND", + "signature_algorithm": "RSA", + "hash_algorithm": "SHA-256", + "public_key": { + "type": "RSA", + "modulus": "0xa9455265eeb4e84373d551203a7f13111069cada447af4804b3674f489bad96400492bbccf5fb90d8ae5c5a7a016704cf58286f3d0f3214cd0d24b85d2614afc563c7ccba5c7d0573bbdd98e73320ad364cd3654de9a4bc6c0724cd06d1e0d638e2edd2239d4d14c37bad537166b32bdd16f97768ef6e28474c4cc9b7b12af38f2f44b8edbbf8acfe55715ddae8dbce5ebb9f7d09e2f12835212417e76d28008bfbbf0e7b94ce271f3503c6de33bee7476098fffaca555ec7a7642ca1b7f8cd83797babe83b83cd3dd371b82f011bc65a72bc6271aa1508d33db0133254ae64228219d904c803497941533bf22b82ecb459d616258a182b907f3dd9cd0d09640a6bff2c1c376882c03b5bd38e87fd4c76d238ba47e6c6a4704d04ddc9adaf5a38aee554d74473a6d102574241d53c1001a5ec6b2c7f92613a3fd5c8580cc52ad4b393507fc55da1e54e9ddb2ac667e795f08e3465ee4086b4d512034c2be8d587521da810b8e68437f8d96aac9f9da44304d9199de40f32d561a410478c42ca708e50208b7736a7edfdaa20dad4efb0692b20c7f9e8d06e03d9a3513925d7cd582b6926b8161ef0e1762b8a986c23ac3135361f7d824e56329fad969c2c8339aa1efdff9e32d588ba91a828da0a60586fa762b2b565f4202729fa0dcbfbd060d75af358b7e6e297c92b816b040be8ddc8b8d7c15c58c37ed9c9ccb27821ad81f", + "exponent": 65537, + "key_size": 4096 + }, + "validity": { "not_before": 1692782529, "not_after": 2103097929 }, + "private_key_usage_period": { "not_before": 1692782529, "not_after": 1803253059 }, + "authority_key_identifier": "0x8dfd77428ca9931b4fd873199040907509a57751", + "subject_key_identifier": "0x8dfd77428ca9931b4fd873199040907509a57751", + "fingerprint": "0x0e630e604d417408bfee77d58f8c57c48bf462f1bbd4253472325e92a613d97b", + "tags": ["IN", "IT"] + }, + { + "country": "IRN", + "signature_algorithm": "RSA", + "hash_algorithm": "SHA-256", + "public_key": { + "type": "RSA", + "modulus": "0xe766bc2e10937a3b61db4979e21807c25c4a3b3af7fd4bcf541721b3a49d13337f5b1ae448d58c3b637afa2280f4b07e983818a8c86e6d041cb94b968c02ee87478514cb6f8fa98af08dd3f82962d49ca4de1ce479d5daf70a2dd146bfa38d3f1afadf3a994d773d76d6caaf22024533744df53e1a2ef4e4d3bc34169230e60966cdfd7f1579398e1be64e258e6a108d82f9758dd6f32dda641dcf4c309ceaec952a159d07fff9d08bce511dd033e33b6fca895accb440df31e15af8ec65804843b28a9daa5513b26860c9da7384cdac37a6205812c1aae1e06582266cf08a18dec2c2727a525bbadd2f5e781db10a2863a1add70a22ab18bf9a385480765a811d8b446d05685f238e653215a97b18bb5374d42ce491178e5d175b7b3855c4c8b3476408666610e8d7445ce56886f66b3e0fc9fb60d5d86be1ceccac3eee6965b39ee29403354dfe794dfea3f7f87330b4805a7940930d991f91229577f5d67de4eccbca5a1d688d06e9ee8a3d484e2016788685822220848eba4491c932e4f4abe33fe27c16807aa7cdce6694d89d7a7d9f712cc18dbb733517ac75b236fdc725b14b5c44499aa305afa580e6325ff42dfa1fa1f8879f701039a26678b9b536cf8fce57cab7efeb4ede16ce76c1466d79f73b3ddab3669fb49ec342345c28c31d08b59cb164d1db6e545678e0b986c9b7b3cfb3760d32f8781fe5b4deb4e23b", + "exponent": 56611, + "key_size": 4096 + }, + "validity": { "not_before": 1502797523, "not_after": 1889527523 }, + "private_key_usage_period": { "not_before": 1502797523, "not_after": 1723722323 }, + "subject_key_identifier": "0x49892e694d1c968aace1b64043dcf4cc318276b8", + "fingerprint": "0x18414027eb492c9dc40b7ed18a4948a944ec4e9d1aff407321c44ac8d2a9a75a", + "tags": ["HU", "IN", "IT", "NL", "NO", "SE", "UN"] + }, + { + "country": "ISL", + "signature_algorithm": "RSA", + "hash_algorithm": "SHA-256", + "public_key": { + "type": "RSA", + "modulus": "0xb016c5ae5c183f07848d01dc01ae19b89a104a59310bde16997eb44571e1fd46cd8dcd1142265defcce35a899b087d24028bda45f606d03a7a7780e3994f768bca6de76c962b73b53ea5b4c3b919593e3cce76de0cd3519a945ab3c091aac12e94fa44f6b4979a92483d05eb1ab342f19c5a10aaa1bebdd1e1e10a904cffdc5e9adf5c702c2e6aaa33814d8944fc240beae9316620a376ab0dd531388999d53dd82f1758cc0fbc57af4d173c52de79bb0f1f45b6df13e3c85437ea1dbb5bf184e65a63c0f5a23e9e3a6b7fed16a05510898fec6ff16a50ca92c772b634ffaf12de1e925a628f43faddc2824c8b15f65d784c54dffc8fa6dd6034f36d6c9d7707", + "exponent": 65537, + "key_size": 2048 + }, + "validity": { "not_before": 1359590400, "not_after": 1990742399 }, + "authority_key_identifier": "0x857ff56a53b6c4d8336005d9ab5e80206773c74e", + "subject_key_identifier": "0x857ff56a53b6c4d8336005d9ab5e80206773c74e", + "fingerprint": "0x11e7307acb2163325c251b2e35a11c8609aa31aa5f6314327dc7ddaf71e6c290", + "tags": ["CA", "CH", "DE", "ES", "FR", "HU", "IN", "IT", "NL", "NO", "RO", "SE", "UN"] + }, + { + "country": "KOR", + "signature_algorithm": "RSA-PSS", + "hash_algorithm": "SHA-256", + "public_key": { + "type": "RSA", + "modulus": "0xc7fe759c6acf9ea74c6bdce1a0605834cf4973892b3344811f04f566e4c5d3e08fbacd1a6db4fd6b4fe6ce412c89c3a71e1064c33559826c428a10db0b5cc0673f024f45408db5352838b4c0c77c9d2f06e3caee0ec4c9135e5dcb9e1c05664c7e68d9a69855d78a4fca8b26c42bad1b74acef0457df01433027875689db78b6c02c0cca73a9b22c917feb513937d041eefa8c5055f8c0f13dc4ff063616d970ec731027e1e9b7e612e85488331a2fd2638e4ee0122d01f4c8d453f1a2ab7912f92e2eed218c09d22ca61075ace99007365472255ae4865ce66413261f49f9f658ddebc7bb459b5e6dc17edbf8fcd9a60d1b541875ecb7a48611df6591ec4be997a755773043499b897ef5d4e6a3bb87232b91bf801b6f4c51950632c430400870db2fe61b296f1f7996cce8ed46a5de2cb7c073591dc2b5425aa468fc72660328746d131342ae2a6d97f9f4172de2d5c4f37fa9aaa5a79c987b97c4c6979510f19f5d7166aa88e4a0bba617aca69b4f14ebe9c129d0a48b15263cf70315608f", + "exponent": 3, + "key_size": 3072 + }, + "validity": { "not_before": 1369989716, "not_after": 1851346799 }, + "private_key_usage_period": { "not_before": 1370022060, "not_after": 1527811140 }, + "subject_key_identifier": "0x7c06261ae37de33ffad61470e5abbf6d147d27f0", + "fingerprint": "0x1bcdbbba14abde122c0eecde54d53295f6cbc4563b54c25177c0e2858fb63b38", + "tags": ["CA", "CH", "DE", "ES", "HU", "IN", "IT", "NL", "NO", "SE", "UN"] + }, + { + "country": "MDA", + "signature_algorithm": "RSA", + "hash_algorithm": "SHA-1", + "public_key": { + "type": "RSA", + "modulus": "0xc57311ca1c839534e98afe81610940324542b0998aee67118225530229a864da4fae392ff514109240bbc0133928c73375289b1fdd8f764e1dda2603d2536f2d47753daacf6be3d5e6a962c445f84ad584df4461f64c239f627392fce4702528fd40c01914abb3680f09117cff7f82b2a459e13324486c91b86d894f1d33bf139c80d80cc36458d364fa5256d939a95f482c055d128f056e9226a8efa1e70446e138c75689990cad0974e3cfe3f1d907fcee8a155d6a84186db3a43f57336aa67583a4f1514c5e8178cb2d6abca85fa962b0f3e637d521cf8cca8def6508e9940e6fa3e7af9cb0c3c9ee4fc68990238e3a9a3d6d8ec3a6ff7ecd77377d76b161047085af2d10717aa0bf0f05f2740c41220807424b426ffe55cb00f35001aecf95225ab62dd25141e2532395a58e597f0423c75ef1f844a6e11d6f60e4f61b119b0d3a675d6aa05a69abe872f61cf4d6a06769925c8831dee634be59afa19626ce4c51a637379f6b13117421f4fb79c4f007dcbbe1c33246d7db13be7f8afec7b7b74baa3ccacc6cc104150cafd312e3795b5333c1cb3e907d62ce36cd161b8f775d4bed140f0afb046d27689a713b775ff043cc85fe50e03eb4c97be9b0e1650cefead0f1cf7e5410ceaa9e1867c5bebdbbc05522a1fd68b870658b484e09f8be4be2a3d44dc02ec32db88894b53835afd95aba18ec76beebba7401b9a7b507029231ffc40cb5e3df3eca806b9d8a61a8f962d9b3ad1f634eedc5a63b39480a525f1f848437331a25ca359bba15d4ce1f0d743f7106289fd6bdb593bfbffe67f24f2bda6fec5cb9dfabf36a4b5a76d63a7eb3730d77e07e190d128ee904a4f6ef43b892e54b9d3d9d257f64b81386280197cc055350ab6ac3be2c01b84248d8f18fa6ae378e585ef7aa3bce26afc5dafbebfbd9011dc218ed7c7b2fb7765d0e52f6ae74c0fc6d8be630f3b696ccd1f7757307ca7ba0f08ea39f725f6e5bf9a598f5d83bfebff1fc08f8fc06a627cd15a3fc5a080cc8e99b61b864a88b67664fa7f6f49d5f2ffc92eb509b7b61e66ec52357ad70ff71b5e8fc036ece79b6cca7", + "exponent": 65537, + "key_size": 6144 + }, + "validity": { "not_before": 1299074708, "not_after": 1772460308 }, + "subject_key_identifier": "0xc59dd59ee7e15cbc2f103d5299ef319f3ef910f6", + "fingerprint": "0x2fa3697919f75c9d397ebb35ab1483a34e7547e8ac019d332d19573e3e595d42", + "tags": ["CH", "DE", "HU", "IN", "IT", "NL", "RO", "SE", "UN"] + }, + { + "country": "NGA", + "signature_algorithm": "RSA", + "hash_algorithm": "SHA-256", + "public_key": { + "type": "RSA", + "modulus": "0xcc7fbcb9331cef9f4be115468b095f622bb84a295af93770388c672f63e3d83a0fecf58520810758b53d03ed6ee7aa9d41c165ccb7bd5cfdb7a7d4bc71b14d2dedc73da6d12ea1abef9dbf1f54ce39f25609d600c33da26e21954a30042aefb96b6ad479f617e587ec07c95fe0b7b99a578355ec1252475866d283de2126b6ebb6ff81778f714c5f452715723bd80be8e46965a933194e749317d321f377b2a240524ea7f025f503a1e1464caefac60194df68755548891c8afd9844f17fc5d5712333764052ac41ead4ec0878938adafb193672f38052d4932307636df5453373ee1b8a4f274e66d33ad4f247033d35ab310a504da71ddc4d2429aca9bef17fd2fa4f90980618f16a1e08c936e4983d849c47d77e338a3ab5aa681c932d11c5b106cb8c7002e65c2a00abeee01dc284b78672a167d4dd8321e12db4d43ba74845819b5cac6c1050aca71637ec0d156a7c88caba9ac5ab22b2b5e43039e44cf742a327d5ff06faa4b2e4688dda1c8d25de5ac661e41a2a55f0162e443c0f757c92eea0dbb126859b1fea614289a37b34a7cb1eeb2886d9ad147a2a4b4484603f21f48985d9c418354e6c236b3131f09f100a2a658a4376e2a24a9c2c58f1c9395a84d06b4662ea9fdc17fddd9c962a1aae61e59b46e50bc96026fa3573580ed051948f29744f3dd01b024eff8d8bb1e5e636becd0feae9afd5cfe3e7634063e3", + "exponent": 107903, + "key_size": 4096 + }, + "validity": { "not_before": 1495027148, "not_after": 1810646348 }, + "private_key_usage_period": { "not_before": 1495027148, "not_after": 1589721548 }, + "authority_key_identifier": "0xaf3cfa7356b2257be9b19df390723726be7c8dfc", + "subject_key_identifier": "0xaf3cfa7356b2257be9b19df390723726be7c8dfc", + "fingerprint": "0x27b1e6bac2778c95e42005be427e6da9db26fc9ba2b3c38062878f18fe94b105", + "tags": ["CH", "HU", "IN", "IT", "NL", "SE"] + }, + { + "country": "NGA", + "signature_algorithm": "RSA", + "hash_algorithm": "SHA-256", + "public_key": { + "type": "RSA", + "modulus": "0xa9241d920e67b58b1662f038a97766ae956d6972b7985641d7509e143135e5ce56025c5579847e0eb901e27806c9deb45f1215b54a066aa67f022b4f14082f68b9b2b7651a69799c47431331ba4e2300b263b58c34e185aae16dafb43217fc1f443abbc3808cd65c44b68107ea50771f65745ff0bfb2ad9b47bdc8438342d61b8a25a313a495585c87ad034886a5224768a1656ac8bcb0f5dc900c226d0341b08d34fc7e1706f1c9ae367f3a920e6d9a22a85256227c8f2aebfc499a22476b031bb00fd62c487b3bb7883fc4653c93d030c3b4898914c6cde3da44366dde9ebe30c4cca77f516899f6085304716e655b91df5de69df1d3c84c3d3b3fc24afdd2f0a180bba6c502e9b77295d0a6903bd35cfa87ac0078ac65d74c18cda0dc369a8adac15847a2e008f7730b0808e585122ad05fd5dbb87b2be890404c3175157a399b5ee83fec12e5d02d5d52d4f153c31e22aab93c56836e2718f6f52df890a4f96d0ee6bd733bf6c43d908f869584e102fee51f0bebfabe437b017a44941ab8b9e97b6fb12b58e56be72fcd5e080890edc98c156f400a0438f2103874f7703c7021e887904f3f920fbf02b1aa5e71ca3496ad8247a1742053624d20dbb758e6e3c3085b7dde5e1c01ed81290d43f31249dbe713470fc169f7f67945b0e1378661b227be591b5fe681002eee7202b3e72267a45736d945266ee88b38f64c619d", + "exponent": 122125, + "key_size": 4096 + }, + "validity": { "not_before": 1554105074, "not_after": 2027490674 }, + "private_key_usage_period": { "not_before": 1554105074, "not_after": 1648799474 }, + "authority_key_identifier": "0x26cb4edc2f52e7d51937344e53dc579f4ff85136", + "subject_key_identifier": "0x26cb4edc2f52e7d51937344e53dc579f4ff85136", + "fingerprint": "0x2e4fc1f8e14f31e3b853838f4488476d3649efeb74245eeb48bfa72d7d40edcf", + "tags": ["CH", "IN", "IT", "SE"] + }, + { + "country": "NGA", + "signature_algorithm": "RSA", + "hash_algorithm": "SHA-256", + "public_key": { + "type": "RSA", + "modulus": "0xbe80fd3db2787979bd79e40e3fdaf351cd08ca23cd0d97daff2e8781fe94df15e94bea233c4a0d857da78eeae10f639fbded32cfc6dccd0b7a97e3cd4ca68f57d767ff160aa8cc765456e00901ebdfaa110ed0dee189fef6b34bcaa4ac2cf3b8764f7489605f037351c725cabaa9e6e8e605ec5f8e581c0679a5fe40c0f6bc2289317a6ad336e83ee1e65b8e7727b7dfe2e640d65f12196a526082df89095501d3759982707b1d2cef9c37e0baf0c12b7c392bbc7724420a24402da71ffd3b163f662c589576e87c8e6ca80f68e0c79ce246c199095c8cee125036312751cf66f8dd49f9641ea49e20dc64bfaf5df46ee5b0cf02b7f540fd08a2ef85b538fdc7624c4a0138502fba4314930ce8328039be103e199bddfa4ae870bad2d8a380efdd453352b9b0de9a2a620dbe24b8e6f8959cd4ba9b04b22d3f6bc6d46612c507d5da0b19feb1fd77835dd6ab6d826606c94ee0cb1d3707ef02419a9d1598d8039857e67d93963d08cf6b627fec7b1937cd1c1f74837b9cbf7489a1f76a3bc2e5b2322b3f185306a707cf61c5a7aa488627a045f3106426fac7d66f4c0dad7773f612018e18057016b9530d01fecb2de865dc7974aeef0f3bfdca0f5aeaa6b82970b08e89adf8eb262d5a950086e766acb192ea8dfe24847764fa46e8db66115a571fc993e8f19320be08468a4857fb4853e0469767b133dfcb051cd3a8255df9", + "exponent": 130689, + "key_size": 4096 + }, + "validity": { "not_before": 1647941034, "not_after": 2121326634 }, + "private_key_usage_period": { "not_before": 1647941034, "not_after": 1742635434 }, + "authority_key_identifier": "0x5681341660d52733f509ff23defdba3cea612650", + "subject_key_identifier": "0x5681341660d52733f509ff23defdba3cea612650", + "fingerprint": "0x054e4f56ed970041554d73203271ba65f06a4dbbf54ba8bb6566461b43577ecc", + "tags": ["CH", "IN", "IT", "SE"] + }, + { + "country": "SEN", + "signature_algorithm": "RSA", + "hash_algorithm": "SHA-256", + "public_key": { + "type": "RSA", + "modulus": "0xda66c33d84cb462d4438c5a5de08633bd55b169638dde20c936a561a08391d64d87aa82c91e3b0facb6deb364ef7fa7fe2ea8f424a9cf7b893ddef3ebee5c35eb815cf047ac765b9d5c3cd90e0d5465cd9f6877ce8213488e443941aeafcbb901d84a4e7b1c1a7b865cd76b251c074ce10bbffa73d0fb0741a761f5a07d383ebb306fb43c388cbb635d0f040f2323f9d322ed8c80150481793da0094069c593b7064775341952b300af600196b2fe0e1029a62f54f6eb7abda45fbaa99265245ecd7ee5b1ecdabf82c32b2562c86f56c0f4e5e89cc00c98b01db99335ff4ef388626a16840ae01d93ad4b4f8751ef9e7749525d5aba6be874e0d4488f3bcd349d0ffda88874bd8b37c9d7e9880af32e6a83d7517009c31238d464f9ad64837004da348148d99c54e61fcb1b1112bb3034cbc7566d46c4657428c6c713549a573ed00aab6a3b2c39a29fdf58ef67726e637bf6c10dce0b6f03328def7b83bc6ebc8dd4f3c7cc3a96ae8d7b000b4a7c684c3692f74086aa58290a8b640dd6b7fc2fe0bba6318a4c696af1197e761b54f93927a5651a8aed94ace167ff72af783e4ae53140b7984a1ea6640deeaf2d2f876f3d2febbf1d2175688ca0b73411814fc435ea79b73470fdfa171ca4adb65aaf6de939a038d86aaac25cb038b476269546c291962c76e8e349bd3353b7d81d15c1c391f948f09fe69952e7bc7d687be27", + "exponent": 109729, + "key_size": 4096 + }, + "validity": { "not_before": 1474339122, "not_after": 1947638322 }, + "private_key_usage_period": { "not_before": 1474339122, "not_after": 1569033522 }, + "authority_key_identifier": "0x245ac54ddd920d5065be705c237ee684f7184d51", + "subject_key_identifier": "0x245ac54ddd920d5065be705c237ee684f7184d51", + "fingerprint": "0x083669a5a225869aabaeb8cca947d0a7c6b7e92aa3e47cd85d351259d375908e", + "tags": ["CH", "IN", "IT", "SE"] + }, + { + "country": "USA", + "signature_algorithm": "RSA", + "hash_algorithm": "SHA-256", + "public_key": { + "type": "RSA", + "modulus": "0xbdbc15fb397fbc1ccb58069daed4d2a42f65ff338ecc040a6f08555c218f28ad127ce8e2a8825255f6e843e4efcfaec58316fc2c3854273a144b11e387b3ef3bc358c065cc850af0d09cc00118cfa9b194493dea5cefc37c4c008a514ac7536f9a5af1660012eb8888a948e5ec81b0600a402c4d4e9398e412f6034c4d7ab827b9450cf4beea9a29c822aeb870216e82e2bdb0c7d1b5c6beffa62208edfa3dec3ee1e72d36d3a3b0b210a51c0990d29e0b48af8dc5ec69eac59a0ec6ff13b8ca8cb73191c2892ec6b2185e7c79d5b87e723dd81b88de90213d226932608899d37c2ef177da8d239d89983ec44594bb23dbe5040271f5ddbb35a92d3bbef467c7709798f6131a5e9a9a56e678f68c0e0578a9633c7bbd5d755823d63c9900d833c787c34fd07cd80f3e230d7764ea54feb056f4e677464d9a48e9850baf55ab5d9c6d8adf5e86dcdc65f243f85be32322ded7cd4b69ea79eb1bd9ae7f1abc4a87038888dac9702967cd396aadd7231077596025d3e2447ac296c601036bb9ec3f05622e5ab1ae8173c1f1a87c7fcb6d2deb463b9e6431a3c36e4f995d8e839438c32f39eeac5d1b13366235c466510f29daba53a11aa61ff5e7b44d0e81ab06cc199c257e6830d0beef3bc42c125c73d6333088175fb479565239fc6be79e7e31ea59a28a8e4559bde4b0c7353166133766e6939b72c8ac6f43a678ad9771fb55", + "exponent": 65537, + "key_size": 4096 + }, + "validity": { "not_before": 1262966787, "not_after": 1912437387 }, + "subject_key_identifier": "0xb11a1df823a296948ee7ea49a8cc8772c6fade9a", + "fingerprint": "0x0f98dcf949037c4f3f46093bd1107a6766292bbc5e862cc47255aa9202dbbd17", + "tags": ["CA", "CH", "DE", "ES", "FR", "HU", "IN", "IT", "NL", "NO", "RO", "SE", "UN"] + }, + { + "country": "VAT", + "signature_algorithm": "RSA", + "hash_algorithm": "SHA-1", + "public_key": { + "type": "RSA", + "modulus": "0x9c4ff9a2006df7f763f75a40bb2f3cb8b69b39dcd0bb01d6567768e403ff74082b7d7a2cc78805b3bb499d59364f422801598fe1af453cf6282a3176b79c6a9962d30c610ac6d80f71a6f590567dcc00de837e314c09558a0f71786eea107d3ec78fc32fd4738a5da1ba81f146d1ae83ab7f5e260fd0fde255055c6ba18b1f5498d3eb2830e1a58af6e15ba7fa1f9de52c73ebb5c4d323e328e5726dec237bc86be5e0b24d49852fa6e1bcc0d240ad8649430fa4b9cf4b566675e5583c919855c896dcd58fd8ba3b0fb7f0570a57d40af5f4c4c93c0efaade0027664a53117ca49be316504e8a6b43346f0ef41a9d5250b3bb54939bcc7a5dee31d9056dda8ca690aca4113455296e0d4bd7c76b68185a59b587f502478b7e21e8803eeafaf6bd8151d2a9e013e00de486f47cdb2e12c24d58bc9aead347e84b2eb3c81bc671a4dc8573be867bc7de9ddb67788dfdb4c45b1aeb93436bc4134af4dff572dc8439201e60f8c0ea710922014208e7a6f286126b6b42e873d3154943db2de0aeb795d9b54db655f83a9f2823c639f6627578ae88eee7b44c49b0659e45ef11e870ab8527c3ecf5461786de1f2b3261588baf3c759a2cf53bab91c0b388e1358960662e332cd0a2561a61d51acce8d36c4d5417cc778fc3a151c0afe115471755ea0107472fc0ea8b4257876b47486a0927daf0c05035bf617af9a08d84aacf61c9f", + "exponent": 3, + "key_size": 4096 + }, + "validity": { "not_before": 1203589065, "not_after": 1834309065 }, + "subject_key_identifier": "0xada907a455abc131269722b5bb502103db28b6fd", + "fingerprint": "0x2301430bfde5e9484d27fb4c8fe04ef634b0f3f16883856f173ef08c3cad8d6c", + "tags": ["CH", "DE", "HU", "IT", "NL", "SE"] + } + ], + "serialised": [ + [ + "0x009951263933be5c915c2003e4c76123e3a2705c9dfa83fcb01161f23275302a", + "0x05dabae8bc4f735bc246b56e974edddc93c7d70293b880a7b40e13851a9e0fb6", + "0x05e1befbf6cedf1a3b3a644f2d7ece2b00eeec4ce6305f1cd02d4332e220752a", + "0x06473907073af634d13b4eb1e0db3f861236540034bc42aaeebee5237cede35e", + "0x065ef9aec10187678cb8de43b3c5abcfd78bd3d983077265513b9894ae6623a7", + "0x06b662ce912277d3b54795a9523f46bc65c9eb4bc6389e9d7bf3978630ac3eac", + "0x06bf4583b421cbdb980291feb9f3f734ad2ede171fc9a5d0e08d0d632d405a25", + "0x06df1990857376eafcf474130e3cd5c31aed510d5d97ca0bec4db470ea5e8615", + "0x081dc87be7d62ed6843b524fdc3e7fef85795c7d1801b7c3045bf253af82eabf", + "0x0a171c49d513cc80d9d3eb3677e2c64cf855e284451da39c1705ac0f65b59628", + "0x0a7facb88360fcab665c1542c849916836220da436027d8944696e663ea54959", + "0x0a85f6e604851e8f1d56bd0c0aa3ea3dc7d6a95d32db53678e6cfd5b9b8cb533", + "0x0b33e4b01c71940518ebb786276f27376fc3ce19c7bc7dfe8498ebd37cc6a784", + "0x0e2e194a645a331ed93205e7312cdcde2e661f3122499896d00722eebd12d346", + "0x1153ac1e235eae079c5c79f76b1d73d7be7dccdcefadf3622f78441cf56e7c47", + "0x131adb9404e1eda178c13032ce036bd78bd8ab5546bce9924a9c8059641f1613", + "0x19746aa8d1ecbccecaf1d157e83374baf5d3a8130cdca756ede57fdefb8df1d3", + "0x19f55fc7c3407b80974e24c19bdb4b6397751a5f5a933b86d188f1c273c6eef1", + "0x1cd1a1ecd34419905a86f4ab665851c64603dbb8948fc187cfdde7e25f20a8c9", + "0x1d73c848fca0012ebcd4c8ed9b34682a15ebcf0a80760d8bcdb25ee68454d866", + "0x21a84fc3db64055d0864d9e1c4539e832e5b6f0793c7e1218368c2f8738b7616", + "0x241d64849c570f43e94bd3d5a40eb844345d32ef120f131ea857f7cb3e2e23b0", + "0x2606e150db719e05da89dbb8eedab35a407852a428286662ff74cc1d565bac86", + "0x2637c4e91cf82c80ff0c4dd0e69c359fc40f39a182d860c46423b078743be7f5", + "0x2693b16a914ec3e02fc4fea8ebffa2efc461cd60ed28264962043f68b166c814", + "0x2695edd82c5b286a836911b8b8043bf4bc0a6b8a074e664f86326d1ff3aff93e", + "0x26fce086c7f09ca38344f2149f40bac7bba53a32bd66c2a57a54d0c0c7277f71", + "0x27bf676c61d67aa66ef1a4a6077969373e98e42cb23271984610fb5e4868d352", + "0x292b3fecef4582da59fd32fc432b6513036cda9c3f8eac0f1e37653a3c7ed5d0", + "0x29b23a6715831c797a1b46842649eabea43c1c69b2b44991a3c7db349591a001", + "0x2ac4c0d76bd9e410c139bb72e97a698674f07783628b295f841836da3f5ac5ba" + ], + [ + "0x1caa5b74aadf98936fcf23d751d2a0735e456d7d4ed97a15ed77ffa22508021a", + "0x0d5046541b06608fd9a8d2fa8f8112d1a119fc1d64e9b420d065bad93905984c", + "0x0476c0bc2dc701ae2f8da24e803bfdc60690064d15a54b6d7fbaa2b6c64025a9", + "0x1295027eae6483795f7d2f159d8b5f71fde0b221a50b07cc8026185046c88c14", + "0x1036e1ca6285b01ddb3ed582f98bb938f0745784ac115701982589ee98e2cfd4", + "0x1f492d438fd04b1a13d62f862b5dc099636436e288692e4a053bfded81e20572", + "0x2add8de4b53399f80c483eded21becb19c129aa05207d0fb6ed9f626fd3f894b", + "0x27d580197e1fb168d14728b3ef2c3fe06b36e5043e3fe517ad991adfbec5adc5", + "0x0ec3481cb494d791494a706e8ac064ccdb033fdea1bb82f33e98862f99bb204f", + "0x236a70c625821149674aef66c73f22b58178d6df6a6974be5324a09ccd02d97a", + "0x1e5e211ff849b77308c00df36288810d1edf0a334636548cb2e5c8b313548ccb", + "0x231b67bd00b6e8393b93d1534c80ba0309cdab4e4195df115cb378821986e923", + "0x1a5c2a871d3e483c4488ab8f0db75731150aa6fe90bef0687f693ab563638d62", + "0x2629adc243192d19e8c041810f9ecb719739c7b056ee2415a46cce5090bbdaec", + "0x14343ba82f7145fd65a49737294bde1b711d4975bb8886f1e1d8aa0cf2ff48c5", + "0x2d4f545d6e3bd03ac76fde4b9aee808ddec7acc57ef2b40a68530452b32e3764" + ], + [ + "0x194d10ce0cae595532e9d34849734288149827ae9103fbcaf60c73d19fe4ccca", + "0x1dbdca1da8f4b8d7ae0641f5d4fdf738082eb3401c6514d842936c669b837b04", + "0x1ad930021aa05d93a47e527e0149f6b7d076e396c19c92330c5bb6b60214ea4a", + "0x1969e517fcb3acbb1e927b30279c025b619a2bb481ef8750d9e18e921f35394c", + "0x055cc563691634b97a07e26ffc755765a6492b94c8a830153ab2510de3eb3757", + "0x2fad5bd27d59f3e2af06a1f007f84dcb7435d6ecc979e33859191da54e6e0f8a", + "0x11873f8d9c6807a67d4e3f864dfd88c62f64ff2a1991e5c6e9c5975fa5a7d6a8", + "0x088410d4247d6ce398d13c4235b499127163df3eec6ebd0556e47cea24318bd1" + ], + [ + "0x1961cbc7648444703e79da69eabd79d18eba2099a3ed92cc032b9d98870672ca", + "0x02973dbd78ae2054a6ec06cc83f522f77071492d70f5a40a16bb9f7af2a93401", + "0x14ec2b60dc0392c55ecefdacc41fcc2c98a661390c009df34766dfd9c7c146e7", + "0x212f5bfc453a37aebb422c73065b3f70713cbd6200e4b4c72df482f2c8a56653" + ], + [ + "0x114a11f24590604c791ca41284e90da30235ee57d2f96494a571b59aed8969df", + "0x1d88f79d351d018a91a5bc911f4563bebbfbf73fef77cd04dc56799557193128" + ], + ["0x0bfe40eade1843d2799445e5ac79f580256e19d022054fe1945c342f7d378958"], + ["0x0ad93c1d1ce7c7d6e7fa3a0fdff77f7effa64e5a557160fc46ff8b9a0867cc30"], + ["0x0f171ad94081a499ef1f772ae8496708daf1cf7003b33e2c35888a1ead5c0fd2"], + ["0x1459741471a054f3ccc7d382eb49fdb573fbae4154b196281781e92915117e53"], + ["0x0324581d07dbac0fc58c2df353a71696969cc051d72ca6244652e86b886a2a6e"], + ["0x29c78d48c2ce79016efdfc20073b6c5b5bbf78c0bba4a48b55994c91c5801f71"], + ["0x2e01c937bc777a3f4e2969264964097334a342104940a2faa8a5a5957fef07ef"], + ["0x25e2d511c49e6b67411cbe3f3a251a9ec386f58dc2fac7592454d6cb19b932ff"], + ["0x198db6fbcb241b12468c2b1c43bafc4c5b9d78263ec37e30d4a424857cd49a5f"], + ["0x0196ec7df4a917b2e88155becbfbc38dd6e44c1bfa4d2179d31a7f2a90a97231"], + ["0x2abef2ad091c7390907eb674e704c63ffa187987d9c6204490886fdf282433be"], + ["0x2b49d7ddaec2fa540efec3311af6223cfd19d3a9e9314e10039f9fae0747f062"] + ] +} diff --git a/packages/zkpassport-utils/tests/registry.test.ts b/packages/zkpassport-utils/tests/registry.test.ts index dbe67bc55..1a8166e34 100644 --- a/packages/zkpassport-utils/tests/registry.test.ts +++ b/packages/zkpassport-utils/tests/registry.test.ts @@ -8,6 +8,7 @@ import { } from "../src/registry" import { PackagedCertificate } from "../src/types" import rootCerts from "./fixtures/root-certs.json" +import rootCertsV1 from "./fixtures/root-certs-v1.json" import circuitManifest from "./fixtures/manifest.json" describe("Registry", () => { @@ -26,12 +27,13 @@ describe("Registry", () => { not_before: 1000000000, not_after: 2000000000, }, - subject_key_identifier: "0x1111", - authority_key_identifier: "0x2222", private_key_usage_period: { not_before: 1000000000, not_after: 2000000000, }, + subject_key_identifier: "0x1111", + authority_key_identifier: "0x2222", + fingerprint: "0x0111111111111111111111111111111111111111111111111111111111111111", tags: ["UN", "DE"], } @@ -52,12 +54,13 @@ describe("Registry", () => { not_before: 1000000000, not_after: 2000000000, }, - subject_key_identifier: "0x1111", - authority_key_identifier: "0x2222", private_key_usage_period: { not_before: 1000000000, not_after: 2000000000, }, + subject_key_identifier: "0x1111", + authority_key_identifier: "0x2222", + fingerprint: "0x0222222222222222222222222222222222222222222222222222222222222222", tags: ["UN", "DE"], } @@ -97,21 +100,21 @@ describe("Registry", () => { expect(bitsFlagToTagsArray([0n, 0n, BigInt("0x8000000")])).toEqual(["UN"]) }) - test("should generate correct canonical leaf for RSA cert", async () => { + test("should generate correct canonical leaf for RSA cert (version 0)", async () => { const leaf = await getCertificateLeafHash(rsaCert) expect(leaf).toEqual( 10374427192692971605115852434399434992383543572583326103540359782862263554570n, ) }) - test("should generate correct canonical leaf for ECDSA cert", async () => { + test("should generate correct canonical leaf for ECDSA cert (version 0)", async () => { const leaf = await getCertificateLeafHash(ecdsaCert) expect(leaf).toEqual( 9676427500440764140387924904666461180023752817896651616722688209534314347621n, ) }) - test("should generate correct canonical leaf for different publisher and type", async () => { + test("should generate correct canonical leaf for different publisher and type (version 0)", async () => { const leaf = await getCertificateLeafHash(rsaCert, { tags: ["UN"], type: CERT_TYPE_DSC, @@ -121,14 +124,58 @@ describe("Registry", () => { ) }) - test("should generate correct canonical certificate root", async () => { + test("should generate correct canonical certificate root (version 0)", async () => { const root = await calculateCertificateRoot(rootCerts.certificates as PackagedCertificate[]) expect(root).toEqual("0x03c239fdfafd89a568efac9175c32b998e208c4ab453d3615a31c83e65c90686") }) + test("should generate correct canonical leaf for RSA cert (version 1)", async () => { + const leaf = await getCertificateLeafHash(rsaCert, { version: 1 }) + expect(leaf).toEqual( + 18821076869038301219571401322686721036085203437552110369443322053623613446966n, + ) + }) + + test("should generate correct canonical leaf for ECDSA cert (version 1)", async () => { + const leaf = await getCertificateLeafHash(ecdsaCert, { version: 1 }) + expect(leaf).toEqual( + 14965224189996577667331983147414903016849320294809859715118036488072996530241n, + ) + }) + + test("should generate correct canonical leaf for different publisher and type (version 1)", async () => { + const leaf = await getCertificateLeafHash(rsaCert, { + version: 1, + tags: ["UN"], + type: CERT_TYPE_DSC, + }) + expect(leaf).toEqual( + 17732559635977458050578953956465414663427303613303769254065708457591008172683n, + ) + }) + + test("should generate correct canonical certificate root (version 1)", async () => { + const root = await calculateCertificateRoot( + rootCertsV1.certificates as PackagedCertificate[], + 1, + ) + expect(root).toEqual("0x2b49d7ddaec2fa540efec3311af6223cfd19d3a9e9314e10039f9fae0747f062") + }) + test("should generate correct canonical circuit root", async () => { const hashes = Object.values(circuitManifest.circuits).map((circuit) => circuit.hash) const root = await calculateCircuitRoot({ hashes }) expect(root).toEqual(circuitManifest.root) }) + + test("should correctly convert timestamp to 4 byte array and back again", () => { + const timestamp = 1768823285 + const expiry = new Uint8Array(4) + expiry[0] = (timestamp >> 24) & 0xff + expiry[1] = (timestamp >> 16) & 0xff + expiry[2] = (timestamp >> 8) & 0xff + expiry[3] = timestamp & 0xff + expect(expiry).toEqual(new Uint8Array([105, 110, 25, 245])) + expect(BigInt(`0x${Buffer.from(expiry).toString("hex")}`)).toEqual(BigInt(timestamp)) + }) }) From 3f28ada779cd9156dacd31574730ae7e2eb66a1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Madzou?= <17496111+madztheo@users.noreply.github.com> Date: Mon, 9 Feb 2026 09:19:09 +0000 Subject: [PATCH 07/30] chore(sdk): Restrict sanctions check API options (#155) * disable lists customisation for sanctions check api * fix tests * bump sdk version to 0.12.5 * add google key attestation ecdsa root key hash * sync deps --- bun.lock | 2 +- packages/zkpassport-sdk/package.json | 2 +- packages/zkpassport-sdk/src/constants.ts | 6 +++++- packages/zkpassport-sdk/src/index.ts | 14 ++++++++------ .../zkpassport-sdk/src/public-input-checker.ts | 6 ++++-- .../zkpassport-sdk/tests/query-builder.test.ts | 4 ++-- packages/zkpassport-utils/src/types/index.ts | 4 ++-- 7 files changed, 23 insertions(+), 15 deletions(-) diff --git a/bun.lock b/bun.lock index 71c1fbd1c..4ab7e4077 100644 --- a/bun.lock +++ b/bun.lock @@ -84,7 +84,7 @@ }, "packages/zkpassport-sdk": { "name": "@zkpassport/sdk", - "version": "0.12.4", + "version": "0.12.5", "dependencies": { "@aztec/bb.js": "2.0.3", "@noble/ciphers": "^1.2.1", diff --git a/packages/zkpassport-sdk/package.json b/packages/zkpassport-sdk/package.json index d17fdb969..cb907f7f7 100644 --- a/packages/zkpassport-sdk/package.json +++ b/packages/zkpassport-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@zkpassport/sdk", - "version": "0.12.4", + "version": "0.12.5", "description": "Privacy-preserving identity verification using passports and ID cards", "author": "ZKPassport", "license": "Apache-2.0", diff --git a/packages/zkpassport-sdk/src/constants.ts b/packages/zkpassport-sdk/src/constants.ts index 0b1b70383..b1834b0c6 100644 --- a/packages/zkpassport-sdk/src/constants.ts +++ b/packages/zkpassport-sdk/src/constants.ts @@ -18,7 +18,11 @@ export const APPLE_APP_ATTEST_ROOT_KEY_HASH = "0x2532418a107c5306fa8308c22255792cf77e4a290cbce8a840a642a3e591340b" // This is the hash of the RSA root key of Google's App Attest -// Google will roll out an ECDSA P384 root key in February 2026 // c.f. https://developer.android.com/privacy-and-security/security-key-attestation#root_certificate export const GOOGLE_APP_ATTEST_RSA_ROOT_KEY_HASH = "0x16700a2d9168a194fc85f237af5829b5a2be05b8ae8ac4879ada34cf54a9c211" + +// This is the hash of the ECDSA P384 root key of Google's App Attest +// c.f. https://developer.android.com/privacy-and-security/security-key-attestation#root_certificate +export const GOOGLE_APP_ATTEST_ECDSA_P384_ROOT_KEY_HASH = + "0x0e1889bec6c1d686abcf08360ff404f803ab345881ea8cba6aad33b7f7f7ffe0" diff --git a/packages/zkpassport-sdk/src/index.ts b/packages/zkpassport-sdk/src/index.ts index 6ca9b90c5..db0c85a11 100644 --- a/packages/zkpassport-sdk/src/index.ts +++ b/packages/zkpassport-sdk/src/index.ts @@ -353,8 +353,9 @@ export class ZKPassport { ) => { this.topicToConfig[topic].sanctions = { ...this.topicToConfig[topic].sanctions, - countries: - countries === "all" + countries, + // TODO: enable this once the circuits support custom lists + /*countries === "all" ? "all" : Array.isArray(countries) ? ([ @@ -364,13 +365,14 @@ export class ZKPassport { : ([ ...(this.topicToConfig[topic].sanctions?.countries ?? []), countries, - ] as SanctionsCountries), - lists: - lists === "all" + ] as SanctionsCountries),*/ + lists, + // TODO: enable this once the circuits support custom lists + /*lists === "all" ? "all" : Array.isArray(lists) ? [...(this.topicToConfig[topic].sanctions?.lists ?? []), ...lists] - : [...(this.topicToConfig[topic].sanctions?.lists ?? []), lists], + : [...(this.topicToConfig[topic].sanctions?.lists ?? []), lists],*/ strict: options.strict ?? false, } return this.getZkPassportRequest(topic) diff --git a/packages/zkpassport-sdk/src/public-input-checker.ts b/packages/zkpassport-sdk/src/public-input-checker.ts index 794e2dd15..05f4dae32 100644 --- a/packages/zkpassport-sdk/src/public-input-checker.ts +++ b/packages/zkpassport-sdk/src/public-input-checker.ts @@ -71,6 +71,7 @@ import { DEFAULT_DATE_VALUE, DEFAULT_VALIDITY, GOOGLE_APP_ATTEST_RSA_ROOT_KEY_HASH, + GOOGLE_APP_ATTEST_ECDSA_P384_ROOT_KEY_HASH, ZKPASSPORT_ANDROID_APP_ID_HASH, ZKPASSPORT_IOS_APP_ID_HASH, } from "./constants" @@ -1246,14 +1247,15 @@ export class PublicInputChecker { // Check if the root key is either from Apple (iOS) or Google (Android) if ( facematchCommittedInputs.rootKeyLeaf !== APPLE_APP_ATTEST_ROOT_KEY_HASH && - facematchCommittedInputs.rootKeyLeaf !== GOOGLE_APP_ATTEST_RSA_ROOT_KEY_HASH + facematchCommittedInputs.rootKeyLeaf !== GOOGLE_APP_ATTEST_RSA_ROOT_KEY_HASH && + facematchCommittedInputs.rootKeyLeaf !== GOOGLE_APP_ATTEST_ECDSA_P384_ROOT_KEY_HASH ) { console.warn("Invalid facematch root key hash") isCorrect = false queryResultErrors.facematch = { ...queryResultErrors.facematch, eq: { - expected: `${APPLE_APP_ATTEST_ROOT_KEY_HASH} (iOS) or ${GOOGLE_APP_ATTEST_RSA_ROOT_KEY_HASH} (Android)`, + expected: `${APPLE_APP_ATTEST_ROOT_KEY_HASH} (iOS) or ${GOOGLE_APP_ATTEST_RSA_ROOT_KEY_HASH} (Android) or ${GOOGLE_APP_ATTEST_ECDSA_P384_ROOT_KEY_HASH} (Android)`, received: facematchCommittedInputs.rootKeyLeaf, message: "Invalid facematch root key hash", }, diff --git a/packages/zkpassport-sdk/tests/query-builder.test.ts b/packages/zkpassport-sdk/tests/query-builder.test.ts index 01a15e328..a96aa1539 100644 --- a/packages/zkpassport-sdk/tests/query-builder.test.ts +++ b/packages/zkpassport-sdk/tests/query-builder.test.ts @@ -248,7 +248,7 @@ describe("Query Builder", () => { }) }) - test("should build sanctions query for single country", async () => { + /*test("should build sanctions query for single country", async () => { const result = queryBuilder.sanctions("GB").done() const configPart = result.url.split("c=")[1].split("&")[0] @@ -303,7 +303,7 @@ describe("Query Builder", () => { lists: "all", strict: false, }) - }) + })*/ test("should build facematch query with strict mode", async () => { const result = queryBuilder.facematch("strict").done() diff --git a/packages/zkpassport-utils/src/types/index.ts b/packages/zkpassport-utils/src/types/index.ts index 29a9da263..129928f9b 100644 --- a/packages/zkpassport-utils/src/types/index.ts +++ b/packages/zkpassport-utils/src/types/index.ts @@ -239,8 +239,8 @@ export type ExtendedAlpha2Code = Alpha2Code | "EU" | "UN" // Explicit list of supported countries for sanction lists // TODO: extend this list as more countries sanction lists are added export type SanctionsAlpha2Code = "US" | "GB" | "CH" | "EU" -export type SanctionsCountries = SanctionsAlpha2Code[] | SanctionsAlpha2Code | "all" -export type SanctionsLists = string[] | "all" +export type SanctionsCountries = /*SanctionsAlpha2Code[] | SanctionsAlpha2Code | "all"*/ "all" // TODO: enable this once the circuits support custom lists +export type SanctionsLists = /*string[] | "all"*/ "all" // TODO: enable this once the circuits support custom lists export type SanctionsConfig = { countries?: SanctionsCountries From 99d5abdb50c2453b71b29c16d8affb22f3d2a8d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Madzou?= <17496111+madztheo@users.noreply.github.com> Date: Tue, 24 Feb 2026 21:01:07 +0000 Subject: [PATCH 08/30] chore(utils): Update Barrett reduction overflow bits to match new Noir BigNum (#156) update barrett reduction overflow bits --- bun.lock | 2 +- packages/zkpassport-utils/package.json | 2 +- .../zkpassport-utils/src/barrett-reduction.ts | 2 +- .../tests/circuit-matcher.test.ts | 53 +++++++++---------- 4 files changed, 29 insertions(+), 30 deletions(-) diff --git a/bun.lock b/bun.lock index 4ab7e4077..210364464 100644 --- a/bun.lock +++ b/bun.lock @@ -110,7 +110,7 @@ }, "packages/zkpassport-utils": { "name": "@zkpassport/utils", - "version": "0.33.3", + "version": "0.34.0", "dependencies": { "@lapo/asn1js": "^2.0.4", "@noble/ciphers": "^1.0.0", diff --git a/packages/zkpassport-utils/package.json b/packages/zkpassport-utils/package.json index fb689c474..f82f58d33 100644 --- a/packages/zkpassport-utils/package.json +++ b/packages/zkpassport-utils/package.json @@ -1,6 +1,6 @@ { "name": "@zkpassport/utils", - "version": "0.33.3", + "version": "0.34.0", "repository": { "type": "git", "url": "https://github.com/zkpassport/zkpassport-packages", diff --git a/packages/zkpassport-utils/src/barrett-reduction.ts b/packages/zkpassport-utils/src/barrett-reduction.ts index 553a4cc4c..ea3012f02 100644 --- a/packages/zkpassport-utils/src/barrett-reduction.ts +++ b/packages/zkpassport-utils/src/barrett-reduction.ts @@ -1,4 +1,4 @@ -const BARRETT_REDUCTION_OVERFLOW_BITS = 4n +const BARRETT_REDUCTION_OVERFLOW_BITS = 6n function getMinNumberOfBits(num: bigint): number { return num.toString(2).length diff --git a/packages/zkpassport-utils/tests/circuit-matcher.test.ts b/packages/zkpassport-utils/tests/circuit-matcher.test.ts index bb0d64f1c..1d84a1bf2 100644 --- a/packages/zkpassport-utils/tests/circuit-matcher.test.ts +++ b/packages/zkpassport-utils/tests/circuit-matcher.test.ts @@ -47,7 +47,6 @@ import { SanctionsBuilder, SECONDS_BETWEEN_1900_AND_1970, HASH_ALGORITHM_SHA256, - SOD, } from "../src" import { DSC } from "../src/passport/dsc" import { AsnParser } from "@peculiar/asn1-schema" @@ -273,19 +272,19 @@ describe("Circuit Matcher - RSA", () => { 175, 212, 84, 17, 99, 184, 221, 3, 182, 43, 64, 87, 73, 218, 234, 77, 87, ], csc_pubkey_redc_param: [ - 16, 128, 205, 249, 236, 27, 125, 199, 140, 153, 23, 150, 236, 212, 75, 83, 237, 68, 216, 38, - 212, 120, 230, 234, 48, 15, 182, 204, 29, 60, 131, 246, 168, 199, 219, 148, 63, 166, 72, 72, - 74, 164, 164, 180, 62, 197, 67, 44, 116, 71, 210, 189, 122, 183, 216, 210, 237, 222, 187, 8, - 78, 51, 33, 8, 79, 98, 136, 116, 161, 63, 148, 130, 37, 182, 207, 41, 71, 19, 251, 6, 34, - 130, 219, 16, 111, 59, 237, 58, 247, 84, 146, 37, 69, 67, 179, 240, 219, 235, 45, 68, 130, - 236, 106, 2, 141, 117, 167, 127, 43, 60, 151, 108, 50, 148, 65, 46, 103, 212, 71, 17, 19, - 105, 224, 234, 237, 214, 102, 190, 216, 163, 11, 217, 33, 189, 122, 180, 133, 176, 90, 2, - 215, 73, 130, 168, 223, 1, 197, 160, 199, 123, 50, 138, 2, 15, 231, 4, 108, 67, 245, 19, - 134, 223, 222, 41, 74, 156, 51, 156, 218, 11, 2, 87, 175, 198, 244, 101, 240, 166, 225, 36, - 176, 65, 86, 48, 63, 244, 124, 39, 86, 239, 190, 173, 234, 21, 195, 20, 200, 72, 212, 42, - 118, 21, 72, 204, 83, 210, 5, 73, 78, 217, 110, 25, 5, 203, 234, 232, 198, 228, 39, 195, - 127, 191, 131, 84, 167, 247, 207, 190, 140, 34, 100, 18, 57, 217, 172, 229, 206, 199, 127, - 69, 114, 173, 18, 116, 85, 147, 110, 175, 128, 173, 176, 234, 234, 179, 232, 160, 56, + 66, 3, 55, 231, 176, 109, 247, 30, 50, 100, 94, 91, 179, 81, 45, 79, 181, 19, 96, 155, 81, + 227, 155, 168, 192, 62, 219, 48, 116, 242, 15, 218, 163, 31, 110, 80, 254, 153, 33, 33, 42, + 146, 146, 208, 251, 21, 12, 177, 209, 31, 74, 245, 234, 223, 99, 75, 183, 122, 236, 33, 56, + 204, 132, 33, 61, 138, 33, 210, 132, 254, 82, 8, 150, 219, 60, 165, 28, 79, 236, 24, 138, + 11, 108, 65, 188, 239, 180, 235, 221, 82, 72, 149, 21, 14, 207, 195, 111, 172, 181, 18, 11, + 177, 168, 10, 53, 214, 157, 252, 172, 242, 93, 176, 202, 81, 4, 185, 159, 81, 28, 68, 77, + 167, 131, 171, 183, 89, 154, 251, 98, 140, 47, 100, 134, 245, 234, 210, 22, 193, 104, 11, + 93, 38, 10, 163, 124, 7, 22, 131, 29, 236, 202, 40, 8, 63, 156, 17, 177, 15, 212, 78, 27, + 127, 120, 165, 42, 112, 206, 115, 104, 44, 9, 94, 191, 27, 209, 151, 194, 155, 132, 146, + 193, 5, 88, 192, 255, 209, 240, 157, 91, 190, 250, 183, 168, 87, 12, 83, 33, 35, 80, 169, + 216, 85, 35, 49, 79, 72, 21, 37, 59, 101, 184, 100, 23, 47, 171, 163, 27, 144, 159, 13, 254, + 254, 13, 82, 159, 223, 62, 250, 48, 137, 144, 72, 231, 102, 179, 151, 59, 29, 253, 21, 202, + 180, 73, 209, 86, 77, 186, 190, 2, 182, 195, 171, 170, 207, 162, 128, 224, ], exponent: 65537, pss_salt_len: 0, @@ -321,19 +320,19 @@ describe("Circuit Matcher - RSA", () => { exponent: 65537, sod_signature: PASSPORTS.john.sod.signerInfo.signature.toNumberArray(), dsc_pubkey_redc_param: [ - 22, 68, 93, 51, 146, 119, 200, 66, 91, 4, 139, 219, 211, 238, 244, 80, 172, 237, 63, 200, - 201, 255, 143, 95, 133, 21, 198, 238, 249, 191, 44, 20, 195, 124, 130, 48, 218, 87, 25, 35, - 148, 240, 137, 79, 16, 220, 88, 104, 16, 172, 53, 242, 255, 71, 108, 14, 33, 24, 190, 49, - 27, 127, 247, 168, 68, 3, 49, 43, 230, 200, 246, 89, 72, 116, 210, 103, 180, 245, 163, 26, - 165, 186, 189, 155, 178, 169, 68, 169, 80, 123, 220, 223, 214, 29, 60, 173, 234, 225, 167, - 152, 98, 169, 20, 186, 101, 131, 241, 108, 3, 101, 44, 164, 56, 51, 107, 39, 107, 32, 84, - 105, 92, 13, 50, 168, 147, 125, 42, 179, 15, 53, 160, 203, 50, 10, 209, 1, 110, 138, 1, 176, - 226, 18, 210, 74, 187, 156, 225, 170, 70, 202, 170, 96, 75, 218, 207, 224, 90, 228, 110, - 104, 21, 62, 109, 117, 182, 242, 219, 35, 0, 216, 250, 95, 178, 73, 192, 56, 107, 219, 141, - 158, 64, 97, 7, 41, 20, 0, 22, 1, 68, 46, 145, 107, 244, 168, 85, 198, 232, 9, 28, 143, 33, - 188, 163, 187, 163, 168, 79, 59, 117, 175, 71, 232, 133, 27, 58, 196, 190, 124, 46, 253, 7, - 234, 196, 93, 211, 101, 180, 103, 120, 132, 124, 71, 169, 77, 94, 147, 235, 0, 74, 214, 230, - 58, 5, 158, 123, 1, 250, 108, 41, 204, 143, 203, 85, 63, 227, 173, 14, + 89, 17, 116, 206, 73, 223, 33, 9, 108, 18, 47, 111, 79, 187, 209, 66, 179, 180, 255, 35, 39, + 254, 61, 126, 20, 87, 27, 187, 230, 252, 176, 83, 13, 242, 8, 195, 105, 92, 100, 142, 83, + 194, 37, 60, 67, 113, 97, 160, 66, 176, 215, 203, 253, 29, 176, 56, 132, 98, 248, 196, 109, + 255, 222, 161, 16, 12, 196, 175, 155, 35, 217, 101, 33, 211, 73, 158, 211, 214, 140, 106, + 150, 234, 246, 110, 202, 165, 18, 165, 65, 239, 115, 127, 88, 116, 242, 183, 171, 134, 158, + 97, 138, 164, 82, 233, 150, 15, 197, 176, 13, 148, 178, 144, 224, 205, 172, 157, 172, 129, + 81, 165, 112, 52, 202, 162, 77, 244, 170, 204, 60, 214, 131, 44, 200, 43, 68, 5, 186, 40, 6, + 195, 136, 75, 73, 42, 238, 115, 134, 169, 27, 42, 169, 129, 47, 107, 63, 129, 107, 145, 185, + 160, 84, 249, 181, 214, 219, 203, 108, 140, 3, 99, 233, 126, 201, 39, 0, 225, 175, 110, 54, + 121, 1, 132, 28, 164, 80, 0, 88, 5, 16, 186, 69, 175, 210, 161, 87, 27, 160, 36, 114, 60, + 134, 242, 142, 238, 142, 161, 60, 237, 214, 189, 31, 162, 20, 108, 235, 18, 249, 240, 187, + 244, 31, 171, 17, 119, 77, 150, 209, 157, 226, 17, 241, 30, 165, 53, 122, 79, 172, 1, 43, + 91, 152, 232, 22, 121, 236, 7, 233, 176, 167, 50, 63, 45, 84, 255, 142, 180, 59, ], tbs_certificate: rightPadArrayWithZeros( PASSPORTS.john.sod.certificate.tbs.bytes.toNumberArray(), From 7e774f79510079e0daff8daf9a3cd9656d83dd8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Madzou?= <17496111+madztheo@users.noreply.github.com> Date: Wed, 4 Mar 2026 11:46:59 +0000 Subject: [PATCH 09/30] chore(utils): Increase max size of signed attributes (#159) * increase signed attrs max size to 256 bytes * fix tests, update utils to 0.35.0 --- bun.lock | 2 +- packages/zkpassport-utils/package.json | 2 +- packages/zkpassport-utils/src/constants/index.ts | 2 +- packages/zkpassport-utils/tests/circuit-matcher.test.ts | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/bun.lock b/bun.lock index 210364464..835195ee9 100644 --- a/bun.lock +++ b/bun.lock @@ -110,7 +110,7 @@ }, "packages/zkpassport-utils": { "name": "@zkpassport/utils", - "version": "0.34.0", + "version": "0.35.0", "dependencies": { "@lapo/asn1js": "^2.0.4", "@noble/ciphers": "^1.0.0", diff --git a/packages/zkpassport-utils/package.json b/packages/zkpassport-utils/package.json index f82f58d33..cf45ec340 100644 --- a/packages/zkpassport-utils/package.json +++ b/packages/zkpassport-utils/package.json @@ -1,6 +1,6 @@ { "name": "@zkpassport/utils", - "version": "0.34.0", + "version": "0.35.0", "repository": { "type": "git", "url": "https://github.com/zkpassport/zkpassport-packages", diff --git a/packages/zkpassport-utils/src/constants/index.ts b/packages/zkpassport-utils/src/constants/index.ts index 3d5a4f11c..21e7818c9 100644 --- a/packages/zkpassport-utils/src/constants/index.ts +++ b/packages/zkpassport-utils/src/constants/index.ts @@ -91,7 +91,7 @@ const MERCOSUR_COUNTRIES: CountryName[] = [ "Uruguay", ] -const SIGNED_ATTR_INPUT_SIZE = 220 +const SIGNED_ATTR_INPUT_SIZE = 256 const DG1_INPUT_SIZE = 95 const E_CONTENT_INPUT_SIZE = 700 diff --git a/packages/zkpassport-utils/tests/circuit-matcher.test.ts b/packages/zkpassport-utils/tests/circuit-matcher.test.ts index 1d84a1bf2..a9c89a39b 100644 --- a/packages/zkpassport-utils/tests/circuit-matcher.test.ts +++ b/packages/zkpassport-utils/tests/circuit-matcher.test.ts @@ -365,13 +365,13 @@ describe("Circuit Matcher - RSA", () => { ).formatForInput(), signed_attributes: rightPadArrayWithZeros( PASSPORTS.john.sod.signerInfo.signedAttrs.bytes.toNumberArray(), - 220, + 256, ), e_content: rightPadArrayWithZeros( PASSPORTS.john.sod.encapContentInfo.eContent.bytes.toNumberArray(), 700, ), - comm_in: "0x1d483dee098c59f3641a5ba2948db5e65ca250d3224cf214edfb9219ceffd0a5", + comm_in: "0x066c592240d43a8677f7988285781cfcfa1974af37cc0dc4e8f03d8b69932cb4", salted_private_nullifier: SaltedValue.fromValue(SALT, EXPECTED_NULLIFIER).formatForInput(), expiry_date_salt: `0x${SALT.toString(16)}`, dg2_hash_salt: `0x${SALT.toString(16)}`, @@ -840,7 +840,7 @@ describe("Circuit Matcher - ECDSA", () => { PASSPORTS.mary.sod.encapContentInfo.eContent.bytes.toNumberArray(), E_CONTENT_INPUT_SIZE, ), - comm_in: "0x18a9c4f5e92fd5e7005bd17bb32d4f95655396e3538c3f3e510cad664f6d7321", + comm_in: "0x20c677937edf1436f0c9aa087b31c4bfee837481eaf4c24242a41d628793c6d6", expiry_date_salt: `0x${SALT.toString(16)}`, dg2_hash_salt: `0x${SALT.toString(16)}`, salted_private_nullifier: SaltedValue.fromValue( @@ -923,7 +923,7 @@ describe("Circuit Matcher - ECDSA", () => { it("should calculate the correct age from passport", () => { const result = calculateAge(PASSPORTS.mary) - expect(result).toBe(50) + expect(result).toBe(51) }) it("should get the correct age circuit inputs", async () => { From ff08f95eaf87b45eb89087da7e309c90863374de Mon Sep 17 00:00:00 2001 From: Michael Elliot Date: Thu, 5 Mar 2026 07:24:11 +1100 Subject: [PATCH 10/30] ci: Update PR check workflow to include contracts scope (#161) --- .github/workflows/check-pr.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/check-pr.yml b/.github/workflows/check-pr.yml index 9f76accb5..f4bd7cabc 100644 --- a/.github/workflows/check-pr.yml +++ b/.github/workflows/check-pr.yml @@ -24,7 +24,7 @@ jobs: build requireScope: false scopes: | - (registry|explorer|registry-sdk|sdk|utils|workspace)(,(registry|explorer|registry-sdk|sdk|utils|workspace))* + (contracts|registry|explorer|registry-sdk|sdk|utils|workspace)(,(contracts|registry|explorer|registry-sdk|sdk|utils|workspace))* subjectPattern: ^[A-Z].+$ subjectPatternError: | The subject must start with an uppercase letter. @@ -38,7 +38,7 @@ jobs: with: requireScope: true scopes: | - (registry|explorer|registry-sdk|sdk|utils|workspace)(,(registry|explorer|registry-sdk|sdk|utils|workspace))* + (contracts|registry|explorer|registry-sdk|sdk|utils|workspace)(,(contracts|registry|explorer|registry-sdk|sdk|utils|workspace))* subjectPattern: ^[A-Z].+$ subjectPatternError: | The subject must start with an uppercase letter. From efb013e15c798a8cd36b92ec17585b391731199b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20Madzou?= <17496111+madztheo@users.noreply.github.com> Date: Mon, 30 Mar 2026 07:52:53 +0100 Subject: [PATCH 11/30] chore(sdk): Add checks against original query in public input checks (#167) * check query results against original query * add tests for original query validation * add tests for rest public input checks * add some missing checks * add validity check tests * bump sdk version to 0.13.0 * add function to create offline query * chore: trigger CI --- bun.lock | 2 +- packages/zkpassport-sdk/package.json | 2 +- packages/zkpassport-sdk/src/index.ts | 43 +- .../src/public-input-checker.ts | 955 +++++- packages/zkpassport-sdk/src/types.ts | 14 +- .../tests/public-input-checker.test.ts | 2581 +++++++++++++++++ .../tests/query-builder.test.ts | 116 + 7 files changed, 3648 insertions(+), 65 deletions(-) create mode 100644 packages/zkpassport-sdk/tests/public-input-checker.test.ts diff --git a/bun.lock b/bun.lock index 835195ee9..743634450 100644 --- a/bun.lock +++ b/bun.lock @@ -84,7 +84,7 @@ }, "packages/zkpassport-sdk": { "name": "@zkpassport/sdk", - "version": "0.12.5", + "version": "0.13.0", "dependencies": { "@aztec/bb.js": "2.0.3", "@noble/ciphers": "^1.2.1", diff --git a/packages/zkpassport-sdk/package.json b/packages/zkpassport-sdk/package.json index cb907f7f7..581c6fefc 100644 --- a/packages/zkpassport-sdk/package.json +++ b/packages/zkpassport-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@zkpassport/sdk", - "version": "0.12.5", + "version": "0.13.0", "description": "Privacy-preserving identity verification using passports and ID cards", "author": "ZKPassport", "license": "Apache-2.0", diff --git a/packages/zkpassport-sdk/src/index.ts b/packages/zkpassport-sdk/src/index.ts index db0c85a11..12e008834 100644 --- a/packages/zkpassport-sdk/src/index.ts +++ b/packages/zkpassport-sdk/src/index.ts @@ -26,7 +26,12 @@ import i18en from "i18n-iso-countries/langs/en.json" import { Buffer } from "buffer/" import { RegistryClient } from "@zkpassport/registry" import { Bridge, BridgeInterface } from "@obsidion/bridge" -import { QueryBuilder, QueryResultErrors } from "./types" +import { + QueryBuilder, + QueryBuilderResult, + OfflineQueryBuilderResult, + QueryResultErrors, +} from "./types" import { PublicInputChecker } from "./public-input-checker" import { SolidityVerifier } from "./solidity-verifier" import { DEFAULT_VALIDITY, VERSION } from "./constants" @@ -189,6 +194,7 @@ export class ZKPassport { // Verify the proofs and extract the unique identifier (aka nullifier) and the verification result const { uniqueIdentifier, verified, queryResultErrors } = await this.verify({ proofs: this.topicToProofs[topic], + originalQuery: this.topicToConfig[topic], queryResult: result, validity: this.topicToLocalConfig[topic]?.validity, scope: this.topicToService[topic]?.scope, @@ -279,7 +285,9 @@ export class ZKPassport { } } - private getZkPassportRequest(topic: string): QueryBuilder { + private getZkPassportRequest( + topic: string, + ): QueryBuilder { return { eq: (key: T, value: IDCredentialValue) => { if (key === "issuing_country" || key === "nationality") { @@ -383,10 +391,16 @@ export class ZKPassport { } return this.getZkPassportRequest(topic) }, - done: () => { + done: (() => { this.topicToFailedProofCount[topic] = 0 + if (topic === "offline-query") { + const query = this.topicToConfig[topic] + delete this.topicToConfig[topic] + return { query } + } return { url: this._getUrl(topic), + query: this.topicToConfig[topic], requestId: topic, onRequestReceived: (callback: () => void) => this.onRequestReceivedCallbacks[topic].push(callback), @@ -410,7 +424,7 @@ export class ZKPassport { isBridgeConnected: () => this.topicToBridge[topic].isBridgeConnected(), requestReceived: () => this.topicToRequestReceived[topic] === true, } - }, + }) as () => T extends "online" ? QueryBuilderResult : OfflineQueryBuilderResult, } } @@ -452,6 +466,10 @@ export class ZKPassport { cloudProverUrl?: string bridgeUrl?: string }): Promise { + if (topicOverride === "offline-query") { + throw new Error("You cannot override the topic with 'offline-query'") + } + const bridge = await Bridge.create({ keyPair: keyPairOverride, bridgeId: topicOverride, @@ -506,9 +524,23 @@ export class ZKPassport { return this.getZkPassportRequest(topic) } + /** + * @notice Create a new offline query + * Unlike request(), this function does not connect to the bridge. + * It returns only the query object and no callbacks and no URL. + * This can be useful to recreate the same query server-side when calling `verify()` + * to ensure the original query wasn't tampered with. + * @returns The query builder object. + */ + public createQuery(): QueryBuilder<"offline"> { + this.topicToConfig["offline-query"] = {} + return this.getZkPassportRequest("offline-query") + } + /** * @notice Verify the proofs received from the mobile app. * @param proofs The proofs to verify. + * @param originalQuery The original query that was sent to the mobile app. * @param queryResult The query result to verify against * @param validity How many seconds ago the proof checking the expiry date of the ID should have been generated * @param scope Scope this request to a specific use case @@ -520,6 +552,7 @@ export class ZKPassport { */ public async verify({ proofs, + originalQuery, queryResult, validity, scope, @@ -527,6 +560,7 @@ export class ZKPassport { writingDirectory, }: { proofs: Array + originalQuery: Query queryResult: QueryResult validity?: number scope?: string @@ -570,6 +604,7 @@ export class ZKPassport { } = await PublicInputChecker.checkPublicInputs( this.domain, proofs, + originalQuery, formattedResult, validity, scope, diff --git a/packages/zkpassport-sdk/src/public-input-checker.ts b/packages/zkpassport-sdk/src/public-input-checker.ts index 05f4dae32..e314521c3 100644 --- a/packages/zkpassport-sdk/src/public-input-checker.ts +++ b/packages/zkpassport-sdk/src/public-input-checker.ts @@ -63,6 +63,7 @@ import { getNullifierTypeFromDisclosureProof, getServiceScopeFromDisclosureProof, getServiceSubScopeFromDisclosureProof, + Query, } from "@zkpassport/utils" import { QueryResultErrors } from "./types" import { RegistryClient } from "@zkpassport/registry" @@ -77,7 +78,11 @@ import { } from "./constants" export class PublicInputChecker { - public static checkDiscloseBytesPublicInputs(proof: ProofResult, queryResult: QueryResult) { + public static checkDiscloseBytesPublicInputs( + proof: ProofResult, + originalQuery: Query, + queryResult: QueryResult, + ) { const queryResultErrors: Partial = {} let isCorrect = true // We can't be certain that the disclosed data is for a passport or an ID card @@ -117,6 +122,34 @@ export class PublicInputChecker { }, } } + if ( + queryResult.document_type.eq && + (originalQuery.document_type?.eq === undefined || + queryResult.document_type.eq.expected !== originalQuery.document_type.eq) + ) { + console.warn("Document type eq does not match the original query") + isCorrect = false + queryResultErrors.document_type = { + ...queryResultErrors.document_type, + eq: { + expected: `${originalQuery.document_type?.eq}`, + received: `${queryResult.document_type.eq.expected}`, + message: "Document type eq does not match the original query", + }, + } + } + if (queryResult.document_type.disclose && !originalQuery.document_type?.disclose) { + console.warn("Document type disclose is not in the original query") + isCorrect = false + queryResultErrors.document_type = { + ...queryResultErrors.document_type, + disclose: { + expected: "Not requested in original query", + received: `${queryResult.document_type.disclose.result}`, + message: "Document type disclose is not in the original query", + }, + } + } } if (queryResult.birthdate) { const birthdatePassport = disclosedDataPassport.dateOfBirth @@ -154,6 +187,34 @@ export class PublicInputChecker { }, } } + if ( + queryResult.birthdate.eq && + (originalQuery.birthdate?.eq === undefined || + !areDatesEqual(queryResult.birthdate.eq.expected, originalQuery.birthdate.eq as Date)) + ) { + console.warn("Birthdate eq does not match the original query") + isCorrect = false + queryResultErrors.birthdate = { + ...queryResultErrors.birthdate, + eq: { + expected: `${(originalQuery.birthdate?.eq as Date)?.toISOString?.() ?? "undefined"}`, + received: `${queryResult.birthdate.eq.expected.toISOString()}`, + message: "Birthdate eq does not match the original query", + }, + } + } + if (queryResult.birthdate.disclose && !originalQuery.birthdate?.disclose) { + console.warn("Birthdate disclose is not in the original query") + isCorrect = false + queryResultErrors.birthdate = { + ...queryResultErrors.birthdate, + disclose: { + expected: "Not requested in original query", + received: `${queryResult.birthdate.disclose.result}`, + message: "Birthdate disclose is not in the original query", + }, + } + } } if (queryResult.expiry_date) { const expiryDatePassport = disclosedDataPassport.dateOfExpiry @@ -191,6 +252,34 @@ export class PublicInputChecker { }, } } + if ( + queryResult.expiry_date.eq && + (originalQuery.expiry_date?.eq === undefined || + !areDatesEqual(queryResult.expiry_date.eq.expected, originalQuery.expiry_date.eq as Date)) + ) { + console.warn("Expiry date eq does not match the original query") + isCorrect = false + queryResultErrors.expiry_date = { + ...queryResultErrors.expiry_date, + eq: { + expected: `${(originalQuery.expiry_date?.eq as Date)?.toISOString?.() ?? "undefined"}`, + received: `${queryResult.expiry_date.eq.expected.toISOString()}`, + message: "Expiry date eq does not match the original query", + }, + } + } + if (queryResult.expiry_date.disclose && !originalQuery.expiry_date?.disclose) { + console.warn("Expiry date disclose is not in the original query") + isCorrect = false + queryResultErrors.expiry_date = { + ...queryResultErrors.expiry_date, + disclose: { + expected: "Not requested in original query", + received: `${queryResult.expiry_date.disclose.result}`, + message: "Expiry date disclose is not in the original query", + }, + } + } } if (queryResult.nationality) { const nationalityPassport = disclosedDataPassport.nationality @@ -228,6 +317,34 @@ export class PublicInputChecker { }, } } + if ( + queryResult.nationality.eq && + (originalQuery.nationality?.eq === undefined || + queryResult.nationality.eq.expected !== originalQuery.nationality.eq) + ) { + console.warn("Nationality eq does not match the original query") + isCorrect = false + queryResultErrors.nationality = { + ...queryResultErrors.nationality, + eq: { + expected: `${originalQuery.nationality?.eq}`, + received: `${queryResult.nationality.eq.expected}`, + message: "Nationality eq does not match the original query", + }, + } + } + if (queryResult.nationality.disclose && !originalQuery.nationality?.disclose) { + console.warn("Nationality disclose is not in the original query") + isCorrect = false + queryResultErrors.nationality = { + ...queryResultErrors.nationality, + disclose: { + expected: "Not requested in original query", + received: `${queryResult.nationality.disclose.result}`, + message: "Nationality disclose is not in the original query", + }, + } + } } if (queryResult.document_number) { const documentNumberPassport = disclosedDataPassport.documentNumber @@ -265,6 +382,34 @@ export class PublicInputChecker { }, } } + if ( + queryResult.document_number.eq && + (originalQuery.document_number?.eq === undefined || + queryResult.document_number.eq.expected !== originalQuery.document_number.eq) + ) { + console.warn("Document number eq does not match the original query") + isCorrect = false + queryResultErrors.document_number = { + ...queryResultErrors.document_number, + eq: { + expected: `${originalQuery.document_number?.eq}`, + received: `${queryResult.document_number.eq.expected}`, + message: "Document number eq does not match the original query", + }, + } + } + if (queryResult.document_number.disclose && !originalQuery.document_number?.disclose) { + console.warn("Document number disclose is not in the original query") + isCorrect = false + queryResultErrors.document_number = { + ...queryResultErrors.document_number, + disclose: { + expected: "Not requested in original query", + received: `${queryResult.document_number.disclose.result}`, + message: "Document number disclose is not in the original query", + }, + } + } } if (queryResult.gender) { const genderPassport = disclosedDataPassport.gender @@ -302,6 +447,34 @@ export class PublicInputChecker { }, } } + if ( + queryResult.gender.eq && + (originalQuery.gender?.eq === undefined || + queryResult.gender.eq.expected !== originalQuery.gender.eq) + ) { + console.warn("Gender eq does not match the original query") + isCorrect = false + queryResultErrors.gender = { + ...queryResultErrors.gender, + eq: { + expected: `${originalQuery.gender?.eq}`, + received: `${queryResult.gender.eq.expected}`, + message: "Gender eq does not match the original query", + }, + } + } + if (queryResult.gender.disclose && !originalQuery.gender?.disclose) { + console.warn("Gender disclose is not in the original query") + isCorrect = false + queryResultErrors.gender = { + ...queryResultErrors.gender, + disclose: { + expected: "Not requested in original query", + received: `${queryResult.gender.disclose.result}`, + message: "Gender disclose is not in the original query", + }, + } + } } if (queryResult.issuing_country) { const issuingCountryPassport = disclosedDataPassport.issuingCountry @@ -339,6 +512,34 @@ export class PublicInputChecker { }, } } + if ( + queryResult.issuing_country.eq && + (originalQuery.issuing_country?.eq === undefined || + queryResult.issuing_country.eq.expected !== originalQuery.issuing_country.eq) + ) { + console.warn("Issuing country eq does not match the original query") + isCorrect = false + queryResultErrors.issuing_country = { + ...queryResultErrors.issuing_country, + eq: { + expected: `${originalQuery.issuing_country?.eq}`, + received: `${queryResult.issuing_country.eq.expected}`, + message: "Issuing country eq does not match the original query", + }, + } + } + if (queryResult.issuing_country.disclose && !originalQuery.issuing_country?.disclose) { + console.warn("Issuing country disclose is not in the original query") + isCorrect = false + queryResultErrors.issuing_country = { + ...queryResultErrors.issuing_country, + disclose: { + expected: "Not requested in original query", + received: `${queryResult.issuing_country.disclose.result}`, + message: "Issuing country disclose is not in the original query", + }, + } + } } if (queryResult.fullname) { const fullnamePassport = disclosedDataPassport.name @@ -379,6 +580,35 @@ export class PublicInputChecker { }, } } + if ( + queryResult.fullname.eq && + (originalQuery.fullname?.eq === undefined || + formatName(queryResult.fullname.eq.expected).toLowerCase() !== + formatName(originalQuery.fullname.eq as string).toLowerCase()) + ) { + console.warn("Fullname eq does not match the original query") + isCorrect = false + queryResultErrors.fullname = { + ...queryResultErrors.fullname, + eq: { + expected: `${originalQuery.fullname?.eq}`, + received: `${queryResult.fullname.eq.expected}`, + message: "Fullname eq does not match the original query", + }, + } + } + if (queryResult.fullname.disclose && !originalQuery.fullname?.disclose) { + console.warn("Fullname disclose is not in the original query") + isCorrect = false + queryResultErrors.fullname = { + ...queryResultErrors.fullname, + disclose: { + expected: "Not requested in original query", + received: `${queryResult.fullname.disclose.result}`, + message: "Fullname disclose is not in the original query", + }, + } + } } if (queryResult.firstname) { // If fullname was not revealed, then the name could be either the first name or last name @@ -427,6 +657,35 @@ export class PublicInputChecker { }, } } + if ( + queryResult.firstname.eq && + (originalQuery.firstname?.eq === undefined || + formatName(queryResult.firstname.eq.expected).toLowerCase() !== + formatName(originalQuery.firstname.eq as string).toLowerCase()) + ) { + console.warn("Firstname eq does not match the original query") + isCorrect = false + queryResultErrors.firstname = { + ...queryResultErrors.firstname, + eq: { + expected: `${originalQuery.firstname?.eq}`, + received: `${queryResult.firstname.eq.expected}`, + message: "Firstname eq does not match the original query", + }, + } + } + if (queryResult.firstname.disclose && !originalQuery.firstname?.disclose) { + console.warn("Firstname disclose is not in the original query") + isCorrect = false + queryResultErrors.firstname = { + ...queryResultErrors.firstname, + disclose: { + expected: "Not requested in original query", + received: `${queryResult.firstname.disclose.result}`, + message: "Firstname disclose is not in the original query", + }, + } + } } if (queryResult.lastname) { // If fullname was not revealed, then the name could be either the first name or last name @@ -474,11 +733,44 @@ export class PublicInputChecker { }, } } + if ( + queryResult.lastname.eq && + (originalQuery.lastname?.eq === undefined || + formatName(queryResult.lastname.eq.expected).toLowerCase() !== + formatName(originalQuery.lastname.eq as string).toLowerCase()) + ) { + console.warn("Lastname eq does not match the original query") + isCorrect = false + queryResultErrors.lastname = { + ...queryResultErrors.lastname, + eq: { + expected: `${originalQuery.lastname?.eq}`, + received: `${queryResult.lastname.eq.expected}`, + message: "Lastname eq does not match the original query", + }, + } + } + if (queryResult.lastname.disclose && !originalQuery.lastname?.disclose) { + console.warn("Lastname disclose is not in the original query") + isCorrect = false + queryResultErrors.lastname = { + ...queryResultErrors.lastname, + disclose: { + expected: "Not requested in original query", + received: `${queryResult.lastname.disclose.result}`, + message: "Lastname disclose is not in the original query", + }, + } + } } return { isCorrect, queryResultErrors } } - public static checkAgePublicInputs(proof: ProofResult, queryResult: QueryResult) { + public static checkAgePublicInputs( + proof: ProofResult, + originalQuery: Query, + queryResult: QueryResult, + ) { const queryResultErrors: Partial = {} let isCorrect = true const currentTime = new Date() @@ -517,6 +809,22 @@ export class PublicInputChecker { }, } } + if ( + queryResult.age.gt && + queryResult.age.gt.result && + minAge !== (queryResult.age.gt.expected as number) + ) { + console.warn("Age is not greater than the expected age") + isCorrect = false + queryResultErrors.age = { + ...queryResultErrors.age, + gt: { + expected: queryResult.age.gt.expected, + received: minAge, + message: "Age is not greater than the expected age", + }, + } + } if ( queryResult.age.lt && queryResult.age.lt.result && @@ -533,6 +841,39 @@ export class PublicInputChecker { }, } } + if ( + queryResult.age.lte && + queryResult.age.lte.result && + maxAge !== (queryResult.age.lte.expected as number) + ) { + console.warn("Age is not less than or equal to the expected age") + isCorrect = false + queryResultErrors.age = { + ...queryResultErrors.age, + lte: { + expected: queryResult.age.lte.expected, + received: maxAge, + message: "Age is not less than or equal to the expected age", + }, + } + } + if ( + queryResult.age.eq && + queryResult.age.eq.result && + (minAge !== (queryResult.age.eq.expected as number) || + maxAge !== (queryResult.age.eq.expected as number)) + ) { + console.warn("Age does not match the expected age") + isCorrect = false + queryResultErrors.age = { + ...queryResultErrors.age, + eq: { + expected: queryResult.age.eq.expected, + received: minAge !== (queryResult.age.eq.expected as number) ? minAge : maxAge, + message: "Age does not match the expected age", + }, + } + } if (queryResult.age.range) { if ( queryResult.age.range.result && @@ -612,10 +953,120 @@ export class PublicInputChecker { }, } } + if ( + queryResult.age?.gte && + (originalQuery.age?.gte === undefined || + queryResult.age.gte.expected !== originalQuery.age.gte) + ) { + console.warn("Age gte does not match the original query") + isCorrect = false + queryResultErrors.age = { + ...queryResultErrors.age, + gte: { + expected: originalQuery.age?.gte, + received: queryResult.age.gte.expected, + message: "Age gte does not match the original query", + }, + } + } + if ( + queryResult.age?.gt && + (originalQuery.age?.gt === undefined || queryResult.age.gt.expected !== originalQuery.age.gt) + ) { + console.warn("Age gt does not match the original query") + isCorrect = false + queryResultErrors.age = { + ...queryResultErrors.age, + gt: { + expected: originalQuery.age?.gt, + received: queryResult.age.gt.expected, + message: "Age gt does not match the original query", + }, + } + } + if ( + queryResult.age?.lt && + (originalQuery.age?.lt === undefined || queryResult.age.lt.expected !== originalQuery.age.lt) + ) { + console.warn("Age lt does not match the original query") + isCorrect = false + queryResultErrors.age = { + ...queryResultErrors.age, + lt: { + expected: originalQuery.age?.lt, + received: queryResult.age.lt.expected, + message: "Age lt does not match the original query", + }, + } + } + if ( + queryResult.age?.lte && + (originalQuery.age?.lte === undefined || + queryResult.age.lte.expected !== originalQuery.age.lte) + ) { + console.warn("Age lte does not match the original query") + isCorrect = false + queryResultErrors.age = { + ...queryResultErrors.age, + lte: { + expected: originalQuery.age?.lte, + received: queryResult.age.lte.expected, + message: "Age lte does not match the original query", + }, + } + } + if ( + queryResult.age?.eq && + (originalQuery.age?.eq === undefined || queryResult.age.eq.expected !== originalQuery.age.eq) + ) { + console.warn("Age eq does not match the original query") + isCorrect = false + queryResultErrors.age = { + ...queryResultErrors.age, + eq: { + expected: originalQuery.age?.eq, + received: queryResult.age.eq.expected, + message: "Age eq does not match the original query", + }, + } + } + if ( + queryResult.age?.range && + (originalQuery.age?.range === undefined || + queryResult.age.range.expected[0] !== originalQuery.age.range[0] || + queryResult.age.range.expected[1] !== originalQuery.age.range[1]) + ) { + console.warn("Age range does not match the original query") + isCorrect = false + queryResultErrors.age = { + ...queryResultErrors.age, + range: { + expected: originalQuery.age?.range, + received: queryResult.age.range.expected, + message: "Age range does not match the original query", + }, + } + } + if (queryResult.age?.disclose && !originalQuery.age?.disclose) { + console.warn("Age disclose is not in the original query") + isCorrect = false + queryResultErrors.age = { + ...queryResultErrors.age, + disclose: { + expected: "Not requested in original query", + received: `${queryResult.age.disclose.result}`, + message: "Age disclose is not in the original query", + }, + } + } return { isCorrect, queryResultErrors } } - public static checkBirthdatePublicInputs(proof: ProofResult, queryResult: QueryResult) { + public static checkBirthdatePublicInputs( + proof: ProofResult, + originalQuery: Query, + queryResult: QueryResult, + ) { const queryResultErrors: Partial = {} let isCorrect = true const currentTime = new Date() @@ -735,10 +1186,101 @@ export class PublicInputChecker { }, } } + if ( + queryResult.birthdate?.gte && + (originalQuery.birthdate?.gte === undefined || + !areDatesEqual(queryResult.birthdate.gte.expected, originalQuery.birthdate.gte as Date)) + ) { + console.warn("Birthdate gte does not match the original query") + isCorrect = false + queryResultErrors.birthdate = { + ...queryResultErrors.birthdate, + gte: { + expected: originalQuery.birthdate?.gte, + received: queryResult.birthdate.gte.expected, + message: "Birthdate gte does not match the original query", + }, + } + } + if ( + queryResult.birthdate?.gt && + (originalQuery.birthdate?.gt === undefined || + !areDatesEqual(queryResult.birthdate.gt.expected, originalQuery.birthdate.gt as Date)) + ) { + console.warn("Birthdate gt does not match the original query") + isCorrect = false + queryResultErrors.birthdate = { + ...queryResultErrors.birthdate, + gt: { + expected: originalQuery.birthdate?.gt, + received: queryResult.birthdate.gt.expected, + message: "Birthdate gt does not match the original query", + }, + } + } + if ( + queryResult.birthdate?.lte && + (originalQuery.birthdate?.lte === undefined || + !areDatesEqual(queryResult.birthdate.lte.expected, originalQuery.birthdate.lte as Date)) + ) { + console.warn("Birthdate lte does not match the original query") + isCorrect = false + queryResultErrors.birthdate = { + ...queryResultErrors.birthdate, + lte: { + expected: originalQuery.birthdate?.lte, + received: queryResult.birthdate.lte.expected, + message: "Birthdate lte does not match the original query", + }, + } + } + if ( + queryResult.birthdate?.lt && + (originalQuery.birthdate?.lt === undefined || + !areDatesEqual(queryResult.birthdate.lt.expected, originalQuery.birthdate.lt as Date)) + ) { + console.warn("Birthdate lt does not match the original query") + isCorrect = false + queryResultErrors.birthdate = { + ...queryResultErrors.birthdate, + lt: { + expected: originalQuery.birthdate?.lt, + received: queryResult.birthdate.lt.expected, + message: "Birthdate lt does not match the original query", + }, + } + } + if ( + queryResult.birthdate?.range && + (originalQuery.birthdate?.range === undefined || + !areDatesEqual( + queryResult.birthdate.range.expected[0], + originalQuery.birthdate.range[0] as Date, + ) || + !areDatesEqual( + queryResult.birthdate.range.expected[1], + originalQuery.birthdate.range[1] as Date, + )) + ) { + console.warn("Birthdate range does not match the original query") + isCorrect = false + queryResultErrors.birthdate = { + ...queryResultErrors.birthdate, + range: { + expected: originalQuery.birthdate?.range, + received: queryResult.birthdate.range.expected, + message: "Birthdate range does not match the original query", + }, + } + } return { isCorrect, queryResultErrors } } - public static checkExpiryDatePublicInputs(proof: ProofResult, queryResult: QueryResult) { + public static checkExpiryDatePublicInputs( + proof: ProofResult, + originalQuery: Query, + queryResult: QueryResult, + ) { const queryResultErrors: Partial = {} let isCorrect = true const currentTime = new Date() @@ -856,10 +1398,98 @@ export class PublicInputChecker { }, } } + if ( + queryResult.expiry_date?.gte && + (originalQuery.expiry_date?.gte === undefined || + !areDatesEqual(queryResult.expiry_date.gte.expected, originalQuery.expiry_date.gte as Date)) + ) { + console.warn("Expiry date gte does not match the original query") + isCorrect = false + queryResultErrors.expiry_date = { + ...queryResultErrors.expiry_date, + gte: { + expected: originalQuery.expiry_date?.gte, + received: queryResult.expiry_date.gte.expected, + message: "Expiry date gte does not match the original query", + }, + } + } + if ( + queryResult.expiry_date?.gt && + (originalQuery.expiry_date?.gt === undefined || + !areDatesEqual(queryResult.expiry_date.gt.expected, originalQuery.expiry_date.gt as Date)) + ) { + console.warn("Expiry date gt does not match the original query") + isCorrect = false + queryResultErrors.expiry_date = { + ...queryResultErrors.expiry_date, + gt: { + expected: originalQuery.expiry_date?.gt, + received: queryResult.expiry_date.gt.expected, + message: "Expiry date gt does not match the original query", + }, + } + } + if ( + queryResult.expiry_date?.lte && + (originalQuery.expiry_date?.lte === undefined || + !areDatesEqual(queryResult.expiry_date.lte.expected, originalQuery.expiry_date.lte as Date)) + ) { + console.warn("Expiry date lte does not match the original query") + isCorrect = false + queryResultErrors.expiry_date = { + ...queryResultErrors.expiry_date, + lte: { + expected: originalQuery.expiry_date?.lte, + received: queryResult.expiry_date.lte.expected, + message: "Expiry date lte does not match the original query", + }, + } + } + if ( + queryResult.expiry_date?.lt && + (originalQuery.expiry_date?.lt === undefined || + !areDatesEqual(queryResult.expiry_date.lt.expected, originalQuery.expiry_date.lt as Date)) + ) { + console.warn("Expiry date lt does not match the original query") + isCorrect = false + queryResultErrors.expiry_date = { + ...queryResultErrors.expiry_date, + lt: { + expected: originalQuery.expiry_date?.lt, + received: queryResult.expiry_date.lt.expected, + message: "Expiry date lt does not match the original query", + }, + } + } + if ( + queryResult.expiry_date?.range && + (originalQuery.expiry_date?.range === undefined || + !areDatesEqual( + queryResult.expiry_date.range.expected[0], + originalQuery.expiry_date.range[0] as Date, + ) || + !areDatesEqual( + queryResult.expiry_date.range.expected[1], + originalQuery.expiry_date.range[1] as Date, + )) + ) { + console.warn("Expiry date range does not match the original query") + isCorrect = false + queryResultErrors.expiry_date = { + ...queryResultErrors.expiry_date, + range: { + expected: originalQuery.expiry_date?.range, + received: queryResult.expiry_date.range.expected, + message: "Expiry date range does not match the original query", + }, + } + } return { isCorrect, queryResultErrors } } public static checkNationalityExclusionPublicInputs( + originalQuery: Query, queryResult: QueryResult, countryList: string[], ) { @@ -912,10 +1542,31 @@ export class PublicInputChecker { } } } + if ( + queryResult.nationality?.out && + (originalQuery.nationality?.out === undefined || + queryResult.nationality.out.expected?.length !== + (originalQuery.nationality.out as string[]).length || + !queryResult.nationality.out.expected?.every((country) => + (originalQuery.nationality!.out as string[]).includes(country), + )) + ) { + console.warn("Nationality exclusion list does not match the original query") + isCorrect = false + queryResultErrors.nationality = { + ...queryResultErrors.nationality, + out: { + expected: originalQuery.nationality?.out as string[], + received: queryResult.nationality.out.expected, + message: "Nationality exclusion list does not match the original query", + }, + } + } return { isCorrect, queryResultErrors } } public static checkIssuingCountryExclusionPublicInputs( + originalQuery: Query, queryResult: QueryResult, countryList: string[], ) { @@ -969,10 +1620,31 @@ export class PublicInputChecker { } } } + if ( + queryResult.issuing_country?.out && + (originalQuery.issuing_country?.out === undefined || + queryResult.issuing_country.out.expected?.length !== + (originalQuery.issuing_country.out as string[]).length || + !queryResult.issuing_country.out.expected?.every((country) => + (originalQuery.issuing_country!.out as string[]).includes(country), + )) + ) { + console.warn("Issuing country exclusion list does not match the original query") + isCorrect = false + queryResultErrors.issuing_country = { + ...queryResultErrors.issuing_country, + out: { + expected: originalQuery.issuing_country?.out as string[], + received: queryResult.issuing_country.out.expected, + message: "Issuing country exclusion list does not match the original query", + }, + } + } return { isCorrect, queryResultErrors } } public static checkNationalityInclusionPublicInputs( + originalQuery: Query, queryResult: QueryResult, countryList: string[], ) { @@ -1005,10 +1677,31 @@ export class PublicInputChecker { }, } } + if ( + queryResult.nationality?.in && + (originalQuery.nationality?.in === undefined || + queryResult.nationality.in.expected?.length !== + (originalQuery.nationality.in as string[]).length || + !queryResult.nationality.in.expected?.every((country) => + (originalQuery.nationality!.in as string[]).includes(country), + )) + ) { + console.warn("Nationality inclusion list does not match the original query") + isCorrect = false + queryResultErrors.nationality = { + ...queryResultErrors.nationality, + in: { + expected: originalQuery.nationality?.in as string[], + received: queryResult.nationality.in.expected, + message: "Nationality inclusion list does not match the original query", + }, + } + } return { isCorrect, queryResultErrors } } public static checkIssuingCountryInclusionPublicInputs( + originalQuery: Query, queryResult: QueryResult, countryList: string[], ) { @@ -1044,6 +1737,26 @@ export class PublicInputChecker { }, } } + if ( + queryResult.issuing_country?.in && + (originalQuery.issuing_country?.in === undefined || + queryResult.issuing_country.in.expected?.length !== + (originalQuery.issuing_country.in as string[]).length || + !queryResult.issuing_country.in.expected?.every((country) => + (originalQuery.issuing_country!.in as string[]).includes(country), + )) + ) { + console.warn("Issuing country inclusion list does not match the original query") + isCorrect = false + queryResultErrors.issuing_country = { + ...queryResultErrors.issuing_country, + in: { + expected: originalQuery.issuing_country?.in as string[], + received: queryResult.issuing_country.in.expected, + message: "Issuing country inclusion list does not match the original query", + }, + } + } return { isCorrect, queryResultErrors } } @@ -1148,37 +1861,32 @@ export class PublicInputChecker { return { isCorrect, queryResultErrors } } - public static checkBindPublicInputs(queryResult: QueryResult, boundData: BoundData) { + public static checkBindPublicInputs( + originalQuery: Query, + queryResult: QueryResult, + boundData: BoundData, + ) { const queryResultErrors: Partial = {} let isCorrect = true if (queryResult.bind) { + const bindMismatches: string[] = [] if ( queryResult.bind.user_address?.toLowerCase().replace("0x", "") !== boundData.user_address?.toLowerCase().replace("0x", "") ) { console.warn("Bound user address does not match the one from the query results") isCorrect = false - queryResultErrors.bind = { - ...queryResultErrors.bind, - eq: { - expected: queryResult.bind.user_address, - received: boundData.user_address, - message: "Bound user address does not match the one from the query results", - }, - } + bindMismatches.push( + `user_address: expected ${queryResult.bind.user_address}, received ${boundData.user_address}`, + ) } if (queryResult.bind.chain !== boundData.chain) { console.warn("Bound chain id does not match the one from the query results") isCorrect = false - queryResultErrors.bind = { - ...queryResultErrors.bind, - eq: { - expected: queryResult.bind.chain, - received: boundData.chain, - message: "Bound chain id does not match the one from the query results", - }, - } + bindMismatches.push( + `chain: expected ${queryResult.bind.chain}, received ${boundData.chain}`, + ) } if ( queryResult.bind.custom_data?.trim().toLowerCase() !== @@ -1186,20 +1894,46 @@ export class PublicInputChecker { ) { console.warn("Bound custom data does not match the one from the query results") isCorrect = false + bindMismatches.push( + `custom_data: expected ${queryResult.bind.custom_data}, received ${boundData.custom_data}`, + ) + } + if (bindMismatches.length > 0) { queryResultErrors.bind = { ...queryResultErrors.bind, eq: { - expected: queryResult.bind.custom_data, - received: boundData.custom_data, - message: "Bound custom data does not match the one from the query results", + expected: `${queryResult.bind.user_address}, ${queryResult.bind.chain}, ${queryResult.bind.custom_data}`, + received: `${boundData.user_address}, ${boundData.chain}, ${boundData.custom_data}`, + message: `Bound data does not match: ${bindMismatches.join("; ")}`, }, } } } + if ( + queryResult.bind && + (originalQuery.bind === undefined || + queryResult.bind.user_address?.toLowerCase().replace("0x", "") !== + originalQuery.bind.user_address?.toLowerCase().replace("0x", "") || + queryResult.bind.chain !== originalQuery.bind.chain || + queryResult.bind.custom_data?.trim().toLowerCase() !== + originalQuery.bind.custom_data?.trim().toLowerCase()) + ) { + console.warn("Bound data does not match the original query") + isCorrect = false + queryResultErrors.bind = { + ...queryResultErrors.bind, + eq: { + expected: `${originalQuery.bind?.user_address}, ${originalQuery.bind?.chain}, ${originalQuery.bind?.custom_data}`, + received: `${queryResult.bind.user_address}, ${queryResult.bind.chain}, ${queryResult.bind.custom_data}`, + message: "Bound data does not match the original query", + }, + } + } return { isCorrect, queryResultErrors } } public static async checkSanctionsExclusionPublicInputs( + originalQuery: Query, queryResult: QueryResult, sanctionsCommittedInputs: SanctionsCommittedInputs, sanctionsBuilder: SanctionsBuilder, @@ -1234,10 +1968,27 @@ export class PublicInputChecker { } } } + if ( + queryResult.sanctions && + (originalQuery.sanctions === undefined || + queryResult.sanctions.isStrict !== (originalQuery.sanctions.strict ?? false)) + ) { + console.warn("Sanctions config does not match the original query") + isCorrect = false + queryResultErrors.sanctions = { + ...queryResultErrors.sanctions, + eq: { + expected: `strict: ${originalQuery.sanctions?.strict ?? false}`, + received: `strict: ${queryResult.sanctions.isStrict}`, + message: "Sanctions config does not match the original query", + }, + } + } return { isCorrect, queryResultErrors } } public static async checkFacematchPublicInputs( + originalQuery: Query, queryResult: QueryResult, facematchCommittedInputs: FacematchCommittedInputs, ) { @@ -1292,6 +2043,21 @@ export class PublicInputChecker { }, } } + if ( + facematchCommittedInputs.mode !== queryResult.facematch?.mode || + facematchCommittedInputs.mode !== originalQuery.facematch?.mode + ) { + console.warn("Invalid facematch mode") + isCorrect = false + queryResultErrors.facematch = { + ...queryResultErrors.facematch, + eq: { + expected: originalQuery.facematch?.mode, + received: facematchCommittedInputs.mode, + message: "Invalid facematch mode", + }, + } + } } return { isCorrect, queryResultErrors } } @@ -1315,9 +2081,8 @@ export class PublicInputChecker { const currentDate = getCurrentDateFromDisclosureProof(proofData) const todayToCurrentDate = today.getTime() - currentDate.getTime() const expectedDifference = validity ? validity * 1000 : DEFAULT_VALIDITY * 1000 - const actualDifference = today.getTime() - (today.getTime() - expectedDifference) let isCorrect = true - if (todayToCurrentDate >= actualDifference) { + if (todayToCurrentDate >= expectedDifference) { console.warn("The date used to check the validity of the ID falls out of the validity period") isCorrect = false if (!queryResultErrors[circuitName as keyof QueryResultErrors]) { @@ -1335,6 +2100,7 @@ export class PublicInputChecker { public static async checkPublicInputs( domain: string, proofs: Array, + originalQuery: Query, queryResult: QueryResult, validity?: number, scope?: string, @@ -1415,8 +2181,7 @@ export class PublicInputChecker { const currentDate = getCurrentDateFromOuterProof(proofData) const todayToCurrentDate = today.getTime() - currentDate.getTime() const expectedDifference = validity ? validity * 1000 : DEFAULT_VALIDITY * 1000 - const actualDifference = today.getTime() - (today.getTime() - expectedDifference) - if (todayToCurrentDate >= actualDifference) { + if (todayToCurrentDate >= expectedDifference) { console.warn( `The date used to check the validity of the ID is older than the validity period`, ) @@ -1493,7 +2258,7 @@ export class PublicInputChecker { } } const { isCorrect: isCorrectAge, queryResultErrors: queryResultErrorsAge } = - this.checkAgePublicInputs(proof, queryResult) + this.checkAgePublicInputs(proof, originalQuery, queryResult) isCorrect = isCorrect && isCorrectAge queryResultErrors = { ...queryResultErrors, @@ -1528,7 +2293,7 @@ export class PublicInputChecker { } } const { isCorrect: isCorrectBirthdate, queryResultErrors: queryResultErrorsBirthdate } = - this.checkBirthdatePublicInputs(proof, queryResult) + this.checkBirthdatePublicInputs(proof, originalQuery, queryResult) isCorrect = isCorrect && isCorrectBirthdate queryResultErrors = { ...queryResultErrors, @@ -1563,7 +2328,7 @@ export class PublicInputChecker { } } const { isCorrect: isCorrectExpiryDate, queryResultErrors: queryResultErrorsExpiryDate } = - this.checkExpiryDatePublicInputs(proof, queryResult) + this.checkExpiryDatePublicInputs(proof, originalQuery, queryResult) isCorrect = isCorrect && isCorrectExpiryDate queryResultErrors = { ...queryResultErrors, @@ -1596,7 +2361,7 @@ export class PublicInputChecker { } } const { isCorrect: isCorrectDisclose, queryResultErrors: queryResultErrorsDisclose } = - this.checkDiscloseBytesPublicInputs(proof, queryResult) + this.checkDiscloseBytesPublicInputs(proof, originalQuery, queryResult) isCorrect = isCorrect && isCorrectDisclose queryResultErrors = { ...queryResultErrors, @@ -1635,7 +2400,7 @@ export class PublicInputChecker { const { isCorrect: isCorrectNationalityInclusion, queryResultErrors: queryResultErrorsNationalityInclusion, - } = this.checkNationalityInclusionPublicInputs(queryResult, countryList) + } = this.checkNationalityInclusionPublicInputs(originalQuery, queryResult, countryList) isCorrect = isCorrect && isCorrectNationalityInclusion queryResultErrors = { ...queryResultErrors, @@ -1674,7 +2439,7 @@ export class PublicInputChecker { const { isCorrect: isCorrectIssuingCountryInclusion, queryResultErrors: queryResultErrorsIssuingCountryInclusion, - } = this.checkIssuingCountryInclusionPublicInputs(queryResult, countryList) + } = this.checkIssuingCountryInclusionPublicInputs(originalQuery, queryResult, countryList) isCorrect = isCorrect && isCorrectIssuingCountryInclusion queryResultErrors = { ...queryResultErrors, @@ -1713,7 +2478,7 @@ export class PublicInputChecker { const { isCorrect: isCorrectNationalityExclusion, queryResultErrors: queryResultErrorsNationalityExclusion, - } = this.checkNationalityExclusionPublicInputs(queryResult, countryList) + } = this.checkNationalityExclusionPublicInputs(originalQuery, queryResult, countryList) isCorrect = isCorrect && isCorrectNationalityExclusion queryResultErrors = { ...queryResultErrors, @@ -1752,7 +2517,7 @@ export class PublicInputChecker { const { isCorrect: isCorrectIssuingCountryExclusion, queryResultErrors: queryResultErrorsIssuingCountryExclusion, - } = this.checkIssuingCountryExclusionPublicInputs(queryResult, countryList) + } = this.checkIssuingCountryExclusionPublicInputs(originalQuery, queryResult, countryList) isCorrect = isCorrect && isCorrectIssuingCountryExclusion queryResultErrors = { ...queryResultErrors, @@ -1779,7 +2544,7 @@ export class PublicInputChecker { } } const { isCorrect: isCorrectBind, queryResultErrors: queryResultErrorsBind } = - this.checkBindPublicInputs(queryResult, bindCommittedInputs.data) + this.checkBindPublicInputs(originalQuery, queryResult, bindCommittedInputs.data) isCorrect = isCorrect && isCorrectBind queryResultErrors = { ...queryResultErrors, @@ -1817,6 +2582,7 @@ export class PublicInputChecker { isCorrect: isCorrectSanctionsExclusion, queryResultErrors: queryResultErrorsSanctionsExclusion, } = await this.checkSanctionsExclusionPublicInputs( + originalQuery, queryResult, exclusionCheckSanctionsCommittedInputs, sanctionsBuilder, @@ -1857,7 +2623,11 @@ export class PublicInputChecker { } } const { isCorrect: isCorrectFacematch, queryResultErrors: queryResultErrorsFacematch } = - await this.checkFacematchPublicInputs(queryResult, facematchCommittedInputs) + await this.checkFacematchPublicInputs( + originalQuery, + queryResult, + facematchCommittedInputs, + ) isCorrect = isCorrect && isCorrectFacematch queryResultErrors = { ...queryResultErrors, @@ -1963,7 +2733,7 @@ export class PublicInputChecker { ...queryResultErrorsScope, } const { isCorrect: isCorrectDisclose, queryResultErrors: queryResultErrorsDisclose } = - this.checkDiscloseBytesPublicInputs(proof, queryResult) + this.checkDiscloseBytesPublicInputs(proof, originalQuery, queryResult) isCorrect = isCorrect && isCorrectDisclose && isCorrectScope queryResultErrors = { ...queryResultErrors, @@ -2025,7 +2795,7 @@ export class PublicInputChecker { const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = this.checkScopeFromDisclosureProof(domain, proofData, queryResultErrors, "age", scope) const { isCorrect: isCorrectAge, queryResultErrors: queryResultErrorsAge } = - this.checkAgePublicInputs(proof, queryResult) + this.checkAgePublicInputs(proof, originalQuery, queryResult) isCorrect = isCorrect && isCorrectAge && isCorrectScope queryResultErrors = { ...queryResultErrors, @@ -2095,7 +2865,7 @@ export class PublicInputChecker { scope, ) const { isCorrect: isCorrectBirthdate, queryResultErrors: queryResultErrorsBirthdate } = - this.checkBirthdatePublicInputs(proof, queryResult) + this.checkBirthdatePublicInputs(proof, originalQuery, queryResult) isCorrect = isCorrect && isCorrectBirthdate && isCorrectScope queryResultErrors = { ...queryResultErrors, @@ -2164,7 +2934,7 @@ export class PublicInputChecker { scope, ) const { isCorrect: isCorrectExpiryDate, queryResultErrors: queryResultErrorsExpiryDate } = - this.checkExpiryDatePublicInputs(proof, queryResult) + this.checkExpiryDatePublicInputs(proof, originalQuery, queryResult) isCorrect = isCorrect && isCorrectExpiryDate && isCorrectScope queryResultErrors = { ...queryResultErrors, @@ -2237,7 +3007,7 @@ export class PublicInputChecker { const { isCorrect: isCorrectNationalityExclusion, queryResultErrors: queryResultErrorsNationalityExclusion, - } = this.checkNationalityExclusionPublicInputs(queryResult, countryList) + } = this.checkNationalityExclusionPublicInputs(originalQuery, queryResult, countryList) isCorrect = isCorrect && isCorrectNationalityExclusion && isCorrectScope queryResultErrors = { ...queryResultErrors, @@ -2265,8 +3035,8 @@ export class PublicInputChecker { "Failed to check the link between the validity of the ID and the issuing country exclusion check", ) isCorrect = false - queryResultErrors.nationality = { - ...queryResultErrors.nationality, + queryResultErrors.issuing_country = { + ...queryResultErrors.issuing_country, commitment: { expected: `Commitment: ${commitmentOut}`, received: `Commitment: ${commitmentIn}`, @@ -2304,13 +3074,13 @@ export class PublicInputChecker { domain, proofData, queryResultErrors, - "nationality", + "issuing_country", scope, ) const { isCorrect: isCorrectIssuingCountryExclusion, queryResultErrors: queryResultErrorsIssuingCountryExclusion, - } = this.checkIssuingCountryExclusionPublicInputs(queryResult, countryList) + } = this.checkIssuingCountryExclusionPublicInputs(originalQuery, queryResult, countryList) isCorrect = isCorrect && isCorrectIssuingCountryExclusion && isCorrectScope queryResultErrors = { ...queryResultErrors, @@ -2383,7 +3153,7 @@ export class PublicInputChecker { const { isCorrect: isCorrectNationalityInclusion, queryResultErrors: queryResultErrorsNationalityInclusion, - } = this.checkNationalityInclusionPublicInputs(queryResult, countryList) + } = this.checkNationalityInclusionPublicInputs(originalQuery, queryResult, countryList) isCorrect = isCorrect && isCorrectNationalityInclusion && isCorrectScope queryResultErrors = { ...queryResultErrors, @@ -2411,8 +3181,8 @@ export class PublicInputChecker { "Failed to check the link between the validity of the ID and the issuing country inclusion check", ) isCorrect = false - queryResultErrors.nationality = { - ...queryResultErrors.nationality, + queryResultErrors.issuing_country = { + ...queryResultErrors.issuing_country, commitment: { expected: `Commitment: ${commitmentOut}`, received: `Commitment: ${commitmentIn}`, @@ -2450,13 +3220,13 @@ export class PublicInputChecker { domain, proofData, queryResultErrors, - "nationality", + "issuing_country", scope, ) const { isCorrect: isCorrectIssuingCountryInclusion, queryResultErrors: queryResultErrorsIssuingCountryInclusion, - } = this.checkIssuingCountryInclusionPublicInputs(queryResult, countryList) + } = this.checkIssuingCountryInclusionPublicInputs(originalQuery, queryResult, countryList) isCorrect = isCorrect && isCorrectIssuingCountryInclusion && isCorrectScope queryResultErrors = { ...queryResultErrors, @@ -2478,6 +3248,19 @@ export class PublicInputChecker { uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10) uniqueIdentifierType = getNullifierTypeFromDisclosureProof(proofData) } else if (proof.name === "bind") { + commitmentIn = getCommitmentInFromDisclosureProof(proofData) + if (commitmentIn !== commitmentOut) { + console.warn("Failed to check the link between the validity of the ID and the bound data") + isCorrect = false + queryResultErrors.bind = { + ...queryResultErrors.bind, + commitment: { + expected: `Commitment: ${commitmentOut}`, + received: `Commitment: ${commitmentIn}`, + message: "Failed to check the link between the validity of the ID and the bound data", + }, + } + } const bindCommittedInputs = proof.committedInputs?.bind as BindCommittedInputs const paramCommittment = getParameterCommitmentFromDisclosureProof(proofData) const calculatedParamCommitment = await getBindParameterCommitment( @@ -2495,12 +3278,15 @@ export class PublicInputChecker { }, } } + const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = + this.checkScopeFromDisclosureProof(domain, proofData, queryResultErrors, "bind", scope) const { isCorrect: isCorrectBind, queryResultErrors: queryResultErrorsBind } = - this.checkBindPublicInputs(queryResult, bindCommittedInputs.data) - isCorrect = isCorrect && isCorrectBind + this.checkBindPublicInputs(originalQuery, queryResult, bindCommittedInputs.data) + isCorrect = isCorrect && isCorrectBind && isCorrectScope queryResultErrors = { ...queryResultErrors, ...queryResultErrorsBind, + ...queryResultErrorsScope, } const { isCorrect: isCorrectCurrentDate, queryResultErrors: queryResultErrorsCurrentDate } = await this.checkCurrentDate( @@ -2517,6 +3303,22 @@ export class PublicInputChecker { uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10) uniqueIdentifierType = getNullifierTypeFromDisclosureProof(proofData) } else if (proof.name === "exclusion_check_sanctions") { + commitmentIn = getCommitmentInFromDisclosureProof(proofData) + if (commitmentIn !== commitmentOut) { + console.warn( + "Failed to check the link between the validity of the ID and the sanctions exclusion check", + ) + isCorrect = false + queryResultErrors.sanctions = { + ...queryResultErrors.sanctions, + commitment: { + expected: `Commitment: ${commitmentOut}`, + received: `Commitment: ${commitmentIn}`, + message: + "Failed to check the link between the validity of the ID and the sanctions exclusion check", + }, + } + } const sanctionsBuilder = await SanctionsBuilder.create() const exclusionCheckSanctionsCommittedInputs = proof.committedInputs ?.exclusion_check_sanctions as SanctionsCommittedInputs @@ -2539,18 +3341,28 @@ export class PublicInputChecker { }, } } + const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = + this.checkScopeFromDisclosureProof( + domain, + proofData, + queryResultErrors, + "sanctions", + scope, + ) const { isCorrect: isCorrectSanctionsExclusion, queryResultErrors: queryResultErrorsSanctionsExclusion, } = await this.checkSanctionsExclusionPublicInputs( + originalQuery, queryResult, exclusionCheckSanctionsCommittedInputs, sanctionsBuilder, ) - isCorrect = isCorrect && isCorrectSanctionsExclusion + isCorrect = isCorrect && isCorrectSanctionsExclusion && isCorrectScope queryResultErrors = { ...queryResultErrors, ...queryResultErrorsSanctionsExclusion, + ...queryResultErrorsScope, } const { isCorrect: isCorrectCurrentDate, queryResultErrors: queryResultErrorsCurrentDate } = await this.checkCurrentDate( @@ -2567,6 +3379,22 @@ export class PublicInputChecker { uniqueIdentifier = getNullifierFromDisclosureProof(proofData).toString(10) uniqueIdentifierType = getNullifierTypeFromDisclosureProof(proofData) } else if (proof.name?.startsWith("facematch") && !proof.name?.endsWith("_evm")) { + commitmentIn = getCommitmentInFromDisclosureProof(proofData) + if (commitmentIn !== commitmentOut) { + console.warn( + "Failed to check the link between the validity of the ID and the facematch check", + ) + isCorrect = false + queryResultErrors.facematch = { + ...queryResultErrors.facematch, + commitment: { + expected: `Commitment: ${commitmentOut}`, + received: `Commitment: ${commitmentIn}`, + message: + "Failed to check the link between the validity of the ID and the facematch check", + }, + } + } const facematchCommittedInputs = proof.committedInputs ?.facematch as FacematchCommittedInputs const paramCommittment = getParameterCommitmentFromDisclosureProof(proofData) @@ -2588,12 +3416,25 @@ export class PublicInputChecker { }, } } + const { isCorrect: isCorrectScope, queryResultErrors: queryResultErrorsScope } = + this.checkScopeFromDisclosureProof( + domain, + proofData, + queryResultErrors, + "facematch", + scope, + ) const { isCorrect: isCorrectFacematch, queryResultErrors: queryResultErrorsFacematch } = - await this.checkFacematchPublicInputs(queryResult, facematchCommittedInputs) - isCorrect = isCorrect && isCorrectFacematch + await this.checkFacematchPublicInputs( + originalQuery, + queryResult, + facematchCommittedInputs, + ) + isCorrect = isCorrect && isCorrectFacematch && isCorrectScope queryResultErrors = { ...queryResultErrors, ...queryResultErrorsFacematch, + ...queryResultErrorsScope, } const { isCorrect: isCorrectCurrentDate, queryResultErrors: queryResultErrorsCurrentDate } = await this.checkCurrentDate( diff --git a/packages/zkpassport-sdk/src/types.ts b/packages/zkpassport-sdk/src/types.ts index d64d13ecd..b675abef1 100644 --- a/packages/zkpassport-sdk/src/types.ts +++ b/packages/zkpassport-sdk/src/types.ts @@ -10,6 +10,7 @@ import { FacematchMode, ProofResult, SupportedChain, + Query, } from "@zkpassport/utils" export type QueryResultError = { @@ -31,6 +32,7 @@ export type QueryResultErrors = { | "sanctions"]: { disclose?: QueryResultError gte?: QueryResultError + gt?: QueryResultError lte?: QueryResultError lt?: QueryResultError range?: QueryResultError<[number | Date, number | Date]> @@ -72,6 +74,10 @@ export type QueryBuilderResult = { * to this URL on your website if they're visiting your website on their phone. */ url: string + /** + * The query object. + */ + query: Query /** * The id of the request. */ @@ -134,7 +140,11 @@ export type QueryBuilderResult = { requestReceived: () => boolean } -export type QueryBuilder = { +export type OfflineQueryBuilderResult = { + query: Query +} + +export type QueryBuilder = { /** * Requires this attribute to be equal to the provided value. * @param key The attribute to compare. @@ -248,5 +258,5 @@ export type QueryBuilder = { * or provide as a link to the user if they're visiting your website on their phone. * It also returns all the callbacks you can use to handle the user's response. */ - done: () => QueryBuilderResult + done: () => T extends "online" ? QueryBuilderResult : OfflineQueryBuilderResult } diff --git a/packages/zkpassport-sdk/tests/public-input-checker.test.ts b/packages/zkpassport-sdk/tests/public-input-checker.test.ts new file mode 100644 index 000000000..f8fe3fc47 --- /dev/null +++ b/packages/zkpassport-sdk/tests/public-input-checker.test.ts @@ -0,0 +1,2581 @@ +import { PublicInputChecker } from "../src/public-input-checker" +import type { + Query, + QueryResult, + ProofResult, + DiscloseCommittedInputs, + SanctionsBuilder, + FacematchCommittedInputs, +} from "@zkpassport/utils" +import { + SECONDS_BETWEEN_1900_AND_1970, + getServiceScopeHash, + getScopeHash, + getAgeParameterCommitment, +} from "@zkpassport/utils" +import { + APPLE_APP_ATTEST_ROOT_KEY_HASH, + GOOGLE_APP_ATTEST_RSA_ROOT_KEY_HASH, + ZKPASSPORT_IOS_APP_ID_HASH, + ZKPASSPORT_ANDROID_APP_ID_HASH, +} from "../src/constants" + +// Helper to build a minimal disclose proof with committed inputs +function makeDiscloseProof(disclosedBytes: number[]): ProofResult { + return { + name: "disclose_bytes", + proof: "", + total: 1, + committedInputs: { + disclose_bytes: { + discloseMask: disclosedBytes.map((b) => (b !== 0 ? 1 : 0)), + disclosedBytes, + } as DiscloseCommittedInputs, + }, + } +} + +// Helper to build a minimal age proof with committed inputs +function makeAgeProof(minAge: number, maxAge: number): ProofResult { + return { + name: "compare_age", + proof: "", + total: 1, + committedInputs: { + compare_age: { minAge, maxAge }, + }, + } +} + +// Helper to check that no error with "original query" is present in a field +function hasOriginalQueryError( + errors: Record | undefined, + field: string, +): boolean { + if (!errors) return false + const err = errors[field] + if (!err) return false + return ( + typeof (err as { message: string }).message === "string" && + (err as { message: string }).message.includes("original query") + ) +} + +describe("PublicInputChecker - originalQuery validation", () => { + describe("checkDiscloseBytesPublicInputs", () => { + // We use zeroed disclosed bytes so disclosed data won't match queryResult expected values. + // The tests focus on originalQuery checks which run independently of disclosed data checks. + const emptyProof = makeDiscloseProof(new Array(90).fill(0)) + + describe("nationality eq", () => { + test("no originalQuery error when queryResult matches originalQuery", () => { + const originalQuery: Query = { nationality: { eq: "FRA" } } + const queryResult: QueryResult = { + nationality: { eq: { expected: "FRA", result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkDiscloseBytesPublicInputs( + emptyProof, + originalQuery, + queryResult, + ) + // The existing disclosed-data check may set an eq error, but it shouldn't be the originalQuery one + expect(hasOriginalQueryError(queryResultErrors.nationality, "eq")).toBe(false) + }) + + test("fails when queryResult eq expected differs from originalQuery", () => { + const originalQuery: Query = { nationality: { eq: "FRA" } } + const queryResult: QueryResult = { + nationality: { eq: { expected: "DEU", result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkDiscloseBytesPublicInputs( + emptyProof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.nationality, "eq")).toBe(true) + }) + + test("fails when queryResult has eq but originalQuery does not", () => { + const originalQuery: Query = { nationality: { disclose: true } } + const queryResult: QueryResult = { + nationality: { eq: { expected: "FRA", result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkDiscloseBytesPublicInputs( + emptyProof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.nationality, "eq")).toBe(true) + }) + }) + + describe("nationality disclose", () => { + test("fails when queryResult has disclose but originalQuery does not", () => { + const originalQuery: Query = { nationality: { eq: "FRA" } } + const queryResult: QueryResult = { + nationality: { disclose: { result: "FRA" } }, + } + const { queryResultErrors } = PublicInputChecker.checkDiscloseBytesPublicInputs( + emptyProof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.nationality, "disclose")).toBe(true) + }) + + test("no originalQuery disclose error when originalQuery requests it", () => { + const originalQuery: Query = { nationality: { disclose: true } } + const queryResult: QueryResult = { + nationality: { disclose: { result: "FRA" } }, + } + const { queryResultErrors } = PublicInputChecker.checkDiscloseBytesPublicInputs( + emptyProof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.nationality, "disclose")).toBe(false) + }) + }) + + describe("gender eq", () => { + test("fails when queryResult gender eq differs from originalQuery", () => { + const originalQuery: Query = { gender: { eq: "female" } } + const queryResult: QueryResult = { + gender: { eq: { expected: "male", result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkDiscloseBytesPublicInputs( + emptyProof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.gender, "eq")).toBe(true) + }) + + test("no originalQuery error when gender eq matches", () => { + const originalQuery: Query = { gender: { eq: "male" } } + const queryResult: QueryResult = { + gender: { eq: { expected: "male", result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkDiscloseBytesPublicInputs( + emptyProof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.gender, "eq")).toBe(false) + }) + }) + + describe("issuing_country eq", () => { + test("fails when queryResult issuing_country eq differs from originalQuery", () => { + const originalQuery: Query = { issuing_country: { eq: "FRA" } } + const queryResult: QueryResult = { + issuing_country: { eq: { expected: "DEU", result: false } }, + } + const { queryResultErrors } = PublicInputChecker.checkDiscloseBytesPublicInputs( + emptyProof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.issuing_country, "eq")).toBe(true) + }) + }) + + describe("document_number eq", () => { + test("fails when queryResult document_number eq not in originalQuery", () => { + const originalQuery: Query = {} + const queryResult: QueryResult = { + document_number: { eq: { expected: "ABC123", result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkDiscloseBytesPublicInputs( + emptyProof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.document_number, "eq")).toBe(true) + }) + }) + + describe("fullname eq", () => { + test("no originalQuery error when names match case-insensitively", () => { + const originalQuery: Query = { fullname: { eq: "JOHN DOE" } } + const queryResult: QueryResult = { + fullname: { eq: { expected: "john doe", result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkDiscloseBytesPublicInputs( + emptyProof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.fullname, "eq")).toBe(false) + }) + + test("fails when names differ", () => { + const originalQuery: Query = { fullname: { eq: "JOHN DOE" } } + const queryResult: QueryResult = { + fullname: { eq: { expected: "JANE DOE", result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkDiscloseBytesPublicInputs( + emptyProof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.fullname, "eq")).toBe(true) + }) + }) + + describe("firstname eq", () => { + test("fails when firstname differs from originalQuery", () => { + const originalQuery: Query = { firstname: { eq: "JOHN" } } + const queryResult: QueryResult = { + firstname: { eq: { expected: "JANE", result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkDiscloseBytesPublicInputs( + emptyProof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.firstname, "eq")).toBe(true) + }) + }) + + describe("lastname eq", () => { + test("fails when lastname not in originalQuery", () => { + const originalQuery: Query = {} + const queryResult: QueryResult = { + lastname: { eq: { expected: "DOE", result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkDiscloseBytesPublicInputs( + emptyProof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.lastname, "eq")).toBe(true) + }) + }) + + describe("document_type eq", () => { + test("fails when document_type eq not in originalQuery", () => { + const originalQuery: Query = {} + const queryResult: QueryResult = { + document_type: { eq: { expected: "passport", result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkDiscloseBytesPublicInputs( + emptyProof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.document_type, "eq")).toBe(true) + }) + + test("no originalQuery error when document_type eq matches", () => { + const originalQuery: Query = { document_type: { eq: "passport" } } + const queryResult: QueryResult = { + document_type: { eq: { expected: "passport", result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkDiscloseBytesPublicInputs( + emptyProof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.document_type, "eq")).toBe(false) + }) + }) + }) + + describe("checkAgePublicInputs", () => { + test("no originalQuery error when gte matches", () => { + const proof = makeAgeProof(18, 0) + const originalQuery: Query = { age: { gte: 18 } } + const queryResult: QueryResult = { + age: { gte: { expected: 18, result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkAgePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.age, "gte")).toBe(false) + }) + + test("fails when gte expected differs from originalQuery", () => { + const proof = makeAgeProof(13, 0) + const originalQuery: Query = { age: { gte: 18 } } + const queryResult: QueryResult = { + age: { gte: { expected: 13, result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkAgePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.age, "gte")).toBe(true) + }) + + test("fails when gte not in originalQuery", () => { + const proof = makeAgeProof(18, 0) + const originalQuery: Query = { age: { lt: 65 } } + const queryResult: QueryResult = { + age: { gte: { expected: 18, result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkAgePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.age, "gte")).toBe(true) + }) + + test("fails when gt expected differs from originalQuery", () => { + const proof = makeAgeProof(17, 0) + const originalQuery: Query = { age: { gt: 18 } } + const queryResult: QueryResult = { + age: { gt: { expected: 17, result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkAgePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.age, "gt")).toBe(true) + }) + + test("fails when lt expected differs from originalQuery", () => { + const proof = makeAgeProof(0, 70) + const originalQuery: Query = { age: { lt: 65 } } + const queryResult: QueryResult = { + age: { lt: { expected: 70, result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkAgePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.age, "lt")).toBe(true) + }) + + test("fails when lte expected differs from originalQuery", () => { + const proof = makeAgeProof(0, 30) + const originalQuery: Query = { age: { lte: 25 } } + const queryResult: QueryResult = { + age: { lte: { expected: 30, result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkAgePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.age, "lte")).toBe(true) + }) + + test("fails when eq expected differs from originalQuery", () => { + const proof = makeAgeProof(25, 25) + const originalQuery: Query = { age: { eq: 30 } } + const queryResult: QueryResult = { + age: { eq: { expected: 25, result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkAgePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.age, "eq")).toBe(true) + }) + + test("fails when range expected differs from originalQuery", () => { + const proof = makeAgeProof(13, 70) + const originalQuery: Query = { age: { range: [18, 65] } } + const queryResult: QueryResult = { + age: { range: { expected: [13, 70], result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkAgePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.age, "range")).toBe(true) + }) + + test("fails when disclose not in originalQuery", () => { + const proof = makeAgeProof(25, 25) + const originalQuery: Query = { age: { gte: 18 } } + const queryResult: QueryResult = { + age: { disclose: { result: 25 } }, + } + const { queryResultErrors } = PublicInputChecker.checkAgePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.age, "disclose")).toBe(true) + }) + }) + + describe("checkBirthdatePublicInputs", () => { + function makeBirthdateProof(minTimestamp: number, maxTimestamp: number): ProofResult { + return { + name: "compare_birthdate", + proof: "", + total: 1, + committedInputs: { + compare_birthdate: { minDateTimestamp: minTimestamp, maxDateTimestamp: maxTimestamp }, + }, + } + } + + test("fails when gte expected differs from originalQuery", () => { + const proof = makeBirthdateProof(0, 0) + const originalQuery: Query = { birthdate: { gte: new Date("2000-01-01") } } + const queryResult: QueryResult = { + birthdate: { gte: { expected: new Date("1990-01-01"), result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkBirthdatePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.birthdate, "gte")).toBe(true) + }) + + test("no originalQuery error when gte matches", () => { + const proof = makeBirthdateProof(0, 0) + const originalQuery: Query = { birthdate: { gte: new Date("2000-01-01") } } + const queryResult: QueryResult = { + birthdate: { gte: { expected: new Date("2000-01-01"), result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkBirthdatePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.birthdate, "gte")).toBe(false) + }) + + test("fails when gt not in originalQuery", () => { + const proof = makeBirthdateProof(0, 0) + const originalQuery: Query = { birthdate: { gte: new Date("2000-01-01") } } + const queryResult: QueryResult = { + birthdate: { gt: { expected: new Date("2000-01-01"), result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkBirthdatePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.birthdate, "gt")).toBe(true) + }) + + test("fails when lt not in originalQuery", () => { + const proof = makeBirthdateProof(0, 0) + const originalQuery: Query = { birthdate: { lte: new Date("2000-01-01") } } + const queryResult: QueryResult = { + birthdate: { lt: { expected: new Date("2000-01-01"), result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkBirthdatePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.birthdate, "lt")).toBe(true) + }) + + test("fails when lte expected differs from originalQuery", () => { + const proof = makeBirthdateProof(0, 0) + const originalQuery: Query = { birthdate: { lte: new Date("2005-01-01") } } + const queryResult: QueryResult = { + birthdate: { lte: { expected: new Date("2010-01-01"), result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkBirthdatePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.birthdate, "lte")).toBe(true) + }) + + test("fails when range differs from originalQuery", () => { + const proof = makeBirthdateProof(0, 0) + const originalQuery: Query = { + birthdate: { range: [new Date("2000-01-01"), new Date("2005-01-01")] }, + } + const queryResult: QueryResult = { + birthdate: { + range: { expected: [new Date("1990-01-01"), new Date("2005-01-01")], result: true }, + }, + } + const { queryResultErrors } = PublicInputChecker.checkBirthdatePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.birthdate, "range")).toBe(true) + }) + }) + + describe("checkExpiryDatePublicInputs", () => { + function makeExpiryProof(minTimestamp: number, maxTimestamp: number): ProofResult { + return { + name: "compare_expiry", + proof: "", + total: 1, + committedInputs: { + compare_expiry: { minDateTimestamp: minTimestamp, maxDateTimestamp: maxTimestamp }, + }, + } + } + + test("fails when gte expected differs from originalQuery", () => { + const proof = makeExpiryProof(0, 0) + const originalQuery: Query = { expiry_date: { gte: new Date("2030-01-01") } } + const queryResult: QueryResult = { + expiry_date: { gte: { expected: new Date("2025-01-01"), result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkExpiryDatePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.expiry_date, "gte")).toBe(true) + }) + + test("fails when gt not in originalQuery", () => { + const proof = makeExpiryProof(0, 0) + const originalQuery: Query = {} + const queryResult: QueryResult = { + expiry_date: { gt: { expected: new Date("2025-01-01"), result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkExpiryDatePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.expiry_date, "gt")).toBe(true) + }) + + test("fails when lt not in originalQuery", () => { + const proof = makeExpiryProof(0, 0) + const originalQuery: Query = {} + const queryResult: QueryResult = { + expiry_date: { lt: { expected: new Date("2030-01-01"), result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkExpiryDatePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.expiry_date, "lt")).toBe(true) + }) + + test("fails when lte expected differs from originalQuery", () => { + const proof = makeExpiryProof(0, 0) + const originalQuery: Query = { expiry_date: { lte: new Date("2030-01-01") } } + const queryResult: QueryResult = { + expiry_date: { lte: { expected: new Date("2035-01-01"), result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkExpiryDatePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.expiry_date, "lte")).toBe(true) + }) + + test("fails when range differs from originalQuery", () => { + const proof = makeExpiryProof(0, 0) + const originalQuery: Query = { + expiry_date: { range: [new Date("2025-01-01"), new Date("2035-01-01")] }, + } + const queryResult: QueryResult = { + expiry_date: { + range: { expected: [new Date("2020-01-01"), new Date("2035-01-01")], result: true }, + }, + } + const { queryResultErrors } = PublicInputChecker.checkExpiryDatePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(hasOriginalQueryError(queryResultErrors.expiry_date, "range")).toBe(true) + }) + }) + + describe("checkNationalityExclusionPublicInputs", () => { + test("no originalQuery error when queryResult out matches originalQuery", () => { + const originalQuery: Query = { nationality: { out: ["USA", "GBR"] } } + const queryResult: QueryResult = { + nationality: { out: { expected: ["USA", "GBR"], result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkNationalityExclusionPublicInputs( + originalQuery, + queryResult, + ["USA", "GBR"], + ) + expect(hasOriginalQueryError(queryResultErrors.nationality, "out")).toBe(false) + }) + + test("fails when queryResult out differs from originalQuery", () => { + const originalQuery: Query = { nationality: { out: ["USA", "GBR"] } } + const queryResult: QueryResult = { + nationality: { out: { expected: ["USA", "FRA"], result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkNationalityExclusionPublicInputs( + originalQuery, + queryResult, + ["USA", "FRA"], + ) + expect(hasOriginalQueryError(queryResultErrors.nationality, "out")).toBe(true) + }) + + test("fails when queryResult has out but originalQuery does not", () => { + const originalQuery: Query = {} + const queryResult: QueryResult = { + nationality: { out: { expected: ["USA"], result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkNationalityExclusionPublicInputs( + originalQuery, + queryResult, + ["USA"], + ) + expect(hasOriginalQueryError(queryResultErrors.nationality, "out")).toBe(true) + }) + }) + + describe("checkNationalityInclusionPublicInputs", () => { + test("no originalQuery error when queryResult in matches originalQuery", () => { + const originalQuery: Query = { nationality: { in: ["FRA", "DEU"] } } + const queryResult: QueryResult = { + nationality: { in: { expected: ["FRA", "DEU"], result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkNationalityInclusionPublicInputs( + originalQuery, + queryResult, + ["FRA", "DEU"], + ) + expect(hasOriginalQueryError(queryResultErrors.nationality, "in")).toBe(false) + }) + + test("fails when queryResult in differs from originalQuery", () => { + const originalQuery: Query = { nationality: { in: ["FRA", "DEU"] } } + const queryResult: QueryResult = { + nationality: { in: { expected: ["FRA", "ITA"], result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkNationalityInclusionPublicInputs( + originalQuery, + queryResult, + ["FRA", "ITA"], + ) + expect(hasOriginalQueryError(queryResultErrors.nationality, "in")).toBe(true) + }) + }) + + describe("checkIssuingCountryExclusionPublicInputs", () => { + test("fails when queryResult out not in originalQuery", () => { + const originalQuery: Query = {} + const queryResult: QueryResult = { + issuing_country: { out: { expected: ["USA"], result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkIssuingCountryExclusionPublicInputs( + originalQuery, + queryResult, + ["USA"], + ) + expect(hasOriginalQueryError(queryResultErrors.issuing_country, "out")).toBe(true) + }) + }) + + describe("checkIssuingCountryInclusionPublicInputs", () => { + test("fails when queryResult in not in originalQuery", () => { + const originalQuery: Query = {} + const queryResult: QueryResult = { + issuing_country: { in: { expected: ["FRA"], result: true } }, + } + const { queryResultErrors } = PublicInputChecker.checkIssuingCountryInclusionPublicInputs( + originalQuery, + queryResult, + ["FRA"], + ) + expect(hasOriginalQueryError(queryResultErrors.issuing_country, "in")).toBe(true) + }) + }) + + describe("checkBindPublicInputs", () => { + test("no originalQuery error when queryResult bind matches originalQuery", () => { + const originalQuery: Query = { + bind: { user_address: "0x1234abcd", chain: "ethereum", custom_data: "test" }, + } + const queryResult: QueryResult = { + bind: { user_address: "0x1234abcd", chain: "ethereum", custom_data: "test" }, + } + const { queryResultErrors } = PublicInputChecker.checkBindPublicInputs( + originalQuery, + queryResult, + { user_address: "0x1234abcd", chain: "ethereum", custom_data: "test" }, + ) + expect(hasOriginalQueryError(queryResultErrors.bind, "eq")).toBe(false) + }) + + test("fails when queryResult bind user_address differs from originalQuery", () => { + const originalQuery: Query = { + bind: { user_address: "0x1234abcd", chain: "ethereum" }, + } + const queryResult: QueryResult = { + bind: { user_address: "0xdeadbeef", chain: "ethereum" }, + } + const { queryResultErrors } = PublicInputChecker.checkBindPublicInputs( + originalQuery, + queryResult, + { user_address: "0xdeadbeef", chain: "ethereum" }, + ) + expect(hasOriginalQueryError(queryResultErrors.bind, "eq")).toBe(true) + }) + + test("fails when queryResult has bind but originalQuery does not", () => { + const originalQuery: Query = {} + const queryResult: QueryResult = { + bind: { user_address: "0x1234abcd", chain: "ethereum" }, + } + const { queryResultErrors } = PublicInputChecker.checkBindPublicInputs( + originalQuery, + queryResult, + { user_address: "0x1234abcd", chain: "ethereum" }, + ) + expect(hasOriginalQueryError(queryResultErrors.bind, "eq")).toBe(true) + }) + }) + + describe("checkSanctionsExclusionPublicInputs", () => { + test("fails when queryResult has sanctions but originalQuery does not", async () => { + const originalQuery: Query = {} + const queryResult: QueryResult = { + sanctions: { passed: true, isStrict: false }, + } + const sanctionsCommittedInputs = { rootHash: "abc", isStrict: false } + const sanctionsBuilder = { getRoot: async () => "abc" } as unknown as SanctionsBuilder + const { queryResultErrors } = await PublicInputChecker.checkSanctionsExclusionPublicInputs( + originalQuery, + queryResult, + sanctionsCommittedInputs, + sanctionsBuilder, + ) + expect(hasOriginalQueryError(queryResultErrors.sanctions, "eq")).toBe(true) + }) + + test("fails when strict mode differs from originalQuery", async () => { + const originalQuery: Query = { + sanctions: { countries: "all", lists: "all", strict: true }, + } + const queryResult: QueryResult = { + sanctions: { passed: true, isStrict: false }, + } + const sanctionsCommittedInputs = { rootHash: "abc", isStrict: false } + const sanctionsBuilder = { getRoot: async () => "abc" } as unknown as SanctionsBuilder + const { queryResultErrors } = await PublicInputChecker.checkSanctionsExclusionPublicInputs( + originalQuery, + queryResult, + sanctionsCommittedInputs, + sanctionsBuilder, + ) + expect(hasOriginalQueryError(queryResultErrors.sanctions, "eq")).toBe(true) + }) + + test("no originalQuery error when strict mode matches", async () => { + const originalQuery: Query = { + sanctions: { countries: "all", lists: "all", strict: false }, + } + const queryResult: QueryResult = { + sanctions: { passed: true, isStrict: false }, + } + const sanctionsCommittedInputs = { rootHash: "abc", isStrict: false } + const sanctionsBuilder = { getRoot: async () => "abc" } as unknown as SanctionsBuilder + const { queryResultErrors } = await PublicInputChecker.checkSanctionsExclusionPublicInputs( + originalQuery, + queryResult, + sanctionsCommittedInputs, + sanctionsBuilder, + ) + expect(hasOriginalQueryError(queryResultErrors.sanctions, "eq")).toBe(false) + }) + }) + + describe("checkFacematchPublicInputs", () => { + const baseFacematchInputs = { + rootKeyLeaf: "0x0", + environment: "production" as const, + appIdHash: "0x0", + integrityPubkeyHash: "0x0", + } + + test("fails when facematch mode differs from originalQuery", async () => { + const originalQuery: Query = { facematch: { mode: "strict" } } + const queryResult: QueryResult = { + facematch: { mode: "regular", passed: true }, + } + const { queryResultErrors } = await PublicInputChecker.checkFacematchPublicInputs( + originalQuery, + queryResult, + { ...baseFacematchInputs, mode: "regular" as const }, + ) + expect(queryResultErrors.facematch?.eq).toBeDefined() + expect(queryResultErrors.facematch!.eq!.message).toContain("facematch mode") + }) + + test("no facematch mode error when modes match", async () => { + const originalQuery: Query = { facematch: { mode: "strict" } } + const queryResult: QueryResult = { + facematch: { mode: "strict", passed: true }, + } + const { queryResultErrors } = await PublicInputChecker.checkFacematchPublicInputs( + originalQuery, + queryResult, + { ...baseFacematchInputs, mode: "strict" as const }, + ) + // Other errors may exist (root key, app id) but mode should not be one + const modeMessage = queryResultErrors.facematch?.eq?.message + if (modeMessage) { + expect(modeMessage).not.toContain("facematch mode") + } + }) + }) +}) + +describe("PublicInputChecker - committed inputs vs queryResult", () => { + describe("checkAgePublicInputs", () => { + test("passes when committed minAge matches queryResult gte", () => { + const proof = makeAgeProof(18, 0) + const originalQuery: Query = { age: { gte: 18 } } + const queryResult: QueryResult = { + age: { gte: { expected: 18, result: true } }, + } + const { isCorrect } = PublicInputChecker.checkAgePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(isCorrect).toBe(true) + }) + + test("fails when committed minAge does not match queryResult gte expected", () => { + const proof = makeAgeProof(16, 0) // committed says 16 + const originalQuery: Query = { age: { gte: 18 } } + const queryResult: QueryResult = { + age: { gte: { expected: 18, result: true } }, // queryResult says 18 + } + const { isCorrect, queryResultErrors } = PublicInputChecker.checkAgePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(isCorrect).toBe(false) + expect(queryResultErrors.age?.gte).toBeDefined() + }) + + test("passes when committed maxAge matches queryResult lt", () => { + const proof = makeAgeProof(0, 65) + const originalQuery: Query = { age: { lt: 65 } } + const queryResult: QueryResult = { + age: { lt: { expected: 65, result: true } }, + } + const { isCorrect } = PublicInputChecker.checkAgePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(isCorrect).toBe(true) + }) + + test("fails when committed maxAge does not match queryResult lt expected", () => { + const proof = makeAgeProof(0, 70) + const originalQuery: Query = { age: { lt: 65 } } + const queryResult: QueryResult = { + age: { lt: { expected: 65, result: true } }, + } + const { isCorrect, queryResultErrors } = PublicInputChecker.checkAgePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(isCorrect).toBe(false) + expect(queryResultErrors.age?.lt).toBeDefined() + }) + + test("passes when committed range matches queryResult range", () => { + const proof = makeAgeProof(18, 65) + const originalQuery: Query = { age: { range: [18, 65] } } + const queryResult: QueryResult = { + age: { range: { expected: [18, 65], result: true } }, + } + const { isCorrect } = PublicInputChecker.checkAgePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(isCorrect).toBe(true) + }) + + test("fails when committed range does not match queryResult range", () => { + const proof = makeAgeProof(13, 70) + const originalQuery: Query = { age: { range: [18, 65] } } + const queryResult: QueryResult = { + age: { range: { expected: [18, 65], result: true } }, + } + const { isCorrect, queryResultErrors } = PublicInputChecker.checkAgePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(isCorrect).toBe(false) + expect(queryResultErrors.age?.range).toBeDefined() + }) + + test("maxAge should be 0 when no upper-bound constraint", () => { + const proof = makeAgeProof(18, 5) // maxAge != 0 but no upper-bound query + const originalQuery: Query = { age: { gte: 18 } } + const queryResult: QueryResult = { + age: { gte: { expected: 18, result: true } }, + } + const { isCorrect, queryResultErrors } = PublicInputChecker.checkAgePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(isCorrect).toBe(false) + expect(queryResultErrors.age?.disclose?.message).toContain("Maximum age should be equal to 0") + }) + + test("minAge should be 0 when no lower-bound constraint", () => { + const proof = makeAgeProof(5, 65) // minAge != 0 but no lower-bound query + const originalQuery: Query = { age: { lt: 65 } } + const queryResult: QueryResult = { + age: { lt: { expected: 65, result: true } }, + } + const { isCorrect, queryResultErrors } = PublicInputChecker.checkAgePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(isCorrect).toBe(false) + expect(queryResultErrors.age?.disclose?.message).toContain("Minimum age should be equal to 0") + }) + + test("fails when age is not set in queryResult", () => { + const proof = makeAgeProof(18, 0) + const originalQuery: Query = { age: { gte: 18 } } + const queryResult: QueryResult = {} + const { isCorrect, queryResultErrors } = PublicInputChecker.checkAgePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(isCorrect).toBe(false) + expect(queryResultErrors.age?.disclose?.message).toContain( + "Age is not set in the query result", + ) + }) + + test("fails when disclosed age does not match committed", () => { + const proof = makeAgeProof(25, 25) // min=max=25 means exact age + const originalQuery: Query = { age: { eq: 25, disclose: true } } + const queryResult: QueryResult = { + age: { disclose: { result: 30 } }, // disclosed 30 but committed 25 + } + const { isCorrect, queryResultErrors } = PublicInputChecker.checkAgePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(isCorrect).toBe(false) + expect(queryResultErrors.age?.disclose?.message).toContain( + "Age does not match the disclosed age", + ) + }) + + test("passes when committed minAge matches queryResult gt", () => { + const proof = makeAgeProof(17, 0) + const originalQuery: Query = { age: { gt: 17 } } + const queryResult: QueryResult = { + age: { gt: { expected: 17, result: true } }, + } + const { isCorrect } = PublicInputChecker.checkAgePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(isCorrect).toBe(true) + }) + + test("fails when committed minAge does not match queryResult gt expected", () => { + const proof = makeAgeProof(15, 0) // committed says 15 + const originalQuery: Query = { age: { gt: 17 } } + const queryResult: QueryResult = { + age: { gt: { expected: 17, result: true } }, // queryResult says 17 + } + const { isCorrect, queryResultErrors } = PublicInputChecker.checkAgePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(isCorrect).toBe(false) + expect(queryResultErrors.age?.gt).toBeDefined() + expect(queryResultErrors.age!.gt!.message).toContain("not greater than") + }) + + test("passes when committed maxAge matches queryResult lte", () => { + const proof = makeAgeProof(0, 65) + const originalQuery: Query = { age: { lte: 65 } } + const queryResult: QueryResult = { + age: { lte: { expected: 65, result: true } }, + } + const { isCorrect } = PublicInputChecker.checkAgePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(isCorrect).toBe(true) + }) + + test("fails when committed maxAge does not match queryResult lte expected", () => { + const proof = makeAgeProof(0, 70) // committed says 70 + const originalQuery: Query = { age: { lte: 65 } } + const queryResult: QueryResult = { + age: { lte: { expected: 65, result: true } }, // queryResult says 65 + } + const { isCorrect, queryResultErrors } = PublicInputChecker.checkAgePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(isCorrect).toBe(false) + expect(queryResultErrors.age?.lte).toBeDefined() + expect(queryResultErrors.age!.lte!.message).toContain("not less than or equal") + }) + + test("passes when committed minAge and maxAge match queryResult eq", () => { + const proof = makeAgeProof(25, 25) + const originalQuery: Query = { age: { eq: 25 } } + const queryResult: QueryResult = { + age: { eq: { expected: 25, result: true } }, + } + const { isCorrect } = PublicInputChecker.checkAgePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(isCorrect).toBe(true) + }) + + test("fails when committed minAge does not match queryResult eq expected", () => { + const proof = makeAgeProof(20, 25) // minAge != expected + const originalQuery: Query = { age: { eq: 25 } } + const queryResult: QueryResult = { + age: { eq: { expected: 25, result: true } }, + } + const { isCorrect, queryResultErrors } = PublicInputChecker.checkAgePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(isCorrect).toBe(false) + expect(queryResultErrors.age?.eq).toBeDefined() + expect(queryResultErrors.age!.eq!.message).toContain("does not match the expected age") + }) + + test("fails when committed maxAge does not match queryResult eq expected", () => { + const proof = makeAgeProof(25, 30) // maxAge != expected + const originalQuery: Query = { age: { eq: 25 } } + const queryResult: QueryResult = { + age: { eq: { expected: 25, result: true } }, + } + const { isCorrect, queryResultErrors } = PublicInputChecker.checkAgePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(isCorrect).toBe(false) + expect(queryResultErrors.age?.eq).toBeDefined() + expect(queryResultErrors.age!.eq!.message).toContain("does not match the expected age") + }) + }) + + describe("checkBirthdatePublicInputs", () => { + // Birthdate timestamps in committed inputs are offset by SECONDS_BETWEEN_1900_AND_1970 + const offset = SECONDS_BETWEEN_1900_AND_1970 + + function birthdateTimestamp(date: Date): number { + return Math.floor(date.getTime() / 1000) + offset + } + + function makeBirthdateProof(minDate: Date | null, maxDate: Date | null): ProofResult { + return { + name: "compare_birthdate", + proof: "", + total: 1, + committedInputs: { + compare_birthdate: { + minDateTimestamp: minDate ? birthdateTimestamp(minDate) : 0, + maxDateTimestamp: maxDate ? birthdateTimestamp(maxDate) : 0, + }, + }, + } + } + + test("passes when committed minDate matches queryResult gte", () => { + const date = new Date("2000-01-01") + const proof = makeBirthdateProof(date, null) + const originalQuery: Query = { birthdate: { gte: date } } + const queryResult: QueryResult = { + birthdate: { gte: { expected: new Date("2000-01-01"), result: true } }, + } + const { isCorrect } = PublicInputChecker.checkBirthdatePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(isCorrect).toBe(true) + }) + + test("fails when committed minDate does not match queryResult gte expected", () => { + const proof = makeBirthdateProof(new Date("1990-01-01"), null) + const originalQuery: Query = { birthdate: { gte: new Date("2000-01-01") } } + const queryResult: QueryResult = { + birthdate: { gte: { expected: new Date("2000-01-01"), result: true } }, + } + const { isCorrect, queryResultErrors } = PublicInputChecker.checkBirthdatePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(isCorrect).toBe(false) + expect(queryResultErrors.birthdate?.gte).toBeDefined() + }) + + test("passes when committed maxDate matches queryResult lte", () => { + const date = new Date("2005-06-15") + const proof = makeBirthdateProof(null, date) + const originalQuery: Query = { birthdate: { lte: date } } + const queryResult: QueryResult = { + birthdate: { lte: { expected: new Date("2005-06-15"), result: true } }, + } + const { isCorrect } = PublicInputChecker.checkBirthdatePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(isCorrect).toBe(true) + }) + + test("fails when committed maxDate does not match queryResult lte expected", () => { + const proof = makeBirthdateProof(null, new Date("2010-01-01")) + const originalQuery: Query = { birthdate: { lte: new Date("2005-01-01") } } + const queryResult: QueryResult = { + birthdate: { lte: { expected: new Date("2005-01-01"), result: true } }, + } + const { isCorrect, queryResultErrors } = PublicInputChecker.checkBirthdatePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(isCorrect).toBe(false) + expect(queryResultErrors.birthdate?.lte).toBeDefined() + }) + + test("fails when birthdate is not set in queryResult", () => { + const proof = makeBirthdateProof(new Date("2000-01-01"), null) + const originalQuery: Query = { birthdate: { gte: new Date("2000-01-01") } } + const queryResult: QueryResult = {} + const { isCorrect, queryResultErrors } = PublicInputChecker.checkBirthdatePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(isCorrect).toBe(false) + expect(queryResultErrors.birthdate?.disclose?.message).toContain( + "Birthdate is not set in the query result", + ) + }) + }) + + describe("checkExpiryDatePublicInputs", () => { + // Expiry date uses direct timestamps (no 1900 offset) + function makeExpiryProof(minDate: Date | null, maxDate: Date | null): ProofResult { + return { + name: "compare_expiry", + proof: "", + total: 1, + committedInputs: { + compare_expiry: { + minDateTimestamp: minDate ? Math.floor(minDate.getTime() / 1000) : 0, + maxDateTimestamp: maxDate ? Math.floor(maxDate.getTime() / 1000) : 0, + }, + }, + } + } + + test("passes when committed minDate matches queryResult gte", () => { + const date = new Date("2030-01-01") + const proof = makeExpiryProof(date, null) + const originalQuery: Query = { expiry_date: { gte: date } } + const queryResult: QueryResult = { + expiry_date: { gte: { expected: new Date("2030-01-01"), result: true } }, + } + const { isCorrect } = PublicInputChecker.checkExpiryDatePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(isCorrect).toBe(true) + }) + + test("fails when committed minDate does not match queryResult gte expected", () => { + const proof = makeExpiryProof(new Date("2025-01-01"), null) + const originalQuery: Query = { expiry_date: { gte: new Date("2030-01-01") } } + const queryResult: QueryResult = { + expiry_date: { gte: { expected: new Date("2030-01-01"), result: true } }, + } + const { isCorrect, queryResultErrors } = PublicInputChecker.checkExpiryDatePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(isCorrect).toBe(false) + expect(queryResultErrors.expiry_date?.gte).toBeDefined() + }) + + test("fails when expiry date is not set in queryResult", () => { + const proof = makeExpiryProof(new Date("2030-01-01"), null) + const originalQuery: Query = { expiry_date: { gte: new Date("2030-01-01") } } + const queryResult: QueryResult = {} + const { isCorrect, queryResultErrors } = PublicInputChecker.checkExpiryDatePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(isCorrect).toBe(false) + expect(queryResultErrors.expiry_date?.disclose?.message).toContain( + "Expiry date is not set in the query result", + ) + }) + }) + + describe("checkNationalityExclusionPublicInputs", () => { + const originalQuery: Query = { nationality: { out: ["GBR", "USA"] } } + + test("passes when country list matches queryResult expected", () => { + const queryResult: QueryResult = { + nationality: { out: { expected: ["GBR", "USA"], result: true } }, + } + const { isCorrect } = PublicInputChecker.checkNationalityExclusionPublicInputs( + originalQuery, + queryResult, + ["GBR", "USA"], + ) + expect(isCorrect).toBe(true) + }) + + test("fails when country list does not match queryResult expected", () => { + const queryResult: QueryResult = { + nationality: { out: { expected: ["GBR", "USA"], result: true } }, + } + // committed list has FRA instead of USA + const { isCorrect, queryResultErrors } = + PublicInputChecker.checkNationalityExclusionPublicInputs(originalQuery, queryResult, [ + "FRA", + "GBR", + ]) + expect(isCorrect).toBe(false) + expect(queryResultErrors.nationality?.out).toBeDefined() + }) + + test("fails when nationality out is not set in queryResult", () => { + const queryResult: QueryResult = {} + const { isCorrect, queryResultErrors } = + PublicInputChecker.checkNationalityExclusionPublicInputs(originalQuery, queryResult, [ + "GBR", + "USA", + ]) + expect(isCorrect).toBe(false) + expect(queryResultErrors.nationality?.out?.message).toContain( + "Nationality exclusion is not set", + ) + }) + + test("fails when country list is not sorted", () => { + const queryResult: QueryResult = { + nationality: { out: { expected: ["USA", "GBR"], result: true } }, + } + // Unsorted list: USA > GBR alphabetically + const { isCorrect, queryResultErrors } = + PublicInputChecker.checkNationalityExclusionPublicInputs( + { nationality: { out: ["USA", "GBR"] } }, + queryResult, + ["USA", "GBR"], + ) + expect(isCorrect).toBe(false) + expect(queryResultErrors.nationality?.out?.message).toContain("not been sorted") + }) + }) + + describe("checkNationalityInclusionPublicInputs", () => { + const originalQuery: Query = { nationality: { in: ["DEU", "FRA"] } } + + test("passes when country list matches queryResult expected", () => { + const queryResult: QueryResult = { + nationality: { in: { expected: ["DEU", "FRA"], result: true } }, + } + const { isCorrect } = PublicInputChecker.checkNationalityInclusionPublicInputs( + originalQuery, + queryResult, + ["DEU", "FRA"], + ) + expect(isCorrect).toBe(true) + }) + + test("fails when country list does not match queryResult expected", () => { + const queryResult: QueryResult = { + nationality: { in: { expected: ["DEU", "FRA"], result: true } }, + } + const { isCorrect, queryResultErrors } = + PublicInputChecker.checkNationalityInclusionPublicInputs(originalQuery, queryResult, [ + "DEU", + "ITA", + ]) + expect(isCorrect).toBe(false) + expect(queryResultErrors.nationality?.in).toBeDefined() + }) + + test("fails when nationality in is not set in queryResult", () => { + const queryResult: QueryResult = {} + const { isCorrect, queryResultErrors } = + PublicInputChecker.checkNationalityInclusionPublicInputs(originalQuery, queryResult, [ + "DEU", + "FRA", + ]) + expect(isCorrect).toBe(false) + expect(queryResultErrors.nationality?.in?.message).toContain( + "Nationality inclusion is not set", + ) + }) + }) + + describe("checkIssuingCountryExclusionPublicInputs", () => { + const originalQuery: Query = { issuing_country: { out: ["GBR", "USA"] } } + + test("passes when country list matches queryResult expected", () => { + const queryResult: QueryResult = { + issuing_country: { out: { expected: ["GBR", "USA"], result: true } }, + } + const { isCorrect } = PublicInputChecker.checkIssuingCountryExclusionPublicInputs( + originalQuery, + queryResult, + ["GBR", "USA"], + ) + expect(isCorrect).toBe(true) + }) + + test("fails when country list does not match queryResult expected", () => { + const queryResult: QueryResult = { + issuing_country: { out: { expected: ["GBR", "USA"], result: true } }, + } + const { isCorrect, queryResultErrors } = + PublicInputChecker.checkIssuingCountryExclusionPublicInputs(originalQuery, queryResult, [ + "FRA", + "GBR", + ]) + expect(isCorrect).toBe(false) + expect(queryResultErrors.issuing_country?.out).toBeDefined() + }) + + test("fails when unsorted country list", () => { + const queryResult: QueryResult = { + issuing_country: { out: { expected: ["USA", "GBR"], result: true } }, + } + const { isCorrect, queryResultErrors } = + PublicInputChecker.checkIssuingCountryExclusionPublicInputs( + { issuing_country: { out: ["USA", "GBR"] } }, + queryResult, + ["USA", "GBR"], + ) + expect(isCorrect).toBe(false) + expect(queryResultErrors.issuing_country?.out?.message).toContain("not been sorted") + }) + }) + + describe("checkIssuingCountryInclusionPublicInputs", () => { + const originalQuery: Query = { issuing_country: { in: ["DEU", "FRA"] } } + + test("passes when country list matches queryResult expected", () => { + const queryResult: QueryResult = { + issuing_country: { in: { expected: ["DEU", "FRA"], result: true } }, + } + const { isCorrect } = PublicInputChecker.checkIssuingCountryInclusionPublicInputs( + originalQuery, + queryResult, + ["DEU", "FRA"], + ) + expect(isCorrect).toBe(true) + }) + + test("fails when country list does not match queryResult expected", () => { + const queryResult: QueryResult = { + issuing_country: { in: { expected: ["DEU", "FRA"], result: true } }, + } + const { isCorrect, queryResultErrors } = + PublicInputChecker.checkIssuingCountryInclusionPublicInputs(originalQuery, queryResult, [ + "DEU", + "ITA", + ]) + expect(isCorrect).toBe(false) + expect(queryResultErrors.issuing_country?.in).toBeDefined() + }) + }) + + describe("checkBindPublicInputs", () => { + const originalQuery: Query = { + bind: { user_address: "0xabcdef", chain: "ethereum", custom_data: "hello" }, + } + + test("passes when all bound data matches", () => { + const queryResult: QueryResult = { + bind: { user_address: "0xabcdef", chain: "ethereum", custom_data: "hello" }, + } + const { isCorrect } = PublicInputChecker.checkBindPublicInputs(originalQuery, queryResult, { + user_address: "0xabcdef", + chain: "ethereum", + custom_data: "hello", + }) + expect(isCorrect).toBe(true) + }) + + test("fails when user_address in bound data does not match queryResult", () => { + const oq: Query = { + bind: { user_address: "0x999999", chain: "ethereum" }, + } + const queryResult: QueryResult = { + bind: { user_address: "0xabcdef", chain: "ethereum" }, + } + const { isCorrect, queryResultErrors } = PublicInputChecker.checkBindPublicInputs( + oq, + queryResult, + { user_address: "0x999999", chain: "ethereum" }, // proof has different address than queryResult + ) + expect(isCorrect).toBe(false) + expect(queryResultErrors.bind?.eq).toBeDefined() + }) + + test("fails when chain in bound data does not match queryResult", () => { + const oq: Query = { + bind: { user_address: "0xabcdef", chain: "ethereum" }, + } + const queryResult: QueryResult = { + bind: { user_address: "0xabcdef", chain: "optimism" }, + } + const { isCorrect, queryResultErrors } = PublicInputChecker.checkBindPublicInputs( + oq, + queryResult, + { user_address: "0xabcdef", chain: "ethereum" }, // proof has different chain than queryResult + ) + expect(isCorrect).toBe(false) + expect(queryResultErrors.bind?.eq).toBeDefined() + }) + + test("fails when custom_data in bound data does not match queryResult", () => { + const oq: Query = { + bind: { user_address: "0xabcdef", chain: "ethereum", custom_data: "world" }, + } + const queryResult: QueryResult = { + bind: { user_address: "0xabcdef", chain: "ethereum", custom_data: "hello" }, + } + const { isCorrect, queryResultErrors } = PublicInputChecker.checkBindPublicInputs( + oq, + queryResult, + { user_address: "0xabcdef", chain: "ethereum", custom_data: "world" }, // proof differs from queryResult + ) + expect(isCorrect).toBe(false) + expect(queryResultErrors.bind?.eq).toBeDefined() + }) + + test("captures all mismatches in a single error when multiple fields differ", () => { + // originalQuery matches queryResult so the originalQuery check doesn't overwrite + const oq: Query = { + bind: { user_address: "0xbbb", chain: "ethereum", custom_data: "bar" }, + } + const queryResult: QueryResult = { + bind: { user_address: "0xbbb", chain: "ethereum", custom_data: "bar" }, + } + // boundData (committed inputs) differs from queryResult on all fields + const { isCorrect, queryResultErrors } = PublicInputChecker.checkBindPublicInputs( + oq, + queryResult, + { user_address: "0xccc", chain: "arbitrum", custom_data: "baz" }, + ) + expect(isCorrect).toBe(false) + expect(queryResultErrors.bind?.eq).toBeDefined() + // The combined error message should mention all three mismatched fields + expect(queryResultErrors.bind!.eq!.message).toContain("user_address") + expect(queryResultErrors.bind!.eq!.message).toContain("chain") + expect(queryResultErrors.bind!.eq!.message).toContain("custom_data") + }) + }) + + describe("checkSanctionsExclusionPublicInputs", () => { + const originalQuery: Query = { + sanctions: { countries: "all", lists: "all", strict: false }, + } + + test("passes when root hash and strict match", async () => { + const queryResult: QueryResult = { + sanctions: { passed: true, isStrict: false }, + } + const sanctionsBuilder = { getRoot: async () => "abc123" } as unknown as SanctionsBuilder + const { isCorrect } = await PublicInputChecker.checkSanctionsExclusionPublicInputs( + originalQuery, + queryResult, + { rootHash: "abc123", isStrict: false }, + sanctionsBuilder, + ) + expect(isCorrect).toBe(true) + }) + + test("fails when root hash does not match", async () => { + const queryResult: QueryResult = { + sanctions: { passed: true, isStrict: false }, + } + const sanctionsBuilder = { getRoot: async () => "abc123" } as unknown as SanctionsBuilder + const { isCorrect, queryResultErrors } = + await PublicInputChecker.checkSanctionsExclusionPublicInputs( + originalQuery, + queryResult, + { rootHash: "wrong_root", isStrict: false }, + sanctionsBuilder, + ) + expect(isCorrect).toBe(false) + expect(queryResultErrors.sanctions?.eq?.message).toContain("sanctions registry root") + }) + + test("fails when strict mode in committed inputs does not match queryResult", async () => { + const oq: Query = { + sanctions: { countries: "all", lists: "all", strict: true }, + } + const queryResult: QueryResult = { + sanctions: { passed: true, isStrict: true }, + } + const sanctionsBuilder = { getRoot: async () => "abc123" } as unknown as SanctionsBuilder + const { isCorrect, queryResultErrors } = + await PublicInputChecker.checkSanctionsExclusionPublicInputs( + oq, + queryResult, + { rootHash: "abc123", isStrict: false }, // committed says non-strict + sanctionsBuilder, + ) + expect(isCorrect).toBe(false) + expect(queryResultErrors.sanctions?.eq?.message).toContain("strict mode") + }) + }) + + describe("checkFacematchPublicInputs", () => { + const originalQuery: Query = { facematch: { mode: "regular" } } + + function makeFacematchInputs( + overrides: Partial = {}, + ): FacematchCommittedInputs { + return { + rootKeyLeaf: APPLE_APP_ATTEST_ROOT_KEY_HASH, + environment: "production", + appIdHash: ZKPASSPORT_IOS_APP_ID_HASH, + mode: "regular", + integrityPubkeyHash: "0x0", + ...overrides, + } + } + + test("passes with valid Apple root key, production env, iOS app id", async () => { + const queryResult: QueryResult = { + facematch: { mode: "regular", passed: true }, + } + const { isCorrect } = await PublicInputChecker.checkFacematchPublicInputs( + originalQuery, + queryResult, + makeFacematchInputs(), + ) + expect(isCorrect).toBe(true) + }) + + test("passes with valid Google RSA root key and Android app id", async () => { + const queryResult: QueryResult = { + facematch: { mode: "regular", passed: true }, + } + const { isCorrect } = await PublicInputChecker.checkFacematchPublicInputs( + originalQuery, + queryResult, + makeFacematchInputs({ + rootKeyLeaf: GOOGLE_APP_ATTEST_RSA_ROOT_KEY_HASH, + appIdHash: ZKPASSPORT_ANDROID_APP_ID_HASH, + }), + ) + expect(isCorrect).toBe(true) + }) + + test("fails with invalid root key hash", async () => { + const queryResult: QueryResult = { + facematch: { mode: "regular", passed: true }, + } + const { isCorrect, queryResultErrors } = await PublicInputChecker.checkFacematchPublicInputs( + originalQuery, + queryResult, + makeFacematchInputs({ rootKeyLeaf: "0xbadkey" }), + ) + expect(isCorrect).toBe(false) + expect(queryResultErrors.facematch?.eq?.message).toContain("root key") + }) + + test("fails with non-production environment", async () => { + const queryResult: QueryResult = { + facematch: { mode: "regular", passed: true }, + } + const { isCorrect, queryResultErrors } = await PublicInputChecker.checkFacematchPublicInputs( + originalQuery, + queryResult, + makeFacematchInputs({ environment: "development" }), + ) + expect(isCorrect).toBe(false) + expect(queryResultErrors.facematch?.eq?.message).toContain("production") + }) + + test("fails with invalid app id hash", async () => { + const queryResult: QueryResult = { + facematch: { mode: "regular", passed: true }, + } + const { isCorrect, queryResultErrors } = await PublicInputChecker.checkFacematchPublicInputs( + originalQuery, + queryResult, + makeFacematchInputs({ appIdHash: "0xbadappid" }), + ) + expect(isCorrect).toBe(false) + expect(queryResultErrors.facematch?.eq?.message).toContain("app id") + }) + + test("fails when committed mode does not match queryResult mode", async () => { + const queryResult: QueryResult = { + facematch: { mode: "regular", passed: true }, + } + const { isCorrect, queryResultErrors } = await PublicInputChecker.checkFacematchPublicInputs( + originalQuery, + queryResult, + makeFacematchInputs({ mode: "strict" }), // committed says strict, queryResult says regular + ) + expect(isCorrect).toBe(false) + expect(queryResultErrors.facematch?.eq?.message).toContain("facematch mode") + }) + + test("does not check when facematch did not pass", async () => { + const queryResult: QueryResult = { + facematch: { mode: "regular", passed: false }, + } + const { isCorrect, queryResultErrors } = await PublicInputChecker.checkFacematchPublicInputs( + originalQuery, + queryResult, + makeFacematchInputs({ rootKeyLeaf: "0xbadkey" }), // invalid but should not be checked + ) + expect(isCorrect).toBe(true) + expect(queryResultErrors.facematch).not.toBeDefined() + }) + }) +}) + +/** + * Build a synthetic proof hex string from an array of field values (bigints). + * Each field becomes a 32-byte big-endian hex chunk. + * `publicInputs` are placed first, followed by `dummyProofFieldCount` zero fields. + */ +function buildProofHex(publicInputs: bigint[], dummyProofFieldCount = 10): string { + const fields = [...publicInputs, ...new Array(dummyProofFieldCount).fill(0n)] + return fields.map((v) => BigInt(v).toString(16).padStart(64, "0")).join("") +} + +/** Get today at midnight (matching what checkPublicInputs uses) */ +function getTodayTimestamp(): number { + const now = new Date() + const today = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0) + return Math.floor(today.getTime() / 1000) +} + +describe("PublicInputChecker - checkPublicInputs", () => { + // We mock checkCertificateRegistryRoot and checkCircuitRegistryRoot + // since they make on-chain RPC calls. We spy on them to return success. + + const successResult = { isCorrect: true, queryResultErrors: {} } + const originalCheckCert = PublicInputChecker.checkCertificateRegistryRoot + const originalCheckCircuit = PublicInputChecker.checkCircuitRegistryRoot + + beforeEach(() => { + // Override on-chain registry checks with mocks + ;(PublicInputChecker as unknown as Record).checkCertificateRegistryRoot = + async () => successResult + ;(PublicInputChecker as unknown as Record).checkCircuitRegistryRoot = + async () => successResult + }) + + afterEach(() => { + ;(PublicInputChecker as unknown as Record).checkCertificateRegistryRoot = + originalCheckCert + ;(PublicInputChecker as unknown as Record).checkCircuitRegistryRoot = + originalCheckCircuit + }) + + describe("non-outer proof path - commitment chain", () => { + const domain = "example.com" + const domainScopeHash = getServiceScopeHash(domain) + const todayTs = BigInt(getTodayTimestamp()) + // Shared commitment value used to link proofs + const commitment1 = 111n + const commitment2 = 222n + const commitment3 = 333n + const nullifier = 999n + + function makeDSCProof(merkleRoot: bigint, commitmentOut: bigint): ProofResult { + // DSC proof: 2 public inputs [merkleRoot, commitmentOut] + return { + name: "sig_check_dsc_1234", + proof: buildProofHex([merkleRoot, commitmentOut]), + total: 5, + } + } + + function makeIDDataProof(commitmentIn: bigint, commitmentOut: bigint): ProofResult { + // ID data proof: 2 public inputs [commitmentIn, commitmentOut] + return { + name: "sig_check_id_data_1234", + proof: buildProofHex([commitmentIn, commitmentOut]), + total: 5, + } + } + + function makeIntegrityProof(commitmentIn: bigint, commitmentOut: bigint): ProofResult { + // Integrity proof: 2 public inputs [commitmentIn, commitmentOut] + return { + name: "data_check_integrity_1234", + proof: buildProofHex([commitmentIn, commitmentOut]), + total: 5, + } + } + + async function makeAgeDisclosureProof( + commitmentIn: bigint, + opts: { minAge?: number; maxAge?: number; scope?: bigint; subscope?: bigint } = {}, + ): Promise { + // Disclosure proof: 7 public inputs + // [commitmentIn, currentDate, serviceScope, subscope, paramCommitment, nullifierType, nullifier] + const scope = opts.scope ?? domainScopeHash + const subscope = opts.subscope ?? 0n + const minAge = opts.minAge ?? 18 + const maxAge = opts.maxAge ?? 0 + const paramCommitment = await getAgeParameterCommitment(minAge, maxAge) + return { + name: "compare_age", + proof: buildProofHex([ + commitmentIn, + todayTs, + scope, + subscope, + paramCommitment, + 0n, + nullifier, + ]), + total: 5, + committedInputs: { + compare_age: { minAge, maxAge }, + }, + } + } + + test("valid commitment chain passes", async () => { + const proofs = [ + makeDSCProof(1n, commitment1), + makeIDDataProof(commitment1, commitment2), + makeIntegrityProof(commitment2, commitment3), + await makeAgeDisclosureProof(commitment3), + ] + const originalQuery: Query = { age: { gte: 18 } } + const queryResult: QueryResult = { + age: { gte: { expected: 18, result: true } }, + } + + const { queryResultErrors, uniqueIdentifier } = await PublicInputChecker.checkPublicInputs( + domain, + proofs, + originalQuery, + queryResult, + 86400 * 365, // large validity + ) + + // Commitment chain should pass; age check should pass + expect(queryResultErrors.sig_check_id_data?.commitment).toBeUndefined() + expect(queryResultErrors.data_check_integrity?.commitment).toBeUndefined() + expect(queryResultErrors.age?.commitment).toBeUndefined() + expect(uniqueIdentifier).toBe(nullifier.toString(10)) + }) + + test("broken commitment chain between DSC and ID data fails", async () => { + const proofs = [ + makeDSCProof(1n, commitment1), + makeIDDataProof(999n, commitment2), // commitmentIn doesn't match DSC's commitmentOut + makeIntegrityProof(commitment2, commitment3), + await makeAgeDisclosureProof(commitment3), + ] + const originalQuery: Query = { age: { gte: 18 } } + const queryResult: QueryResult = { + age: { gte: { expected: 18, result: true } }, + } + + const { queryResultErrors } = await PublicInputChecker.checkPublicInputs( + domain, + proofs, + originalQuery, + queryResult, + 86400 * 365, + ) + + expect(queryResultErrors.sig_check_id_data?.commitment).toBeDefined() + expect(queryResultErrors.sig_check_id_data!.commitment!.message).toContain( + "certificate signature and ID signature", + ) + }) + + test("broken commitment chain between ID data and integrity fails", async () => { + const proofs = [ + makeDSCProof(1n, commitment1), + makeIDDataProof(commitment1, commitment2), + makeIntegrityProof(999n, commitment3), // commitmentIn doesn't match + await makeAgeDisclosureProof(commitment3), + ] + const originalQuery: Query = { age: { gte: 18 } } + const queryResult: QueryResult = { + age: { gte: { expected: 18, result: true } }, + } + + const { queryResultErrors } = await PublicInputChecker.checkPublicInputs( + domain, + proofs, + originalQuery, + queryResult, + 86400 * 365, + ) + + expect(queryResultErrors.data_check_integrity?.commitment).toBeDefined() + expect(queryResultErrors.data_check_integrity!.commitment!.message).toContain( + "ID signature and the data signed", + ) + }) + + test("broken commitment chain between integrity and disclosure fails", async () => { + const proofs = [ + makeDSCProof(1n, commitment1), + makeIDDataProof(commitment1, commitment2), + makeIntegrityProof(commitment2, commitment3), + await makeAgeDisclosureProof(999n), // commitmentIn doesn't match integrity's commitmentOut + ] + const originalQuery: Query = { age: { gte: 18 } } + const queryResult: QueryResult = { + age: { gte: { expected: 18, result: true } }, + } + + const { queryResultErrors } = await PublicInputChecker.checkPublicInputs( + domain, + proofs, + originalQuery, + queryResult, + 86400 * 365, + ) + + expect(queryResultErrors.age?.commitment).toBeDefined() + expect(queryResultErrors.age!.commitment!.message).toContain("validity of the ID and the age") + }) + + test("proofs are sorted by expected order regardless of input order", async () => { + // Provide proofs in wrong order - they should be sorted internally + // Use only the signature/integrity proofs to test sorting without + // disclosure param commitment complexity + const proofs = [ + makeIntegrityProof(commitment2, commitment3), + makeDSCProof(1n, commitment1), + makeIDDataProof(commitment1, commitment2), + ] + const originalQuery: Query = {} + const queryResult: QueryResult = {} + + const { queryResultErrors } = await PublicInputChecker.checkPublicInputs( + domain, + proofs, + originalQuery, + queryResult, + 86400 * 365, + ) + + // Commitment chain between DSC → IDData → Integrity should pass + // because proofs are sorted internally + expect(queryResultErrors.sig_check_id_data?.commitment).toBeUndefined() + expect(queryResultErrors.data_check_integrity?.commitment).toBeUndefined() + }) + }) + + describe("non-outer proof path - scope validation", () => { + const domain = "example.com" + const domainScopeHash = getServiceScopeHash(domain) + const todayTs = BigInt(getTodayTimestamp()) + const commitment = 100n + const nullifier = 42n + + function makeDisclosureAge(scope: bigint, subscope: bigint): ProofResult { + return { + name: "compare_age", + proof: buildProofHex([commitment, todayTs, scope, subscope, 0n, 0n, nullifier]), + total: 1, + committedInputs: { + compare_age: { minAge: 18, maxAge: 0 }, + }, + } + } + + test("fails when proof domain scope does not match expected", async () => { + const wrongScope = getServiceScopeHash("wrong-domain.com") + const proofs = [makeDisclosureAge(wrongScope, 0n)] + const originalQuery: Query = { age: { gte: 18 } } + const queryResult: QueryResult = { + age: { gte: { expected: 18, result: true } }, + } + + const { isCorrect, queryResultErrors } = await PublicInputChecker.checkPublicInputs( + domain, + proofs, + originalQuery, + queryResult, + 86400 * 365, + ) + + expect(isCorrect).toBe(false) + expect(queryResultErrors.age?.scope?.message).toContain("different domain") + }) + + test("fails when proof subscope does not match expected", async () => { + const wrongSubscope = getScopeHash("wrong-scope") + const proofs = [makeDisclosureAge(domainScopeHash, wrongSubscope)] + const originalQuery: Query = { age: { gte: 18 } } + const queryResult: QueryResult = { + age: { gte: { expected: 18, result: true } }, + } + + const { isCorrect, queryResultErrors } = await PublicInputChecker.checkPublicInputs( + domain, + proofs, + originalQuery, + queryResult, + 86400 * 365, + "my-scope", + ) + + expect(isCorrect).toBe(false) + expect(queryResultErrors.age?.scope?.message).toContain("different scope") + }) + + test("passes when scope and subscope match", async () => { + const scopeValue = "my-scope" + const subscope = getScopeHash(scopeValue) + const proofs = [makeDisclosureAge(domainScopeHash, subscope)] + const originalQuery: Query = { age: { gte: 18 } } + const queryResult: QueryResult = { + age: { gte: { expected: 18, result: true } }, + } + + const { queryResultErrors } = await PublicInputChecker.checkPublicInputs( + domain, + proofs, + originalQuery, + queryResult, + 86400 * 365, + scopeValue, + ) + + expect(queryResultErrors.age?.scope).toBeUndefined() + }) + }) + + describe("non-outer proof path - current date validation", () => { + const domain = "example.com" + const domainScopeHash = getServiceScopeHash(domain) + const commitment = 100n + const nullifier = 42n + + test("fails when proof date is too old", async () => { + // Use a date from 30 days ago + const oldTs = BigInt(getTodayTimestamp() - 86400 * 30) + const proofs: ProofResult[] = [ + { + name: "compare_age", + proof: buildProofHex([commitment, oldTs, domainScopeHash, 0n, 0n, 0n, nullifier]), + total: 1, + committedInputs: { + compare_age: { minAge: 18, maxAge: 0 }, + }, + }, + ] + const originalQuery: Query = { age: { gte: 18 } } + const queryResult: QueryResult = { + age: { gte: { expected: 18, result: true } }, + } + + const { isCorrect, queryResultErrors } = await PublicInputChecker.checkPublicInputs( + domain, + proofs, + originalQuery, + queryResult, + 86400, // 1 day validity + ) + + expect(isCorrect).toBe(false) + expect(queryResultErrors.age?.date?.message).toContain("validity period") + }) + + test("passes when proof date is within validity period", async () => { + const recentTs = BigInt(getTodayTimestamp()) + const proofs: ProofResult[] = [ + { + name: "compare_age", + proof: buildProofHex([commitment, recentTs, domainScopeHash, 0n, 0n, 0n, nullifier]), + total: 1, + committedInputs: { + compare_age: { minAge: 18, maxAge: 0 }, + }, + }, + ] + const originalQuery: Query = { age: { gte: 18 } } + const queryResult: QueryResult = { + age: { gte: { expected: 18, result: true } }, + } + + const { queryResultErrors } = await PublicInputChecker.checkPublicInputs( + domain, + proofs, + originalQuery, + queryResult, + 86400 * 365, // large validity + ) + + expect(queryResultErrors.age?.date).toBeUndefined() + }) + + test("fails when proof date is exactly at the validity boundary", async () => { + const validitySeconds = 86400 // 1 day + // Proof date exactly `validitySeconds` ago: todayToCurrentDate == expectedDifference + // The condition is `>=`, so this should fail + const boundaryTs = BigInt(getTodayTimestamp() - validitySeconds) + const proofs: ProofResult[] = [ + { + name: "compare_age", + proof: buildProofHex([commitment, boundaryTs, domainScopeHash, 0n, 0n, 0n, nullifier]), + total: 1, + committedInputs: { + compare_age: { minAge: 18, maxAge: 0 }, + }, + }, + ] + const originalQuery: Query = { age: { gte: 18 } } + const queryResult: QueryResult = { + age: { gte: { expected: 18, result: true } }, + } + + const { isCorrect, queryResultErrors } = await PublicInputChecker.checkPublicInputs( + domain, + proofs, + originalQuery, + queryResult, + validitySeconds, + ) + + expect(isCorrect).toBe(false) + expect(queryResultErrors.age?.date?.message).toContain("validity period") + }) + + test("passes when proof date is 1 second before the validity boundary", async () => { + const validitySeconds = 86400 // 1 day + // Proof date (validitySeconds - 1) ago: todayToCurrentDate < expectedDifference + const justInsideTs = BigInt(getTodayTimestamp() - validitySeconds + 1) + const proofs: ProofResult[] = [ + { + name: "compare_age", + proof: buildProofHex([commitment, justInsideTs, domainScopeHash, 0n, 0n, 0n, nullifier]), + total: 1, + committedInputs: { + compare_age: { minAge: 18, maxAge: 0 }, + }, + }, + ] + const originalQuery: Query = { age: { gte: 18 } } + const queryResult: QueryResult = { + age: { gte: { expected: 18, result: true } }, + } + + const { queryResultErrors } = await PublicInputChecker.checkPublicInputs( + domain, + proofs, + originalQuery, + queryResult, + validitySeconds, + ) + + expect(queryResultErrors.age?.date).toBeUndefined() + }) + }) + + describe("outer proof path - current date validation", () => { + const domain = "example.com" + const domainScopeHash = getServiceScopeHash(domain) + const nullifier = 42n + + // Outer proof public inputs for `outer_4` (1 disclosure proof → 8 public inputs): + // [certRegistryRoot, circuitRegistryRoot, currentDate, serviceScope, subscope, + // paramCommitment, nullifierType, nullifier] + function makeOuterProof(currentDateTs: bigint): ProofResult { + return { + name: "outer_4", + proof: buildProofHex([ + 1n, // certRegistryRoot (mocked) + 2n, // circuitRegistryRoot (mocked) + currentDateTs, + domainScopeHash, + 0n, // subscope + 0n, // paramCommitment (will fail param check, but we're testing date) + 0n, // nullifierType + nullifier, + ]), + total: 1, + committedInputs: {}, + } + } + + test("fails when outer proof date is too old", async () => { + const oldTs = BigInt(getTodayTimestamp() - 86400 * 30) // 30 days ago + const proofs = [makeOuterProof(oldTs)] + + const { isCorrect, queryResultErrors } = await PublicInputChecker.checkPublicInputs( + domain, + proofs, + {}, + {}, + 86400, // 1 day validity + ) + + expect(isCorrect).toBe(false) + expect(queryResultErrors.outer?.date?.message).toContain("validity period") + }) + + test("passes when outer proof date is within validity period", async () => { + const recentTs = BigInt(getTodayTimestamp()) + const proofs = [makeOuterProof(recentTs)] + + const { queryResultErrors } = await PublicInputChecker.checkPublicInputs( + domain, + proofs, + {}, + {}, + 86400 * 365, // large validity + ) + + expect(queryResultErrors.outer?.date).toBeUndefined() + }) + + test("fails when outer proof date is exactly at the validity boundary", async () => { + const validitySeconds = 86400 + const boundaryTs = BigInt(getTodayTimestamp() - validitySeconds) + const proofs = [makeOuterProof(boundaryTs)] + + const { isCorrect, queryResultErrors } = await PublicInputChecker.checkPublicInputs( + domain, + proofs, + {}, + {}, + validitySeconds, + ) + + expect(isCorrect).toBe(false) + expect(queryResultErrors.outer?.date?.message).toContain("validity period") + }) + }) + + describe("non-outer proof path - nullifier extraction", () => { + const domain = "example.com" + const domainScopeHash = getServiceScopeHash(domain) + const todayTs = BigInt(getTodayTimestamp()) + const commitment = 100n + + test("returns unique identifier from disclosure proof", async () => { + const expectedNullifier = 123456789n + const proofs: ProofResult[] = [ + { + name: "compare_age", + proof: buildProofHex([ + commitment, + todayTs, + domainScopeHash, + 0n, + 0n, + 0n, // nullifier type + expectedNullifier, + ]), + total: 1, + committedInputs: { + compare_age: { minAge: 18, maxAge: 0 }, + }, + }, + ] + const originalQuery: Query = { age: { gte: 18 } } + const queryResult: QueryResult = { + age: { gte: { expected: 18, result: true } }, + } + + const { uniqueIdentifier } = await PublicInputChecker.checkPublicInputs( + domain, + proofs, + originalQuery, + queryResult, + 86400 * 365, + ) + + expect(uniqueIdentifier).toBe(expectedNullifier.toString(10)) + }) + }) + + describe("non-outer proof path - parameter commitment validation", () => { + const domain = "example.com" + const domainScopeHash = getServiceScopeHash(domain) + const todayTs = BigInt(getTodayTimestamp()) + const commitmentIn = 100n + const nullifier = 42n + + test("fails when parameter commitment does not match calculated", async () => { + // The proof has paramCommitment = 0, but the calculated one from committed inputs + // will be a real hash. This should fail the commitment check. + const proofs: ProofResult[] = [ + { + name: "compare_age", + proof: buildProofHex([ + commitmentIn, + todayTs, + domainScopeHash, + 0n, + 999n, // wrong parameter commitment + 0n, + nullifier, + ]), + total: 1, + committedInputs: { + compare_age: { minAge: 18, maxAge: 0 }, + }, + }, + ] + const originalQuery: Query = { age: { gte: 18 } } + const queryResult: QueryResult = { + age: { gte: { expected: 18, result: true } }, + } + + const { queryResultErrors } = await PublicInputChecker.checkPublicInputs( + domain, + proofs, + originalQuery, + queryResult, + 86400 * 365, + ) + + expect(queryResultErrors.age?.commitment).toBeDefined() + expect(queryResultErrors.age!.commitment!.message).toContain("conditions for the age check") + }) + }) + + describe("certificate registry root validation", () => { + const domain = "example.com" + const domainScopeHash = getServiceScopeHash(domain) + const todayTs = BigInt(getTodayTimestamp()) + const commitment = 100n + const nullifier = 42n + + test("calls checkCertificateRegistryRoot for DSC proof", async () => { + const merkleRoot = 12345n + const proofs: ProofResult[] = [ + { + name: "sig_check_dsc_1234", + proof: buildProofHex([merkleRoot, commitment]), + total: 2, + }, + { + name: "compare_age", + proof: buildProofHex([commitment, todayTs, domainScopeHash, 0n, 0n, 0n, nullifier]), + total: 2, + committedInputs: { + compare_age: { minAge: 18, maxAge: 0 }, + }, + }, + ] + const originalQuery: Query = { age: { gte: 18 } } + const queryResult: QueryResult = { + age: { gte: { expected: 18, result: true } }, + } + + await PublicInputChecker.checkPublicInputs( + domain, + proofs, + originalQuery, + queryResult, + 86400 * 365, + ) + + // Verified by the test passing without RPC errors - the mock was called + expect(true).toBe(true) + }) + + test("fails when certificate registry root is invalid", async () => { + const failResult = { + isCorrect: false, + queryResultErrors: { + sig_check_dsc: { + certificate: { + expected: "A valid root from ZKPassport Registry", + received: "Got invalid certificate registry root", + message: "The ID was signed by an unrecognized root certificate", + }, + }, + }, + } + ;(PublicInputChecker as unknown as Record).checkCertificateRegistryRoot = + async () => failResult + + const proofs: ProofResult[] = [ + { + name: "sig_check_dsc_1234", + proof: buildProofHex([999n, commitment]), + total: 2, + }, + { + name: "compare_age", + proof: buildProofHex([commitment, todayTs, domainScopeHash, 0n, 0n, 0n, nullifier]), + total: 2, + committedInputs: { + compare_age: { minAge: 18, maxAge: 0 }, + }, + }, + ] + const originalQuery: Query = { age: { gte: 18 } } + const queryResult: QueryResult = { + age: { gte: { expected: 18, result: true } }, + } + + const { isCorrect, queryResultErrors } = await PublicInputChecker.checkPublicInputs( + domain, + proofs, + originalQuery, + queryResult, + 86400 * 365, + ) + + expect(isCorrect).toBe(false) + expect(queryResultErrors.sig_check_dsc?.certificate?.message).toContain( + "unrecognized root certificate", + ) + }) + }) + + describe("non-outer proof path - bind commitment chain and scope", () => { + const domain = "example.com" + const domainScopeHash = getServiceScopeHash(domain) + const todayTs = BigInt(getTodayTimestamp()) + const commitment = 100n + const nullifier = 42n + + function makeBindProof(commitmentIn: bigint, scope: bigint = domainScopeHash): ProofResult { + return { + name: "bind", + proof: buildProofHex([commitmentIn, todayTs, scope, 0n, 0n, 0n, nullifier]), + total: 1, + committedInputs: { + bind: { + data: { user_address: "0xabc", chain: "ethereum", custom_data: "test" }, + }, + }, + } + } + + test("fails when bind proof commitmentIn does not match integrity commitmentOut", async () => { + const proofs = [makeBindProof(999n)] // wrong commitmentIn + const originalQuery: Query = { + bind: { user_address: "0xabc", chain: "ethereum", custom_data: "test" }, + } + const queryResult: QueryResult = { + bind: { user_address: "0xabc", chain: "ethereum", custom_data: "test" }, + } + + const { isCorrect, queryResultErrors } = await PublicInputChecker.checkPublicInputs( + domain, + proofs, + originalQuery, + queryResult, + 86400 * 365, + ) + + expect(isCorrect).toBe(false) + expect(queryResultErrors.bind?.commitment).toBeDefined() + expect(queryResultErrors.bind!.commitment!.message).toContain("bound data") + }) + + test("fails when bind proof domain scope does not match expected", async () => { + const wrongScope = getServiceScopeHash("wrong-domain.com") + const proofs = [makeBindProof(commitment, wrongScope)] + const originalQuery: Query = { + bind: { user_address: "0xabc", chain: "ethereum", custom_data: "test" }, + } + const queryResult: QueryResult = { + bind: { user_address: "0xabc", chain: "ethereum", custom_data: "test" }, + } + + const { isCorrect, queryResultErrors } = await PublicInputChecker.checkPublicInputs( + domain, + proofs, + originalQuery, + queryResult, + 86400 * 365, + ) + + expect(isCorrect).toBe(false) + expect(queryResultErrors.bind?.scope).toBeDefined() + expect(queryResultErrors.bind!.scope!.message).toContain("different domain") + }) + }) + + describe("non-outer proof path - sanctions commitment chain and scope", () => { + const domain = "example.com" + const domainScopeHash = getServiceScopeHash(domain) + const todayTs = BigInt(getTodayTimestamp()) + const commitment = 100n + const nullifier = 42n + + function makeSanctionsProof( + commitmentIn: bigint, + scope: bigint = domainScopeHash, + ): ProofResult { + return { + name: "exclusion_check_sanctions", + proof: buildProofHex([commitmentIn, todayTs, scope, 0n, 0n, 0n, nullifier]), + total: 1, + committedInputs: { + exclusion_check_sanctions: { rootHash: "abc", isStrict: false }, + }, + } + } + + test("fails when sanctions proof commitmentIn does not match", async () => { + const proofs = [makeSanctionsProof(999n)] + const originalQuery: Query = { + sanctions: { countries: "all", lists: "all", strict: false }, + } + const queryResult: QueryResult = { + sanctions: { passed: true, isStrict: false }, + } + + const { isCorrect, queryResultErrors } = await PublicInputChecker.checkPublicInputs( + domain, + proofs, + originalQuery, + queryResult, + 86400 * 365, + ) + + expect(isCorrect).toBe(false) + expect(queryResultErrors.sanctions?.commitment).toBeDefined() + }) + + test("fails when sanctions proof domain scope does not match expected", async () => { + const wrongScope = getServiceScopeHash("wrong-domain.com") + const proofs = [makeSanctionsProof(commitment, wrongScope)] + const originalQuery: Query = { + sanctions: { countries: "all", lists: "all", strict: false }, + } + const queryResult: QueryResult = { + sanctions: { passed: true, isStrict: false }, + } + + const { isCorrect, queryResultErrors } = await PublicInputChecker.checkPublicInputs( + domain, + proofs, + originalQuery, + queryResult, + 86400 * 365, + ) + + expect(isCorrect).toBe(false) + expect(queryResultErrors.sanctions?.scope).toBeDefined() + expect(queryResultErrors.sanctions!.scope!.message).toContain("different domain") + }) + }) + + describe("non-outer proof path - facematch commitment chain and scope", () => { + const domain = "example.com" + const domainScopeHash = getServiceScopeHash(domain) + const todayTs = BigInt(getTodayTimestamp()) + const commitment = 100n + + function makeFacematchProof( + commitmentIn: bigint, + scope: bigint = domainScopeHash, + ): ProofResult { + return { + name: "facematch_1234", + proof: buildProofHex([commitmentIn, todayTs, scope, 0n, 0n, 0n, 0n]), + total: 1, + committedInputs: { + facematch: { + rootKeyLeaf: APPLE_APP_ATTEST_ROOT_KEY_HASH, + environment: "production", + appIdHash: ZKPASSPORT_IOS_APP_ID_HASH, + mode: "regular", + integrityPubkeyHash: "0x0", + }, + }, + } + } + + test("fails when facematch proof commitmentIn does not match", async () => { + const proofs = [makeFacematchProof(999n)] + const originalQuery: Query = { facematch: { mode: "regular" } } + const queryResult: QueryResult = { + facematch: { mode: "regular", passed: true }, + } + + const { isCorrect, queryResultErrors } = await PublicInputChecker.checkPublicInputs( + domain, + proofs, + originalQuery, + queryResult, + 86400 * 365, + ) + + expect(isCorrect).toBe(false) + expect(queryResultErrors.facematch?.commitment).toBeDefined() + }) + + test("fails when facematch proof domain scope does not match expected", async () => { + const wrongScope = getServiceScopeHash("wrong-domain.com") + const proofs = [makeFacematchProof(commitment, wrongScope)] + const originalQuery: Query = { facematch: { mode: "regular" } } + const queryResult: QueryResult = { + facematch: { mode: "regular", passed: true }, + } + + const { isCorrect, queryResultErrors } = await PublicInputChecker.checkPublicInputs( + domain, + proofs, + originalQuery, + queryResult, + 86400 * 365, + ) + + expect(isCorrect).toBe(false) + expect(queryResultErrors.facematch?.scope).toBeDefined() + expect(queryResultErrors.facematch!.scope!.message).toContain("different domain") + }) + }) +}) diff --git a/packages/zkpassport-sdk/tests/query-builder.test.ts b/packages/zkpassport-sdk/tests/query-builder.test.ts index a96aa1539..2dff070f8 100644 --- a/packages/zkpassport-sdk/tests/query-builder.test.ts +++ b/packages/zkpassport-sdk/tests/query-builder.test.ts @@ -327,3 +327,119 @@ describe("Query Builder", () => { }) }) }) + +describe("createQuery (offline mode)", () => { + let zkPassport: ZkPassportVerifier + + beforeEach(() => { + zkPassport = new ZkPassportVerifier("localhost") + }) + + test("done() returns only { query } without url or callbacks", () => { + const result = zkPassport.createQuery().eq("nationality", "FRA").done() + + expect(result.query).toBeDefined() + // Should NOT have online-mode properties + expect((result as Record).url).toBeUndefined() + expect((result as Record).requestId).toBeUndefined() + expect((result as Record).onResult).toBeUndefined() + expect((result as Record).onReject).toBeUndefined() + expect((result as Record).onError).toBeUndefined() + expect((result as Record).onBridgeConnect).toBeUndefined() + expect((result as Record).onRequestReceived).toBeUndefined() + expect((result as Record).onGeneratingProof).toBeUndefined() + expect((result as Record).onProofGenerated).toBeUndefined() + expect((result as Record).isBridgeConnected).toBeUndefined() + expect((result as Record).requestReceived).toBeUndefined() + }) + + test("should build equality query", () => { + const result = zkPassport + .createQuery() + .eq("document_type", "passport") + .eq("gender", "female") + .done() + + expect(result.query).toEqual({ + document_type: { eq: "passport" }, + gender: { eq: "female" }, + }) + }) + + test("should build age comparison query", () => { + const result = zkPassport.createQuery().gte("age", 18).lt("age", 65).done() + + expect(result.query.age).toEqual({ + gte: 18, + lt: 65, + }) + }) + + test("should build disclosure request", () => { + const result = zkPassport.createQuery().disclose("fullname").disclose("birthdate").done() + + expect(result.query).toEqual({ + fullname: { disclose: true }, + birthdate: { disclose: true }, + }) + }) + + test("should build nationality inclusion/exclusion query", () => { + const result = zkPassport + .createQuery() + .in("nationality", ["FRA", "DEU"]) + .out("issuing_country", ["USA"]) + .done() + + expect(result.query.nationality).toEqual({ in: ["FRA", "DEU"] }) + expect(result.query.issuing_country).toEqual({ out: ["USA"] }) + }) + + test("should build combined query", () => { + const result = zkPassport + .createQuery() + .eq("document_type", "passport") + .gte("age", 18) + .disclose("fullname") + .in("nationality", ["FRA", "DEU"]) + .sanctions() + .done() + + expect(result.query).toEqual({ + document_type: { eq: "passport" }, + age: { gte: 18 }, + fullname: { disclose: true }, + nationality: { in: ["FRA", "DEU"] }, + sanctions: { countries: "all", lists: "all", strict: false }, + }) + }) + + test("should build sanctions query with strict mode", () => { + const result = zkPassport.createQuery().sanctions("all", "all", { strict: true }).done() + + expect(result.query.sanctions).toEqual({ + countries: "all", + lists: "all", + strict: true, + }) + }) + + test("should build bind query", () => { + const result = zkPassport + .createQuery() + .bind("user_address", "0x1234abcd") + .bind("chain", "ethereum") + .done() + + expect(result.query.bind).toEqual({ + user_address: "0x1234abcd", + chain: "ethereum", + }) + }) + + test("should build facematch query", () => { + const result = zkPassport.createQuery().facematch("strict").done() + + expect(result.query.facematch).toEqual({ mode: "strict" }) + }) +}) From a155e5da2dfa44f4f10c95c20b1e5603614fa2bf Mon Sep 17 00:00:00 2001 From: Robert Brada <44506010+robertbrada@users.noreply.github.com> Date: Wed, 8 Apr 2026 16:11:49 +0200 Subject: [PATCH 12/30] fix(sdk): Public input checkers (#169) * fix(sdk): guard document_type disclose check in public input verification * fix(sdk): account for strict comparison offset in age public input verification * fix(sdk): fix birthdate verification failing in compressed-evm mode * chore: bump sdk version --- bun.lock | 2 +- packages/registry-sdk/package.json | 2 +- .../src/public-input-checker.ts | 43 ++++++++++++- .../tests/public-input-checker.test.ts | 62 ++++++++++++++++++- 4 files changed, 102 insertions(+), 7 deletions(-) diff --git a/bun.lock b/bun.lock index 743634450..abfde746a 100644 --- a/bun.lock +++ b/bun.lock @@ -67,7 +67,7 @@ }, "packages/registry-sdk": { "name": "@zkpassport/registry", - "version": "0.13.0", + "version": "0.13.1", "dependencies": { "@zkpassport/poseidon2": "^0.6.2", "@zkpassport/utils": "workspace:*", diff --git a/packages/registry-sdk/package.json b/packages/registry-sdk/package.json index 6165ea343..ba8881e2a 100644 --- a/packages/registry-sdk/package.json +++ b/packages/registry-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@zkpassport/registry", - "version": "0.13.0", + "version": "0.13.1", "description": "Registry SDK for interacting with the ZKPassport Registry", "author": "ZKPassport", "license": "Apache-2.0", diff --git a/packages/zkpassport-sdk/src/public-input-checker.ts b/packages/zkpassport-sdk/src/public-input-checker.ts index e314521c3..85f5f3f8f 100644 --- a/packages/zkpassport-sdk/src/public-input-checker.ts +++ b/packages/zkpassport-sdk/src/public-input-checker.ts @@ -110,7 +110,10 @@ export class PublicInputChecker { }, } } - if (queryResult.document_type.disclose?.result !== disclosedDataIDCard.documentType) { + if ( + queryResult.document_type.disclose && + queryResult.document_type.disclose.result !== disclosedDataIDCard.documentType + ) { console.warn("Document type does not match the disclosed document type in query result") isCorrect = false queryResultErrors.document_type = { @@ -812,7 +815,7 @@ export class PublicInputChecker { if ( queryResult.age.gt && queryResult.age.gt.result && - minAge !== (queryResult.age.gt.expected as number) + minAge !== (queryResult.age.gt.expected as number) + 1 ) { console.warn("Age is not greater than the expected age") isCorrect = false @@ -828,7 +831,7 @@ export class PublicInputChecker { if ( queryResult.age.lt && queryResult.age.lt.result && - maxAge !== (queryResult.age.lt.expected as number) + maxAge !== (queryResult.age.lt.expected as number) - 1 ) { console.warn("Age is not less than the expected age") isCorrect = false @@ -1106,6 +1109,22 @@ export class PublicInputChecker { }, } } + if (queryResult.birthdate.gt && queryResult.birthdate.gt.result) { + const expectedPlusOneDay = new Date(queryResult.birthdate.gt.expected as Date) + expectedPlusOneDay.setDate(expectedPlusOneDay.getDate() + 1) + if (!areDatesEqual(minDate, expectedPlusOneDay)) { + console.warn("Birthdate is not greater than the expected birthdate") + isCorrect = false + queryResultErrors.birthdate = { + ...queryResultErrors.birthdate, + gt: { + expected: queryResult.birthdate.gt.expected, + received: minDate, + message: "Birthdate is not greater than the expected birthdate", + }, + } + } + } if ( queryResult.birthdate.lte && queryResult.birthdate.lte.result && @@ -1122,6 +1141,22 @@ export class PublicInputChecker { }, } } + if (queryResult.birthdate.lt && queryResult.birthdate.lt.result) { + const expectedMinusOneDay = new Date(queryResult.birthdate.lt.expected as Date) + expectedMinusOneDay.setDate(expectedMinusOneDay.getDate() - 1) + if (!areDatesEqual(maxDate, expectedMinusOneDay)) { + console.warn("Birthdate is not less than the expected birthdate") + isCorrect = false + queryResultErrors.birthdate = { + ...queryResultErrors.birthdate, + lt: { + expected: queryResult.birthdate.lt.expected, + received: maxDate, + message: "Birthdate is not less than the expected birthdate", + }, + } + } + } if (queryResult.birthdate.range) { if ( queryResult.birthdate.range.result && @@ -2274,11 +2309,13 @@ export class PublicInputChecker { ProofType.BIRTHDATE, birthdateCommittedInputs.minDateTimestamp, birthdateCommittedInputs.maxDateTimestamp, + 0, ) : await getDateParameterCommitment( ProofType.BIRTHDATE, birthdateCommittedInputs.minDateTimestamp, birthdateCommittedInputs.maxDateTimestamp, + 0, ) if (!paramCommitments.includes(birthdateParameterCommitment)) { console.warn("This proof does not verify the birthdate") diff --git a/packages/zkpassport-sdk/tests/public-input-checker.test.ts b/packages/zkpassport-sdk/tests/public-input-checker.test.ts index f8fe3fc47..116044fc9 100644 --- a/packages/zkpassport-sdk/tests/public-input-checker.test.ts +++ b/packages/zkpassport-sdk/tests/public-input-checker.test.ts @@ -869,7 +869,7 @@ describe("PublicInputChecker - committed inputs vs queryResult", () => { }) test("passes when committed maxAge matches queryResult lt", () => { - const proof = makeAgeProof(0, 65) + const proof = makeAgeProof(0, 64) const originalQuery: Query = { age: { lt: 65 } } const queryResult: QueryResult = { age: { lt: { expected: 65, result: true } }, @@ -989,7 +989,7 @@ describe("PublicInputChecker - committed inputs vs queryResult", () => { }) test("passes when committed minAge matches queryResult gt", () => { - const proof = makeAgeProof(17, 0) + const proof = makeAgeProof(18, 0) const originalQuery: Query = { age: { gt: 17 } } const queryResult: QueryResult = { age: { gt: { expected: 17, result: true } }, @@ -1177,6 +1177,64 @@ describe("PublicInputChecker - committed inputs vs queryResult", () => { expect(queryResultErrors.birthdate?.lte).toBeDefined() }) + test("passes when committed minDate matches queryResult gt (offset by +1 day)", () => { + const proof = makeBirthdateProof(new Date("1995-01-02"), null) + const originalQuery: Query = { birthdate: { gt: new Date("1995-01-01") } } + const queryResult: QueryResult = { + birthdate: { gt: { expected: new Date("1995-01-01"), result: true } }, + } + const { isCorrect } = PublicInputChecker.checkBirthdatePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(isCorrect).toBe(true) + }) + + test("fails when committed minDate does not match queryResult gt expected +1 day", () => { + const proof = makeBirthdateProof(new Date("1995-01-01"), null) + const originalQuery: Query = { birthdate: { gt: new Date("1995-01-01") } } + const queryResult: QueryResult = { + birthdate: { gt: { expected: new Date("1995-01-01"), result: true } }, + } + const { isCorrect, queryResultErrors } = PublicInputChecker.checkBirthdatePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(isCorrect).toBe(false) + expect(queryResultErrors.birthdate?.gt).toBeDefined() + }) + + test("passes when committed maxDate matches queryResult lt (offset by -1 day)", () => { + const proof = makeBirthdateProof(null, new Date("1997-12-30")) + const originalQuery: Query = { birthdate: { lt: new Date("1997-12-31") } } + const queryResult: QueryResult = { + birthdate: { lt: { expected: new Date("1997-12-31"), result: true } }, + } + const { isCorrect } = PublicInputChecker.checkBirthdatePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(isCorrect).toBe(true) + }) + + test("fails when committed maxDate does not match queryResult lt expected -1 day", () => { + const proof = makeBirthdateProof(null, new Date("1997-12-31")) + const originalQuery: Query = { birthdate: { lt: new Date("1997-12-31") } } + const queryResult: QueryResult = { + birthdate: { lt: { expected: new Date("1997-12-31"), result: true } }, + } + const { isCorrect, queryResultErrors } = PublicInputChecker.checkBirthdatePublicInputs( + proof, + originalQuery, + queryResult, + ) + expect(isCorrect).toBe(false) + expect(queryResultErrors.birthdate?.lt).toBeDefined() + }) + test("fails when birthdate is not set in queryResult", () => { const proof = makeBirthdateProof(new Date("2000-01-01"), null) const originalQuery: Query = { birthdate: { gte: new Date("2000-01-01") } } From 6ac2cc422449caf04ee3864809d23e71d8709938 Mon Sep 17 00:00:00 2001 From: saleel Date: Sun, 26 Apr 2026 10:13:25 +0400 Subject: [PATCH 13/30] feat(sdk): Update oprf utils, add oprf params to input generators (#173) * feat: update oprf utils, add oprf params to input generators * chore: add tests for public inputs indexes * chore: cleanup oprf client * chore: bump version numbers * chore: remove padding in proof parse --- bun.lock | 43 +++------ packages/registry-sdk/package.json | 6 +- packages/registry-sdk/src/mock-client.ts | 51 ++++++++++ packages/registry-sdk/tsup.config.ts | 2 +- packages/zkpassport-sdk/package.json | 4 +- packages/zkpassport-sdk/src/index.ts | 77 ++++++++++++--- .../src/public-input-checker.ts | 46 +++++++++ .../zkpassport-sdk/src/solidity-verifier.ts | 3 + packages/zkpassport-sdk/src/types.ts | 4 + .../tests/public-input-checker.test.ts | 2 + packages/zkpassport-utils/package.json | 7 +- .../zkpassport-utils/src/circuit-matcher.ts | 95 ++++++++++++++++++- .../zkpassport-utils/src/circuits/index.ts | 14 ++- packages/zkpassport-utils/src/index.ts | 1 + packages/zkpassport-utils/src/oprf/client.ts | 80 ++++++++++++++++ .../zkpassport-utils/src/oprf/constants.ts | 38 ++++++++ packages/zkpassport-utils/src/oprf/index.ts | 15 +++ packages/zkpassport-utils/src/oprf/mock.ts | 69 ++++++++++++++ packages/zkpassport-utils/src/oprf/types.ts | 34 +++++++ .../zkpassport-utils/src/recursion.test.ts | 84 ++++++++++++++++ packages/zkpassport-utils/src/recursion.ts | 11 ++- packages/zkpassport-utils/src/types/index.ts | 2 + .../tests/circuit-matcher.test.ts | 19 ++++ packages/zkpassport-utils/tsup.config.ts | 1 + 24 files changed, 650 insertions(+), 58 deletions(-) create mode 100644 packages/registry-sdk/src/mock-client.ts create mode 100644 packages/zkpassport-utils/src/oprf/client.ts create mode 100644 packages/zkpassport-utils/src/oprf/constants.ts create mode 100644 packages/zkpassport-utils/src/oprf/index.ts create mode 100644 packages/zkpassport-utils/src/oprf/mock.ts create mode 100644 packages/zkpassport-utils/src/oprf/types.ts create mode 100644 packages/zkpassport-utils/src/recursion.test.ts diff --git a/bun.lock b/bun.lock index abfde746a..cef0e6729 100644 --- a/bun.lock +++ b/bun.lock @@ -67,7 +67,7 @@ }, "packages/registry-sdk": { "name": "@zkpassport/registry", - "version": "0.13.1", + "version": "0.14.0-beta.1", "dependencies": { "@zkpassport/poseidon2": "^0.6.2", "@zkpassport/utils": "workspace:*", @@ -84,9 +84,9 @@ }, "packages/zkpassport-sdk": { "name": "@zkpassport/sdk", - "version": "0.13.0", + "version": "0.14.0-beta.1", "dependencies": { - "@aztec/bb.js": "2.0.3", + "@aztec/bb.js": "4.2.0-aztecnr-rc.2", "@noble/ciphers": "^1.2.1", "@noble/hashes": "^2.0.1", "@noble/secp256k1": "^2.2.3", @@ -110,7 +110,7 @@ }, "packages/zkpassport-utils": { "name": "@zkpassport/utils", - "version": "0.35.0", + "version": "0.36.0-beta.1", "dependencies": { "@lapo/asn1js": "^2.0.4", "@noble/ciphers": "^1.0.0", @@ -123,6 +123,7 @@ "@peculiar/asn1-schema": "^2.3.15", "@peculiar/asn1-x509": "^2.3.15", "@peculiar/x509": "^1.12.3", + "@taceo/oprf-client": "^0.9.0", "@zk-kit/utils": "^1.2.1", "@zkpassport/poseidon2": "^0.6.2", "date-fns": "^4.1.0", @@ -145,7 +146,7 @@ "@arethetypeswrong/core": ["@arethetypeswrong/core@0.18.2", "", { "dependencies": { "@andrewbranch/untar.js": "^1.0.3", "@loaderkit/resolve": "^1.0.2", "cjs-module-lexer": "^1.2.3", "fflate": "^0.8.2", "lru-cache": "^11.0.1", "semver": "^7.5.4", "typescript": "5.6.1-rc", "validate-npm-package-name": "^5.0.0" } }, "sha512-GiwTmBFOU1/+UVNqqCGzFJYfBXEytUkiI+iRZ6Qx7KmUVtLm00sYySkfe203C9QtPG11yOz1ZaMek8dT/xnlgg=="], - "@aztec/bb.js": ["@aztec/bb.js@2.0.3", "", { "dependencies": { "comlink": "^4.4.1", "commander": "^12.1.0", "idb-keyval": "^6.2.1", "msgpackr": "^1.11.2", "pako": "^2.1.0", "pino": "^9.5.0", "tslib": "^2.4.0" }, "bin": { "bb.js": "dest/node/main.js" } }, "sha512-sI8lA2L8RMACsi6iBtcuKgGLx4crMzoAaTNtfP3VAaOpjoIwB3O/AMETz5IDGdkOA6tOqM2R0nWh1J+wDYPlVQ=="], + "@aztec/bb.js": ["@aztec/bb.js@4.2.0-aztecnr-rc.2", "", { "dependencies": { "comlink": "^4.4.1", "commander": "^12.1.0", "idb-keyval": "^6.2.1", "msgpackr": "^1.11.2", "pako": "^2.1.0", "tslib": "^2.4.0" }, "bin": { "bb": "dest/node/bin/index.js" } }, "sha512-ksFWHrm8QYAXP059paItEKCM/UhpHg5Dwl/eSp2BI6EAtD9+JlonkOwJ+94TYai2y5Gz0qnrgd65dsvDwJelVQ=="], "@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], @@ -341,8 +342,6 @@ "@peculiar/x509": ["@peculiar/x509@1.14.3", "", { "dependencies": { "@peculiar/asn1-cms": "^2.6.0", "@peculiar/asn1-csr": "^2.6.0", "@peculiar/asn1-ecc": "^2.6.0", "@peculiar/asn1-pkcs9": "^2.6.0", "@peculiar/asn1-rsa": "^2.6.0", "@peculiar/asn1-schema": "^2.6.0", "@peculiar/asn1-x509": "^2.6.0", "pvtsutils": "^1.3.6", "reflect-metadata": "^0.2.2", "tslib": "^2.8.1", "tsyringe": "^4.10.0" } }, "sha512-C2Xj8FZ0uHWeCXXqX5B4/gVFQmtSkiuOolzAgutjTfseNOHT3pUjljDZsTSxXFGgio54bCzVFqmEOUrIVk8RDA=="], - "@pinojs/redact": ["@pinojs/redact@0.4.0", "", {}, "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg=="], - "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], "@pkgr/core": ["@pkgr/core@0.2.9", "", {}, "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA=="], @@ -477,6 +476,12 @@ "@swc/helpers": ["@swc/helpers@0.5.5", "", { "dependencies": { "@swc/counter": "^0.1.3", "tslib": "^2.4.0" } }, "sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A=="], + "@taceo/oprf-client": ["@taceo/oprf-client@0.9.0", "", { "dependencies": { "@noble/curves": "^2.0.1", "@noble/hashes": "^2.0.1", "@taceo/oprf-core": "0.4.0" } }, "sha512-kokCCLYjLSH3I7n4D2Yhg1ybNquMRnbHh3r/YTgHIiXxJ+FLsbE9AGT8vhwTmwe2m4X1U3r57yKMsIiaeu/DAg=="], + + "@taceo/oprf-core": ["@taceo/oprf-core@0.4.0", "", { "dependencies": { "@noble/curves": "^2.0.1", "@noble/hashes": "^2.0.1", "@taceo/poseidon2": "0.2.0" } }, "sha512-Mlo2pjb8O9HDGvjpcun06ZWrW7oBblQESr9EDhW1WvHLDkKDgdlKdx43EVzJMGHcFXaVT4/1MnC1De/5KTQTNg=="], + + "@taceo/poseidon2": ["@taceo/poseidon2@0.2.0", "", { "dependencies": { "@noble/curves": "^2.0.1" } }, "sha512-+EyFO7zaRrlsdzNEvzTLELDkrgjUgZgSlxGUSQghmmtlZ14nZklYX7D+gecyOkVe/47AGDtA+uZ9sdXiNB8rng=="], + "@trysound/sax": ["@trysound/sax@0.2.0", "", {}, "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA=="], "@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="], @@ -651,8 +656,6 @@ "async-function": ["async-function@1.0.0", "", {}, "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA=="], - "atomic-sleep": ["atomic-sleep@1.0.0", "", {}, "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="], - "available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="], "axe-core": ["axe-core@4.11.1", "", {}, "sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A=="], @@ -1189,8 +1192,6 @@ "object.values": ["object.values@1.2.1", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" } }, "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA=="], - "on-exit-leak-free": ["on-exit-leak-free@2.1.2", "", {}, "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA=="], - "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], @@ -1233,12 +1234,6 @@ "pify": ["pify@2.3.0", "", {}, "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog=="], - "pino": ["pino@9.14.0", "", { "dependencies": { "@pinojs/redact": "^0.4.0", "atomic-sleep": "^1.0.0", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^5.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "sonic-boom": "^4.0.1", "thread-stream": "^3.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-8OEwKp5juEvb/MjpIc4hjqfgCNysrS94RIOMXYvpYCdm/jglrKEiAYmiumbmGhCvs+IcInsphYDFwqrjr7398w=="], - - "pino-abstract-transport": ["pino-abstract-transport@2.0.0", "", { "dependencies": { "split2": "^4.0.0" } }, "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw=="], - - "pino-std-serializers": ["pino-std-serializers@7.1.0", "", {}, "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw=="], - "pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], "pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], @@ -1267,8 +1262,6 @@ "pretty-format": ["pretty-format@30.2.0", "", { "dependencies": { "@jest/schemas": "30.0.5", "ansi-styles": "^5.2.0", "react-is": "^18.3.1" } }, "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA=="], - "process-warning": ["process-warning@5.0.0", "", {}, "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA=="], - "prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], "publint": ["publint@0.3.17", "", { "dependencies": { "@publint/pack": "^0.1.3", "package-manager-detector": "^1.6.0", "picocolors": "^1.1.1", "sade": "^1.8.1" }, "bin": { "publint": "src/cli.js" } }, "sha512-Q3NLegA9XM6usW+dYQRG1g9uEHiYUzcCVBJDJ7yMcWRqVU9LYZUWdqbwMZfmTCFC5PZLQpLAmhvRcQRl3exqkw=="], @@ -1281,8 +1274,6 @@ "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], - "quick-format-unescaped": ["quick-format-unescaped@4.0.4", "", {}, "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="], - "react": ["react@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ=="], "react-dom": ["react-dom@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" }, "peerDependencies": { "react": "^18.3.1" } }, "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw=="], @@ -1305,8 +1296,6 @@ "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], - "real-require": ["real-require@0.2.0", "", {}, "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg=="], - "reflect-metadata": ["reflect-metadata@0.2.2", "", {}, "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q=="], "reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="], @@ -1343,8 +1332,6 @@ "safe-regex-test": ["safe-regex-test@1.1.0", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-regex": "^1.2.1" } }, "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw=="], - "safe-stable-stringify": ["safe-stable-stringify@2.5.0", "", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="], - "scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="], "semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], @@ -1373,14 +1360,10 @@ "slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], - "sonic-boom": ["sonic-boom@4.2.0", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww=="], - "source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], - "split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="], - "stable-hash": ["stable-hash@0.0.5", "", {}, "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA=="], "stack-utils": ["stack-utils@2.0.6", "", { "dependencies": { "escape-string-regexp": "^2.0.0" } }, "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ=="], @@ -1443,8 +1426,6 @@ "thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="], - "thread-stream": ["thread-stream@3.1.0", "", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A=="], - "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], diff --git a/packages/registry-sdk/package.json b/packages/registry-sdk/package.json index ba8881e2a..77205a8c3 100644 --- a/packages/registry-sdk/package.json +++ b/packages/registry-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@zkpassport/registry", - "version": "0.13.1", + "version": "0.14.0-beta.1", "description": "Registry SDK for interacting with the ZKPassport Registry", "author": "ZKPassport", "license": "Apache-2.0", @@ -17,6 +17,10 @@ ".": { "import": "./dist/esm/index.js", "require": "./dist/cjs/index.cjs" + }, + "./mock": { + "import": "./dist/esm/mock-client.js", + "require": "./dist/cjs/mock-client.cjs" } }, "scripts": { diff --git a/packages/registry-sdk/src/mock-client.ts b/packages/registry-sdk/src/mock-client.ts new file mode 100644 index 000000000..b0e647c2b --- /dev/null +++ b/packages/registry-sdk/src/mock-client.ts @@ -0,0 +1,51 @@ +import type { CircuitManifest, PackagedCircuit } from "@zkpassport/utils" +import { RegistryClient } from "./client" +import type { RegistryClientOptions } from "./types" + +/** + * MockRegistryClient that extends RegistryClient, overriding only the circuit + * artifact methods to fetch from a local HTTP server. + * Warning: This is only meant for development purposes. + */ +export class MockRegistryClient extends RegistryClient { + private readonly mockBaseUrl: string + + constructor(options: Partial & { baseUrl?: string } = {}) { + super({ chainId: 11155111, ...options }) + const envMockRegistryUrl = (globalThis as { MOCK_REGISTRY_URL?: string })?.MOCK_REGISTRY_URL + this.mockBaseUrl = options.baseUrl ?? envMockRegistryUrl ?? "http://localhost:8080" + + console.log("Mock Registry Base URL:", this.mockBaseUrl) + } + + override async getCircuitManifest( + _root?: string, + _options?: { validate?: boolean; ipfs?: boolean; version?: string }, + ): Promise { + const response = await fetch(`${this.mockBaseUrl}/manifest.json`) + if (!response.ok) { + throw new Error(`Failed to fetch circuit manifest from ${this.mockBaseUrl}`) + } + return response.json() + } + + override async getPackagedCircuit( + circuitName: string, + _manifest?: CircuitManifest, + _options?: { validate?: boolean; ipfs?: boolean }, + ): Promise { + const response = await fetch(`${this.mockBaseUrl}/circuits/${circuitName}.json`) + if (!response.ok) { + throw new Error(`Failed to fetch circuit ${circuitName} from ${this.mockBaseUrl}`) + } + const circuit = await response.json() + if (!circuit) { + throw new Error(`Empty response for circuit ${circuitName}`) + } + return circuit + } + + override async isCircuitRootValid(_root: string, _timestamp?: number): Promise { + return true + } +} diff --git a/packages/registry-sdk/tsup.config.ts b/packages/registry-sdk/tsup.config.ts index a1ab2b8ec..99de0eb29 100644 --- a/packages/registry-sdk/tsup.config.ts +++ b/packages/registry-sdk/tsup.config.ts @@ -4,7 +4,7 @@ const isDev = process.env.DEV_BUILD === "true" export default defineConfig( (["esm", "cjs"] as const).map((format) => ({ - entry: ["src/index.ts"], + entry: ["src/index.ts", "src/mock-client.ts"], dts: { compilerOptions: { composite: false, diff --git a/packages/zkpassport-sdk/package.json b/packages/zkpassport-sdk/package.json index 581c6fefc..77757cb75 100644 --- a/packages/zkpassport-sdk/package.json +++ b/packages/zkpassport-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@zkpassport/sdk", - "version": "0.13.0", + "version": "0.14.0-beta.1", "description": "Privacy-preserving identity verification using passports and ID cards", "author": "ZKPassport", "license": "Apache-2.0", @@ -40,7 +40,7 @@ "sdk" ], "dependencies": { - "@aztec/bb.js": "2.0.3", + "@aztec/bb.js": "4.2.0-aztecnr-rc.2", "@noble/ciphers": "^1.2.1", "@noble/hashes": "^2.0.1", "@noble/secp256k1": "^2.2.3", diff --git a/packages/zkpassport-sdk/src/index.ts b/packages/zkpassport-sdk/src/index.ts index 12e008834..6929bf20a 100644 --- a/packages/zkpassport-sdk/src/index.ts +++ b/packages/zkpassport-sdk/src/index.ts @@ -20,11 +20,13 @@ import { getProofData, getNumberOfPublicInputs, formatQueryResultDates, + OPRF_DEFAULT_KEY_ID, } from "@zkpassport/utils" import { noLogger as logger } from "./logger" import i18en from "i18n-iso-countries/langs/en.json" import { Buffer } from "buffer/" import { RegistryClient } from "@zkpassport/registry" +// import { MockRegistryClient as RegistryClient } from "@zkpassport/registry/mock" import { Bridge, BridgeInterface } from "@obsidion/bridge" import { QueryBuilder, @@ -133,6 +135,8 @@ export class ZKPassport { validity: number mode: ProofMode devMode: boolean + uniqueIdentifierType: NullifierType | undefined + oprfKeyId: string | null } > = {} private topicToPublicKey: Record = {} @@ -152,6 +156,7 @@ export class ZKPassport { Array< (response: { uniqueIdentifier: string | undefined + uniqueIdentifierType: NullifierType | undefined verified: boolean result: QueryResult queryResultErrors?: Partial @@ -192,14 +197,16 @@ export class ZKPassport { // Clear the results straight away to avoid concurrency issues delete this.topicToResults[topic] // Verify the proofs and extract the unique identifier (aka nullifier) and the verification result - const { uniqueIdentifier, verified, queryResultErrors } = await this.verify({ - proofs: this.topicToProofs[topic], - originalQuery: this.topicToConfig[topic], - queryResult: result, - validity: this.topicToLocalConfig[topic]?.validity, - scope: this.topicToService[topic]?.scope, - devMode: this.topicToLocalConfig[topic]?.devMode, - }) + const { uniqueIdentifier, uniqueIdentifierType, verified, queryResultErrors } = + await this.verify({ + proofs: this.topicToProofs[topic], + originalQuery: this.topicToConfig[topic], + queryResult: result, + validity: this.topicToLocalConfig[topic]?.validity, + scope: this.topicToService[topic]?.scope, + devMode: this.topicToLocalConfig[topic]?.devMode, + oprfKeyId: this.topicToLocalConfig[topic]?.oprfKeyId ?? undefined, + }) delete this.topicToProofs[topic] const hasFailedProofs = this.topicToFailedProofCount[topic] > 0 await Promise.all( @@ -208,6 +215,7 @@ export class ZKPassport { // If there are failed proofs, we don't return the unique identifier // and we set the verified result to false uniqueIdentifier: hasFailedProofs ? undefined : uniqueIdentifier, + uniqueIdentifierType: hasFailedProofs ? undefined : uniqueIdentifierType, verified: hasFailedProofs ? false : verified, result, queryResultErrors, @@ -398,6 +406,28 @@ export class ZKPassport { delete this.topicToConfig[topic] return { query } } + + const localConfig = this.topicToLocalConfig[topic] + const query = this.topicToConfig[topic] + const hasStrictFacematch = !!query.facematch && query.facematch?.mode === "strict" + + // If nullifier type wasn't explicitly set, default to SALTED only for strict facematch + if (localConfig.uniqueIdentifierType === undefined) { + if (hasStrictFacematch) { + localConfig.uniqueIdentifierType = NullifierType.SALTED + if (!localConfig.oprfKeyId) { + localConfig.oprfKeyId = OPRF_DEFAULT_KEY_ID + } + } + } + + // Validate: SALTED requires strict facematch + if (localConfig.uniqueIdentifierType === NullifierType.SALTED && !hasStrictFacematch) { + throw new Error( + "Salted nullifier requires strict facematch. Add .facematch('strict') to your query or remove the salted nullifier option.", + ) + } + return { url: this._getUrl(topic), query: this.topicToConfig[topic], @@ -413,6 +443,7 @@ export class ZKPassport { onResult: ( callback: (response: { uniqueIdentifier: string | undefined + uniqueIdentifierType: NullifierType | undefined verified: boolean result: QueryResult queryResultErrors?: Partial @@ -448,6 +479,8 @@ export class ZKPassport { mode, validity, devMode, + uniqueIdentifierType, + oprfKeyId, topicOverride, keyPairOverride, cloudProverUrl, @@ -461,6 +494,8 @@ export class ZKPassport { projectID?: string validity?: number devMode?: boolean + uniqueIdentifierType?: NullifierType.NON_SALTED | NullifierType.SALTED + oprfKeyId?: string topicOverride?: string keyPairOverride?: { privateKey: Uint8Array; publicKey: Uint8Array } cloudProverUrl?: string @@ -494,6 +529,8 @@ export class ZKPassport { validity: validity || DEFAULT_VALIDITY, mode: mode || "fast", devMode: devMode || false, + uniqueIdentifierType: oprfKeyId ? NullifierType.SALTED : uniqueIdentifierType, + oprfKeyId: oprfKeyId ?? null, } this.onRequestReceivedCallbacks[topic] = [] @@ -558,6 +595,7 @@ export class ZKPassport { scope, devMode = false, writingDirectory, + oprfKeyId, }: { proofs: Array originalQuery: Query @@ -566,6 +604,7 @@ export class ZKPassport { scope?: string devMode?: boolean writingDirectory?: string + oprfKeyId?: string }): Promise<{ uniqueIdentifier: string | undefined uniqueIdentifierType: NullifierType | undefined @@ -583,15 +622,16 @@ export class ZKPassport { } const formattedResult: QueryResult = formatQueryResultDates(queryResult) - const { UltraHonkVerifierBackend } = await import("@aztec/bb.js") + const { UltraHonkVerifierBackend, Barretenberg } = await import("@aztec/bb.js") // Automatically set the writing directory to `/tmp` if it is not provided // and the code is not running in the browser if (typeof window === "undefined" && !writingDirectory) { writingDirectory = "/tmp" } - const verifier = new UltraHonkVerifierBackend({ + const barretenberg = await Barretenberg.new({ crsPath: writingDirectory ? writingDirectory + "/.bb-crs" : undefined, }) + const verifier = new UltraHonkVerifierBackend(barretenberg) let verified = true let uniqueIdentifier: string | undefined let uniqueIdentifierType: NullifierType | undefined @@ -608,6 +648,7 @@ export class ZKPassport { formattedResult, validity, scope, + oprfKeyId, ) uniqueIdentifier = uniqueIdentifierFromPublicInputs uniqueIdentifierType = uniqueIdentifierTypeFromPublicInputs @@ -643,8 +684,6 @@ export class ZKPassport { proofName, circuitManifest, // TODO: set to always validate when the issue is vkey hash calculation is fixed - // Not as important anyway, as the solidity verifier is the ultimate anchor for - // EVM outer proofs verification { validate: !isOuterEVM }, ) if (isOuterEVM) { @@ -683,7 +722,7 @@ export class ZKPassport { verificationKey: new Uint8Array(vkeyBytes), }) } catch (e) { - console.warn("Error verifying proof", e) + console.warn(`Error verifying proof ${proofName}`, e) verified = false } } @@ -694,6 +733,7 @@ export class ZKPassport { } } } + // If the proofs are not verified, we don't return the unique identifier uniqueIdentifier = verified ? uniqueIdentifier : undefined uniqueIdentifierType = verified ? uniqueIdentifierType : undefined @@ -746,7 +786,16 @@ export class ZKPassport { // The timestamp is the current time minus the validity period // essentially, the data integrity check proof needs to have been generated after the timestamp const timestamp = Math.floor(Date.now() / 1000) - this.topicToLocalConfig[requestId].validity - return `https://zkpassport.id/r?d=${this.domain}&t=${requestId}&c=${base64Config}&s=${base64Service}&p=${pubkey}&m=${this.topicToLocalConfig[requestId].mode}&v=${VERSION}&dt=${timestamp}&dev=${this.topicToLocalConfig[requestId].devMode ? "1" : "0"}` + const nullifierType = this.topicToLocalConfig[requestId].uniqueIdentifierType + const oprfKeyId = this.topicToLocalConfig[requestId].oprfKeyId + let url = `https://zkpassport.id/r?d=${this.domain}&t=${requestId}&c=${base64Config}&s=${base64Service}&p=${pubkey}&m=${this.topicToLocalConfig[requestId].mode}&v=${VERSION}&dt=${timestamp}&dev=${this.topicToLocalConfig[requestId].devMode ? "1" : "0"}` + if (nullifierType) { + url += `&nt=${nullifierType}` + } + if (oprfKeyId) { + url += `&oprf_k=${oprfKeyId}` + } + return url } /** diff --git a/packages/zkpassport-sdk/src/public-input-checker.ts b/packages/zkpassport-sdk/src/public-input-checker.ts index 85f5f3f8f..fc9963faf 100644 --- a/packages/zkpassport-sdk/src/public-input-checker.ts +++ b/packages/zkpassport-sdk/src/public-input-checker.ts @@ -63,10 +63,15 @@ import { getNullifierTypeFromDisclosureProof, getServiceScopeFromDisclosureProof, getServiceSubScopeFromDisclosureProof, + getOprfPkHashFromDisclosureProof, + OPRF_DEFAULT_KEY_ID, + getOprfPublicKey, + hashOprfPublicKey, Query, } from "@zkpassport/utils" import { QueryResultErrors } from "./types" import { RegistryClient } from "@zkpassport/registry" +// import { MockRegistryClient as RegistryClient } from "@zkpassport/registry/mock" import { APPLE_APP_ATTEST_ROOT_KEY_HASH, DEFAULT_DATE_VALUE, @@ -1877,6 +1882,7 @@ export class PublicInputChecker { if (!isValid) { console.warn("The proof uses unrecognized circuits") isCorrect = false + if (!queryResultErrors.outer) queryResultErrors.outer = {} queryResultErrors.outer.circuit = { expected: `A valid circuit from ZKPassport Registry`, received: `Got invalid circuit registry root: ${root}`, @@ -1887,6 +1893,7 @@ export class PublicInputChecker { console.warn(error) console.warn("The proof uses unrecognized circuits") isCorrect = false + if (!queryResultErrors.outer) queryResultErrors.outer = {} queryResultErrors.outer.circuit = { expected: `A valid circuit from ZKPassport Registry`, received: `Got invalid circuit registry root: ${root}`, @@ -2139,6 +2146,7 @@ export class PublicInputChecker { queryResult: QueryResult, validity?: number, scope?: string, + oprfKeyId?: string, ) { let commitmentIn: bigint | undefined let commitmentOut: bigint | undefined @@ -3491,6 +3499,44 @@ export class PublicInputChecker { // uniqueIdentifierType = getNullifierTypeFromDisclosureProof(proofData) } } + + // Verify OPRF public key if the proof uses a salted nullifier + if ( + isCorrect && + uniqueIdentifierType && + (uniqueIdentifierType === NullifierType.SALTED || + uniqueIdentifierType === NullifierType.SALTED_MOCK) + ) { + try { + const oprfPk = await getOprfPublicKey(oprfKeyId ?? OPRF_DEFAULT_KEY_ID) + const expectedPkHash = await hashOprfPublicKey(oprfPk) + + // Find a disclosure proof to extract oprfPkHash from + const disclosureProof = sortedProofs.find( + (p) => + p.name && + !p.name.startsWith("sig_check_") && + !p.name.startsWith("data_check_") && + !p.name.startsWith("outer") && + !p.name.startsWith("facematch"), + ) + if (disclosureProof) { + const dpData = getProofData( + disclosureProof.proof as string, + getNumberOfPublicInputs(disclosureProof.name!), + ) + const proofPkHash = getOprfPkHashFromDisclosureProof(dpData) + if (proofPkHash !== expectedPkHash) { + console.warn("OPRF public key hash mismatch: proof uses an unknown OPRF key") + isCorrect = false + } + } + } catch (error) { + console.warn("Failed to verify OPRF public key:", error) + isCorrect = false + } + } + return { isCorrect, uniqueIdentifier, uniqueIdentifierType, queryResultErrors } } } diff --git a/packages/zkpassport-sdk/src/solidity-verifier.ts b/packages/zkpassport-sdk/src/solidity-verifier.ts index c4698ca0a..a7b948cce 100644 --- a/packages/zkpassport-sdk/src/solidity-verifier.ts +++ b/packages/zkpassport-sdk/src/solidity-verifier.ts @@ -11,6 +11,7 @@ import { formatBoundData, getCommittedInputCount, getNumberOfPublicInputs, + getOprfPkHashFromOuterProof, getParamCommitmentsFromOuterProof, getProofData, numberToBytesBE, @@ -245,6 +246,7 @@ export class SolidityVerifier { ...numberToBytesBE(versionParts[2], 2), ]) const versionBytes32 = `0x${bytesToHex(versionBytes).padEnd(64, "0")}` + const oprfPkHash = getOprfPkHashFromOuterProof(proofData) const params: SolidityVerifierParameters = { version: versionBytes32, proofVerificationData: { @@ -260,6 +262,7 @@ export class SolidityVerifier { scope: scope ?? "", devMode, }, + oprfPkHash: `0x${oprfPkHash.toString(16).padStart(64, "0")}`, } return params } diff --git a/packages/zkpassport-sdk/src/types.ts b/packages/zkpassport-sdk/src/types.ts index b675abef1..38c5d351b 100644 --- a/packages/zkpassport-sdk/src/types.ts +++ b/packages/zkpassport-sdk/src/types.ts @@ -3,6 +3,7 @@ import { IDCredential, IDCredentialValue, NumericalIDCredential, + NullifierType, QueryResult, SanctionsCountries, SanctionsLists, @@ -64,6 +65,8 @@ export type SolidityVerifierParameters = { proofVerificationData: SolidityProofVerificationData committedInputs: string serviceConfig: SolidityServiceConfig + /** Hash of the OPRF public key used in the proof. Check this against the OPRF key registry on-chain. Zero for non-salted nullifiers. */ + oprfPkHash: string } export type QueryBuilderResult = { @@ -115,6 +118,7 @@ export type QueryBuilderResult = { onResult: ( callback: (response: { uniqueIdentifier: string | undefined + uniqueIdentifierType: NullifierType | undefined verified: boolean result: QueryResult queryResultErrors?: Partial diff --git a/packages/zkpassport-sdk/tests/public-input-checker.test.ts b/packages/zkpassport-sdk/tests/public-input-checker.test.ts index 116044fc9..9f97a03d4 100644 --- a/packages/zkpassport-sdk/tests/public-input-checker.test.ts +++ b/packages/zkpassport-sdk/tests/public-input-checker.test.ts @@ -1742,6 +1742,8 @@ describe("PublicInputChecker - committed inputs vs queryResult", () => { * Build a synthetic proof hex string from an array of field values (bigints). * Each field becomes a 32-byte big-endian hex chunk. * `publicInputs` are placed first, followed by `dummyProofFieldCount` zero fields. + * Layout: [public_inputs][proof_body] — no prefix (matches normalised format + * consumed by `getProofData` with default offset 0). */ function buildProofHex(publicInputs: bigint[], dummyProofFieldCount = 10): string { const fields = [...publicInputs, ...new Array(dummyProofFieldCount).fill(0n)] diff --git a/packages/zkpassport-utils/package.json b/packages/zkpassport-utils/package.json index cf45ec340..65efd7475 100644 --- a/packages/zkpassport-utils/package.json +++ b/packages/zkpassport-utils/package.json @@ -1,6 +1,6 @@ { "name": "@zkpassport/utils", - "version": "0.35.0", + "version": "0.36.0-beta.1", "repository": { "type": "git", "url": "https://github.com/zkpassport/zkpassport-packages", @@ -77,6 +77,10 @@ "./types": { "import": "./dist/esm/types/index.js", "require": "./dist/cjs/types/index.cjs" + }, + "./oprf": { + "import": "./dist/esm/oprf/index.js", + "require": "./dist/cjs/oprf/index.cjs" } }, "scripts": { @@ -102,6 +106,7 @@ "@lapo/asn1js": "^2.0.4", "@noble/ciphers": "^1.0.0", "@noble/curves": "^2.0.1", + "@taceo/oprf-client": "^0.9.0", "@noble/hashes": "^2.0.1", "@noble/secp256k1": "^2.1.0", "@peculiar/asn1-cms": "^2.3.15", diff --git a/packages/zkpassport-utils/src/circuit-matcher.ts b/packages/zkpassport-utils/src/circuit-matcher.ts index 6b1415701..afb28a252 100644 --- a/packages/zkpassport-utils/src/circuit-matcher.ts +++ b/packages/zkpassport-utils/src/circuit-matcher.ts @@ -78,6 +78,7 @@ import { getLastNameRange, getNationalityRange, } from "./passport/getters" +import { type OPRFProof, OPRF_ZERO_PROOF } from "./oprf" import { SanctionsBuilder } from "./circuits/sanctions" export { SanctionsBuilder } @@ -775,7 +776,12 @@ export async function getDiscloseCircuitInputs( service_scope: bigint = 0n, service_subscope: bigint = 0n, currentDateTimestamp: number, + oprfProof: OPRFProof = OPRF_ZERO_PROOF, ) { + if (nullifierSecret !== 0n && !oprfProof) { + throw new Error("OPRF proof is required when nullifier secret is not 0") + } + const idData = await getIDDataInputs(passport) if (!idData) return null const privateNullifier = await calculatePrivateNullifier( @@ -863,6 +869,7 @@ export async function getDiscloseCircuitInputs( service_scope: `0x${service_scope.toString(16)}`, service_subscope: `0x${service_subscope.toString(16)}`, nullifier_secret: `0x${nullifierSecret.toString(16)}`, + oprf_proof: oprfProof, } } @@ -888,7 +895,12 @@ export async function getAgeCircuitInputs( service_scope: bigint = 0n, service_subscope: bigint = 0n, currentDateTimestamp: number, + oprfProof: OPRFProof = OPRF_ZERO_PROOF, ): Promise { + if (nullifierSecret !== 0n && !oprfProof) { + throw new Error("OPRF proof is required when nullifier secret is not 0") + } + const idData = await getIDDataInputs(passport) if (!idData) return null const privateNullifier = await calculatePrivateNullifier( @@ -945,6 +957,7 @@ export async function getAgeCircuitInputs( min_age_required: minAge, max_age_required: maxAge, nullifier_secret: `0x${nullifierSecret.toString(16)}`, + oprf_proof: oprfProof, } } @@ -964,7 +977,12 @@ export async function getNationalityInclusionCircuitInputs( service_scope: bigint = 0n, service_subscope: bigint = 0n, currentDateTimestamp: number, + oprfProof: OPRFProof = OPRF_ZERO_PROOF, ): Promise { + if (nullifierSecret !== 0n && !oprfProof) { + throw new Error("OPRF proof is required when nullifier secret is not 0") + } + const idData = await getIDDataInputs(passport) if (!idData) return null const privateNullifier = await calculatePrivateNullifier( @@ -991,6 +1009,7 @@ export async function getNationalityInclusionCircuitInputs( service_scope: `0x${service_scope.toString(16)}`, service_subscope: `0x${service_subscope.toString(16)}`, nullifier_secret: `0x${nullifierSecret.toString(16)}`, + oprf_proof: oprfProof, } } @@ -1002,7 +1021,12 @@ export async function getIssuingCountryInclusionCircuitInputs( service_scope: bigint = 0n, service_subscope: bigint = 0n, currentDateTimestamp: number, + oprfProof: OPRFProof = OPRF_ZERO_PROOF, ): Promise { + if (nullifierSecret !== 0n && !oprfProof) { + throw new Error("OPRF proof is required when nullifier secret is not 0") + } + const idData = await getIDDataInputs(passport) if (!idData) return null const privateNullifier = await calculatePrivateNullifier( @@ -1029,6 +1053,7 @@ export async function getIssuingCountryInclusionCircuitInputs( service_scope: `0x${service_scope.toString(16)}`, service_subscope: `0x${service_subscope.toString(16)}`, nullifier_secret: `0x${nullifierSecret.toString(16)}`, + oprf_proof: oprfProof, } } @@ -1040,7 +1065,12 @@ export async function getNationalityExclusionCircuitInputs( service_scope: bigint = 0n, service_subscope: bigint = 0n, currentDateTimestamp: number, + oprfProof: OPRFProof = OPRF_ZERO_PROOF, ): Promise { + if (nullifierSecret !== 0n && !oprfProof) { + throw new Error("OPRF proof is required when nullifier secret is not 0") + } + const idData = await getIDDataInputs(passport) if (!idData) return null const privateNullifier = await calculatePrivateNullifier( @@ -1077,6 +1107,7 @@ export async function getNationalityExclusionCircuitInputs( service_scope: `0x${service_scope.toString(16)}`, service_subscope: `0x${service_subscope.toString(16)}`, nullifier_secret: `0x${nullifierSecret.toString(16)}`, + oprf_proof: oprfProof, } } @@ -1088,6 +1119,7 @@ export async function getIssuingCountryExclusionCircuitInputs( service_scope: bigint = 0n, service_subscope: bigint = 0n, currentDateTimestamp: number, + oprfProof: OPRFProof = OPRF_ZERO_PROOF, ): Promise { const idData = await getIDDataInputs(passport) if (!idData) return null @@ -1125,6 +1157,7 @@ export async function getIssuingCountryExclusionCircuitInputs( service_scope: `0x${service_scope.toString(16)}`, service_subscope: `0x${service_subscope.toString(16)}`, nullifier_secret: `0x${nullifierSecret.toString(16)}`, + oprf_proof: oprfProof, } } @@ -1136,8 +1169,13 @@ export async function getSanctionsExclusionCheckCircuitInputs( service_scope: bigint = 0n, service_subscope: bigint = 0n, currentDateTimestamp: number, + oprfProof: OPRFProof = OPRF_ZERO_PROOF, sanctions?: SanctionsBuilder, // Optional sanctions builder so it can be reused if already instantiated ): Promise { + if (nullifierSecret !== 0n && !oprfProof) { + throw new Error("OPRF proof is required when nullifier secret is not 0") + } + const idData = await getIDDataInputs(passport) if (!idData) return null const privateNullifier = await calculatePrivateNullifier( @@ -1170,6 +1208,7 @@ export async function getSanctionsExclusionCheckCircuitInputs( service_scope: `0x${service_scope.toString(16)}`, service_subscope: `0x${service_subscope.toString(16)}`, nullifier_secret: `0x${nullifierSecret.toString(16)}`, + oprf_proof: oprfProof, } } @@ -1181,7 +1220,12 @@ export async function getBirthdateCircuitInputs( service_scope: bigint = 0n, service_subscope: bigint = 0n, currentDateTimestamp: number, + oprfProof: OPRFProof = OPRF_ZERO_PROOF, ): Promise { + if (nullifierSecret !== 0n && !oprfProof) { + throw new Error("OPRF proof is required when nullifier secret is not 0") + } + const idData = await getIDDataInputs(passport) if (!idData) return null const privateNullifier = await calculatePrivateNullifier( @@ -1241,6 +1285,7 @@ export async function getBirthdateCircuitInputs( min_date: minDate ? getUnixTimestamp(minDate) + SECONDS_BETWEEN_1900_AND_1970 : 0, max_date: maxDate ? getUnixTimestamp(maxDate) + SECONDS_BETWEEN_1900_AND_1970 : 0, nullifier_secret: `0x${nullifierSecret.toString(16)}`, + oprf_proof: oprfProof, } } @@ -1252,7 +1297,12 @@ export async function getExpiryDateCircuitInputs( service_scope: bigint = 0n, service_subscope: bigint = 0n, currentDateTimestamp: number, + oprfProof: OPRFProof = OPRF_ZERO_PROOF, ): Promise { + if (nullifierSecret !== 0n && !oprfProof) { + throw new Error("OPRF proof is required when nullifier secret is not 0") + } + const idData = await getIDDataInputs(passport) if (!idData) return null const privateNullifier = await calculatePrivateNullifier( @@ -1309,6 +1359,7 @@ export async function getExpiryDateCircuitInputs( min_date: minDate ? getUnixTimestamp(minDate) : 0, max_date: maxDate ? getUnixTimestamp(maxDate) : 0, nullifier_secret: `0x${nullifierSecret.toString(16)}`, + oprf_proof: oprfProof, } } @@ -1320,6 +1371,7 @@ export async function getBindCircuitInputs( service_scope: bigint = 0n, service_subscope: bigint = 0n, currentDateTimestamp: number, + oprfProof: OPRFProof = OPRF_ZERO_PROOF, hideSensitiveInputs: boolean = false, ): Promise { const idData = await getIDDataInputs(passport) @@ -1356,6 +1408,7 @@ export async function getBindCircuitInputs( service_scope: `0x${service_scope.toString(16)}`, service_subscope: `0x${service_subscope.toString(16)}`, nullifier_secret: `0x${nullifierSecret.toString(16)}`, + oprf_proof: oprfProof, } } @@ -1387,7 +1440,8 @@ export async function getFacematchCircuitInputs( privateNullifier.toBigInt(), ) - if (!query.facematch) throw new Error("Facematch query is required") + // Default to regular mode when facematch is auto-generated (e.g. for SALTED nullifier without explicit facematch query) + const facematchMode = query.facematch?.mode ?? "regular" return { ...(await getSaltedValuesForDisclosureCircuit( @@ -1402,9 +1456,46 @@ export async function getFacematchCircuitInputs( service_scope: `0x${service_scope.toString(16)}`, service_subscope: `0x${service_subscope.toString(16)}`, // FACEMATCH_MODE_REGULAR (1) or FACEMATCH_MODE_STRICT (2) - facematch_mode: query.facematch.mode === "regular" ? 1 : 2, + facematch_mode: facematchMode === "regular" ? 1 : 2, // APP_ATTEST_ENV_DEVELOPMENT (0) or APP_ATTEST_ENV_PRODUCTION (1) environment: 1, nullifier_secret: `0x${nullifierSecret.toString(16)}`, } } + +/** + * Generate circuit inputs for the oprf_auth circuit. + * This circuit proves the blinded OPRF query was derived from the committed DG2 hash. + */ +export async function getOprfAuthCircuitInputs( + passport: PassportViewModel, + salts: IntegrityToDisclosureSalts, + beta: bigint, +): Promise { + const idData = await getIDDataInputs(passport) + if (!idData) throw new Error("Error getting ID data inputs") + const privateNullifier = await calculatePrivateNullifier( + Binary.from(idData.dg1).padEnd(DG1_INPUT_SIZE), + Binary.from(idData.e_content).padEnd(E_CONTENT_INPUT_SIZE), + Binary.from( + processSodSignature(passport?.sod.signerInfo.signature.toNumberArray() ?? [], passport), + ), + ) + const commIn = await hashSaltDg1Dg2HashPrivateNullifier( + salts, + Binary.from(idData.dg1).padEnd(DG1_INPUT_SIZE), + passport.passportExpiry, + idData.dg2_hash_normalized, + idData.dg2_hash_type, + privateNullifier.toBigInt(), + ) + + return { + inputs: { + ...(await getSaltedValuesForDisclosureCircuit(passport, idData, privateNullifier, salts)), + comm_in: commIn.toHex(), + beta: `0x${beta.toString(16)}`, + }, + privateNullifier: privateNullifier.toBigInt(), + } +} diff --git a/packages/zkpassport-utils/src/circuits/index.ts b/packages/zkpassport-utils/src/circuits/index.ts index 7d47e37dd..bf2619229 100644 --- a/packages/zkpassport-utils/src/circuits/index.ts +++ b/packages/zkpassport-utils/src/circuits/index.ts @@ -105,11 +105,15 @@ export async function hashSaltDg1Dg2HashPrivateNullifier( } export function getNullifierFromDisclosureProof(proofData: ProofData): bigint { + return BigInt(proofData.publicInputs[proofData.publicInputs.length - 2]) +} + +export function getOprfPkHashFromDisclosureProof(proofData: ProofData): bigint { return BigInt(proofData.publicInputs[proofData.publicInputs.length - 1]) } export function getNullifierTypeFromDisclosureProof(proofData: ProofData): NullifierType { - const nullifierType = BigInt(proofData.publicInputs[proofData.publicInputs.length - 2]) + const nullifierType = BigInt(proofData.publicInputs[proofData.publicInputs.length - 3]) if (nullifierType === 0n) { return NullifierType.NON_SALTED } else if (nullifierType === 1n) { @@ -186,14 +190,16 @@ export function getNumberOfPublicInputs(circuitName: string) { return getIDDataProofPublicInputCount() } else if (circuitName.startsWith("sig_check_dsc")) { return getDSCProofPublicInputCount() + } else if (circuitName.startsWith("oprf_auth")) { + return 3 } else if (circuitName.startsWith("outer")) { // Get the characters after the last underscore const disclosureProofCount = Number(circuitName.substring(circuitName.lastIndexOf("_") + 1)) - 3 - return 7 + disclosureProofCount + return 8 + disclosureProofCount } // Any other circuits are assumed to be disclosure circuits - // which have a universal interface of 7 public inputs - return 7 + // which have a universal interface of 8 public inputs + return 8 } export function getCommittedInputCount(circuitName: DisclosureCircuitName) { diff --git a/packages/zkpassport-utils/src/index.ts b/packages/zkpassport-utils/src/index.ts index 64c82b248..c931aee22 100644 --- a/packages/zkpassport-utils/src/index.ts +++ b/packages/zkpassport-utils/src/index.ts @@ -14,3 +14,4 @@ export * from "./types" export * from "./utils" export * from "./registry" export * from "./country/country" +export * from "./oprf" diff --git a/packages/zkpassport-utils/src/oprf/client.ts b/packages/zkpassport-utils/src/oprf/client.ts new file mode 100644 index 000000000..ffaac6800 --- /dev/null +++ b/packages/zkpassport-utils/src/oprf/client.ts @@ -0,0 +1,80 @@ +import { poseidon2HashAsync } from "@zkpassport/poseidon2" +import { toOprfUri, distributedOprf } from "@taceo/oprf-client" +import { + OPRF_DEFAULT_SERVICES, + OPRF_DEFAULT_THRESHOLD, + OPRF_DEFAULT_MODULE, + OPRF_DEFAULT_DOMAIN_SEPARATOR, +} from "./constants" +import { evaluateMock } from "./mock" +import type { OPRFEvaluatorAuth, OPRFEvaluatorOptions, OPRFPublicKey, OPRFResult } from "./types" + +export async function evaluateOPRF( + privateNullifier: bigint, + blindingFactor: bigint, + auth: OPRFEvaluatorAuth, + options: OPRFEvaluatorOptions = {}, +): Promise { + if (options.mock) { + const sk = typeof options.mock === "object" ? options.mock.secretKey : undefined + return evaluateMock(privateNullifier, sk) + } + + const baseUrls = options.services ?? OPRF_DEFAULT_SERVICES + const threshold = options.threshold ?? OPRF_DEFAULT_THRESHOLD + const domainSeparator = options.domainSeparator ?? OPRF_DEFAULT_DOMAIN_SEPARATOR + const services = baseUrls.map((url) => toOprfUri(url, options.moduleName ?? OPRF_DEFAULT_MODULE)) + + const result = await distributedOprf( + services, + threshold, + privateNullifier, // query + blindingFactor, + domainSeparator, + auth, + ) + const pk = result.oprfPublicKey + const dlogProof = result.dlogProof + const blindedResponse = result.blindedResponse + const response = result.unblindedResponse + const oprfOutput = result.output + + return { + oprfProof: { + pk: { x: toHex(pk.x), y: toHex(pk.y) }, + dlog_e: toHex(dlogProof.e), + dlog_s: toHex(dlogProof.s), + response_blinded: { x: toHex(blindedResponse.x), y: toHex(blindedResponse.y) }, + response: { x: toHex(response.x), y: toHex(response.y) }, + beta: toHex(blindingFactor), + }, + oprfOutput, + publicKey: pk, + } +} + +function toHex(v: bigint): string { + return `0x${v.toString(16)}` +} + +export async function getOprfPublicKey(keyId: string, services?: string[]): Promise { + const baseUrls = services ?? OPRF_DEFAULT_SERVICES + let lastError: Error | undefined + for (const baseUrl of baseUrls) { + try { + const response = await fetch(`${baseUrl}/oprf_pub/${keyId}`) + if (!response.ok) { + throw new Error(`OPRF node returned ${response.status}`) + } + const { key } = (await response.json()) as { key: [string, string]; epoch: number } + return { x: BigInt(key[0]), y: BigInt(key[1]) } + } catch (error) { + lastError = error instanceof Error ? error : new Error(String(error)) + } + } + throw new Error(`Failed to fetch OPRF public key for key ID ${keyId}: ${lastError?.message}`) +} + +export async function hashOprfPublicKey(pk: OPRFPublicKey): Promise { + return poseidon2HashAsync([pk.x, pk.y]) +} diff --git a/packages/zkpassport-utils/src/oprf/constants.ts b/packages/zkpassport-utils/src/oprf/constants.ts new file mode 100644 index 000000000..f01fdd8c4 --- /dev/null +++ b/packages/zkpassport-utils/src/oprf/constants.ts @@ -0,0 +1,38 @@ +import type { OPRFProof, OPRFPublicKey } from "./types" + +// Default OPRF service configuration +// TODO: Update the URLS +export const OPRF_DEFAULT_SERVICES = [ + "https://oprf.zkpassport.id", + "https://oprf-2.zkpassport.id", + "https://oprf-3.zkpassport.id", +] + +export const OPRF_DEFAULT_KEY_ID = "1" +export const OPRF_DEFAULT_THRESHOLD = 2 +export const OPRF_DEFAULT_MODULE = "face-match" +export const OPRF_DEFAULT_DOMAIN_SEPARATOR = 1330664006n // matching oprf-nr library + +// TODO: Replace with the real OPRF public key for OPRF_DEFAULT_KEY_ID once the DKG ceremony +// has produced the global default key. The DEFAULT_OPRF_PUB_KEY_HASH below must be kept +// consistent with this value (enforced by a unit test). +export const DEFAULT_OPRF_PUB_KEY: OPRFPublicKey = { + x: 1n, + y: 2n, +} + +// Poseidon2 hash of [DEFAULT_OPRF_PUB_KEY.x, DEFAULT_OPRF_PUB_KEY.y]. +// Same hash computed by Noir circuits on the OPRF public key, and by app smart contracts +// when validating the `oprf_pk_hash` public input against this default. +export const DEFAULT_OPRF_PUB_KEY_HASH = + 1594597865669602199208529098208508950092942746041644072252494753744672355203n + +// Default zero OPRF proof for non-salted nullifier mode +export const OPRF_ZERO_PROOF: OPRFProof = { + pk: { x: "0", y: "0" }, + dlog_e: "0", + dlog_s: "0", + response_blinded: { x: "0", y: "0" }, + response: { x: "0", y: "0" }, + beta: "0", +} diff --git a/packages/zkpassport-utils/src/oprf/index.ts b/packages/zkpassport-utils/src/oprf/index.ts new file mode 100644 index 000000000..d35168c00 --- /dev/null +++ b/packages/zkpassport-utils/src/oprf/index.ts @@ -0,0 +1,15 @@ +export { evaluateOPRF, getOprfPublicKey, hashOprfPublicKey } from "./client" +export { generateOPRFKeypair } from "./mock" +export type { + OPRFEvaluatorOptions as OPRFOptions, + OPRFResult, + OPRFProof, + OPRFPublicKey, +} from "./types" +export { + OPRF_ZERO_PROOF, + OPRF_DEFAULT_KEY_ID, + DEFAULT_OPRF_PUB_KEY, + DEFAULT_OPRF_PUB_KEY_HASH, +} from "./constants" +export { randomBlindingFactor } from "@taceo/oprf-core" diff --git a/packages/zkpassport-utils/src/oprf/mock.ts b/packages/zkpassport-utils/src/oprf/mock.ts new file mode 100644 index 000000000..baaae92c3 --- /dev/null +++ b/packages/zkpassport-utils/src/oprf/mock.ts @@ -0,0 +1,69 @@ +import { babyjubjub } from "@noble/curves/misc.js" +import { + blindQuery, + randomBlindingFactor, + prepareBlindingFactor, + unblindResponse, + finalizeOutput, + dlogEqualityProof, + Fr, + BABYJUBJUB_SUBGROUP_GENERATOR_AFFINE, +} from "@taceo/oprf-core" +import type { OPRFProof, OPRFResult } from "./types" +import { OPRF_DEFAULT_DOMAIN_SEPARATOR } from "./constants" + +const G = babyjubjub.Point.fromAffine(BABYJUBJUB_SUBGROUP_GENERATOR_AFFINE) +const SCALAR_ORDER = Fr.ORDER + +function toHex(value: bigint): string { + return `0x${value.toString(16)}` +} + +function randomScalar(): bigint { + const bytes = new Uint8Array(32) + if (typeof globalThis.crypto !== "undefined" && globalThis.crypto.getRandomValues) { + globalThis.crypto.getRandomValues(bytes) + } else { + // eslint-disable-next-line @typescript-eslint/no-require-imports + const { randomBytes } = require("crypto") + const buf = randomBytes(32) as Buffer + bytes.set(buf) + } + let scalar = BigInt("0x" + Buffer.from(bytes).toString("hex")) % SCALAR_ORDER + if (scalar === 0n) scalar = 1n + return scalar +} + +export function generateOPRFKeypair(): { sk: bigint; pk: { x: bigint; y: bigint } } { + const sk = randomScalar() + const pkPoint = G.multiply(sk).toAffine() + return { sk, pk: { x: pkPoint.x, y: pkPoint.y } } +} + +export async function evaluateMock(dg2Hash: bigint, secretKey?: bigint): Promise { + const sk = secretKey ?? randomScalar() + const pk = G.multiply(sk).toAffine() + + // blind + const beta = randomBlindingFactor() + const blindedQuery = blindQuery(dg2Hash, beta) + + // evaluate + proof (server) + const responseBlinded = babyjubjub.Point.fromAffine(blindedQuery).multiply(sk).toAffine() + const proof = dlogEqualityProof(blindedQuery, sk) + + // unblind + finalize + const response = unblindResponse(responseBlinded, prepareBlindingFactor(beta)) + const oprfOutput = finalizeOutput(OPRF_DEFAULT_DOMAIN_SEPARATOR, dg2Hash, response) + + const oprfProof: OPRFProof = { + pk: { x: toHex(pk.x), y: toHex(pk.y) }, + dlog_e: toHex(proof.e), + dlog_s: toHex(proof.s), + response_blinded: { x: toHex(responseBlinded.x), y: toHex(responseBlinded.y) }, + response: { x: toHex(response.x), y: toHex(response.y) }, + beta: toHex(beta), + } + + return { oprfProof, oprfOutput, publicKey: pk } +} diff --git a/packages/zkpassport-utils/src/oprf/types.ts b/packages/zkpassport-utils/src/oprf/types.ts new file mode 100644 index 000000000..9d524e135 --- /dev/null +++ b/packages/zkpassport-utils/src/oprf/types.ts @@ -0,0 +1,34 @@ +import { ProofResult } from "@/types" + +export type OPRFEvaluatorAuth = { + oprf_key_id: string + proofs: ProofResult[] +} + +export type OPRFEvaluatorOptions = { + services?: string[] + threshold?: number + moduleName?: string + domainSeparator?: bigint + mock?: boolean | { secretKey: bigint } +} + +export type OPRFProof = { + pk: { x: string; y: string } + dlog_e: string + dlog_s: string + response_blinded: { x: string; y: string } + response: { x: string; y: string } + beta: string +} + +export type OPRFPublicKey = { + x: bigint + y: bigint +} + +export type OPRFResult = { + oprfProof: OPRFProof + oprfOutput: bigint + publicKey: OPRFPublicKey +} diff --git a/packages/zkpassport-utils/src/recursion.test.ts b/packages/zkpassport-utils/src/recursion.test.ts new file mode 100644 index 000000000..bf4b1a2b7 --- /dev/null +++ b/packages/zkpassport-utils/src/recursion.test.ts @@ -0,0 +1,84 @@ +import { NullifierType, ProofData } from "." +import { + getNullifierTypeFromOuterProof, + getNullifierFromOuterProof, + getOprfPkHashFromOuterProof, + getParamCommitmentsFromOuterProof, +} from "./recursion" + +// Trailing public inputs layout (last 3 elements, in order): +// [length-3] nullifier_type +// [length-2] scoped_nullifier +// [length-1] oprf_pk_hash +// Header (first 5 elements) is: certificate_registry_root, circuit_registry_root, +// current_date, service_scope, service_subscope. +// Anything between header and trailing is the param_commitments slice. + +function buildProofData( + paramCommitments: string[], + nullifierType: bigint, + scopedNullifier: string, + oprfPkHash: string, +): ProofData { + const header = [ + "0x01", // certificate_registry_root + "0x02", // circuit_registry_root + "0x03", // current_date + "0x04", // service_scope + "0x05", // service_subscope + ] + const trailing = [`0x${nullifierType.toString(16)}`, scopedNullifier, oprfPkHash] + return { + publicInputs: [...header, ...paramCommitments, ...trailing], + proof: [], + } +} + +describe("outer proof public inputs", () => { + const PARAM_COMMITMENTS = ["0xaa", "0xbb", "0xcc"] + const SCOPED_NULLIFIER = "0xdead" + const OPRF_PK_HASH = "0xbeef" + + test("getNullifierTypeFromOuterProof reads length-3", () => { + const cases: Array<[bigint, NullifierType]> = [ + [0n, NullifierType.NON_SALTED], + [1n, NullifierType.SALTED], + [2n, NullifierType.NON_SALTED_MOCK], + [3n, NullifierType.SALTED_MOCK], + ] + for (const [raw, expected] of cases) { + const proof = buildProofData(PARAM_COMMITMENTS, raw, SCOPED_NULLIFIER, OPRF_PK_HASH) + expect(getNullifierTypeFromOuterProof(proof)).toEqual(expected) + } + }) + + test("getNullifierTypeFromOuterProof throws on invalid type", () => { + const proof = buildProofData(PARAM_COMMITMENTS, 4n, SCOPED_NULLIFIER, OPRF_PK_HASH) + expect(() => getNullifierTypeFromOuterProof(proof)).toThrow("Invalid nullifier type") + }) + + test("getNullifierFromOuterProof reads length-2 (scoped_nullifier, not oprf_pk_hash)", () => { + const proof = buildProofData(PARAM_COMMITMENTS, 1n, SCOPED_NULLIFIER, OPRF_PK_HASH) + expect(getNullifierFromOuterProof(proof)).toEqual(BigInt(SCOPED_NULLIFIER)) + expect(getNullifierFromOuterProof(proof)).not.toEqual(BigInt(OPRF_PK_HASH)) + }) + + test("getOprfPkHashFromOuterProof reads length-1", () => { + const proof = buildProofData(PARAM_COMMITMENTS, 1n, SCOPED_NULLIFIER, OPRF_PK_HASH) + expect(getOprfPkHashFromOuterProof(proof)).toEqual(BigInt(OPRF_PK_HASH)) + }) + + test("getParamCommitmentsFromOuterProof excludes all 3 trailing fields", () => { + const proof = buildProofData(PARAM_COMMITMENTS, 1n, SCOPED_NULLIFIER, OPRF_PK_HASH) + const result = getParamCommitmentsFromOuterProof(proof) + expect(result).toEqual(PARAM_COMMITMENTS.map(BigInt)) + expect(result).not.toContain(1n) // nullifier_type + expect(result).not.toContain(BigInt(SCOPED_NULLIFIER)) + expect(result).not.toContain(BigInt(OPRF_PK_HASH)) + }) + + test("getParamCommitmentsFromOuterProof handles empty param commitments", () => { + const proof = buildProofData([], 0n, SCOPED_NULLIFIER, OPRF_PK_HASH) + expect(getParamCommitmentsFromOuterProof(proof)).toEqual([]) + }) +}) diff --git a/packages/zkpassport-utils/src/recursion.ts b/packages/zkpassport-utils/src/recursion.ts index 8309fbb81..77c5822cb 100644 --- a/packages/zkpassport-utils/src/recursion.ts +++ b/packages/zkpassport-utils/src/recursion.ts @@ -39,6 +39,7 @@ export function getOuterCircuitInputs( const subscope = disclosureProofWithNonZeroNullifier.publicInputs[3] const nullifierType = disclosureProofWithNonZeroNullifier.publicInputs[5] const nullifier = disclosureProofWithNonZeroNullifier.publicInputs[6] + const oprfPkHash = disclosureProofWithNonZeroNullifier.publicInputs[7] const paramCommitments = disclosureProofs.map((proof) => proof.publicInputs[4]) return { @@ -50,6 +51,7 @@ export function getOuterCircuitInputs( param_commitments: paramCommitments, scoped_nullifier: nullifier, nullifier_type: nullifierType, + oprf_pk_hash: oprfPkHash, csc_to_dsc_proof: { vkey: cscToDscProof.vkey, proof: cscToDscProof.proof, @@ -119,7 +121,7 @@ export function getSubscopeFromOuterProof(proofData: ProofData): bigint { } export function getNullifierTypeFromOuterProof(proofData: ProofData): NullifierType { - const nullifierType = BigInt(proofData.publicInputs[proofData.publicInputs.length - 2]) + const nullifierType = BigInt(proofData.publicInputs[proofData.publicInputs.length - 3]) if (nullifierType === 0n) { return NullifierType.NON_SALTED } else if (nullifierType === 1n) { @@ -138,6 +140,10 @@ export function getNullifierTypeFromOuterProof(proofData: ProofData): NullifierT * @returns The scoped nullifier. */ export function getNullifierFromOuterProof(proofData: ProofData): bigint { + return BigInt(proofData.publicInputs[proofData.publicInputs.length - 2]) +} + +export function getOprfPkHashFromOuterProof(proofData: ProofData): bigint { return BigInt(proofData.publicInputs[proofData.publicInputs.length - 1]) } @@ -147,5 +153,6 @@ export function getNullifierFromOuterProof(proofData: ProofData): bigint { * @returns The param commitments. */ export function getParamCommitmentsFromOuterProof(proofData: ProofData): bigint[] { - return proofData.publicInputs.slice(5, proofData.publicInputs.length - 2).map(BigInt) + // Trailing public inputs (in order): nullifier_type, scoped_nullifier, oprf_pk_hash. + return proofData.publicInputs.slice(5, proofData.publicInputs.length - 3).map(BigInt) } diff --git a/packages/zkpassport-utils/src/types/index.ts b/packages/zkpassport-utils/src/types/index.ts index 129928f9b..ed6570977 100644 --- a/packages/zkpassport-utils/src/types/index.ts +++ b/packages/zkpassport-utils/src/types/index.ts @@ -422,6 +422,8 @@ export type QRCodeData = { sdkVersion: string | null timestamp: number | null devMode: boolean | null + uniqueIdentifierType: NullifierType | null + oprfKeyId: string | null } export interface JsonRpcRequest { diff --git a/packages/zkpassport-utils/tests/circuit-matcher.test.ts b/packages/zkpassport-utils/tests/circuit-matcher.test.ts index a9c89a39b..037fd4e6c 100644 --- a/packages/zkpassport-utils/tests/circuit-matcher.test.ts +++ b/packages/zkpassport-utils/tests/circuit-matcher.test.ts @@ -47,6 +47,7 @@ import { SanctionsBuilder, SECONDS_BETWEEN_1900_AND_1970, HASH_ALGORITHM_SHA256, + OPRF_ZERO_PROOF, } from "../src" import { DSC } from "../src/passport/dsc" import { AsnParser } from "@peculiar/asn1-schema" @@ -438,6 +439,7 @@ describe("Circuit Matcher - RSA", () => { service_scope: EXPECTED_SERVICE_SCOPE, service_subscope: EXPECTED_SERVICE_SUBSCOPE, nullifier_secret: EXPECTED_NULLIFIER_SECRET, + oprf_proof: OPRF_ZERO_PROOF, }) }) @@ -482,6 +484,7 @@ describe("Circuit Matcher - RSA", () => { min_age_required: 18, max_age_required: 0, nullifier_secret: EXPECTED_NULLIFIER_SECRET, + oprf_proof: OPRF_ZERO_PROOF, }) }) @@ -519,6 +522,7 @@ describe("Circuit Matcher - RSA", () => { service_scope: EXPECTED_SERVICE_SCOPE, service_subscope: EXPECTED_SERVICE_SUBSCOPE, nullifier_secret: EXPECTED_NULLIFIER_SECRET, + oprf_proof: OPRF_ZERO_PROOF, }) }) @@ -559,6 +563,7 @@ describe("Circuit Matcher - RSA", () => { service_scope: EXPECTED_SERVICE_SCOPE, service_subscope: EXPECTED_SERVICE_SUBSCOPE, nullifier_secret: EXPECTED_NULLIFIER_SECRET, + oprf_proof: OPRF_ZERO_PROOF, }) }) @@ -596,6 +601,7 @@ describe("Circuit Matcher - RSA", () => { service_scope: EXPECTED_SERVICE_SCOPE, service_subscope: EXPECTED_SERVICE_SUBSCOPE, nullifier_secret: EXPECTED_NULLIFIER_SECRET, + oprf_proof: OPRF_ZERO_PROOF, }) }) @@ -635,6 +641,7 @@ describe("Circuit Matcher - RSA", () => { service_scope: EXPECTED_SERVICE_SCOPE, service_subscope: EXPECTED_SERVICE_SUBSCOPE, nullifier_secret: EXPECTED_NULLIFIER_SECRET, + oprf_proof: OPRF_ZERO_PROOF, }) }) @@ -674,6 +681,7 @@ describe("Circuit Matcher - RSA", () => { min_date: getUnixTimestamp(new Date("1980-01-01")) + SECONDS_BETWEEN_1900_AND_1970, max_date: getUnixTimestamp(new Date("1990-01-01")) + SECONDS_BETWEEN_1900_AND_1970, nullifier_secret: EXPECTED_NULLIFIER_SECRET, + oprf_proof: OPRF_ZERO_PROOF, }) }) @@ -713,6 +721,7 @@ describe("Circuit Matcher - RSA", () => { min_date: getUnixTimestamp(new Date("2025-01-01")), max_date: getUnixTimestamp(new Date("2035-12-31")), nullifier_secret: EXPECTED_NULLIFIER_SECRET, + oprf_proof: OPRF_ZERO_PROOF, }) }) }) @@ -918,6 +927,7 @@ describe("Circuit Matcher - ECDSA", () => { service_scope: EXPECTED_SERVICE_SCOPE, service_subscope: EXPECTED_SERVICE_SUBSCOPE, nullifier_secret: EXPECTED_NULLIFIER_SECRET, + oprf_proof: OPRF_ZERO_PROOF, }) }) @@ -964,6 +974,7 @@ describe("Circuit Matcher - ECDSA", () => { min_age_required: 18, max_age_required: 0, nullifier_secret: EXPECTED_NULLIFIER_SECRET, + oprf_proof: OPRF_ZERO_PROOF, }) }) @@ -1004,6 +1015,7 @@ describe("Circuit Matcher - ECDSA", () => { service_scope: EXPECTED_SERVICE_SCOPE, service_subscope: EXPECTED_SERVICE_SUBSCOPE, nullifier_secret: EXPECTED_NULLIFIER_SECRET, + oprf_proof: OPRF_ZERO_PROOF, }) }) @@ -1047,6 +1059,7 @@ describe("Circuit Matcher - ECDSA", () => { service_scope: EXPECTED_SERVICE_SCOPE, service_subscope: EXPECTED_SERVICE_SUBSCOPE, nullifier_secret: EXPECTED_NULLIFIER_SECRET, + oprf_proof: OPRF_ZERO_PROOF, }) }) @@ -1087,6 +1100,7 @@ describe("Circuit Matcher - ECDSA", () => { service_scope: EXPECTED_SERVICE_SCOPE, service_subscope: EXPECTED_SERVICE_SUBSCOPE, nullifier_secret: EXPECTED_NULLIFIER_SECRET, + oprf_proof: OPRF_ZERO_PROOF, }) }) @@ -1129,6 +1143,7 @@ describe("Circuit Matcher - ECDSA", () => { service_scope: EXPECTED_SERVICE_SCOPE, service_subscope: EXPECTED_SERVICE_SUBSCOPE, nullifier_secret: EXPECTED_NULLIFIER_SECRET, + oprf_proof: OPRF_ZERO_PROOF, }) }) @@ -1171,6 +1186,7 @@ describe("Circuit Matcher - ECDSA", () => { min_date: getUnixTimestamp(new Date("1980-01-01")) + SECONDS_BETWEEN_1900_AND_1970, max_date: getUnixTimestamp(new Date("1990-01-01")) + SECONDS_BETWEEN_1900_AND_1970, nullifier_secret: EXPECTED_NULLIFIER_SECRET, + oprf_proof: OPRF_ZERO_PROOF, }) }) @@ -1213,6 +1229,7 @@ describe("Circuit Matcher - ECDSA", () => { min_date: getUnixTimestamp(new Date("2025-01-01")), max_date: getUnixTimestamp(new Date("2035-12-31")), nullifier_secret: EXPECTED_NULLIFIER_SECRET, + oprf_proof: OPRF_ZERO_PROOF, }) }) @@ -1228,6 +1245,7 @@ describe("Circuit Matcher - ECDSA", () => { SERVICE_SCOPE, SERVICE_SUBSCOPE, CURRENT_DATE, + undefined, // oprfProof sanctions, ) expect(result).toEqual({ @@ -1256,6 +1274,7 @@ describe("Circuit Matcher - ECDSA", () => { service_scope: EXPECTED_SERVICE_SCOPE, service_subscope: EXPECTED_SERVICE_SUBSCOPE, nullifier_secret: EXPECTED_NULLIFIER_SECRET, + oprf_proof: OPRF_ZERO_PROOF, }) }, 30000) }) diff --git a/packages/zkpassport-utils/tsup.config.ts b/packages/zkpassport-utils/tsup.config.ts index aba65dfbb..5202efe34 100644 --- a/packages/zkpassport-utils/tsup.config.ts +++ b/packages/zkpassport-utils/tsup.config.ts @@ -21,6 +21,7 @@ export default defineConfig( "passport/index": "src/passport/index.ts", "registry/index": "src/registry/index.ts", "types/index": "src/types/index.ts", + "oprf/index": "src/oprf/index.ts", }, dts: { compilerOptions: { From d027018e6eef32c5bea068b92ac10e2381ca8630 Mon Sep 17 00:00:00 2001 From: Michael Elliot Date: Tue, 28 Apr 2026 13:11:26 +0800 Subject: [PATCH 14/30] feat(contracts): Add new ProtocolController contract (#160) * feat(contracts): add new ProtocolController contract - Added new ProtocolController contract to manage operator roles for RootRegistry and RootVerifier - Added new forge deployment scripts for ProtocolController and RootVerifier - Added scripts for calculating init codes for RootRegistry and RootVerifier - Moved CertificateRegistry, CircuitRegistry, and SanctionsRegistry into their own folder - Added new test deployment scripts for RootRegistry and RootVerifier for local testing - Updated copyright year - Added natspec comments to ProtocolController, VerifierHelper, and SubVerifier - Refactored deployment scripts - Added Google ECDSA root key hash to VerifierHelper - Refactored address writing in DeployRegistryHelper script --- packages/registry-contracts/foundry.toml | 11 +- .../script/DeployBase.s.sol | 39 ++ .../script/DeployCertificateRegistry.s.sol | 8 +- .../script/DeployCircuitRegistry.s.sol | 8 +- .../script/DeployProtocolController.s.sol | 61 +++ .../script/DeployRegistryHelper.s.sol | 14 +- .../script/DeployRootRegistry.s.sol | 25 +- .../script/DeployRootVerifier.s.sol | 144 ++++++ .../script/DeploySanctionsRegistry.s.sol | 11 +- .../script/test/SeedRegistries.s.sol | 2 +- .../script/test/deploy-protocol-controller.sh | 64 +++ .../{deploy.sh => deploy-root-registry.sh} | 8 +- .../script/test/deploy-root-verifier.sh | 54 ++ .../script/test/run-local.sh | 8 +- .../registry-contracts/src/IProofVerifier.sol | 14 + .../src/IRegistryInstance.sol | 2 +- .../src/ProtocolController.sol | 225 ++++++++ .../registry-contracts/src/RegistryHelper.sol | 2 +- .../src/RegistryInstance.sol | 2 +- .../registry-contracts/src/RootRegistry.sol | 2 +- .../registry-contracts/src/RootVerifier.sol | 257 +++++++++ .../registry-contracts/src/SubVerifier.sol | 259 ++++++++++ .../registry-contracts/src/VerifierHelper.sol | 489 ++++++++++++++++++ .../registry-contracts/src/lib/Constants.sol | 134 +++++ .../registry-contracts/src/lib/DateUtils.sol | 28 + .../src/lib/InputsExtractor.sol | 359 +++++++++++++ .../src/lib/StringUtils.sol | 20 + packages/registry-contracts/src/lib/Types.sol | 122 +++++ .../src/mocks/MockHonkVerifier.sol | 8 + .../{ => registries}/CertificateRegistry.sol | 6 +- .../src/{ => registries}/CircuitRegistry.sol | 6 +- .../{ => registries}/SanctionsRegistry.sol | 6 +- .../test/ProtocolController.t.sol | 454 ++++++++++++++++ .../test/RegistryHelper.t.sol | 2 +- .../test/RootRegistry.t.sol | 32 ++ packages/registry-sdk/tests/utils/helpers.ts | 2 +- 36 files changed, 2860 insertions(+), 28 deletions(-) create mode 100644 packages/registry-contracts/script/DeployBase.s.sol create mode 100644 packages/registry-contracts/script/DeployProtocolController.s.sol create mode 100644 packages/registry-contracts/script/DeployRootVerifier.s.sol create mode 100755 packages/registry-contracts/script/test/deploy-protocol-controller.sh rename packages/registry-contracts/script/test/{deploy.sh => deploy-root-registry.sh} (95%) create mode 100755 packages/registry-contracts/script/test/deploy-root-verifier.sh create mode 100644 packages/registry-contracts/src/IProofVerifier.sol create mode 100644 packages/registry-contracts/src/ProtocolController.sol create mode 100644 packages/registry-contracts/src/RootVerifier.sol create mode 100644 packages/registry-contracts/src/SubVerifier.sol create mode 100644 packages/registry-contracts/src/VerifierHelper.sol create mode 100644 packages/registry-contracts/src/lib/Constants.sol create mode 100644 packages/registry-contracts/src/lib/DateUtils.sol create mode 100644 packages/registry-contracts/src/lib/InputsExtractor.sol create mode 100644 packages/registry-contracts/src/lib/StringUtils.sol create mode 100644 packages/registry-contracts/src/lib/Types.sol create mode 100644 packages/registry-contracts/src/mocks/MockHonkVerifier.sol rename packages/registry-contracts/src/{ => registries}/CertificateRegistry.sol (80%) rename packages/registry-contracts/src/{ => registries}/CircuitRegistry.sol (80%) rename packages/registry-contracts/src/{ => registries}/SanctionsRegistry.sol (80%) create mode 100644 packages/registry-contracts/test/ProtocolController.t.sol diff --git a/packages/registry-contracts/foundry.toml b/packages/registry-contracts/foundry.toml index 1f33a543f..93f9811a1 100644 --- a/packages/registry-contracts/foundry.toml +++ b/packages/registry-contracts/foundry.toml @@ -11,10 +11,19 @@ optimizer_runs = 200 bytecode_hash = "none" # Remappings remappings = ["forge-std/=lib/forge-std/src/"] +# File system permissions +fs_permissions = [{ access = "read-write", path = "./deployments"}] [lint] lint_on_build = false -exclude_lints = ["screaming-snake-case-immutable", "unwrapped-modifier-logic"] +exclude_lints = ["mixed-case-function", "screaming-snake-case-immutable", "unwrapped-modifier-logic"] + +[fmt] +# tab_width = 4 +ignore = [ + "src/mocks", + "src/lib/Constants.sol" +] [rpc_endpoints] mainnet = "${MAINNET_RPC_URL}" diff --git a/packages/registry-contracts/script/DeployBase.s.sol b/packages/registry-contracts/script/DeployBase.s.sol new file mode 100644 index 000000000..bfe9f62ac --- /dev/null +++ b/packages/registry-contracts/script/DeployBase.s.sol @@ -0,0 +1,39 @@ +/* + * DeployBase.s.sol + * + * Shared base contract for deploy scripts. Provides helpers for writing + * deployment data into the shared addresses file. + */ + +pragma solidity ^0.8.30; + +import {Script, console} from "forge-std/Script.sol"; + +abstract contract DeployBase is Script { + string internal constant DEPLOYMENTS_DIR = "./deployments"; + + function _ensureDeploymentsDir() internal { + if (!vm.exists(DEPLOYMENTS_DIR)) { + vm.createDir(DEPLOYMENTS_DIR, true); + } + } + + function _chainIdStr() internal view returns (string memory) { + return vm.toString(block.chainid); + } + + function _addressesFilePath() internal view returns (string memory) { + return string.concat(DEPLOYMENTS_DIR, "/addresses-", _chainIdStr(), ".json"); + } + + /// Write a serialized JSON object to a top-level key in `addresses-.json`. + function _writeToAddresses(string memory key, string memory json) internal { + _ensureDeploymentsDir(); + string memory path = _addressesFilePath(); + if (!vm.exists(path)) { + vm.writeJson("{}", path); + } + vm.writeJson(json, path, string.concat(".", key)); + console.log("Updated addresses file:", path); + } +} diff --git a/packages/registry-contracts/script/DeployCertificateRegistry.s.sol b/packages/registry-contracts/script/DeployCertificateRegistry.s.sol index 43a5b2446..ce1b86e29 100644 --- a/packages/registry-contracts/script/DeployCertificateRegistry.s.sol +++ b/packages/registry-contracts/script/DeployCertificateRegistry.s.sol @@ -1,7 +1,13 @@ +/* + * DeployCertificateRegistry.s.sol + * + * Deploys the certificate registry. + */ + pragma solidity ^0.8.30; import {Script, console} from "forge-std/Script.sol"; -import {CertificateRegistry} from "../src/CertificateRegistry.sol"; +import {CertificateRegistry} from "../src/registries/CertificateRegistry.sol"; import {RootValidationMode} from "../src/IRegistryInstance.sol"; contract DeployCertificateRegistryScript is Script { diff --git a/packages/registry-contracts/script/DeployCircuitRegistry.s.sol b/packages/registry-contracts/script/DeployCircuitRegistry.s.sol index 28fc8dfdc..6fdf20b89 100644 --- a/packages/registry-contracts/script/DeployCircuitRegistry.s.sol +++ b/packages/registry-contracts/script/DeployCircuitRegistry.s.sol @@ -1,7 +1,13 @@ +/* + * DeployCircuitRegistry.s.sol + * + * Deploys the circuit registry. + */ + pragma solidity ^0.8.30; import {Script, console} from "forge-std/Script.sol"; -import {CircuitRegistry} from "../src/CircuitRegistry.sol"; +import {CircuitRegistry} from "../src/registries/CircuitRegistry.sol"; import {RootValidationMode} from "../src/IRegistryInstance.sol"; contract DeployCircuitRegistryScript is Script { diff --git a/packages/registry-contracts/script/DeployProtocolController.s.sol b/packages/registry-contracts/script/DeployProtocolController.s.sol new file mode 100644 index 000000000..244c67ead --- /dev/null +++ b/packages/registry-contracts/script/DeployProtocolController.s.sol @@ -0,0 +1,61 @@ +/* + * DeployProtocolController.s.sol + * + * Deploys the protocol controller. + */ + +pragma solidity ^0.8.30; + +import {console} from "forge-std/Script.sol"; +import {stdJson} from "forge-std/StdJson.sol"; +import {DeployBase} from "./DeployBase.s.sol"; +import {ProtocolController} from "../src/ProtocolController.sol"; + +contract DeployProtocolControllerScript is DeployBase { + using stdJson for string; + + ProtocolController public controller; + + function setUp() public {} + + function run() public { + address adminAddress = vm.envAddress("PROTOCOL_CONTROLLER_ADMIN"); + require(adminAddress != address(0), "PROTOCOL_CONTROLLER_ADMIN must be set"); + + address rootRegistry = vm.envAddress("ROOT_REGISTRY_ADDRESS"); + require(rootRegistry != address(0), "ROOT_REGISTRY_ADDRESS must be set"); + + address rootRegistryOperator = vm.envAddress("ROOT_REGISTRY_OPERATOR_ADDRESS"); + require(rootRegistryOperator != address(0), "ROOT_REGISTRY_OPERATOR_ADDRESS must be set"); + + address rootVerifier = vm.envAddress("ROOT_VERIFIER_ADDRESS"); + require(rootVerifier != address(0), "ROOT_VERIFIER_ADDRESS must be set"); + + address rootVerifierOperator = vm.envAddress("ROOT_VERIFIER_OPERATOR_ADDRESS"); + require(rootVerifierOperator != address(0), "ROOT_VERIFIER_OPERATOR_ADDRESS must be set"); + + vm.startBroadcast(); + controller = new ProtocolController( + adminAddress, rootRegistry, rootRegistryOperator, rootVerifier, rootVerifierOperator + ); + vm.stopBroadcast(); + + console.log("ProtocolController deployed at:", address(controller)); + console.log("Admin:", controller.admin()); + console.log("Root Registry:", address(controller.rootRegistry())); + console.log("Root Registry Operator:", controller.rootRegistryOperator()); + console.log("Root Verifier:", address(controller.rootVerifier())); + console.log("Root Verifier Operator:", controller.rootVerifierOperator()); + + string memory section = "protocol_controller"; + vm.serializeAddress(section, "address", address(controller)); + vm.serializeAddress(section, "admin", adminAddress); + vm.serializeAddress(section, "root_registry", rootRegistry); + vm.serializeAddress(section, "root_registry_operator", rootRegistryOperator); + vm.serializeAddress(section, "root_verifier", rootVerifier); + vm.serializeAddress(section, "root_verifier_operator", rootVerifierOperator); + section = vm.serializeUint(section, "deployed_at", block.timestamp); + + _writeToAddresses("protocol_controller", section); + } +} diff --git a/packages/registry-contracts/script/DeployRegistryHelper.s.sol b/packages/registry-contracts/script/DeployRegistryHelper.s.sol index 9b850ebd5..56e1d2670 100644 --- a/packages/registry-contracts/script/DeployRegistryHelper.s.sol +++ b/packages/registry-contracts/script/DeployRegistryHelper.s.sol @@ -1,10 +1,18 @@ +/* + * DeployRegistryHelper.s.sol + * + * Deploys the registry helper, a read-only utility contract for querying + * data across the root registry's sub-registries. + */ + pragma solidity ^0.8.30; -import {Script, console} from "forge-std/Script.sol"; +import {console} from "forge-std/Script.sol"; +import {DeployBase} from "./DeployBase.s.sol"; import {RegistryHelper} from "../src/RegistryHelper.sol"; import {RootRegistry} from "../src/RootRegistry.sol"; -contract DeployRegistryHelperScript is Script { +contract DeployRegistryHelperScript is DeployBase { RegistryHelper public helper; function setUp() public {} @@ -19,5 +27,7 @@ contract DeployRegistryHelperScript is Script { vm.stopBroadcast(); console.log("RegistryHelper deployed at:", address(helper)); console.log("RegistryHelper using RootRegistry at:", rootRegistryAddress); + + _writeToAddresses("root_registry.helper", string.concat('"', vm.toString(address(helper)), '"')); } } diff --git a/packages/registry-contracts/script/DeployRootRegistry.s.sol b/packages/registry-contracts/script/DeployRootRegistry.s.sol index 2a5a1c74c..0fc45e71b 100644 --- a/packages/registry-contracts/script/DeployRootRegistry.s.sol +++ b/packages/registry-contracts/script/DeployRootRegistry.s.sol @@ -1,9 +1,22 @@ +/* + * DeployRootRegistry.s.sol + * + * ⚠️ FOR LOCAL TESTING ONLY — DO NOT USE IN PRODUCTION ⚠️ + * + * Deploys the root registry using a plain CREATE. The production RootRegistry + * is deployed via a CREATE2 factory with a salt to get a universal multichain address. + */ + pragma solidity ^0.8.30; -import {Script, console} from "forge-std/Script.sol"; +import {console} from "forge-std/Script.sol"; +import {stdJson} from "forge-std/StdJson.sol"; +import {DeployBase} from "./DeployBase.s.sol"; import {RootRegistry} from "../src/RootRegistry.sol"; -contract DeployRootRegistryScript is Script { +contract DeployRootRegistryScript is DeployBase { + using stdJson for string; + RootRegistry public registry; function setUp() public {} @@ -23,5 +36,13 @@ contract DeployRootRegistryScript is Script { console.log("RootRegistry deployed at:", address(registry)); console.log("Admin:", registry.admin()); console.log("Guardian:", registry.guardian()); + + string memory section = "root_registry"; + vm.serializeAddress(section, "address", address(registry)); + vm.serializeAddress(section, "admin", adminAddress); + vm.serializeAddress(section, "guardian", guardianAddress); + section = vm.serializeUint(section, "deployed_at", block.timestamp); + + _writeToAddresses("root_registry", section); } } diff --git a/packages/registry-contracts/script/DeployRootVerifier.s.sol b/packages/registry-contracts/script/DeployRootVerifier.s.sol new file mode 100644 index 000000000..ff385ca10 --- /dev/null +++ b/packages/registry-contracts/script/DeployRootVerifier.s.sol @@ -0,0 +1,144 @@ +/* + * DeployRootVerifier.s.sol + * + * ⚠️ FOR LOCAL TESTING ONLY — DO NOT USE IN PRODUCTION ⚠️ + * + * Deploys the ZKPassport root verifier, verifier helper, a subverifier, and mock + * proof verifiers using a plain CREATE. The production RootVerifier is deployed + * via a CREATE2 factory with a salt to get a universal multichain address. + */ + +pragma solidity ^0.8.30; + +import {console} from "forge-std/Script.sol"; +import {stdJson} from "forge-std/StdJson.sol"; +import {DeployBase} from "./DeployBase.s.sol"; +import {HonkVerifier} from "../src/mocks/MockHonkVerifier.sol"; +import {RootRegistry} from "../src/RootRegistry.sol"; +import {RootVerifier} from "../src/RootVerifier.sol"; +import {SubVerifier} from "../src/SubVerifier.sol"; +import {VerifierHelper} from "../src/VerifierHelper.sol"; +import {ProofVerifier} from "../src/lib/Types.sol"; + +contract DeployRootVerifierScript is DeployBase { + using stdJson for string; + + bytes32 public SUB_VERIFIER_VERSION; + bytes32 public CREATE2_SALT; + + bytes32[] public vkeyHashes = [ + bytes32(hex"0404040404040404040404040404040404040404040404040404040404040404"), + bytes32(hex"0505050505050505050505050505050505050505050505050505050505050505"), + bytes32(hex"0606060606060606060606060606060606060606060606060606060606060606"), + bytes32(hex"0707070707070707070707070707070707070707070707070707070707070707"), + bytes32(hex"0808080808080808080808080808080808080808080808080808080808080808"), + bytes32(hex"0909090909090909090909090909090909090909090909090909090909090909"), + bytes32(hex"1010101010101010101010101010101010101010101010101010101010101010"), + bytes32(hex"1111111111111111111111111111111111111111111111111111111111111111"), + bytes32(hex"1212121212121212121212121212121212121212121212121212121212121212"), + bytes32(hex"1313131313131313131313131313131313131313131313131313131313131313") + ]; + address[] public proofVerifiers = new address[](10); + + function setUp() public {} + + function run() public { + // Semver encoded as bytes32: first 2 bytes = major, next 2 = minor, next 2 = patch (e.g. 0x000000000001... = v0.0.1) + SUB_VERIFIER_VERSION = vm.envOr( + "SUB_VERIFIER_VERSION", bytes32(0x0000000000010000000000000000000000000000000000000000000000000000) + ); + CREATE2_SALT = vm.envOr("CREATE2_SALT", bytes32(0)); + + address adminAddress = vm.envAddress("ROOT_VERIFIER_ADMIN_ADDRESS"); + require(adminAddress != address(0), "ROOT_VERIFIER_ADMIN_ADDRESS must be set"); + + address guardianAddress = vm.envOr("ROOT_VERIFIER_GUARDIAN_ADDRESS", address(0)); + + RootRegistry rootRegistry = RootRegistry(vm.envAddress("ROOT_REGISTRY_ADDRESS")); + require(address(rootRegistry) != address(0), "ROOT_REGISTRY_ADDRESS must be set"); + + vm.startBroadcast(); + + // Deploy the root verifier + console.log("Deploying RootVerifier..."); + RootVerifier rootVerifier = new RootVerifier(adminAddress, guardianAddress, rootRegistry); + console.log("RootVerifier deployed at:", address(rootVerifier)); + + // Deploy the sub verifier + console.log("Deploying SubVerifier..."); + SubVerifier subVerifier = new SubVerifier{salt: CREATE2_SALT}(adminAddress, rootVerifier); + console.log("SubVerifier deployed at:", address(subVerifier)); + + // Add the sub verifier to the root verifier + rootVerifier.addSubVerifier(SUB_VERIFIER_VERSION, subVerifier); + console.log("Sub verifier added to root verifier"); + + // Deploy the verifier helper + console.log("Deploying VerifierHelper..."); + VerifierHelper helper = new VerifierHelper{salt: CREATE2_SALT}(rootRegistry); + console.log("VerifierHelper deployed at:", address(helper)); + + // Add the helper to the root verifier + rootVerifier.addHelper(SUB_VERIFIER_VERSION, address(helper)); + console.log("Helper added to root verifier"); + + // Deploy the proof verifiers (mock HonkVerifier for each outer circuit count) + console.log("Deploying proof verifiers..."); + for (uint256 i = 0; i < 10; i++) { + proofVerifiers[i] = address(new HonkVerifier{salt: bytes32(i)}()); + console.log(" Outer proof verifier", i + 4, "deployed at:", proofVerifiers[i]); + } + + // Add proof verifiers to the sub verifier + ProofVerifier[] memory proofVerifiersArray = new ProofVerifier[](10); + for (uint256 i = 0; i < 10; i++) { + proofVerifiersArray[i] = ProofVerifier({vkeyHash: vkeyHashes[i], verifier: proofVerifiers[i]}); + } + subVerifier.addProofVerifiers(proofVerifiersArray); + console.log("Proof verifiers added to sub verifier"); + + vm.stopBroadcast(); + + _writeVerifierAddresses(rootVerifier, subVerifier, helper); + } + + function _writeVerifierAddresses(RootVerifier rootVerifier, SubVerifier subVerifier, VerifierHelper helper) + internal + { + uint256 v = uint256(SUB_VERIFIER_VERSION); + string memory versionStr = string.concat( + vm.toString(uint16(v >> 240)), ".", vm.toString(uint16(v >> 224)), ".", vm.toString(uint16(v >> 208)) + ); + + // Build proof_verifiers object + string memory pvJson = "pv"; + vm.serializeAddress(pvJson, "outer_count_4", proofVerifiers[0]); + vm.serializeAddress(pvJson, "outer_count_5", proofVerifiers[1]); + vm.serializeAddress(pvJson, "outer_count_6", proofVerifiers[2]); + vm.serializeAddress(pvJson, "outer_count_7", proofVerifiers[3]); + vm.serializeAddress(pvJson, "outer_count_8", proofVerifiers[4]); + vm.serializeAddress(pvJson, "outer_count_9", proofVerifiers[5]); + vm.serializeAddress(pvJson, "outer_count_10", proofVerifiers[6]); + vm.serializeAddress(pvJson, "outer_count_11", proofVerifiers[7]); + vm.serializeAddress(pvJson, "outer_count_12", proofVerifiers[8]); + pvJson = vm.serializeAddress(pvJson, "outer_count_13", proofVerifiers[9]); + + // Build version object: { subverifier, helper, proof_verifiers } + string memory versionJson = "version"; + vm.serializeAddress(versionJson, "subverifier", address(subVerifier)); + vm.serializeAddress(versionJson, "helper", address(helper)); + versionJson = vm.serializeString(versionJson, "proof_verifiers", pvJson); + + // Wrap in subverifiers: { "": { ... } } + string memory subverifiersJson = "subverifiers"; + subverifiersJson = vm.serializeString(subverifiersJson, versionStr, versionJson); + + // Build root_verifier section + string memory section = "root_verifier"; + vm.serializeAddress(section, "address", address(rootVerifier)); + vm.serializeString(section, "subverifiers", subverifiersJson); + section = vm.serializeUint(section, "deployed_at", block.timestamp); + + _writeToAddresses("root_verifier", section); + } +} diff --git a/packages/registry-contracts/script/DeploySanctionsRegistry.s.sol b/packages/registry-contracts/script/DeploySanctionsRegistry.s.sol index e6938873e..3d58d96f6 100644 --- a/packages/registry-contracts/script/DeploySanctionsRegistry.s.sol +++ b/packages/registry-contracts/script/DeploySanctionsRegistry.s.sol @@ -1,9 +1,16 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright © 2025 ZKPassport +// Copyright © 2026 ZKPassport + +/* + * DeploySanctionsRegistry.s.sol + * + * Deploys the sanctions registry. + */ + pragma solidity ^0.8.30; import {Script, console} from "forge-std/Script.sol"; -import {SanctionsRegistry} from "../src/SanctionsRegistry.sol"; +import {SanctionsRegistry} from "../src/registries/SanctionsRegistry.sol"; import {RootValidationMode} from "../src/IRegistryInstance.sol"; contract DeploySanctionsRegistryScript is Script { diff --git a/packages/registry-contracts/script/test/SeedRegistries.s.sol b/packages/registry-contracts/script/test/SeedRegistries.s.sol index ce695f905..75e928f3b 100644 --- a/packages/registry-contracts/script/test/SeedRegistries.s.sol +++ b/packages/registry-contracts/script/test/SeedRegistries.s.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright © 2025 ZKPassport +// Copyright © 2026 ZKPassport pragma solidity ^0.8.30; import {Script, console} from "forge-std/Script.sol"; diff --git a/packages/registry-contracts/script/test/deploy-protocol-controller.sh b/packages/registry-contracts/script/test/deploy-protocol-controller.sh new file mode 100755 index 000000000..9115e1b0b --- /dev/null +++ b/packages/registry-contracts/script/test/deploy-protocol-controller.sh @@ -0,0 +1,64 @@ +#!/bin/bash + +# Test deployment script for the ProtocolController +# ⚠️ FOR TESTING ONLY - DO NOT USE IN PRODUCTION ⚠️ +# This script deploys the ProtocolController and transfers admin of RootRegistry +# and RootVerifier to the ProtocolController address. +# Expects ROOT_REGISTRY_ADDRESS and ROOT_VERIFIER_ADDRESS to already be set +# (run deploy-root-registry.sh and deploy-root-verifier.sh first) + +set -e + +# Hardcoded for test environment +export CHAIN_ID=31337 +export RPC_URL=${RPC_URL:-http://localhost:8545} + +export DEPLOYER_PRIVATE_KEY=${DEPLOYER_PRIVATE_KEY:-0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80} + +export PROTOCOL_CONTROLLER_ADMIN=${PROTOCOL_CONTROLLER_ADMIN:-0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266} +export ROOT_REGISTRY_OPERATOR_ADDRESS=${ROOT_REGISTRY_OPERATOR_ADDRESS:-0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc} +export ROOT_VERIFIER_OPERATOR_ADDRESS=${ROOT_VERIFIER_OPERATOR_ADDRESS:-0x976EA74026E726554dB657fA54763abd0C3a0aa9} + +export ROOT_REGISTRY_ADMIN_PRIVATE_KEY=${ROOT_REGISTRY_ADMIN_PRIVATE_KEY:-0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80} +export ROOT_VERIFIER_ADMIN_PRIVATE_KEY=${ROOT_VERIFIER_ADMIN_PRIVATE_KEY:-0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80} + +if [ -z "$ROOT_REGISTRY_ADDRESS" ]; then + echo "Error: ROOT_REGISTRY_ADDRESS must be set" + echo "Deploy the registry contracts first with deploy-root-registry.sh and export ROOT_REGISTRY_ADDRESS" + exit 1 +fi + +if [ -z "$ROOT_VERIFIER_ADDRESS" ]; then + echo "Error: ROOT_VERIFIER_ADDRESS must be set" + echo "Deploy the verifier contracts first with deploy-root-verifier.sh and export ROOT_VERIFIER_ADDRESS" + exit 1 +fi + +# Deploy the ProtocolController contract +echo "Deploying ProtocolController..." +forge script script/DeployProtocolController.s.sol:DeployProtocolControllerScript \ + --rpc-url $RPC_URL \ + --private-key $DEPLOYER_PRIVATE_KEY \ + --broadcast + +export PROTOCOL_CONTROLLER_ADDRESS=$(cat broadcast/DeployProtocolController.s.sol/$CHAIN_ID/run-latest.json | jq -r '.transactions[] | select(.transactionType=="CREATE") | .contractAddress') +echo "" +echo "ProtocolController deployed at: $PROTOCOL_CONTROLLER_ADDRESS" + +# Transfer RootRegistry admin to the ProtocolController +echo "Transferring RootRegistry admin to ProtocolController..." +cast send $ROOT_REGISTRY_ADDRESS "transferAdmin(address)" $PROTOCOL_CONTROLLER_ADDRESS --rpc-url $RPC_URL --private-key $ROOT_REGISTRY_ADMIN_PRIVATE_KEY + +# Transfer RootVerifier admin to the ProtocolController +echo "Transferring RootVerifier admin to ProtocolController..." +cast send $ROOT_VERIFIER_ADDRESS "transferAdmin(address)" $PROTOCOL_CONTROLLER_ADDRESS --rpc-url $RPC_URL --private-key $ROOT_VERIFIER_ADMIN_PRIVATE_KEY + +# Verify the admin transfers +REGISTRY_ADMIN=$(cast call $ROOT_REGISTRY_ADDRESS "admin()" --rpc-url $RPC_URL) +echo "RootRegistry admin: $REGISTRY_ADMIN" + +VERIFIER_ADMIN=$(cast call $ROOT_VERIFIER_ADDRESS "admin()" --rpc-url $RPC_URL) +echo "RootVerifier admin: $VERIFIER_ADMIN" + +CONTROLLER_ADMIN=$(cast call $PROTOCOL_CONTROLLER_ADDRESS "admin()" --rpc-url $RPC_URL) +echo "ProtocolController admin: $CONTROLLER_ADMIN" diff --git a/packages/registry-contracts/script/test/deploy.sh b/packages/registry-contracts/script/test/deploy-root-registry.sh similarity index 95% rename from packages/registry-contracts/script/test/deploy.sh rename to packages/registry-contracts/script/test/deploy-root-registry.sh index c7a31fc17..2f9a3b0ca 100755 --- a/packages/registry-contracts/script/test/deploy.sh +++ b/packages/registry-contracts/script/test/deploy-root-registry.sh @@ -2,7 +2,8 @@ # Test deployment script for integration tests # ⚠️ FOR TESTING ONLY - DO NOT USE IN PRODUCTION ⚠️ -# This script deploys contracts to a local Anvil instance for testing purposes +# This script deploys the RootRegistry, RegistryHelper, and sub-registries (CertificateRegistry, CircuitRegistry, and SanctionsRegistry) +# to a local Anvil instance for testing purposes set -e @@ -50,6 +51,11 @@ forge script script/DeployRegistryHelper.s.sol:DeployRegistryHelperScript --rpc- REGISTRY_HELPER_ADDRESS=$(cat broadcast/DeployRegistryHelper.s.sol/$CHAIN_ID/run-latest.json | jq -r '.transactions[] | select(.transactionType=="CREATE") | .contractAddress') echo "RegistryHelper deployed at: $REGISTRY_HELPER_ADDRESS" +if [[ " $* " == *" --skip-registries "* ]]; then + echo "Skipping registry deployments..." + return +fi + # Deploy the CertificateRegistry contract echo "Deploying CertificateRegistry..." forge script script/DeployCertificateRegistry.s.sol:DeployCertificateRegistryScript --rpc-url $RPC_URL --private-key $DEPLOYER_PRIVATE_KEY --broadcast diff --git a/packages/registry-contracts/script/test/deploy-root-verifier.sh b/packages/registry-contracts/script/test/deploy-root-verifier.sh new file mode 100755 index 000000000..8fe4acebe --- /dev/null +++ b/packages/registry-contracts/script/test/deploy-root-verifier.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +# Test deployment script for RootVerifier, SubVerifier, VerifierHelper, and ProofVerifiers +# ⚠️ FOR TESTING ONLY - DO NOT USE IN PRODUCTION ⚠️ +# This script deploys all verifier contracts to a local Anvil instance +# Expects ROOT_REGISTRY_ADDRESS to already be deployed (run deploy-root-registry.sh first) + +set -e + +# Hardcoded for test environment +export CHAIN_ID=31337 +export RPC_URL=${RPC_URL:-http://localhost:8545} + +export DEPLOYER_PRIVATE_KEY=${DEPLOYER_PRIVATE_KEY:-0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80} + +export ROOT_VERIFIER_ADMIN_ADDRESS=${ROOT_VERIFIER_ADMIN_ADDRESS:-0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266} +export ROOT_VERIFIER_GUARDIAN_ADDRESS=${ROOT_VERIFIER_GUARDIAN_ADDRESS:-0x0000000000000000000000000000000000000000} + +if [ -z "$ROOT_REGISTRY_ADDRESS" ]; then + echo "Error: ROOT_REGISTRY_ADDRESS must be set" + echo "Deploy the registry contracts first with deploy-root-registry.sh and export ROOT_REGISTRY_ADDRESS" + exit 1 +fi + +# Deploy all verifier contracts (RootVerifier + VerifierHelper + SubVerifier + proof verifiers) +echo "Deploying ZKPassport verifier stack..." +forge script script/DeployRootVerifier.s.sol:DeployRootVerifierScript \ + --rpc-url $RPC_URL \ + --private-key $DEPLOYER_PRIVATE_KEY \ + --broadcast + +# Extract the RootVerifier address (first CREATE transaction) +export ROOT_VERIFIER_ADDRESS=$(cat broadcast/DeployRootVerifier.s.sol/$CHAIN_ID/run-latest.json | jq -r '[.transactions[] | select(.transactionType=="CREATE")][0].contractAddress') +echo "" +echo "RootVerifier deployed at: $ROOT_VERIFIER_ADDRESS" + +# Verify deployment +VERIFIER_ADMIN=$(cast call $ROOT_VERIFIER_ADDRESS "admin()" --rpc-url $RPC_URL) +echo "Verified admin: $VERIFIER_ADMIN" + +VERIFIER_REGISTRY=$(cast call $ROOT_VERIFIER_ADDRESS "rootRegistry()" --rpc-url $RPC_URL) +echo "Verified rootRegistry: $VERIFIER_REGISTRY" + +SUBVERIFIER_COUNT=$(cast call $ROOT_VERIFIER_ADDRESS "subverifierCount()" --rpc-url $RPC_URL) +echo "Verified subverifierCount: $SUBVERIFIER_COUNT" + +HELPER_COUNT=$(cast call $ROOT_VERIFIER_ADDRESS "helperCount()" --rpc-url $RPC_URL) +echo "Verified helperCount: $HELPER_COUNT" + +# Check for deployment artifact +if [ -f deployments/addresses-$CHAIN_ID.json ]; then + echo "" + echo "Deployment artifact written to deployments/addresses-$CHAIN_ID.json" +fi diff --git a/packages/registry-contracts/script/test/run-local.sh b/packages/registry-contracts/script/test/run-local.sh index 04ee6bdaa..5abe4c54c 100755 --- a/packages/registry-contracts/script/test/run-local.sh +++ b/packages/registry-contracts/script/test/run-local.sh @@ -26,8 +26,12 @@ trap cleanup EXIT SIGINT SIGTERM sleep 1 # Run the deployment and seeding scripts -./script/test/deploy.sh -./script/test/seed-registries.sh +source ./script/test/deploy-root-registry.sh +source ./script/test/deploy-root-verifier.sh +source ./script/test/deploy-protocol-controller.sh +if [[ " $* " != *" --no-seed "* ]]; then + source ./script/test/seed-registries.sh +fi echo "Test environment ready!" echo "Anvil is running on http://localhost:8545 (Chain ID: 31337)" diff --git a/packages/registry-contracts/src/IProofVerifier.sol b/packages/registry-contracts/src/IProofVerifier.sol new file mode 100644 index 000000000..5cdc10cd9 --- /dev/null +++ b/packages/registry-contracts/src/IProofVerifier.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright © 2026 ZKPassport +/* + ______ _ _ _____ _______ _______ _______ _____ _____ ______ _______ + ____/ |____/ |_____] |_____| |______ |______ |_____] | | |_____/ | + /_____ | \_ | | | ______| ______| | |_____| | \_ | + +*/ + +pragma solidity ^0.8.30; + +interface IProofVerifier { + function verify(bytes calldata _proof, bytes32[] calldata _publicInputs) external view returns (bool); +} diff --git a/packages/registry-contracts/src/IRegistryInstance.sol b/packages/registry-contracts/src/IRegistryInstance.sol index 8ef2d64d6..68a7e2a50 100644 --- a/packages/registry-contracts/src/IRegistryInstance.sol +++ b/packages/registry-contracts/src/IRegistryInstance.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright © 2025 ZKPassport +// Copyright © 2026 ZKPassport /* ______ _ _ _____ _______ _______ _______ _____ _____ ______ _______ ____/ |____/ |_____] |_____| |______ |______ |_____] | | |_____/ | diff --git a/packages/registry-contracts/src/ProtocolController.sol b/packages/registry-contracts/src/ProtocolController.sol new file mode 100644 index 000000000..b28b4ef57 --- /dev/null +++ b/packages/registry-contracts/src/ProtocolController.sol @@ -0,0 +1,225 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright © 2026 ZKPassport +/* + ______ _ _ _____ _______ _______ _______ _____ _____ ______ _______ + ____/ |____/ |_____] |_____| |______ |______ |_____] | | |_____/ | + /_____ | \_ | | | ______| ______| | |_____| | \_ | + +*/ + +pragma solidity ^0.8.30; + +interface IRootRegistryAdmin { + function transferAdmin(address newAdmin) external; + function setGuardian(address newGuardian) external; + function addRegistry(bytes32 registryId, address registryAddress) external; + function updateRegistry(bytes32 registryId, address newAddress) external; + function removeRegistry(bytes32 registryId) external; + function updateConfig(bytes32 key, bytes32 value) external; + function pause() external; + function unpause() external; +} + +interface IRootVerifierAdmin { + function transferAdmin(address newAdmin) external; + function setGuardian(address newGuardian) external; + function addSubVerifier(bytes32 version, address subVerifier) external; + function removeSubVerifier(bytes32 version) external; + function updateSubVerifier(bytes32 version, address newSubVerifier) external; + function addHelper(bytes32 version, address newHelper) external; + function removeHelper(bytes32 version) external; + function updateHelper(bytes32 version, address newHelper) external; + function updateConfig(bytes32 key, bytes32 value) external; + function pause() external; + function unpause() external; +} + +/** + * @title ProtocolController + * @dev Manages operator roles for ZKPassport RootVerifier and RootRegistry contracts. + * The admin can reassign operator roles and transfer admin on the underlying + * contracts back to itself. Operators can call the respective admin functions + * on the underlying contracts through this controller. + */ +contract ProtocolController { + address public admin; + address public pendingAdmin; + address public rootRegistryOperator; + address public rootVerifierOperator; + + IRootRegistryAdmin public rootRegistry; + IRootVerifierAdmin public rootVerifier; + + event AdminTransferStarted(address indexed currentAdmin, address indexed pendingAdmin); + event AdminTransferred(address indexed oldAdmin, address indexed newAdmin); + event RootRegistryOperatorUpdated(address indexed oldOperator, address indexed newOperator); + event RootVerifierOperatorUpdated(address indexed oldOperator, address indexed newOperator); + + /// @dev Constructor to initialize the protocol controller + /// @param _admin The admin address + /// @param _rootRegistry The RootRegistry contract address + /// @param _rootRegistryOperator The operator address for the RootRegistry + /// @param _rootVerifier The RootVerifier contract address + /// @param _rootVerifierOperator The operator address for the RootVerifier + constructor( + address _admin, + address _rootRegistry, + address _rootRegistryOperator, + address _rootVerifier, + address _rootVerifierOperator + ) { + require(_admin != address(0), "Admin cannot be zero address"); + admin = _admin; + rootRegistry = IRootRegistryAdmin(_rootRegistry); + rootRegistryOperator = _rootRegistryOperator; + rootVerifier = IRootVerifierAdmin(_rootVerifier); + rootVerifierOperator = _rootVerifierOperator; + } + + modifier onlyAdmin() { + require(msg.sender == admin, "Not authorized: admin only"); + _; + } + + modifier onlyAdminOrRootRegistryOperator() { + require( + msg.sender == admin || msg.sender == rootRegistryOperator, + "Not authorized: admin or root registry operator only" + ); + _; + } + + modifier onlyAdminOrRootVerifierOperator() { + require( + msg.sender == admin || msg.sender == rootVerifierOperator, + "Not authorized: admin or root verifier operator only" + ); + _; + } + + // ===== Admin functions ===== + + /// @notice Initiates a two-step admin transfer to a new address + function transferAdmin(address newAdmin) external onlyAdmin { + require(newAdmin != address(0), "Admin cannot be zero address"); + pendingAdmin = newAdmin; + emit AdminTransferStarted(admin, newAdmin); + } + + /// @notice Completes the admin transfer; must be called by the pending admin + function acceptAdmin() external { + require(msg.sender == pendingAdmin, "Not authorized: pending admin only"); + address oldAdmin = admin; + admin = pendingAdmin; + pendingAdmin = address(0); + emit AdminTransferred(oldAdmin, msg.sender); + } + + /// @notice Restores admin of the RootRegistry contract from this controller back to the admin + function restoreRootRegistryAdmin() external onlyAdmin { + rootRegistry.transferAdmin(admin); + } + + /// @notice Restores admin of the RootVerifier contract from this controller back to the admin + function restoreRootVerifierAdmin() external onlyAdmin { + rootVerifier.transferAdmin(admin); + } + + /// @notice Sets the operator address for the RootRegistry + function setRootRegistryOperator(address newOperator) external onlyAdmin { + address oldOperator = rootRegistryOperator; + rootRegistryOperator = newOperator; + emit RootRegistryOperatorUpdated(oldOperator, newOperator); + } + + /// @notice Sets the operator address for the RootVerifier + function setRootVerifierOperator(address newOperator) external onlyAdmin { + address oldOperator = rootVerifierOperator; + rootVerifierOperator = newOperator; + emit RootVerifierOperatorUpdated(oldOperator, newOperator); + } + + // ===== Root Registry Operator functions ===== + + function rootRegistry_addRegistry(bytes32 registryId, address registryAddress) + external + onlyAdminOrRootRegistryOperator + { + rootRegistry.addRegistry(registryId, registryAddress); + } + + function rootRegistry_updateRegistry(bytes32 registryId, address newAddress) + external + onlyAdminOrRootRegistryOperator + { + rootRegistry.updateRegistry(registryId, newAddress); + } + + function rootRegistry_removeRegistry(bytes32 registryId) external onlyAdminOrRootRegistryOperator { + rootRegistry.removeRegistry(registryId); + } + + function rootRegistry_setGuardian(address newGuardian) external onlyAdminOrRootRegistryOperator { + rootRegistry.setGuardian(newGuardian); + } + + function rootRegistry_updateConfig(bytes32 key, bytes32 value) external onlyAdminOrRootRegistryOperator { + rootRegistry.updateConfig(key, value); + } + + function rootRegistry_pause() external onlyAdminOrRootRegistryOperator { + rootRegistry.pause(); + } + + function rootRegistry_unpause() external onlyAdminOrRootRegistryOperator { + rootRegistry.unpause(); + } + + // ===== Root Verifier Operator functions ===== + + function rootVerifier_addSubVerifier(bytes32 version, address subVerifier) + external + onlyAdminOrRootVerifierOperator + { + rootVerifier.addSubVerifier(version, subVerifier); + } + + function rootVerifier_removeSubVerifier(bytes32 version) external onlyAdminOrRootVerifierOperator { + rootVerifier.removeSubVerifier(version); + } + + function rootVerifier_updateSubVerifier(bytes32 version, address newSubVerifier) + external + onlyAdminOrRootVerifierOperator + { + rootVerifier.updateSubVerifier(version, newSubVerifier); + } + + function rootVerifier_addHelper(bytes32 version, address newHelper) external onlyAdminOrRootVerifierOperator { + rootVerifier.addHelper(version, newHelper); + } + + function rootVerifier_removeHelper(bytes32 version) external onlyAdminOrRootVerifierOperator { + rootVerifier.removeHelper(version); + } + + function rootVerifier_updateHelper(bytes32 version, address newHelper) external onlyAdminOrRootVerifierOperator { + rootVerifier.updateHelper(version, newHelper); + } + + function rootVerifier_setGuardian(address newGuardian) external onlyAdminOrRootVerifierOperator { + rootVerifier.setGuardian(newGuardian); + } + + function rootVerifier_updateConfig(bytes32 key, bytes32 value) external onlyAdminOrRootVerifierOperator { + rootVerifier.updateConfig(key, value); + } + + function rootVerifier_pause() external onlyAdminOrRootVerifierOperator { + rootVerifier.pause(); + } + + function rootVerifier_unpause() external onlyAdminOrRootVerifierOperator { + rootVerifier.unpause(); + } +} diff --git a/packages/registry-contracts/src/RegistryHelper.sol b/packages/registry-contracts/src/RegistryHelper.sol index 8c5ec4051..ee78b85fb 100644 --- a/packages/registry-contracts/src/RegistryHelper.sol +++ b/packages/registry-contracts/src/RegistryHelper.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright © 2025 ZKPassport +// Copyright © 2026 ZKPassport /* ______ _ _ _____ _______ _______ _______ _____ _____ ______ _______ ____/ |____/ |_____] |_____| |______ |______ |_____] | | |_____/ | diff --git a/packages/registry-contracts/src/RegistryInstance.sol b/packages/registry-contracts/src/RegistryInstance.sol index 9b69c3bf7..7011ce971 100644 --- a/packages/registry-contracts/src/RegistryInstance.sol +++ b/packages/registry-contracts/src/RegistryInstance.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright © 2025 ZKPassport +// Copyright © 2026 ZKPassport /* ______ _ _ _____ _______ _______ _______ _____ _____ ______ _______ ____/ |____/ |_____] |_____| |______ |______ |_____] | | |_____/ | diff --git a/packages/registry-contracts/src/RootRegistry.sol b/packages/registry-contracts/src/RootRegistry.sol index af74ce170..0f9798a39 100644 --- a/packages/registry-contracts/src/RootRegistry.sol +++ b/packages/registry-contracts/src/RootRegistry.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright © 2025 ZKPassport +// Copyright © 2026 ZKPassport /* ______ _ _ _____ _______ _______ _______ _____ _____ ______ _______ ____/ |____/ |_____] |_____| |______ |______ |_____] | | |_____/ | diff --git a/packages/registry-contracts/src/RootVerifier.sol b/packages/registry-contracts/src/RootVerifier.sol new file mode 100644 index 000000000..bb57a935a --- /dev/null +++ b/packages/registry-contracts/src/RootVerifier.sol @@ -0,0 +1,257 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright © 2026 ZKPassport +/* + ______ _ _ _____ _______ _______ _______ _____ _____ ______ _______ + ____/ |____/ |_____] |_____| |______ |______ |_____] | | |_____/ | + /_____ | \_ | | | ______| ______| | |_____| | \_ | + +*/ + +pragma solidity ^0.8.30; + +import {RootRegistry} from "./RootRegistry.sol"; +import {SubVerifier} from "./SubVerifier.sol"; +import {VerifierHelper} from "./VerifierHelper.sol"; +import {ProofVerificationParams} from "./lib/Types.sol"; + +/** + * @title ZKPassport Root Verifier + * @notice Main entry point for verifying ZKPassport identity proofs + */ +contract RootVerifier { + address public admin; + address public guardian; + bool public paused; + + // ZKPassport Root Registry + RootRegistry public rootRegistry; + + // Subverifier mapping + mapping(bytes32 => SubVerifier) public subverifiers; + // Counter for the number of subverifiers + uint256 public subverifierCount; + + // Helper mapping + mapping(bytes32 => VerifierHelper) public helpers; + // Counter for the number of helpers + uint256 public helperCount; + + // Config mapping + mapping(bytes32 key => bytes32 value) public config; + + // Events + event RootVerifierDeployed(address admin, address guardian, address rootRegistry); + event AdminUpdated(address indexed oldAdmin, address indexed newAdmin); + event GuardianUpdated(address indexed oldGuardian, address indexed newGuardian); + event RootRegistryUpdated(address indexed oldRootRegistry, address indexed newRootRegistry); + event SubVerifierAdded(bytes32 indexed version, address indexed subVerifier); + event SubVerifierRemoved(bytes32 indexed version, address indexed subVerifier); + event SubVerifierUpdated(bytes32 indexed version, address indexed oldSubVerifier, address indexed newSubVerifier); + event HelperAdded(bytes32 indexed version, address indexed helper); + event HelperRemoved(bytes32 indexed version, address indexed helper); + event HelperUpdated(bytes32 indexed version, address indexed oldHelper, address indexed newHelper); + event PausedStatusChanged(bool paused); + event ConfigUpdated(bytes32 indexed key, bytes32 oldValue, bytes32 newValue); + + /** + * @notice Constructor + * @param _admin The admin address + * @param _guardian The guardian address + * @param _rootRegistry The root registry address + */ + constructor(address _admin, address _guardian, RootRegistry _rootRegistry) { + require(_admin != address(0), "Admin cannot be zero address"); + admin = _admin; + guardian = _guardian; + rootRegistry = _rootRegistry; + emit RootVerifierDeployed(admin, guardian, address(_rootRegistry)); + } + + /** + * @notice Verifies a ZKPassport zero-knowledge proof + * @dev This function is called by the root verifier to verify a proof for a specific version + * @param params The proof verification parameters + * @return valid True if the proof is valid or false otherwise + * @return uniqueIdentifier The unique identifier associated with the ID used to generate the proof + * @return helper The helper for the calling contract to use to verify the committed inputs + */ + function verify(ProofVerificationParams calldata params) + external + view + whenNotPaused + returns (bool valid, bytes32 uniqueIdentifier, VerifierHelper helper) + { + SubVerifier subverifier = subverifiers[params.version]; + require(address(subverifier) != address(0), "Subverifier not found for version"); + (valid, uniqueIdentifier) = subverifier.verify(rootRegistry, params); + return (valid, uniqueIdentifier, helpers[params.version]); + } + + modifier onlyAdmin() { + require(msg.sender == admin, "Not authorized: admin only"); + _; + } + + modifier onlyAdminOrGuardian() { + require(msg.sender == admin || msg.sender == guardian, "Not authorized: admin or guardian only"); + _; + } + + modifier whenNotPaused() { + require(!paused, "Root verifier is paused"); + _; + } + + /** + * @notice Transfers the admin role to a new address + * @param newAdmin The new admin address + */ + function transferAdmin(address newAdmin) external onlyAdmin { + require(newAdmin != address(0), "Admin cannot be zero address"); + address oldAdmin = admin; + admin = newAdmin; + emit AdminUpdated(oldAdmin, newAdmin); + } + + /** + * @notice Sets the guardian role to a new address + * @param newGuardian The new guardian address + */ + function setGuardian(address newGuardian) external onlyAdmin { + address oldGuardian = guardian; + guardian = newGuardian; + emit GuardianUpdated(oldGuardian, newGuardian); + } + + /** + * @notice Adds a subverifier for a specific version + * @param version The version identifier + * @param subVerifier The address of the subverifier + */ + function addSubVerifier(bytes32 version, SubVerifier subVerifier) external onlyAdmin { + require(address(subVerifier) != address(0), "Subverifier cannot be zero address"); + require(version != bytes32(0), "Version cannot be zero"); + require(address(subverifiers[version]) == address(0), "Subverifier already exists for version"); + subverifiers[version] = subVerifier; + subverifierCount++; + emit SubVerifierAdded(version, address(subVerifier)); + } + + /** + * @notice Removes a subverifier for a specific version + * @param version The version identifier + */ + function removeSubVerifier(bytes32 version) external onlyAdmin { + require(version != bytes32(0), "Version cannot be zero"); + address subVerifier = address(subverifiers[version]); + require(subVerifier != address(0), "Subverifier not found for version"); + delete subverifiers[version]; + subverifierCount--; + emit SubVerifierRemoved(version, subVerifier); + } + + /** + * @notice Updates a subverifier for a specific version + * @param version The version identifier + * @param newSubVerifier The address of the new subverifier + */ + function updateSubVerifier(bytes32 version, address newSubVerifier) external onlyAdmin { + require(version != bytes32(0), "Version cannot be zero"); + require(newSubVerifier != address(0), "Subverifier cannot be zero address"); + require(address(subverifiers[version]) != address(0), "Subverifier not found for version"); + address oldSubVerifier = address(subverifiers[version]); + subverifiers[version] = SubVerifier(newSubVerifier); + emit SubVerifierUpdated(version, oldSubVerifier, newSubVerifier); + } + + /** + * @notice Gets the subverifier address for a specific version + * @dev Returns zero address if no subverifier exists for the given version + * @param version The version identifier + * @return The address of the subverifier contract, or zero address if not found + */ + function getSubVerifier(bytes32 version) external view returns (address) { + return address(subverifiers[version]); + } + + /** + * @notice Adds a helper for a specific version + * @param version The version identifier + * @param newHelper The address of the helper + */ + function addHelper(bytes32 version, address newHelper) external onlyAdmin { + require(newHelper != address(0), "Helper cannot be zero address"); + require(version != bytes32(0), "Version cannot be zero"); + require(address(helpers[version]) == address(0), "Helper already exists for version"); + helpers[version] = VerifierHelper(newHelper); + helperCount++; + emit HelperAdded(version, newHelper); + } + + /** + * @notice Removes a helper for a specific version + * @param version The version identifier + */ + function removeHelper(bytes32 version) external onlyAdmin { + require(version != bytes32(0), "Version cannot be zero"); + address helper = address(helpers[version]); + require(helper != address(0), "Helper not found for version"); + delete helpers[version]; + helperCount--; + emit HelperRemoved(version, helper); + } + + /** + * @notice Updates a helper for a specific version + * @param version The version identifier + * @param newHelper The address of the new helper + */ + function updateHelper(bytes32 version, address newHelper) external onlyAdmin { + require(version != bytes32(0), "Version cannot be zero"); + require(newHelper != address(0), "Helper cannot be zero address"); + require(address(helpers[version]) != address(0), "Helper not found for version"); + address oldHelper = address(helpers[version]); + helpers[version] = VerifierHelper(newHelper); + emit HelperUpdated(version, oldHelper, newHelper); + } + + /** + * @notice Gets the helper address for a specific version + * @dev Returns zero address if no helper exists for the given version + * @param version The version identifier + * @return The address of the helper contract, or zero address if not found + */ + function getHelper(bytes32 version) external view returns (address) { + return address(helpers[version]); + } + + /** + * @notice Update a config value + * @param key The config key + * @param value The config value + */ + function updateConfig(bytes32 key, bytes32 value) external onlyAdmin { + bytes32 oldValue = config[key]; + config[key] = value; + emit ConfigUpdated(key, oldValue, value); + } + + /** + * @notice Pause the root verifier + * @dev Only admin or guardian can pause the root verifier + * @dev This is a security measure to pause all proof verification operations in the event of an emergency + */ + function pause() external onlyAdminOrGuardian { + paused = true; + emit PausedStatusChanged(true); + } + + /** + * @notice Unpause the root verifier + * @dev Only admin can unpause the root verifier + */ + function unpause() external onlyAdmin { + paused = false; + emit PausedStatusChanged(false); + } +} diff --git a/packages/registry-contracts/src/SubVerifier.sol b/packages/registry-contracts/src/SubVerifier.sol new file mode 100644 index 000000000..6b55e0d45 --- /dev/null +++ b/packages/registry-contracts/src/SubVerifier.sol @@ -0,0 +1,259 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright © 2026 ZKPassport +/* + ______ _ _ _____ _______ _______ _______ _____ _____ ______ _______ + ____/ |____/ |_____] |_____| |______ |______ |_____] | | |_____/ | + /_____ | \_ | | | ______| ______| | |_____| | \_ | + +*/ + +pragma solidity ^0.8.30; + +import {RootVerifier} from "./RootVerifier.sol"; +import {RootRegistry} from "./RootRegistry.sol"; +import {IProofVerifier} from "./IProofVerifier.sol"; +import {ProofVerificationParams, NullifierType, ProofVerifier} from "./lib/Types.sol"; +import {PublicInput, RegistryID} from "./lib/Constants.sol"; +import {DateUtils} from "./lib/DateUtils.sol"; +import {StringUtils} from "./lib/StringUtils.sol"; + +contract SubVerifier { + address public admin; + bool public paused; + + // The address of the root verifier + RootVerifier public rootVerifier; + + // Mapping from vkey hash of each outer circuit to its proof verifier (UltraHonk verifier) address + // Maps use the vkeyHash of the outer circuit to the ProofVerifier contract address + mapping(bytes32 => address) public proofVerifiers; + + event SubVerifierDeployed(address indexed admin, address indexed rootVerifier); + event AdminUpdated(address indexed oldAdmin, address indexed newAdmin); + event ProofVerifierAdded(address indexed proofVerifier, bytes32 indexed vkeyHash); + event ProofVerifierRemoved(address indexed proofVerifier, bytes32 indexed vkeyHash); + event PausedStatusChanged(bool paused); + + /** + * @dev Constructor + * @param _admin The admin address + * @param _rootVerifier The address of the ZKPassport root verifier + */ + constructor(address _admin, RootVerifier _rootVerifier) { + require(_admin != address(0), "Admin cannot be zero address"); + admin = _admin; + require(address(_rootVerifier) != address(0), "Root verifier cannot be zero address"); + rootVerifier = _rootVerifier; + emit SubVerifierDeployed(admin, address(_rootVerifier)); + } + + modifier onlyAdmin() { + require(msg.sender == admin, "Not authorized: admin only"); + _; + } + + modifier onlyRootVerifier() { + require(msg.sender == address(rootVerifier), "This function can only be called from the root verifier"); + _; + } + + modifier whenNotPaused() { + require(!paused, "Contract is paused"); + _; + } + + function transferAdmin(address newAdmin) external onlyAdmin { + require(newAdmin != address(0), "Admin cannot be zero address"); + address oldAdmin = admin; + admin = newAdmin; + emit AdminUpdated(oldAdmin, newAdmin); + } + + function setPaused(bool _paused) external onlyAdmin { + paused = _paused; + emit PausedStatusChanged(_paused); + } + + function addProofVerifiers(ProofVerifier[] calldata _proofVerifiers) external onlyAdmin { + for (uint256 i = 0; i < _proofVerifiers.length; i++) { + proofVerifiers[_proofVerifiers[i].vkeyHash] = _proofVerifiers[i].verifier; + emit ProofVerifierAdded(_proofVerifiers[i].verifier, _proofVerifiers[i].vkeyHash); + } + } + + function removeProofVerifiers(bytes32[] calldata vkeyHashes) external onlyAdmin { + for (uint256 i = 0; i < vkeyHashes.length; i++) { + address proofVerifier = proofVerifiers[vkeyHashes[i]]; + if (proofVerifier != address(0)) { + delete proofVerifiers[vkeyHashes[i]]; + emit ProofVerifierRemoved(proofVerifier, vkeyHashes[i]); + } + } + } + + function _checkDateValidity(uint256 currentDateTimeStamp, uint256 validityPeriodInSeconds) + internal + view + returns (bool) + { + return DateUtils.isDateValid(currentDateTimeStamp, validityPeriodInSeconds); + } + + /** + * @notice Verifies that the proof was generated for the given scope (domain) and subscope (service scope) + * @param publicInputs The public inputs of the proof + * @param scope The scope (domain) to check against + * @param subscope The subscope (service scope) to check against + * @return True if valid, false otherwise + */ + function _verifyScopes(bytes32[] calldata publicInputs, string calldata scope, string calldata subscope) + internal + pure + returns (bool) + { + // One byte is dropped at the end + // What we call scope internally is derived from the domain + bytes32 scopeHash = StringUtils.isEmpty(scope) ? bytes32(0) : sha256(abi.encodePacked(scope)) >> 8; + // What we call the subscope internally is the service scope specified manually in the SDK + bytes32 subscopeHash = StringUtils.isEmpty(subscope) ? bytes32(0) : sha256(abi.encodePacked(subscope)) >> 8; + return + publicInputs[PublicInput.SCOPE_INDEX] == scopeHash + && publicInputs[PublicInput.SUBSCOPE_INDEX] == subscopeHash; + } + + function _verifyCommittedInputs(bytes32[] memory paramCommitments, bytes calldata committedInputs) internal pure { + uint256 offset = 0; + uint256 index = 0; + while (offset < committedInputs.length && index < paramCommitments.length) { + // The committed inputs are formatted as follows: + // - 1 byte: proof type + // - 2 bytes: length of the committed inputs + // - N bytes: committed inputs for a given proof + uint16 length = uint16(bytes2(committedInputs[offset + 1:offset + 3])); + // One byte is dropped inside the circuit as BN254 is limited to 254 bits + // We also add 3 bytes to take into account the proof type and length + bytes32 calculatedCommitment = sha256(abi.encodePacked(committedInputs[offset:offset + length + 3])) >> 8; + require(calculatedCommitment == paramCommitments[index], "Invalid commitment"); + offset += length + 3; + index++; + } + // Check that all the committed inputs have been covered, otherwise something is wrong + require(offset == committedInputs.length, "Invalid committed inputs length"); + require(index == paramCommitments.length, "Invalid parameter commitments"); + } + + function _getProofVerifier(bytes32 vkeyHash) internal view returns (address) { + address verifier = proofVerifiers[vkeyHash]; + require(verifier != address(0), "Verifier not found"); + return verifier; + } + + function _validateCertificateRoot(RootRegistry _rootRegistry, bytes32 certificateRoot, uint256 timestamp) + internal + view + { + require( + _rootRegistry.isRootValid(RegistryID.CERTIFICATE, certificateRoot, timestamp), + "Invalid certificate registry root" + ); + } + + function _validateCircuitRoot(RootRegistry _rootRegistry, bytes32 circuitRoot, uint256 timestamp) internal view { + require(_rootRegistry.isRootValid(RegistryID.CIRCUIT, circuitRoot, timestamp), "Invalid circuit registry root"); + } + + /** + * @notice Verifies a ZKPassport proof + * @dev This function is called by the root verifier to verify a proof for a specific version + * @param rootRegistry The root registry + * @param params The proof verification parameters + * @return isValid True if the proof is valid, false otherwise + * @return uniqueIdentifier The unique identifier associated to the identity document that generated the proof + */ + function verify(RootRegistry rootRegistry, ProofVerificationParams calldata params) + external + view + whenNotPaused + onlyRootVerifier + returns (bool isValid, bytes32 uniqueIdentifier) + { + // Get the verifier for the Outer Circuit corresponding to the vkey hash + address verifier = _getProofVerifier(params.proofVerificationData.vkeyHash); + + uint256 currentTimestamp = uint256(params.proofVerificationData.publicInputs[PublicInput.CURRENT_DATE_INDEX]); + + // Validate certificate registry root + _validateCertificateRoot( + rootRegistry, + params.proofVerificationData.publicInputs[PublicInput.CERTIFICATE_REGISTRY_ROOT_INDEX], + currentTimestamp + ); + + // Validate circuit registry root + _validateCircuitRoot( + rootRegistry, + params.proofVerificationData.publicInputs[PublicInput.CIRCUIT_REGISTRY_ROOT_INDEX], + currentTimestamp + ); + + // Checks the date of the proof + // This is the current date used as public input in the disclosure proofs + // so verifying it here guarantees that the disclosure proofs were generated with this date + require( + _checkDateValidity(currentTimestamp, params.serviceConfig.validityPeriodInSeconds), + "The proof was generated outside the validity period" + ); + + // Validate scopes + // It is recommended to verify this against static variables in your contract + // by calling `helper.verifyScopes(publicInputs, domain, scope)` or setting the domain and scope + // in the params inside your smart contract function before calling `verifier.verify(params)` + // Check SampleContract.sol for an example + require( + _verifyScopes( + params.proofVerificationData.publicInputs, params.serviceConfig.domain, params.serviceConfig.scope + ), + "Invalid domain or scope" + ); + + // Verifies the commitments against the committed inputs + _verifyCommittedInputs( + // Extracts the commitments from the public inputs + params.proofVerificationData + .publicInputs[PublicInput.PARAM_COMMITMENTS_INDEX:params.proofVerificationData.publicInputs.length - 2], + params.committedInputs + ); + + NullifierType nullifierType = NullifierType( + uint256(params.proofVerificationData.publicInputs[params.proofVerificationData.publicInputs.length - 2]) + ); + + // Allow mock proofs in dev mode + // Note: On mainnets, this stage won't be reached as the ZKR certificates will not be part + // of the mainnet registries and the verification will fail at _validateCertificateRoot + require( + (nullifierType != NullifierType.NON_SALTED_MOCK_NULLIFIER + && nullifierType != NullifierType.SALTED_MOCK_NULLIFIER) || params.serviceConfig.devMode, + "Mock proofs are only allowed in dev mode" + ); + + // For now, only non-salted nullifiers are supported + // but salted nullifiers can be used in dev mode + // They will be later once a proper registration mechanism is implemented + require( + nullifierType == NullifierType.NON_SALTED_NULLIFIER || params.serviceConfig.devMode, + "Salted nullifiers are not supported for now" + ); + + // Call the proof verifier for the given Outer Circuit to verify if the actual proof is valid + isValid = IProofVerifier(verifier) + .verify(params.proofVerificationData.proof, params.proofVerificationData.publicInputs); + + // Get the unique identifier from the public inputs + uint256 uniqueIdentifierIndex = params.proofVerificationData.publicInputs.length - 1; + uniqueIdentifier = params.proofVerificationData.publicInputs[uniqueIdentifierIndex]; + + // Return the validity of the proof verification and the unique identifier + return (isValid, uniqueIdentifier); + } +} diff --git a/packages/registry-contracts/src/VerifierHelper.sol b/packages/registry-contracts/src/VerifierHelper.sol new file mode 100644 index 000000000..bb8ac0332 --- /dev/null +++ b/packages/registry-contracts/src/VerifierHelper.sol @@ -0,0 +1,489 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright © 2026 ZKPassport +/* + ______ _ _ _____ _______ _______ _______ _____ _____ ______ _______ + ____/ |____/ |_____] |_____| |______ |______ |_____] | | |_____/ | + /_____ | \_ | | | ______| ______| | |_____| | \_ | + +*/ + +pragma solidity ^0.8.30; + +import {RootRegistry} from "./RootRegistry.sol"; +import {DateUtils} from "./lib/DateUtils.sol"; +import {StringUtils} from "./lib/StringUtils.sol"; +import {InputsExtractor} from "./lib/InputsExtractor.sol"; +import {SECONDS_BETWEEN_1900_AND_1970, PublicInput, AppAttest, RegistryID} from "./lib/Constants.sol"; +import {ProofType, DisclosedData, BoundData, FaceMatchMode, Environment, OS} from "./lib/Types.sol"; + +contract VerifierHelper { + RootRegistry public immutable rootRegistry; + + constructor(RootRegistry _rootRegistry) { + require(address(_rootRegistry) != address(0), "Root registry cannot be zero address"); + rootRegistry = _rootRegistry; + } + + /** + * @notice Gets the data disclosed by the proof + * @param committedInputs The committed inputs + * @param isIDCard Whether the proof is an ID card + * @return disclosedData The data disclosed by the proof + */ + function getDisclosedData(bytes calldata committedInputs, bool isIDCard) + external + pure + returns (DisclosedData memory disclosedData) + { + (, bytes memory discloseBytes) = InputsExtractor.getDiscloseProofInputs(committedInputs); + disclosedData = InputsExtractor.getDisclosedData(discloseBytes, isIDCard); + } + + /** + * @notice Checks if the age is above or equal to the given age + * @param minAge The age must be above or equal to this age + * @param committedInputs The committed inputs + * @return True if the age is above or equal to the given age, false otherwise + */ + function isAgeAboveOrEqual(uint8 minAge, bytes calldata committedInputs) public pure returns (bool) { + (uint8 min, uint8 max) = InputsExtractor.getAgeProofInputs(committedInputs); + require(max == 0, "The proof upper bound must be 0, please use isAgeBetween instead"); + return minAge == min; + } + + /** + * @notice Checks if the age is above the given age + * @param minAge The age must be above this age + * @param committedInputs The committed inputs + * @return True if the age is above the given age, false otherwise + */ + function isAgeAbove(uint8 minAge, bytes calldata committedInputs) public pure returns (bool) { + return isAgeAboveOrEqual(minAge + 1, committedInputs); + } + + /** + * @notice Checks if the age is in the given range + * @param minAge The age must be greater than or equal to this age + * @param maxAge The age must be less than or equal to this age + * @param committedInputs The committed inputs + * @return True if the age is in the given range, false otherwise + */ + function isAgeBetween(uint8 minAge, uint8 maxAge, bytes calldata committedInputs) public pure returns (bool) { + (uint8 min, uint8 max) = InputsExtractor.getAgeProofInputs(committedInputs); + require(minAge <= maxAge, "Min age must be less than or equal to max age"); + require(min != 0, "The proof lower bound must be non-zero, please use isAgeBelowOrEqual instead"); + require(max != 0, "The proof upper bound must be non-zero, please use isAgeAboveOrEqual instead"); + return minAge == min && maxAge == max; + } + + /** + * @notice Checks if the age is below or equal to the given age + * @param maxAge The age must be below or equal to this age + * @param committedInputs The committed inputs + * @return True if the age is below or equal to the given age, false otherwise + */ + function isAgeBelowOrEqual(uint8 maxAge, bytes calldata committedInputs) public pure returns (bool) { + (uint8 min, uint8 max) = InputsExtractor.getAgeProofInputs(committedInputs); + require(min == 0, "The proof lower bound must be 0, please use isAgeBetween instead"); + return maxAge == max; + } + + /** + * @notice Checks if the age is below the given age + * @param maxAge The age must be below this age + * @param committedInputs The committed inputs + * @return True if the age is below the given age, false otherwise + */ + function isAgeBelow(uint8 maxAge, bytes calldata committedInputs) public pure returns (bool) { + require(maxAge > 0, "Max age must be greater than 0"); + return isAgeBelowOrEqual(maxAge - 1, committedInputs); + } + + /** + * @notice Checks if the age is equal to the given age + * @param age The age must be equal to this age + * @param committedInputs The committed inputs + * @return True if the age is equal to the given age, false otherwise + */ + function isAgeEqual(uint8 age, bytes calldata committedInputs) public pure returns (bool) { + return isAgeBetween(age, age, committedInputs); + } + + function _isDateAfterOrEqual(uint256 minDate, ProofType proofType, bytes calldata committedInputs) + private + pure + returns (bool) + { + (uint256 min, uint256 max) = InputsExtractor.getDateProofInputs(committedInputs, proofType); + require(proofType == ProofType.BIRTHDATE || proofType == ProofType.EXPIRY_DATE, "Invalid proof type"); + if (proofType == ProofType.BIRTHDATE) { + require(max == 0, "The proof upper bound must be 0, please use isBirthdateBetween instead"); + // Birthdate comparison dates use 1900 as the starting epoch so the proof can take in value + // prior to 1970, so we need to subtract the difference between 1900 and 1970 (starting UNIX epoch) + return minDate == min - SECONDS_BETWEEN_1900_AND_1970; + } else { + require(max == 0, "The proof upper bound must be 0, please use isExpiryDateBetween instead"); + return minDate == min; + } + } + + function _isDateBetween(uint256 minDate, uint256 maxDate, ProofType proofType, bytes calldata committedInputs) + private + pure + returns (bool) + { + (uint256 min, uint256 max) = InputsExtractor.getDateProofInputs(committedInputs, proofType); + require(minDate <= maxDate, "Min date must be less than or equal to max date"); + require(proofType == ProofType.BIRTHDATE || proofType == ProofType.EXPIRY_DATE, "Invalid proof type"); + if (proofType == ProofType.BIRTHDATE) { + require(min != 0, "The proof lower bound must be non-zero, please use isBirthdateBelowOrEqual instead"); + require(max != 0, "The proof upper bound must be non-zero, please use isBirthdateAboveOrEqual instead"); + // Birthdate comparison dates use 1900 as the starting epoch so the proof can take in values + // prior to 1970, so we need to subtract the difference between 1900 and 1970 (starting UNIX epoch) + return minDate == min - SECONDS_BETWEEN_1900_AND_1970 && maxDate == max - SECONDS_BETWEEN_1900_AND_1970; + } else { + require(min != 0, "The proof lower bound must be non-zero, please use isExpiryDateBelowOrEqual instead"); + require(max != 0, "The proof upper bound must be non-zero, please use isExpiryDateAboveOrEqual instead"); + return minDate == min && maxDate == max; + } + } + + function _isDateBeforeOrEqual(uint256 maxDate, ProofType proofType, bytes calldata committedInputs) + private + pure + returns (bool) + { + (uint256 min, uint256 max) = InputsExtractor.getDateProofInputs(committedInputs, proofType); + require(min == 0, "The proof lower bound must be 0, please use _isDateBetween instead"); + require(proofType == ProofType.BIRTHDATE || proofType == ProofType.EXPIRY_DATE, "Invalid proof type"); + if (proofType == ProofType.BIRTHDATE) { + require(max != 0, "The proof upper bound must be non-zero, please use isBirthdateAboveOrEqual instead"); + // Birthdate comparison dates use 1900 as the starting epoch so the proof can take in value + // prior to 1970, so we need to subtract the difference between 1900 and 1970 (starting UNIX epoch) + return maxDate == max - SECONDS_BETWEEN_1900_AND_1970; + } else { + require(max != 0, "The proof upper bound must be non-zero, please use isExpiryDateAboveOrEqual instead"); + return maxDate == max; + } + } + + /** + * @notice Checks if the birthdate is after or equal to the given date + * @param minDate The birthdate must be after or equal to this date + * @param committedInputs The committed inputs + * @return True if the birthdate is after or equal to the given date, false otherwise + */ + function isBirthdateAfterOrEqual(uint256 minDate, bytes calldata committedInputs) public pure returns (bool) { + return _isDateAfterOrEqual(minDate, ProofType.BIRTHDATE, committedInputs); + } + + /** + * @notice Checks if the birthdate is after the given date + * @param minDate The birthdate must be after this date + * @param committedInputs The committed inputs + * @return True if the birthdate is after the given date, false otherwise + */ + function isBirthdateAfter(uint256 minDate, bytes calldata committedInputs) public pure returns (bool) { + return _isDateAfterOrEqual(minDate + 1 days, ProofType.BIRTHDATE, committedInputs); + } + + /** + * @notice Checks if the birthdate is between the given dates + * @param minDate The birthdate must be after or equal to this date + * @param maxDate The birthdate must be before or equal to this date + * @param committedInputs The committed inputs + * @return True if the birthdate is between the given dates, false otherwise + */ + function isBirthdateBetween(uint256 minDate, uint256 maxDate, bytes calldata committedInputs) + public + pure + returns (bool) + { + return _isDateBetween(minDate, maxDate, ProofType.BIRTHDATE, committedInputs); + } + + /** + * @notice Checks if the birthdate is before or equal to the given date + * @param maxDate The birthdate must be before or equal to this date + * @param committedInputs The committed inputs + * @return True if the birthdate is before or equal to the given date, false otherwise + */ + function isBirthdateBeforeOrEqual(uint256 maxDate, bytes calldata committedInputs) public pure returns (bool) { + return _isDateBeforeOrEqual(maxDate, ProofType.BIRTHDATE, committedInputs); + } + + /** + * @notice Checks if the birthdate is before the given date + * @param maxDate The birthdate must be before this date + * @param committedInputs The committed inputs + * @return True if the birthdate is before the given date, false otherwise + */ + function isBirthdateBefore(uint256 maxDate, bytes calldata committedInputs) public pure returns (bool) { + return _isDateBeforeOrEqual(maxDate - 1 days, ProofType.BIRTHDATE, committedInputs); + } + + /** + * @notice Checks if the birthdate is equal to the given date + * @param date The birthdate must be equal to this date + * @param committedInputs The committed inputs + * @return True if the birthdate is equal to the given date, false otherwise + */ + function isBirthdateEqual(uint256 date, bytes calldata committedInputs) public pure returns (bool) { + return _isDateBetween(date, date, ProofType.BIRTHDATE, committedInputs); + } + + /** + * @notice Checks if the expiry date is after or equal to the given date + * @param minDate The expiry date must be after or equal to this date + * @param committedInputs The committed inputs + * @return True if the expiry date is after or equal to the given date, false otherwise + */ + function isExpiryDateAfterOrEqual(uint256 minDate, bytes calldata committedInputs) public pure returns (bool) { + return _isDateAfterOrEqual(minDate, ProofType.EXPIRY_DATE, committedInputs); + } + + /** + * @notice Checks if the expiry date is after the given date + * @param minDate The expiry date must be after this date + * @param committedInputs The committed inputs + * @return True if the expiry date is after the given date, false otherwise + */ + function isExpiryDateAfter(uint256 minDate, bytes calldata committedInputs) public pure returns (bool) { + return _isDateAfterOrEqual(minDate + 1 days, ProofType.EXPIRY_DATE, committedInputs); + } + + /** + * @notice Checks if the expiry date is between the given dates + * @param minDate The expiry date must be after or equal to this date + * @param maxDate The expiry date must be before or equal to this date + * @param committedInputs The committed inputs + * @return True if the expiry date is between the given dates, false otherwise + */ + function isExpiryDateBetween(uint256 minDate, uint256 maxDate, bytes calldata committedInputs) + public + pure + returns (bool) + { + return _isDateBetween(minDate, maxDate, ProofType.EXPIRY_DATE, committedInputs); + } + + /** + * @notice Checks if the expiry date is before or equal to the given date + * @param maxDate The expiry date must be before or equal to this date + * @param committedInputs The committed inputs + * @return True if the expiry date is before or equal to the given date, false otherwise + */ + function isExpiryDateBeforeOrEqual(uint256 maxDate, bytes calldata committedInputs) public pure returns (bool) { + return _isDateBeforeOrEqual(maxDate, ProofType.EXPIRY_DATE, committedInputs); + } + + /** + * @notice Checks if the expiry date is before the given date + * @param maxDate The expiry date must be before this date + * @param committedInputs The committed inputs + * @return True if the expiry date is before the given date, false otherwise + */ + function isExpiryDateBefore(uint256 maxDate, bytes calldata committedInputs) public pure returns (bool) { + return _isDateBeforeOrEqual(maxDate - 1 days, ProofType.EXPIRY_DATE, committedInputs); + } + + /** + * @notice Checks if the expiry date is equal to the given date + * @param date The expiry date must be equal to this date + * @param committedInputs The committed inputs + * @return True if the expiry date is equal to the given date, false otherwise + */ + function isExpiryDateEqual(uint256 date, bytes calldata committedInputs) public pure returns (bool) { + return _isDateBetween(date, date, ProofType.EXPIRY_DATE, committedInputs); + } + + function isCountryInOrOut(string[] memory countryList, ProofType proofType, bytes calldata committedInputs) + private + pure + returns (bool) + { + (string[] memory inputCountryList, uint256 inputCountryListLength) = + InputsExtractor.getCountryProofInputs(committedInputs, proofType); + if (countryList.length != inputCountryListLength) { + return false; + } + for (uint256 i = 0; i < inputCountryListLength; i++) { + if (!StringUtils.equals(countryList[i], inputCountryList[i])) { + return false; + } + } + return true; + } + + /** + * @notice Checks if the nationality is in the list of countries + * @param countryList The list of countries (needs to match exactly the list of countries in the proof) + * @param committedInputs The committed inputs + * @return True if the nationality is in the list of countries, false otherwise + */ + function isNationalityIn(string[] memory countryList, bytes calldata committedInputs) external pure returns (bool) { + return isCountryInOrOut(countryList, ProofType.NATIONALITY_INCLUSION, committedInputs); + } + + /** + * @notice Checks if the issuing country is in the list of countries + * @param countryList The list of countries (needs to match exactly the list of countries in the proof) + * @param committedInputs The committed inputs + * @return True if the issuing country is in the list of countries, false otherwise + */ + function isIssuingCountryIn(string[] memory countryList, bytes calldata committedInputs) + external + pure + returns (bool) + { + return isCountryInOrOut(countryList, ProofType.ISSUING_COUNTRY_INCLUSION, committedInputs); + } + + /** + * @notice Checks if the nationality is not in the list of countries + * @param countryList The list of countries (needs to match exactly the list of countries in the proof) + * Note: The list of countries must be sorted in alphabetical order + * @param committedInputs The committed inputs + * @return True if the nationality is not in the list of countries, false otherwise + */ + function isNationalityOut(string[] memory countryList, bytes calldata committedInputs) + external + pure + returns (bool) + { + return isCountryInOrOut(countryList, ProofType.NATIONALITY_EXCLUSION, committedInputs); + } + + /** + * @notice Checks if the issuing country is not in the list of countries + * @param countryList The list of countries (needs to match exactly the list of countries in the proof) + * Note: The list of countries must be sorted in alphabetical order + * @param committedInputs The committed inputs + * @return True if the issuing country is not in the list of countries, false otherwise + */ + function isIssuingCountryOut(string[] memory countryList, bytes calldata committedInputs) + external + pure + returns (bool) + { + return isCountryInOrOut(countryList, ProofType.ISSUING_COUNTRY_EXCLUSION, committedInputs); + } + + /** + * @notice Gets the data bound to the proof + * @param committedInputs The committed inputs + * @return boundData The data bound to the proof + */ + function getBoundData(bytes calldata committedInputs) external pure returns (BoundData memory boundData) { + bytes memory data = InputsExtractor.getBindProofInputs(committedInputs); + (boundData.senderAddress, boundData.chainId, boundData.customData) = InputsExtractor.getBoundData(data); + } + + /** + * @notice Checks if the sanctions root is valid against the expected sanction list(s) + * @param currentTimestamp The current timestamp (preferably from the proof rather than the block timestamp). + * This is used to check the validity of the sanctions root at that specific time. + * @param isStrict Whether the sanctions check was strict or not + * @param committedInputs The committed inputs + * @return True if the sanctions root is valid against the expected sanction list(s), false otherwise + */ + function isSanctionsRootValid(uint256 currentTimestamp, bool isStrict, bytes calldata committedInputs) + external + view + returns (bool) + { + return _isSanctionsRootValid(currentTimestamp, isStrict, committedInputs); + } + + function _isSanctionsRootValid(uint256 currentTimestamp, bool isStrict, bytes calldata committedInputs) + internal + view + returns (bool) + { + (bytes32 proofSanctionsRoot, bool retrievedIsStrict) = InputsExtractor.getSanctionsProofInputs(committedInputs); + require(isStrict == retrievedIsStrict, "Invalid sanctions check mode"); + return rootRegistry.isRootValid(RegistryID.SANCTIONS, proofSanctionsRoot, currentTimestamp); + } + + /** + * @notice Enforces that the proof checks against the expected sanction list(s) + * @param currentTimestamp The current timestamp (preferably from the proof rather than the block timestamp). + * This is used to check the validity of the sanctions root at that specific time. + * @param isStrict Whether the sanctions check was strict or not + * @param committedInputs The committed inputs + */ + function enforceSanctionsRoot(uint256 currentTimestamp, bool isStrict, bytes calldata committedInputs) + external + view + { + bool isValid = _isSanctionsRootValid(currentTimestamp, isStrict, committedInputs); + require(isValid, "Invalid sanctions registry root"); + } + + /** + * @notice Checks if the proof is tied to a FaceMatch verification + * @param faceMatchMode The FaceMatch mode expected to be used in the verification + * @param os The operating system on which the proof should have been generated (Any (0), iOS (1), Android (2)) + * @param committedInputs The committed inputs + * @return True if the proof is tied to a valid FaceMatch verification, false otherwise + */ + function isFaceMatchVerified(FaceMatchMode faceMatchMode, OS os, bytes calldata committedInputs) + external + pure + returns (bool) + { + ( + bytes32 rootKeyHash, + Environment environment, + bytes32 appIdHash, + bytes32 integrityPublicKeyHash, + FaceMatchMode retrievedFaceMatchMode + ) = InputsExtractor.getFacematchProofInputs(committedInputs); + bool isProduction = environment == Environment.PRODUCTION; + bool isCorrectMode = retrievedFaceMatchMode == faceMatchMode; + bool isCorrectRootKeyHash = (rootKeyHash == AppAttest.APPLE_ROOT_KEY_HASH && (os == OS.IOS || os == OS.ANY)) + || ((rootKeyHash == AppAttest.GOOGLE_RSA_ROOT_KEY_HASH + || rootKeyHash == AppAttest.GOOGLE_ECDSA_ROOT_KEY_HASH) + && (os == OS.ANDROID || os == OS.ANY)); + bool isCorrectAppIdHash = (appIdHash == AppAttest.IOS_APP_ID_HASH && (os == OS.IOS || os == OS.ANY)) + || (appIdHash == AppAttest.ANDROID_APP_ID_HASH && (os == OS.ANDROID || os == OS.ANY)); + // The integrity public key hash is 0 for iOS as it's logic specific to Android + bool isCorrectIntegrityPublicKeyHash = (integrityPublicKeyHash == bytes32(0) && (os == OS.IOS || os == OS.ANY)) + || (integrityPublicKeyHash == AppAttest.ANDROID_INTEGRITY_PUBLIC_KEY_HASH + && (os == OS.ANDROID || os == OS.ANY)); + return + isProduction && isCorrectMode && isCorrectRootKeyHash && isCorrectAppIdHash + && isCorrectIntegrityPublicKeyHash; + } + + /** + * @notice Gets the timestamp the proof was generated at + * @param publicInputs The public inputs of the proof + * @return The timestamp the proof was generated at + */ + function getProofTimestamp(bytes32[] calldata publicInputs) external pure returns (uint256) { + return uint256(publicInputs[PublicInput.CURRENT_DATE_INDEX]); + } + + /** + * @notice Verifies that the proof was generated for the given scope (domain) and subscope (service scope) + * @param publicInputs The public inputs of the proof + * @param scope The scope (domain) to check against + * @param subscope The subscope (service scope) to check against + * @return True if valid, false otherwise + */ + function verifyScopes(bytes32[] calldata publicInputs, string calldata scope, string calldata subscope) + external + pure + returns (bool) + { + // One byte is dropped at the end + // What we call scope internally is derived from the domain + bytes32 scopeHash = StringUtils.isEmpty(scope) ? bytes32(0) : sha256(abi.encodePacked(scope)) >> 8; + // What we call the subscope internally is the service scope specified manually in the SDK + bytes32 subscopeHash = StringUtils.isEmpty(subscope) ? bytes32(0) : sha256(abi.encodePacked(subscope)) >> 8; + return + publicInputs[PublicInput.SCOPE_INDEX] == scopeHash + && publicInputs[PublicInput.SUBSCOPE_INDEX] == subscopeHash; + } +} diff --git a/packages/registry-contracts/src/lib/Constants.sol b/packages/registry-contracts/src/lib/Constants.sol new file mode 100644 index 000000000..4d35f392d --- /dev/null +++ b/packages/registry-contracts/src/lib/Constants.sol @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright © 2026 ZKPassport +/* + ______ _ _ _____ _______ _______ _______ _____ _____ ______ _______ + ____/ |____/ |_____] |_____| |______ |______ |_____] | | |_____/ | + /_____ | \_ | | | ______| ______| | |_____| | \_ | + +*/ + +pragma solidity ^0.8.30; + +uint256 constant SECONDS_BETWEEN_1900_AND_1970 = 2208988800; +uint256 constant COUNTRY_LIST_LENGTH = 200; +uint256 constant BOUND_DATA_LENGTH = 509; +uint256 constant TIMESTAMP_LENGTH = 8; + +// Registry IDs +library RegistryID { + bytes32 constant CERTIFICATE = bytes32(0x0000000000000000000000000000000000000000000000000000000000000001); + bytes32 constant CIRCUIT = bytes32(0x0000000000000000000000000000000000000000000000000000000000000002); + bytes32 constant SANCTIONS = bytes32(0x0000000000000000000000000000000000000000000000000000000000000003); +} + +// The lengths of the preimages of the `param_commitments` of the various disclosure circuits. +// Note: this is excluding the 3 bytes for the proof type and length +library CommittedInputLen { + uint256 constant COMPARE_AGE = 2; + uint256 constant COMPARE_BIRTHDATE = 16; + uint256 constant COMPARE_EXPIRY = 16; + uint256 constant DISCLOSE_BYTES = 180; + uint256 constant INCL_ISSUING_COUNTRY = 600; + uint256 constant EXCL_ISSUING_COUNTRY = 600; + uint256 constant INCL_NATIONALITY = 600; + uint256 constant EXCL_NATIONALITY = 600; + uint256 constant BIND = 509; + uint256 constant SANCTIONS = 33; + uint256 constant FACEMATCH = 98; +} + +// Gather all the public input indices in one place +library PublicInput { + uint256 constant CERTIFICATE_REGISTRY_ROOT_INDEX = 0; + uint256 constant CIRCUIT_REGISTRY_ROOT_INDEX = 1; + uint256 constant CURRENT_DATE_INDEX = 2; + uint256 constant SCOPE_INDEX = 3; + uint256 constant SUBSCOPE_INDEX = 4; + uint256 constant PARAM_COMMITMENTS_INDEX = 5; + // The length of the public inputs excluding the param commitments + uint256 constant PUBLIC_INPUTS_EXCLUDING_PARAM_COMMITMENTS_LENGTH = 7; +} + +// Gather all the MRZ indices in one place +library MRZIndex { + // Index for the country of issuance of the passport + uint256 constant PASSPORT_MRZ_ISSUING_COUNTRY_INDEX = 2; + // Index for the three letter code of the country of citizenship + // Note that the first three letter code (index 2) in the MRZ is the country of issuance + // not citizenship. It is important to keep in mind for residence permits + // where the issuing country differs from the citizenship country + uint256 constant PASSPORT_MRZ_NATIONALITY_INDEX = 54; + // Index for the gender of the passport holder (M, F or < if unspecified) + uint256 constant PASSPORT_MRZ_GENDER_INDEX = 64; + // Index for the date of expiry (YYMMDD) + uint256 constant PASSPORT_MRZ_EXPIRY_DATE_INDEX = 65; + // Index for the date of birth (YYMMDD) in TD1 (i.e. passport) MRZ + uint256 constant PASSPORT_MRZ_BIRTHDATE_INDEX = 57; + // Index for the document number in the MRZ + uint256 constant PASSPORT_MRZ_DOCUMENT_NUMBER_INDEX = 44; + // Index for the document type in the MRZ + uint256 constant PASSPORT_MRZ_DOCUMENT_TYPE_INDEX = 0; + // Index for the name of the passport holder + uint256 constant PASSPORT_MRZ_NAME_INDEX = 5; + + // Index for the country of issuance of the ID card + uint256 constant ID_CARD_MRZ_ISSUING_COUNTRY_INDEX = 2; + // Note that the first three letter code (index 2) in the MRZ is the country of issuance + // not citizenship. It is important to keep in mind for residence permits + // where the issuing country differs from the citizenship country + uint256 constant ID_CARD_MRZ_NATIONALITY_INDEX = 45; + // Index for the gender of the passport holder (M, F or < if unspecified) + uint256 constant ID_CARD_MRZ_GENDER_INDEX = 37; + // Index for the date of expiry (YYMMDD) + uint256 constant ID_CARD_MRZ_EXPIRY_DATE_INDEX = 38; + // Index for the date of birth (YYMMDD) in TD3 (i.e. ID cards) MRZ + uint256 constant ID_CARD_MRZ_BIRTHDATE_INDEX = 30; + // Index for the document number in the MRZ + uint256 constant ID_CARD_MRZ_DOCUMENT_NUMBER_INDEX = 5; + // Index for the document type in the MRZ + uint256 constant ID_CARD_MRZ_DOCUMENT_TYPE_INDEX = 0; + // Index for the name of the passport holder + uint256 constant ID_CARD_MRZ_NAME_INDEX = 60; +} + +// Gather all the MRZ field lengths in one place +library MRZLength { + uint256 constant PASSPORT_MRZ_LENGTH = 88; + uint256 constant ID_CARD_MRZ_LENGTH = 90; + uint256 constant MRZ_MAX_LENGTH = 90; + uint256 constant PASSPORT_MRZ_ISSUING_COUNTRY_LENGTH = 3; + uint256 constant ID_CARD_MRZ_ISSUING_COUNTRY_LENGTH = 3; + uint256 constant PASSPORT_MRZ_NATIONALITY_LENGTH = 3; + uint256 constant ID_CARD_MRZ_NATIONALITY_LENGTH = 3; + uint256 constant PASSPORT_MRZ_GENDER_LENGTH = 1; + uint256 constant ID_CARD_MRZ_GENDER_LENGTH = 1; + uint256 constant PASSPORT_MRZ_BIRTHDATE_LENGTH = 6; + uint256 constant ID_CARD_MRZ_BIRTHDATE_LENGTH = 6; + uint256 constant PASSPORT_MRZ_EXPIRY_DATE_LENGTH = 6; + uint256 constant ID_CARD_MRZ_EXPIRY_DATE_LENGTH = 6; + uint256 constant PASSPORT_MRZ_DOCUMENT_NUMBER_LENGTH = 9; + uint256 constant ID_CARD_MRZ_DOCUMENT_NUMBER_LENGTH = 9; + uint256 constant PASSPORT_MRZ_DOCUMENT_TYPE_LENGTH = 2; + uint256 constant ID_CARD_MRZ_DOCUMENT_TYPE_LENGTH = 2; + uint256 constant PASSPORT_MRZ_NAME_LENGTH = 39; + uint256 constant ID_CARD_MRZ_NAME_LENGTH = 30; + uint256 constant PASSPORT_MRZ_YEAR_OF_BIRTH_LENGTH = 2; + uint256 constant ID_CARD_MRZ_YEAR_OF_BIRTH_LENGTH = 2; +} + +library AppAttest { + // ZKPassport iOS App ID hash + // Little-endian packed and poseidon2 hash of `YL5MS3Z639.app.zkpassport.zkpassport` + bytes32 constant IOS_APP_ID_HASH = 0x1fa73686cf510f8f85757b0602de0dd72a13e68ae2092462be8b72662e7f179b; + // ZKPassport Android App ID hash + // Little-endian packed and poseidon2 hash of `app.zkpassport.zkpassport` + bytes32 constant ANDROID_APP_ID_HASH = 0x24d9929b248be7eeecaa98e105c034a50539610f3fdd4cb9c8983ef4100d615d; + // The hash of Apple's root certificate public key + bytes32 constant APPLE_ROOT_KEY_HASH = 0x2532418a107c5306fa8308c22255792cf77e4a290cbce8a840a642a3e591340b; + // The hash of Google's RSA root certificate public key + bytes32 constant GOOGLE_RSA_ROOT_KEY_HASH = 0x16700a2d9168a194fc85f237af5829b5a2be05b8ae8ac4879ada34cf54a9c211; + // The hash of Google's ECDSA (P384) root certificate public key + bytes32 constant GOOGLE_ECDSA_ROOT_KEY_HASH = 0x0e1889bec6c1d686abcf08360ff404f803ab345881ea8cba6aad33b7f7f7ffe0; + // The hash of the Android integrity public key + bytes32 constant ANDROID_INTEGRITY_PUBLIC_KEY_HASH = 0x12e3dc7cc8fec0205b51ff21825630865028f3be5bc64a6eec9ee5e71221319f; +} diff --git a/packages/registry-contracts/src/lib/DateUtils.sol b/packages/registry-contracts/src/lib/DateUtils.sol new file mode 100644 index 000000000..5f1186b96 --- /dev/null +++ b/packages/registry-contracts/src/lib/DateUtils.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright © 2026 ZKPassport +/* + ______ _ _ _____ _______ _______ _______ _____ _____ ______ _______ + ____/ |____/ |_____] |_____| |______ |______ |_____] | | |_____/ | + /_____ | \_ | | | ______| ______| | |_____| | \_ | + +*/ + +pragma solidity ^0.8.30; + +/** + * @title DateUtils + * @dev Utility functions for date operations + */ +library DateUtils { + /** + * @dev Validates if a date is within a validity period + * @param timestamp The timestamp in seconds since the Unix epoch + * @param validityPeriodInSeconds The validity period in seconds + * @return True if the date is valid and within the validity period + */ + function isDateValid(uint256 timestamp, uint256 validityPeriodInSeconds) internal view returns (bool) { + uint256 validityPeriodTimestamp = timestamp + validityPeriodInSeconds; + return block.timestamp >= timestamp && validityPeriodTimestamp > timestamp + && validityPeriodTimestamp > block.timestamp; + } +} diff --git a/packages/registry-contracts/src/lib/InputsExtractor.sol b/packages/registry-contracts/src/lib/InputsExtractor.sol new file mode 100644 index 000000000..d3f55772f --- /dev/null +++ b/packages/registry-contracts/src/lib/InputsExtractor.sol @@ -0,0 +1,359 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright © 2026 ZKPassport +/* + ______ _ _ _____ _______ _______ _______ _____ _____ ______ _______ + ____/ |____/ |_____] |_____| |______ |______ |_____] | | |_____/ | + /_____ | \_ | | | ______| ______| | |_____| | \_ | + +*/ + +pragma solidity ^0.8.30; + +import { + MRZIndex, + MRZLength, + CommittedInputLen, + COUNTRY_LIST_LENGTH, + BOUND_DATA_LENGTH, + TIMESTAMP_LENGTH +} from "./Constants.sol"; +import {DisclosedData, ProofType, FaceMatchMode, Environment, BoundDataIdentifier} from "./Types.sol"; + +/** + * @title InputsExtractor + * @dev Utility functions for extracting inputs from committed inputs + */ +library InputsExtractor { + function getDisclosedData(bytes calldata discloseBytes, bool isIDCard) + public + pure + returns (DisclosedData memory disclosedData) + { + if (!isIDCard) { + disclosedData.name = string( + discloseBytes[MRZIndex.PASSPORT_MRZ_NAME_INDEX:MRZIndex.PASSPORT_MRZ_NAME_INDEX + + MRZLength.PASSPORT_MRZ_NAME_LENGTH + ] + ); + disclosedData.issuingCountry = string( + discloseBytes[MRZIndex.PASSPORT_MRZ_ISSUING_COUNTRY_INDEX:MRZIndex.PASSPORT_MRZ_ISSUING_COUNTRY_INDEX + + MRZLength.PASSPORT_MRZ_ISSUING_COUNTRY_LENGTH + ] + ); + disclosedData.nationality = string( + discloseBytes[MRZIndex.PASSPORT_MRZ_NATIONALITY_INDEX:MRZIndex.PASSPORT_MRZ_NATIONALITY_INDEX + + MRZLength.PASSPORT_MRZ_NATIONALITY_LENGTH + ] + ); + disclosedData.gender = string( + discloseBytes[MRZIndex.PASSPORT_MRZ_GENDER_INDEX:MRZIndex.PASSPORT_MRZ_GENDER_INDEX + + MRZLength.PASSPORT_MRZ_GENDER_LENGTH + ] + ); + disclosedData.birthDate = string( + discloseBytes[MRZIndex.PASSPORT_MRZ_BIRTHDATE_INDEX:MRZIndex.PASSPORT_MRZ_BIRTHDATE_INDEX + + MRZLength.PASSPORT_MRZ_BIRTHDATE_LENGTH + ] + ); + disclosedData.expiryDate = string( + discloseBytes[MRZIndex.PASSPORT_MRZ_EXPIRY_DATE_INDEX:MRZIndex.PASSPORT_MRZ_EXPIRY_DATE_INDEX + + MRZLength.PASSPORT_MRZ_EXPIRY_DATE_LENGTH + ] + ); + disclosedData.documentNumber = string( + discloseBytes[MRZIndex.PASSPORT_MRZ_DOCUMENT_NUMBER_INDEX:MRZIndex.PASSPORT_MRZ_DOCUMENT_NUMBER_INDEX + + MRZLength.PASSPORT_MRZ_DOCUMENT_NUMBER_LENGTH + ] + ); + disclosedData.documentType = string( + discloseBytes[MRZIndex.PASSPORT_MRZ_DOCUMENT_TYPE_INDEX:MRZIndex.PASSPORT_MRZ_DOCUMENT_TYPE_INDEX + + MRZLength.PASSPORT_MRZ_DOCUMENT_TYPE_LENGTH + ] + ); + } else { + disclosedData.name = string( + discloseBytes[MRZIndex.ID_CARD_MRZ_NAME_INDEX:MRZIndex.ID_CARD_MRZ_NAME_INDEX + + MRZLength.ID_CARD_MRZ_NAME_LENGTH + ] + ); + disclosedData.issuingCountry = string( + discloseBytes[MRZIndex.ID_CARD_MRZ_ISSUING_COUNTRY_INDEX:MRZIndex.ID_CARD_MRZ_ISSUING_COUNTRY_INDEX + + MRZLength.ID_CARD_MRZ_ISSUING_COUNTRY_LENGTH + ] + ); + disclosedData.nationality = string( + discloseBytes[MRZIndex.ID_CARD_MRZ_NATIONALITY_INDEX:MRZIndex.ID_CARD_MRZ_NATIONALITY_INDEX + + MRZLength.ID_CARD_MRZ_NATIONALITY_LENGTH + ] + ); + disclosedData.gender = string( + discloseBytes[MRZIndex.ID_CARD_MRZ_GENDER_INDEX:MRZIndex.ID_CARD_MRZ_GENDER_INDEX + + MRZLength.ID_CARD_MRZ_GENDER_LENGTH + ] + ); + disclosedData.birthDate = string( + discloseBytes[MRZIndex.ID_CARD_MRZ_BIRTHDATE_INDEX:MRZIndex.ID_CARD_MRZ_BIRTHDATE_INDEX + + MRZLength.ID_CARD_MRZ_BIRTHDATE_LENGTH + ] + ); + disclosedData.expiryDate = string( + discloseBytes[MRZIndex.ID_CARD_MRZ_EXPIRY_DATE_INDEX:MRZIndex.ID_CARD_MRZ_EXPIRY_DATE_INDEX + + MRZLength.ID_CARD_MRZ_EXPIRY_DATE_LENGTH + ] + ); + disclosedData.documentNumber = string( + discloseBytes[MRZIndex.ID_CARD_MRZ_DOCUMENT_NUMBER_INDEX:MRZIndex.ID_CARD_MRZ_DOCUMENT_NUMBER_INDEX + + MRZLength.ID_CARD_MRZ_DOCUMENT_NUMBER_LENGTH + ] + ); + disclosedData.documentType = string( + discloseBytes[MRZIndex.ID_CARD_MRZ_DOCUMENT_TYPE_INDEX:MRZIndex.ID_CARD_MRZ_DOCUMENT_TYPE_INDEX + + MRZLength.ID_CARD_MRZ_DOCUMENT_TYPE_LENGTH + ] + ); + } + } + + function getDiscloseProofInputs(bytes calldata committedInputs) + public + pure + returns (bytes memory discloseMask, bytes memory discloseBytes) + { + uint256 offset = 0; + uint256 foundCount = 0; + while (offset < committedInputs.length) { + ProofType proofType = ProofType(uint8(committedInputs[offset])); + uint16 length = uint16(bytes2(committedInputs[offset + 1:offset + 3])); + offset += 3; + if (proofType == ProofType.DISCLOSE && length == CommittedInputLen.DISCLOSE_BYTES) { + discloseMask = committedInputs[offset:offset + MRZLength.MRZ_MAX_LENGTH]; + discloseBytes = committedInputs[offset + MRZLength.MRZ_MAX_LENGTH:offset + MRZLength.MRZ_MAX_LENGTH * 2]; + foundCount++; + } + offset += length; + } + require(foundCount > 0, "Disclose proof inputs not found"); + require(foundCount == 1, "Found multiple disclose proofs, the proof should only have one"); + } + + function getDateProofInputs(bytes calldata committedInputs, ProofType proofType) + public + pure + returns (uint256 minDate, uint256 maxDate) + { + uint256 offset = 0; + uint256 foundCount = 0; + while (offset < committedInputs.length) { + ProofType retrievedProofType = ProofType(uint8(committedInputs[offset])); + uint16 length = uint16(bytes2(committedInputs[offset + 1:offset + 3])); + offset += 3; + if (proofType == retrievedProofType && length == CommittedInputLen.COMPARE_EXPIRY) { + // Get rid of the padding 0s bytes as the timestamp is contained within the first 64 bits + // i.e. 256 - 64 = 192 + minDate = uint256(bytes32(committedInputs[offset:offset + TIMESTAMP_LENGTH])) >> 192; + maxDate = + uint256(bytes32(committedInputs[offset + TIMESTAMP_LENGTH:offset + TIMESTAMP_LENGTH * 2])) >> 192; + foundCount++; + } + offset += length; + } + if (proofType == ProofType.BIRTHDATE) { + require(foundCount > 0, "Compare birthdate proof inputs not found"); + require(foundCount == 1, "Found multiple compare birthdate proofs, the proof should only have one"); + } else { + require(foundCount > 0, "Compare expiry date proof inputs not found"); + require(foundCount == 1, "Found multiple compare expiry date proofs, the proof should only have one"); + } + } + + function getAgeProofInputs(bytes calldata committedInputs) public pure returns (uint8 minAge, uint8 maxAge) { + uint256 offset = 0; + uint256 foundCount = 0; + while (offset < committedInputs.length) { + ProofType retrievedProofType = ProofType(uint8(committedInputs[offset])); + uint16 length = uint16(bytes2(committedInputs[offset + 1:offset + 3])); + offset += 3; + if (retrievedProofType == ProofType.AGE && length == CommittedInputLen.COMPARE_AGE) { + minAge = uint8(committedInputs[offset]); + maxAge = uint8(committedInputs[offset + 1]); + foundCount++; + } + offset += length; + } + require(foundCount > 0, "Compare age proof inputs not found"); + require(foundCount == 1, "Found multiple compare age proofs, the proof should only have one"); + } + + function getCountryListLength(bytes calldata committedInputs, ProofType proofType) + public + pure + returns (uint256 countryListLength) + { + uint256 offset = 0; + while (offset < committedInputs.length) { + ProofType retrievedProofType = ProofType(uint8(committedInputs[offset])); + uint16 length = uint16(bytes2(committedInputs[offset + 1:offset + 3])); + offset += 3; + if (proofType == retrievedProofType && length == CommittedInputLen.INCL_NATIONALITY) { + for (uint256 j = 0; j < COUNTRY_LIST_LENGTH; j++) { + // The circuit constrains that once we've reached the first `0`, + // we won't encounter any further nonzero values. + // We don't need to include the padding bytes + if (committedInputs[offset] == 0) return j; + offset += 3; + } + offset += length - COUNTRY_LIST_LENGTH * 3; + } else { + offset += length; + } + } + } + + function getCountryProofInputs(bytes calldata committedInputs, ProofType proofType) + public + pure + returns (string[] memory countryList, uint256 countryListLength) + { + require( + proofType == ProofType.NATIONALITY_INCLUSION || proofType == ProofType.ISSUING_COUNTRY_INCLUSION + || proofType == ProofType.NATIONALITY_EXCLUSION || proofType == ProofType.ISSUING_COUNTRY_EXCLUSION, + "Invalid proof type" + ); + uint256 offset = 0; + uint256 foundCount = 0; + countryListLength = getCountryListLength(committedInputs, proofType); + countryList = new string[](countryListLength); + while (offset < committedInputs.length) { + ProofType retrievedProofType = ProofType(uint8(committedInputs[offset])); + uint16 length = uint16(bytes2(committedInputs[offset + 1:offset + 3])); + offset += 3; + if (proofType == retrievedProofType && length == CommittedInputLen.INCL_NATIONALITY) { + for (uint256 j = 0; j < countryListLength; j++) { + countryList[j] = string(committedInputs[offset:offset + 3]); + offset += 3; + } + offset += length - countryListLength * 3; + foundCount++; + } else { + offset += length; + } + } + if (proofType == ProofType.ISSUING_COUNTRY_INCLUSION) { + require(foundCount > 0, "Inclusion country proof inputs not found"); + require(foundCount == 1, "Found multiple inclusion country proofs, the proof should only have one"); + } else if (proofType == ProofType.ISSUING_COUNTRY_EXCLUSION) { + require(foundCount > 0, "Exclusion country proof inputs not found"); + require(foundCount == 1, "Found multiple exclusion country proofs, the proof should only have one"); + } else if (proofType == ProofType.NATIONALITY_INCLUSION) { + require(foundCount > 0, "Inclusion nationality proof inputs not found"); + require(foundCount == 1, "Found multiple inclusion nationality proofs, the proof should only have one"); + } else if (proofType == ProofType.NATIONALITY_EXCLUSION) { + require(foundCount > 0, "Exclusion nationality proof inputs not found"); + require(foundCount == 1, "Found multiple exclusion nationality proofs, the proof should only have one"); + } + } + + function getBindProofInputs(bytes calldata committedInputs) public pure returns (bytes memory data) { + uint256 offset = 0; + uint256 foundCount = 0; + while (offset < committedInputs.length) { + ProofType retrievedProofType = ProofType(uint8(committedInputs[offset])); + uint16 length = uint16(bytes2(committedInputs[offset + 1:offset + 3])); + offset += 3; + if (retrievedProofType == ProofType.BIND && length == CommittedInputLen.BIND) { + data = committedInputs[offset:offset + BOUND_DATA_LENGTH]; + foundCount++; + } + offset += length; + } + require(foundCount > 0, "Bind data proof inputs not found"); + require(foundCount == 1, "Found multiple bind data proofs, the proof should only have one"); + } + + function getSanctionsProofInputs(bytes calldata committedInputs) + public + pure + returns (bytes32 sanctionsTreesCommitment, bool isStrict) + { + uint256 offset = 0; + uint256 foundCount = 0; + while (offset < committedInputs.length) { + ProofType retrievedProofType = ProofType(uint8(committedInputs[offset])); + uint16 length = uint16(bytes2(committedInputs[offset + 1:offset + 3])); + offset += 3; + if (retrievedProofType == ProofType.SANCTIONS && length == CommittedInputLen.SANCTIONS) { + sanctionsTreesCommitment = bytes32(committedInputs[offset:offset + 32]); + isStrict = uint8(committedInputs[offset + 32]) == 1; + foundCount++; + } + offset += length; + } + require(foundCount > 0, "Sanctions proof inputs not found"); + require(foundCount == 1, "Found multiple sanctions proofs, the proof should only have one"); + } + + function getBoundData(bytes calldata data) + public + pure + returns (address senderAddress, uint256 chainId, string memory customData) + { + uint256 offset = 0; + while (offset < BOUND_DATA_LENGTH) { + if (data[offset] == bytes1(uint8(BoundDataIdentifier.USER_ADDRESS))) { + uint16 addressLength = uint16(bytes2(data[offset + 1:offset + 3])); + senderAddress = address(bytes20(data[offset + 3:offset + 3 + addressLength])); + offset += 2 + addressLength + 1; + } else if (data[offset] == bytes1(uint8(BoundDataIdentifier.CHAIN_ID))) { + uint16 chainIdLength = uint16(bytes2(data[offset + 1:offset + 3])); + require(chainIdLength <= 32, "Chain id length too long"); + // bytes32 right pads while we want to left pad + // so we shift the bytes to the right by 256 - (chainIdLength * 8) + chainId = uint256(bytes32(data[offset + 3:offset + 3 + chainIdLength]) >> (256 - (chainIdLength * 8))); + offset += 2 + chainIdLength + 1; + } else if (data[offset] == bytes1(uint8(BoundDataIdentifier.CUSTOM_DATA))) { + uint16 customDataLength = uint16(bytes2(data[offset + 1:offset + 3])); + customData = string(data[offset + 3:offset + 3 + customDataLength]); + offset += 2 + customDataLength + 1; + } else { + // Check that the data length is valid + require(offset > 0 && offset <= BOUND_DATA_LENGTH, "Invalid data length"); + // Check that the padding is valid + for (uint256 i = offset; i < BOUND_DATA_LENGTH; i++) { + require(data[i] == 0, "Invalid padding"); + } + break; + } + } + } + + function getFacematchProofInputs(bytes calldata committedInputs) + public + pure + returns ( + bytes32 rootKeyHash, + Environment environment, + bytes32 appIdHash, + bytes32 integrityPublicKeyHash, + FaceMatchMode facematchMode + ) + { + uint256 offset = 0; + uint256 foundCount = 0; + while (offset < committedInputs.length) { + ProofType retrievedProofType = ProofType(uint8(committedInputs[offset])); + uint16 length = uint16(bytes2(committedInputs[offset + 1:offset + 3])); + offset += 3; + if (retrievedProofType == ProofType.FACEMATCH && length == CommittedInputLen.FACEMATCH) { + rootKeyHash = bytes32(committedInputs[offset:offset + 32]); + environment = Environment(uint8(committedInputs[offset + 32])); + appIdHash = bytes32(committedInputs[offset + 33:offset + 65]); + integrityPublicKeyHash = bytes32(committedInputs[offset + 65:offset + 97]); + facematchMode = FaceMatchMode(uint8(committedInputs[offset + 97])); + foundCount++; + } + offset += length; + } + require(foundCount > 0, "Facematch proof inputs not found"); + require(foundCount == 1, "Found multiple facematch proofs, the proof should only have one"); + } +} diff --git a/packages/registry-contracts/src/lib/StringUtils.sol b/packages/registry-contracts/src/lib/StringUtils.sol new file mode 100644 index 000000000..1718d347f --- /dev/null +++ b/packages/registry-contracts/src/lib/StringUtils.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright © 2026 ZKPassport +/* + ______ _ _ _____ _______ _______ _______ _____ _____ ______ _______ + ____/ |____/ |_____] |_____| |______ |______ |_____] | | |_____/ | + /_____ | \_ | | | ______| ______| | |_____| | \_ | + +*/ + +pragma solidity ^0.8.30; + +library StringUtils { + function equals(string memory a, string memory b) internal pure returns (bool) { + return keccak256(bytes(a)) == keccak256(bytes(b)); + } + + function isEmpty(string memory a) internal pure returns (bool) { + return bytes(a).length == 0; + } +} diff --git a/packages/registry-contracts/src/lib/Types.sol b/packages/registry-contracts/src/lib/Types.sol new file mode 100644 index 000000000..ed924b309 --- /dev/null +++ b/packages/registry-contracts/src/lib/Types.sol @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright © 2026 ZKPassport +/* + ______ _ _ _____ _______ _______ _______ _____ _____ ______ _______ + ____/ |____/ |_____] |_____| |______ |______ |_____] | | |_____/ | + /_____ | \_ | | | ______| ______| | |_____| | \_ | + +*/ + +pragma solidity ^0.8.30; + +struct ProofVerifier { + bytes32 vkeyHash; + address verifier; +} + +enum ProofType { + DISCLOSE, + AGE, + BIRTHDATE, + EXPIRY_DATE, + NATIONALITY_INCLUSION, + NATIONALITY_EXCLUSION, + ISSUING_COUNTRY_INCLUSION, + ISSUING_COUNTRY_EXCLUSION, + BIND, + SANCTIONS, + FACEMATCH +} + +enum BoundDataIdentifier { + NONE, + USER_ADDRESS, + CHAIN_ID, + CUSTOM_DATA +} + +enum FaceMatchMode { + NONE, + REGULAR, + STRICT +} + +enum Environment { + DEVELOPMENT, + PRODUCTION +} + +enum NullifierType { + NON_SALTED_NULLIFIER, + SALTED_NULLIFIER, + NON_SALTED_MOCK_NULLIFIER, + SALTED_MOCK_NULLIFIER +} + +enum OS { + ANY, + IOS, + ANDROID +} + +// ProofVerificationParams +// │ +// ├── bytes32 version // Version identifier of the verifier +// │ +// ├── ProofVerificationData proofVerificationData +// │ ├── bytes32 vkeyHash // Verification key hash +// │ ├── bytes proof // The actual ZK proof +// │ └── bytes32[] publicInputs // Array of public inputs (7+ elements) +// │ │ // Use PublicInputsCast.asStruct() for structured access: +// │ ├── [0] certificate_registry_root // Field - struct.certificateRegistryRoot +// │ ├── [1] circuit_registry_root // Field - struct.circuitRegistryRoot +// │ ├── [2] current_date // u64 - PublicInputsCast.getCurrentDate(struct) +// │ ├── [3] service_scope // Field - struct.serviceScope +// │ ├── [4] service_subscope // Field - struct.serviceSubscope +// │ ├── [5:5+N] param_commitments // Field[N] - PublicInputsCast.getParamCommitment(array, index) +// │ ├── [5+N] nullifier_type // u8 - PublicInputsCast.getNullifierType(array, paramCount) +// │ └── [6+N] scoped_nullifier // Field - PublicInputsCast.getScopedNullifier(array, paramCount) +// │ +// ├── bytes committedInputs // Preimages of param_commitments +// │ +// └── ServiceConfig serviceConfig +// ├── uint256 validityPeriodInSeconds // How long the proof is valid +// ├── string domain // Service domain +// ├── string scope // Service scope +// └── bool devMode // Development mode flag +struct ProofVerificationParams { + bytes32 version; + ProofVerificationData proofVerificationData; + bytes committedInputs; + ServiceConfig serviceConfig; +} + +struct ProofVerificationData { + bytes32 vkeyHash; + bytes proof; + bytes32[] publicInputs; +} + +struct ServiceConfig { + uint256 validityPeriodInSeconds; + string domain; + string scope; + bool devMode; +} + +struct DisclosedData { + string name; + string issuingCountry; + string nationality; + string gender; + string birthDate; + string expiryDate; + string documentNumber; + string documentType; +} + +struct BoundData { + address senderAddress; + uint256 chainId; + string customData; +} diff --git a/packages/registry-contracts/src/mocks/MockHonkVerifier.sol b/packages/registry-contracts/src/mocks/MockHonkVerifier.sol new file mode 100644 index 000000000..4519bff73 --- /dev/null +++ b/packages/registry-contracts/src/mocks/MockHonkVerifier.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.30; + +contract HonkVerifier { + function verify(bytes calldata, bytes32[] calldata) external pure returns (bool) { + return true; + } +} diff --git a/packages/registry-contracts/src/CertificateRegistry.sol b/packages/registry-contracts/src/registries/CertificateRegistry.sol similarity index 80% rename from packages/registry-contracts/src/CertificateRegistry.sol rename to packages/registry-contracts/src/registries/CertificateRegistry.sol index 439a614aa..5ca93914a 100644 --- a/packages/registry-contracts/src/CertificateRegistry.sol +++ b/packages/registry-contracts/src/registries/CertificateRegistry.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright © 2025 ZKPassport +// Copyright © 2026 ZKPassport /* ______ _ _ _____ _______ _______ _______ _____ _____ ______ _______ ____/ |____/ |_____] |_____| |______ |______ |_____] | | |_____/ | @@ -9,8 +9,8 @@ pragma solidity ^0.8.30; -import {RegistryInstance} from "./RegistryInstance.sol"; -import {RootValidationMode} from "./IRegistryInstance.sol"; +import {RegistryInstance} from "../RegistryInstance.sol"; +import {RootValidationMode} from "../IRegistryInstance.sol"; /** * @title CertificateRegistry diff --git a/packages/registry-contracts/src/CircuitRegistry.sol b/packages/registry-contracts/src/registries/CircuitRegistry.sol similarity index 80% rename from packages/registry-contracts/src/CircuitRegistry.sol rename to packages/registry-contracts/src/registries/CircuitRegistry.sol index cb81e4d1a..34d548541 100644 --- a/packages/registry-contracts/src/CircuitRegistry.sol +++ b/packages/registry-contracts/src/registries/CircuitRegistry.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright © 2025 ZKPassport +// Copyright © 2026 ZKPassport /* ______ _ _ _____ _______ _______ _______ _____ _____ ______ _______ ____/ |____/ |_____] |_____| |______ |______ |_____] | | |_____/ | @@ -9,8 +9,8 @@ pragma solidity ^0.8.30; -import {RegistryInstance} from "./RegistryInstance.sol"; -import {RootValidationMode} from "./IRegistryInstance.sol"; +import {RegistryInstance} from "../RegistryInstance.sol"; +import {RootValidationMode} from "../IRegistryInstance.sol"; /** * @title CircuitRegistry diff --git a/packages/registry-contracts/src/SanctionsRegistry.sol b/packages/registry-contracts/src/registries/SanctionsRegistry.sol similarity index 80% rename from packages/registry-contracts/src/SanctionsRegistry.sol rename to packages/registry-contracts/src/registries/SanctionsRegistry.sol index 0cd235e68..55a65c1da 100644 --- a/packages/registry-contracts/src/SanctionsRegistry.sol +++ b/packages/registry-contracts/src/registries/SanctionsRegistry.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright © 2025 ZKPassport +// Copyright © 2026 ZKPassport /* ______ _ _ _____ _______ _______ _______ _____ _____ ______ _______ ____/ |____/ |_____] |_____| |______ |______ |_____] | | |_____/ | @@ -9,8 +9,8 @@ pragma solidity ^0.8.30; -import {RegistryInstance} from "./RegistryInstance.sol"; -import {RootValidationMode} from "./IRegistryInstance.sol"; +import {RegistryInstance} from "../RegistryInstance.sol"; +import {RootValidationMode} from "../IRegistryInstance.sol"; /** * @title SanctionsRegistry diff --git a/packages/registry-contracts/test/ProtocolController.t.sol b/packages/registry-contracts/test/ProtocolController.t.sol new file mode 100644 index 000000000..b6b99363f --- /dev/null +++ b/packages/registry-contracts/test/ProtocolController.t.sol @@ -0,0 +1,454 @@ +pragma solidity ^0.8.30; + +import "forge-std/Test.sol"; +import "../src/ProtocolController.sol"; +import {RootRegistry} from "../src/RootRegistry.sol"; +import {RootVerifier} from "../src/RootVerifier.sol"; + +contract ProtocolControllerTest is Test { + RootRegistry public rootRegistry; + RootVerifier public rootVerifier; + ProtocolController public controller; + + address public admin = makeAddr("admin"); + address public registryOperator = makeAddr("registryOperator"); + address public verifierOperator = makeAddr("verifierOperator"); + address public user = makeAddr("user"); + address public newAddr = makeAddr("newAddr"); + + function setUp() public { + rootRegistry = new RootRegistry(address(this), address(0)); + rootVerifier = new RootVerifier(address(this), address(0), RootRegistry(address(0))); + controller = new ProtocolController({ + _admin: admin, + _rootRegistry: address(rootRegistry), + _rootRegistryOperator: registryOperator, + _rootVerifier: address(rootVerifier), + _rootVerifierOperator: verifierOperator + }); + + rootRegistry.transferAdmin(address(controller)); + rootVerifier.transferAdmin(address(controller)); + } + + // ===== Deployment ===== + + function testDeployment() public view { + assertEq(controller.admin(), admin); + assertEq(controller.rootRegistryOperator(), registryOperator); + assertEq(controller.rootVerifierOperator(), verifierOperator); + assertEq(address(controller.rootRegistry()), address(rootRegistry)); + assertEq(address(controller.rootVerifier()), address(rootVerifier)); + } + + function testDeployRevertsWithZeroAdmin() public { + vm.expectRevert("Admin cannot be zero address"); + new ProtocolController( + address(0), address(rootRegistry), registryOperator, address(rootVerifier), verifierOperator + ); + } + + // ===== Admin: two-step admin transfer ===== + + function testTransferAdmin() public { + // Step 1: admin initiates transfer + vm.prank(admin); + controller.transferAdmin(newAddr); + assertEq(controller.pendingAdmin(), newAddr); + assertEq(controller.admin(), admin); + + // Step 2: new admin accepts + vm.prank(newAddr); + controller.acceptAdmin(); + assertEq(controller.admin(), newAddr); + assertEq(controller.pendingAdmin(), address(0)); + + // New admin can act, old admin cannot + vm.prank(newAddr); + controller.setRootRegistryOperator(user); + assertEq(controller.rootRegistryOperator(), user); + + vm.prank(admin); + vm.expectRevert("Not authorized: admin only"); + controller.setRootRegistryOperator(user); + } + + function testTransferAdminReverts() public { + vm.prank(user); + vm.expectRevert("Not authorized: admin only"); + controller.transferAdmin(newAddr); + + vm.prank(admin); + vm.expectRevert("Admin cannot be zero address"); + controller.transferAdmin(address(0)); + } + + function testAcceptAdminRevertsForNonPendingAdmin() public { + vm.prank(admin); + controller.transferAdmin(newAddr); + + vm.prank(user); + vm.expectRevert("Not authorized: pending admin only"); + controller.acceptAdmin(); + + // Original admin also cannot accept + vm.prank(admin); + vm.expectRevert("Not authorized: pending admin only"); + controller.acceptAdmin(); + } + + function testAdminCanOverwritePendingAdmin() public { + vm.prank(admin); + controller.transferAdmin(newAddr); + assertEq(controller.pendingAdmin(), newAddr); + + // Admin changes their mind + vm.prank(admin); + controller.transferAdmin(user); + assertEq(controller.pendingAdmin(), user); + + // Old pending admin can no longer accept + vm.prank(newAddr); + vm.expectRevert("Not authorized: pending admin only"); + controller.acceptAdmin(); + + // New pending admin can accept + vm.prank(user); + controller.acceptAdmin(); + assertEq(controller.admin(), user); + } + + // ===== Admin: operator role management ===== + + function testSetRootRegistryOperator() public { + vm.prank(admin); + controller.setRootRegistryOperator(newAddr); + assertEq(controller.rootRegistryOperator(), newAddr); + } + + function testSetRootVerifierOperator() public { + vm.prank(admin); + controller.setRootVerifierOperator(newAddr); + assertEq(controller.rootVerifierOperator(), newAddr); + } + + function testSetOperatorRolesRevertsForNonAdmin() public { + vm.startPrank(user); + vm.expectRevert("Not authorized: admin only"); + controller.setRootRegistryOperator(newAddr); + vm.expectRevert("Not authorized: admin only"); + controller.setRootVerifierOperator(newAddr); + vm.stopPrank(); + } + + // ===== Admin: restore underlying contract admins ===== + + function testRestoreRootRegistryAdmin() public { + vm.prank(admin); + controller.restoreRootRegistryAdmin(); + assertEq(rootRegistry.admin(), admin); + } + + function testRestoreRootVerifierAdmin() public { + vm.prank(admin); + controller.restoreRootVerifierAdmin(); + assertEq(rootVerifier.admin(), admin); + } + + function testRestoreContractAdminsRevertsForNonAdmin() public { + vm.startPrank(user); + vm.expectRevert("Not authorized: admin only"); + controller.restoreRootRegistryAdmin(); + vm.expectRevert("Not authorized: admin only"); + controller.restoreRootVerifierAdmin(); + vm.stopPrank(); + } + + // ===== Registry operator: delegation ===== + + function testRegistryOperatorDelegation() public { + bytes32 id = keccak256("registry1"); + bytes32 k = keccak256("key"); + bytes32 val = keccak256("val"); + address anotherAddr = makeAddr("anotherAddr"); + + vm.startPrank(registryOperator); + + controller.rootRegistry_addRegistry(id, newAddr); + assertEq(address(rootRegistry.registries(id)), newAddr); + + controller.rootRegistry_updateRegistry(id, anotherAddr); + assertEq(address(rootRegistry.registries(id)), anotherAddr); + + controller.rootRegistry_removeRegistry(id); + assertEq(address(rootRegistry.registries(id)), address(0)); + + controller.rootRegistry_setGuardian(newAddr); + assertEq(rootRegistry.guardian(), newAddr); + + controller.rootRegistry_updateConfig(k, val); + assertEq(rootRegistry.config(k), val); + + controller.rootRegistry_pause(); + assertTrue(rootRegistry.paused()); + + controller.rootRegistry_unpause(); + assertFalse(rootRegistry.paused()); + + vm.stopPrank(); + } + + function testRegistryOperatorFunctionsRevertForUnauthorized() public { + bytes32 id = keccak256("r"); + + vm.startPrank(user); + vm.expectRevert("Not authorized: admin or root registry operator only"); + controller.rootRegistry_addRegistry(id, newAddr); + vm.expectRevert("Not authorized: admin or root registry operator only"); + controller.rootRegistry_updateRegistry(id, newAddr); + vm.expectRevert("Not authorized: admin or root registry operator only"); + controller.rootRegistry_removeRegistry(id); + vm.expectRevert("Not authorized: admin or root registry operator only"); + controller.rootRegistry_setGuardian(newAddr); + vm.expectRevert("Not authorized: admin or root registry operator only"); + controller.rootRegistry_updateConfig(id, id); + vm.expectRevert("Not authorized: admin or root registry operator only"); + controller.rootRegistry_pause(); + vm.expectRevert("Not authorized: admin or root registry operator only"); + controller.rootRegistry_unpause(); + vm.stopPrank(); + } + + function testAdminCanCallRegistryFunctions() public { + bytes32 id = keccak256("registry1"); + vm.prank(admin); + controller.rootRegistry_addRegistry(id, newAddr); + assertEq(address(rootRegistry.registries(id)), newAddr); + } + + // ===== Verifier operator: delegation ===== + + function testVerifierOperatorDelegation() public { + bytes32 v = keccak256("v1"); + bytes32 k = keccak256("key"); + bytes32 val = keccak256("val"); + + vm.startPrank(verifierOperator); + + controller.rootVerifier_addSubVerifier(v, newAddr); + assertEq(rootVerifier.getSubVerifier(v), newAddr); + + controller.rootVerifier_updateSubVerifier(v, user); + assertEq(rootVerifier.getSubVerifier(v), user); + + controller.rootVerifier_removeSubVerifier(v); + assertEq(rootVerifier.getSubVerifier(v), address(0)); + + controller.rootVerifier_addHelper(v, newAddr); + assertEq(rootVerifier.getHelper(v), newAddr); + + controller.rootVerifier_updateHelper(v, user); + assertEq(rootVerifier.getHelper(v), user); + + controller.rootVerifier_removeHelper(v); + assertEq(rootVerifier.getHelper(v), address(0)); + + controller.rootVerifier_setGuardian(newAddr); + assertEq(rootVerifier.guardian(), newAddr); + + controller.rootVerifier_updateConfig(k, val); + assertEq(rootVerifier.config(k), val); + + controller.rootVerifier_pause(); + assertTrue(rootVerifier.paused()); + + controller.rootVerifier_unpause(); + assertFalse(rootVerifier.paused()); + + vm.stopPrank(); + } + + function testVerifierOperatorFunctionsRevertForUnauthorized() public { + bytes32 v = keccak256("v1"); + + vm.startPrank(user); + vm.expectRevert("Not authorized: admin or root verifier operator only"); + controller.rootVerifier_addSubVerifier(v, newAddr); + vm.expectRevert("Not authorized: admin or root verifier operator only"); + controller.rootVerifier_removeSubVerifier(v); + vm.expectRevert("Not authorized: admin or root verifier operator only"); + controller.rootVerifier_updateSubVerifier(v, newAddr); + vm.expectRevert("Not authorized: admin or root verifier operator only"); + controller.rootVerifier_addHelper(v, newAddr); + vm.expectRevert("Not authorized: admin or root verifier operator only"); + controller.rootVerifier_removeHelper(v); + vm.expectRevert("Not authorized: admin or root verifier operator only"); + controller.rootVerifier_updateHelper(v, newAddr); + vm.expectRevert("Not authorized: admin or root verifier operator only"); + controller.rootVerifier_setGuardian(newAddr); + vm.expectRevert("Not authorized: admin or root verifier operator only"); + controller.rootVerifier_updateConfig(v, v); + vm.expectRevert("Not authorized: admin or root verifier operator only"); + controller.rootVerifier_pause(); + vm.expectRevert("Not authorized: admin or root verifier operator only"); + controller.rootVerifier_unpause(); + vm.stopPrank(); + } + + function testAdminCanCallVerifierFunctions() public { + bytes32 v = keccak256("v1"); + vm.prank(admin); + controller.rootVerifier_addSubVerifier(v, newAddr); + assertEq(rootVerifier.getSubVerifier(v), newAddr); + } + + // ===== Cross-role isolation ===== + + function testCrossRoleIsolation() public { + vm.prank(registryOperator); + vm.expectRevert("Not authorized: admin or root verifier operator only"); + controller.rootVerifier_pause(); + + vm.prank(verifierOperator); + vm.expectRevert("Not authorized: admin or root registry operator only"); + controller.rootRegistry_pause(); + } + + function testOperatorsCannotCallAdminOnlyFunctions() public { + vm.prank(registryOperator); + vm.expectRevert("Not authorized: admin only"); + controller.transferAdmin(newAddr); + + vm.prank(verifierOperator); + vm.expectRevert("Not authorized: admin only"); + controller.transferAdmin(newAddr); + } + + // ===== Operator role reassignment ===== + + function testNewRegistryOperatorCanActAfterReassignment() public { + vm.prank(admin); + controller.setRootRegistryOperator(newAddr); + + vm.prank(newAddr); + controller.rootRegistry_pause(); + assertTrue(rootRegistry.paused()); + + vm.prank(registryOperator); + vm.expectRevert("Not authorized: admin or root registry operator only"); + controller.rootRegistry_unpause(); + } + + function testNewVerifierOperatorCanActAfterReassignment() public { + vm.prank(admin); + controller.setRootVerifierOperator(newAddr); + + vm.prank(newAddr); + controller.rootVerifier_pause(); + assertTrue(rootVerifier.paused()); + + vm.prank(verifierOperator); + vm.expectRevert("Not authorized: admin or root verifier operator only"); + controller.rootVerifier_unpause(); + } + + // ===== Admin transfer round-trip ===== + + function testRootRegistryAdminTransferToControllerAndBack() public { + address multisig = makeAddr("multisig"); + + RootRegistry freshRegistry = new RootRegistry(multisig, address(0)); + assertEq(freshRegistry.admin(), multisig); + + ProtocolController ctrl = new ProtocolController({ + _admin: multisig, + _rootRegistry: address(freshRegistry), + _rootRegistryOperator: address(0), + _rootVerifier: address(0), + _rootVerifierOperator: address(0) + }); + + // Multisig transfers RootRegistry admin to the controller + vm.prank(multisig); + freshRegistry.transferAdmin(address(ctrl)); + assertEq(freshRegistry.admin(), address(ctrl)); + + // Multisig can no longer act directly on the RootRegistry + vm.prank(multisig); + vm.expectRevert("Not authorized: admin or guardian only"); + freshRegistry.pause(); + + // Controller (via multisig as admin) can now act on the RootRegistry + vm.prank(multisig); + ctrl.rootRegistry_pause(); + assertTrue(freshRegistry.paused()); + + vm.prank(multisig); + ctrl.rootRegistry_unpause(); + assertFalse(freshRegistry.paused()); + + // Multisig (as controller admin) transfers RootRegistry admin back to itself + vm.prank(multisig); + ctrl.restoreRootRegistryAdmin(); + assertEq(freshRegistry.admin(), multisig); + + // Controller can no longer act on the RootRegistry + vm.prank(multisig); + vm.expectRevert("Not authorized: admin or guardian only"); + ctrl.rootRegistry_pause(); + + // Multisig can act directly on the RootRegistry again + vm.prank(multisig); + freshRegistry.pause(); + assertTrue(freshRegistry.paused()); + } + + function testRootVerifierAdminTransferToControllerAndBack() public { + address multisig = makeAddr("multisig"); + + RootVerifier freshVerifier = new RootVerifier(multisig, address(0), RootRegistry(address(0))); + assertEq(freshVerifier.admin(), multisig); + + ProtocolController ctrl = new ProtocolController({ + _admin: multisig, + _rootRegistry: address(0), + _rootRegistryOperator: address(0), + _rootVerifier: address(freshVerifier), + _rootVerifierOperator: address(0) + }); + + // Multisig transfers RootVerifier admin to the controller + vm.prank(multisig); + freshVerifier.transferAdmin(address(ctrl)); + assertEq(freshVerifier.admin(), address(ctrl)); + + // Multisig can no longer act directly on the RootVerifier + vm.prank(multisig); + vm.expectRevert("Not authorized: admin or guardian only"); + freshVerifier.pause(); + + // Controller (via multisig as admin) can now act on the RootVerifier + vm.prank(multisig); + ctrl.rootVerifier_pause(); + assertTrue(freshVerifier.paused()); + + vm.prank(multisig); + ctrl.rootVerifier_unpause(); + assertFalse(freshVerifier.paused()); + + // Multisig (as controller admin) transfers RootVerifier admin back to itself + vm.prank(multisig); + ctrl.restoreRootVerifierAdmin(); + assertEq(freshVerifier.admin(), multisig); + + // Controller can no longer act on the RootVerifier + vm.prank(multisig); + vm.expectRevert("Not authorized: admin or guardian only"); + ctrl.rootVerifier_pause(); + + // Multisig can act directly on the RootVerifier again + vm.prank(multisig); + freshVerifier.pause(); + assertTrue(freshVerifier.paused()); + } +} diff --git a/packages/registry-contracts/test/RegistryHelper.t.sol b/packages/registry-contracts/test/RegistryHelper.t.sol index 7ca407454..7bb3746bb 100644 --- a/packages/registry-contracts/test/RegistryHelper.t.sol +++ b/packages/registry-contracts/test/RegistryHelper.t.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.30; import "forge-std/Test.sol"; import "../src/RootRegistry.sol"; -import "../src/CertificateRegistry.sol"; +import "../src/registries/CertificateRegistry.sol"; import "../src/RegistryHelper.sol"; import {TestConstants} from "./TestConstants.sol"; import {MockRegistry} from "./MockRegistry.sol"; diff --git a/packages/registry-contracts/test/RootRegistry.t.sol b/packages/registry-contracts/test/RootRegistry.t.sol index 015aeb03d..4737e4754 100644 --- a/packages/registry-contracts/test/RootRegistry.t.sol +++ b/packages/registry-contracts/test/RootRegistry.t.sol @@ -200,6 +200,38 @@ contract RootRegistryTest is Test { registry.addRegistry(circuitRegistryId, mockValidRegistry); } + function testTransferAdminRoundTrip() public { + address multisig = makeAddr("multisig"); + + // Admin (acting as initial deployer) transfers to multisig + vm.prank(admin); + registry.transferAdmin(multisig); + assertEq(registry.admin(), multisig); + + // Old admin can no longer act + vm.prank(admin); + vm.expectRevert("Not authorized: admin only"); + registry.addRegistry(certificateRegistryId, mockValidRegistry); + + // Multisig can act + vm.prank(multisig); + registry.addRegistry(certificateRegistryId, mockValidRegistry); + + // Multisig transfers back to original admin + vm.prank(multisig); + registry.transferAdmin(admin); + assertEq(registry.admin(), admin); + + // Original admin can act again + vm.prank(admin); + registry.addRegistry(circuitRegistryId, mockValidRegistry); + + // Multisig can no longer act + vm.prank(multisig); + vm.expectRevert("Not authorized: admin only"); + registry.addRegistry(keccak256("another"), mockValidRegistry); + } + function testCannotTransferAdminToZeroAddress() public { // Admin tries to transfer admin role to zero address vm.prank(admin); diff --git a/packages/registry-sdk/tests/utils/helpers.ts b/packages/registry-sdk/tests/utils/helpers.ts index ae171ccba..b31c28288 100644 --- a/packages/registry-sdk/tests/utils/helpers.ts +++ b/packages/registry-sdk/tests/utils/helpers.ts @@ -239,7 +239,7 @@ export async function startAnvil({ if (verbose) console.log("Deploying contracts...") let deployOutput = "" try { - deployOutput = execSync(`script/test/deploy.sh`, { + deployOutput = execSync(`script/test/deploy-root-registry.sh`, { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"], env: { ...process.env, RPC_URL }, From e6c8b7da293fdd920e2e6f345feb1b3ec1d3152d Mon Sep 17 00:00:00 2001 From: Michael Elliot Date: Tue, 28 Apr 2026 14:01:00 +0800 Subject: [PATCH 15/30] feat(workspace): New certificate root format (#174) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduces v1 of the packaged certificates file format, including a new certificate root derivation that binds the certificate, revocation, and masterlist trees together. This also includes the onchain, SDK, and explorer changes required to publish, validate, and consume the new format. ## Root format Adds the v1 root derivation: ```text state_root = H(cert_tree_root, revocation_tree_root, masterlist_tree_root) certificate_root = H(packed(schema_version | timestamp), state_root) ``` `schema_version` is encoded as 2 big-endian bytes and `timestamp` as 4 big-endian bytes, packed into one 31-byte field. v0 behaviour is preserved for backward compatibility: ```text certificate_root = cert_tree_root ``` ## zkpassport-utils - Adds v1 support for `PackagedCertificatesFile`. - `PackagedCertificatesFile` is now a discriminated union of: - `PackagedCertificatesFileV0` - `PackagedCertificatesFileV1` - v1 adds: - `revocations` - `revocations_serialised` - `masterlists` - v1 renames: - `serialised` → `certificates_serialised` - Removes `PackagedCertificate.hash_algorithm` from the schema. - Adds revocation tree and masterlist tree primitives: - `IntermediateCertificateRevocation` - `getRevocationLeafHash` - `getRevocationLeafHashes` - `buildMerkleTreeFromRevocations` - `buildMerkleTreeFromMasterlists` - Adds ordered-tree non-membership proofs for revocations: - `OrderedMerkleExclusionProof` - `buildRevocationExclusionProof` - `verifyRevocationExclusionProof` - Documents left, interior, and after-the-end boundary encoding for revocation exclusion proofs. - Exports canonical tree heights explicitly: - `CERTIFICATE_MERKLE_TREE_HEIGHT = 16` - `REVOCATION_MERKLE_TREE_HEIGHT = 14` - `MASTERLIST_MERKLE_TREE_HEIGHT = 8` - Renames `CERTIFICATE_REGISTRY_HEIGHT` to `CERTIFICATE_MERKLE_TREE_HEIGHT`. - Adds an optional `now` parameter to `calculateAge` for testability. ## registry-contracts - Extends `RegistryHelper.RootDetails` with: - `metadata1` - `metadata2` - `metadata3` - For the certificate registry: - `metadata1` stores the v1 `state_root` - `metadata2` is reserved - `metadata3` is reserved - Routes all root-detail getters through a new `_buildRootDetails` helper. ## registry-sdk - Makes `validateCertificates` static. - Updates certificate validation to delegate to `calculatePackagedCertificatesRoot`, allowing v0 and v1 files to be validated through the same canonical derivation path. - Updates `RootDetails` ABI decoding from 7 to 10 `bytes32` words. - Exposes the new root metadata fields: - `metadata1` - `metadata2` - `metadata3` - Adds `getRegistryHelperAddress()`. - Updates Mainnet and Sepolia `registryHelper` addresses to the new deployments. ## registry-explorer - Adds `NetworkProvider` and `NetworkSwitcher` with support for: Mainnet, Testnet and Local (when localhost detected) - Reworks the certificate diff page for the v1 root/state-root structure. - Adds `CertificateCard`, searchable country filter, and broader UI, theming, and accessibility improvements --- .eslintrc.cjs | 2 +- bun.lock | 4 +- .../script/test/SeedRegistries.s.sol | 2 +- .../script/test/seed-registries.sh | 2 +- .../registry-contracts/src/RegistryHelper.sol | 90 +- .../test/RegistryHelper.t.sol | 47 + .../app/certificates/diff/page.tsx | 983 ++++++++++++++---- .../app/certificates/history/page.tsx | 22 +- .../app/certificates/page.tsx | 2 +- packages/registry-explorer/app/layout.tsx | 7 +- packages/registry-explorer/app/map/page.tsx | 4 - packages/registry-explorer/app/page.tsx | 2 + .../components/CertificateRootCard.tsx | 11 +- .../components/CertificateSearch.tsx | 356 +++---- .../components/Map/CertificateDetails.tsx | 5 +- .../components/Map/RegistryDiff.tsx | 9 +- .../components/Navigation.tsx | 21 +- .../components/NetworkProvider.tsx | 186 ++++ .../components/NetworkSwitcher.tsx | 53 + .../components/ThemeProvider.tsx | 33 +- .../components/ThemeToggle.tsx | 24 +- .../certificate/CertificateCard.tsx | 348 +++++++ .../certificate/CertificateFilters.tsx | 287 +++-- .../certificate/CertificateList.tsx | 282 +---- .../components/certificate/StatsCardIcons.tsx | 31 + .../components/ui/searchable-select.tsx | 184 ++++ .../hooks/useCertificates.ts | 55 +- .../hooks/useHistoricalCertificateRoots.ts | 12 +- .../hooks/useHistoricalCircuitRoots.ts | 12 +- .../hooks/useRegistryInfo.ts | 13 +- .../registry-explorer/lib/certificate-url.ts | 11 +- packages/registry-explorer/lib/utils.ts | 13 + packages/registry-sdk/package.json | 2 +- packages/registry-sdk/src/client.ts | 72 +- packages/registry-sdk/src/constants.ts | 6 +- packages/registry-sdk/src/types.ts | 16 + .../tests/fixtures/certificates.json | 12 +- .../tests/registry-client.test.ts | 20 +- packages/registry-sdk/tests/retry.test.ts | 10 +- .../registry-sdk/tests/utils/constants.ts | 4 +- packages/registry-sdk/tests/utils/helpers.ts | 9 +- packages/registry-sdk/tsup.config.ts | 2 +- packages/zkpassport-sdk/tsup.config.ts | 2 +- packages/zkpassport-utils/package.json | 2 +- .../zkpassport-utils/src/circuit-matcher.ts | 51 +- packages/zkpassport-utils/src/cms/utils.ts | 122 +-- .../zkpassport-utils/src/country/country.ts | 11 +- .../zkpassport-utils/src/registry/index.ts | 520 ++++++++- .../src/signature-verification.ts | 25 - packages/zkpassport-utils/src/types/index.ts | 3 + .../zkpassport-utils/src/types/registry.ts | 61 +- .../tests/circuit-matcher.test.ts | 11 +- .../tests/fixtures/root-certs-v1.json | 12 +- .../zkpassport-utils/tests/registry.test.ts | 579 ++++++++++- packages/zkpassport-utils/tsup.config.ts | 2 +- 55 files changed, 3412 insertions(+), 1255 deletions(-) create mode 100644 packages/registry-explorer/components/NetworkProvider.tsx create mode 100644 packages/registry-explorer/components/NetworkSwitcher.tsx create mode 100644 packages/registry-explorer/components/certificate/CertificateCard.tsx create mode 100644 packages/registry-explorer/components/certificate/StatsCardIcons.tsx create mode 100644 packages/registry-explorer/components/ui/searchable-select.tsx diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 2359ebaca..9bb9e3f67 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -15,7 +15,7 @@ module.exports = { "semi": ["error", "never"], "no-unused-vars": "off", "@typescript-eslint/no-unused-vars": [ - "error", + "warn", { args: "all", argsIgnorePattern: "^_", diff --git a/bun.lock b/bun.lock index cef0e6729..1f2539b22 100644 --- a/bun.lock +++ b/bun.lock @@ -67,7 +67,7 @@ }, "packages/registry-sdk": { "name": "@zkpassport/registry", - "version": "0.14.0-beta.1", + "version": "0.14.0-beta.2", "dependencies": { "@zkpassport/poseidon2": "^0.6.2", "@zkpassport/utils": "workspace:*", @@ -110,7 +110,7 @@ }, "packages/zkpassport-utils": { "name": "@zkpassport/utils", - "version": "0.36.0-beta.1", + "version": "0.36.0-beta.2", "dependencies": { "@lapo/asn1js": "^2.0.4", "@noble/ciphers": "^1.0.0", diff --git a/packages/registry-contracts/script/test/SeedRegistries.s.sol b/packages/registry-contracts/script/test/SeedRegistries.s.sol index 75e928f3b..50f9af7aa 100644 --- a/packages/registry-contracts/script/test/SeedRegistries.s.sol +++ b/packages/registry-contracts/script/test/SeedRegistries.s.sol @@ -32,7 +32,7 @@ import {RegistryInstance} from "../../src/RegistryInstance.sol"; contract SeedRegistriesScript is Script { // These are the test fixture roots and CIDs from registry-sdk bytes32 constant DEFAULT_CERTIFICATE_REGISTRY_ROOT = - 0x2b49d7ddaec2fa540efec3311af6223cfd19d3a9e9314e10039f9fae0747f062; + 0x23e802a448e80b578b81ed587e325cd0dcfb0dac0e6cc6dd6464012fdcdcfd2d; bytes32 constant DEFAULT_CIRCUIT_REGISTRY_ROOT = 0x068f6e356f993bd2afaf3d3466efff1dd4bc06f61952ac336085b832b93289a7; bytes32 constant DEFAULT_SANCTIONS_REGISTRY_ROOT = 0x099699583ea7729a4a05821667645e927b74feb4e6e5382c6e4370e35ed2b23c; diff --git a/packages/registry-contracts/script/test/seed-registries.sh b/packages/registry-contracts/script/test/seed-registries.sh index 07a87f6a1..fe7c40d16 100755 --- a/packages/registry-contracts/script/test/seed-registries.sh +++ b/packages/registry-contracts/script/test/seed-registries.sh @@ -13,7 +13,7 @@ export ETHERSCAN_API_KEY=${ETHERSCAN_API_KEY:-dummy} export ORACLE_ADDRESS=${ORACLE_ADDRESS:-0x70997970C51812dc3A010C7d01b50e0d17dc79C8} export ORACLE_PRIVATE_KEY=${ORACLE_PRIVATE_KEY:-0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d} -export CERTIFICATE_REGISTRY_ROOT=${CERTIFICATE_REGISTRY_ROOT:-0x2b49d7ddaec2fa540efec3311af6223cfd19d3a9e9314e10039f9fae0747f062} +export CERTIFICATE_REGISTRY_ROOT=${CERTIFICATE_REGISTRY_ROOT:-0x23e802a448e80b578b81ed587e325cd0dcfb0dac0e6cc6dd6464012fdcdcfd2d} export CIRCUIT_REGISTRY_ROOT=${CIRCUIT_REGISTRY_ROOT:-0x068f6e356f993bd2afaf3d3466efff1dd4bc06f61952ac336085b832b93289a7} export SANCTIONS_REGISTRY_ROOT=${SANCTIONS_REGISTRY_ROOT:-0x099699583ea7729a4a05821667645e927b74feb4e6e5382c6e4370e35ed2b23c} diff --git a/packages/registry-contracts/src/RegistryHelper.sol b/packages/registry-contracts/src/RegistryHelper.sol index ee78b85fb..716650b16 100644 --- a/packages/registry-contracts/src/RegistryHelper.sol +++ b/packages/registry-contracts/src/RegistryHelper.sol @@ -36,6 +36,46 @@ contract RegistryHelper { bool revoked; uint256 leaves; bytes32 cid; + bytes32 metadata1; + bytes32 metadata2; + bytes32 metadata3; + } + + /** + * @dev Build a RootDetails entry for a given root by reading from the registry's + * consolidated `historicalRoots` mapping. Extracted to avoid stack-too-deep errors + * in callers that would otherwise hold all 10 fields as locals. + */ + function _buildRootDetails(IRegistryInstance registry, bytes32 root, uint256 index) + private + view + returns (RootDetails memory details) + { + // Read the root details from the registry + ( + uint256 validFrom, + uint256 validTo, + bool revoked, + uint256 leaves, + bytes32 cid, + bytes32 metadata1, + bytes32 metadata2, + bytes32 metadata3 + ) = registry.historicalRoots(root); + + // Return the RootDetails entry + details = RootDetails({ + index: index, + root: root, + validFrom: validFrom, + validTo: validTo, + revoked: revoked, + leaves: leaves, + cid: cid, + metadata1: metadata1, + metadata2: metadata2, + metadata3: metadata3 + }); } /** @@ -80,22 +120,8 @@ contract RegistryHelper { // Populate the results array for (uint256 i = 0; i < actualLimit; i++) { bytes32 rootHash = registry.rootByIndex(currentIndex); - - // Get the root details - accessing all fields from the consolidated HistoricalRoot struct - (uint256 validFrom, uint256 validTo, bool revoked, uint256 leaves, bytes32 cid,,,) = - registry.historicalRoots(rootHash); - // Add to results - roots[i] = RootDetails({ - index: currentIndex, - root: rootHash, - validFrom: validFrom, - validTo: validTo, - revoked: revoked, - leaves: leaves, - cid: cid - }); - + roots[i] = _buildRootDetails(registry, rootHash, currentIndex); // Move to the next index currentIndex++; } @@ -147,22 +173,10 @@ contract RegistryHelper { bytes32 latestRoot = registry.latestRoot(); require(latestRoot != bytes32(0), "No roots exist yet"); - // Get the consolidated data from historicalRoots - (uint256 validFrom, uint256 validTo, bool revoked, uint256 leaves, bytes32 cid,,,) = - registry.historicalRoots(latestRoot); - // Get the index of the latest root uint256 index = registry.indexByRoot(latestRoot); - - return RootDetails({ - index: index, - root: latestRoot, - validFrom: validFrom, - validTo: validTo, - revoked: revoked, - leaves: leaves, - cid: cid - }); + // Build and return the RootDetails entry + return _buildRootDetails(registry, latestRoot, index); } /** @@ -178,13 +192,8 @@ contract RegistryHelper { bytes32 root = registry.rootByIndex(index); require(root != bytes32(0), "Root not found"); - // Get the consolidated data from historicalRoots - (uint256 validFrom, uint256 validTo, bool revoked, uint256 leaves, bytes32 cid,,,) = - registry.historicalRoots(root); - - return RootDetails({ - index: index, root: root, validFrom: validFrom, validTo: validTo, revoked: revoked, leaves: leaves, cid: cid - }); + // Return the RootDetails entry + return _buildRootDetails(registry, root, index); } /** @@ -201,13 +210,8 @@ contract RegistryHelper { uint256 index = registry.indexByRoot(root); require(index != 0, "Root not found"); - // Get the consolidated data from historicalRoots - (uint256 validFrom, uint256 validTo, bool revoked, uint256 leaves, bytes32 cid,,,) = - registry.historicalRoots(root); - - return RootDetails({ - index: index, root: root, validFrom: validFrom, validTo: validTo, revoked: revoked, leaves: leaves, cid: cid - }); + // Return the RootDetails entry + return _buildRootDetails(registry, root, index); } /** diff --git a/packages/registry-contracts/test/RegistryHelper.t.sol b/packages/registry-contracts/test/RegistryHelper.t.sol index 7bb3746bb..e56791b6f 100644 --- a/packages/registry-contracts/test/RegistryHelper.t.sol +++ b/packages/registry-contracts/test/RegistryHelper.t.sol @@ -347,6 +347,53 @@ contract RegistryHelperTest is Test { helper.getRootDetailsByRoot(CERTIFICATE_REGISTRY_ID, bytes32(uint256(1))); } + function testRootDetailsIncludesMetadataFields() public { + bytes32 root1 = bytes32(uint256(1)); + bytes32 root2 = bytes32(uint256(2)); + bytes32 ipfsCid1 = bytes32(uint256(100)); + bytes32 ipfsCid2 = bytes32(uint256(200)); + bytes32 m1a = bytes32(uint256(0xaaaa)); + bytes32 m2a = bytes32(uint256(0xbbbb)); + bytes32 m3a = bytes32(uint256(0xcccc)); + bytes32 m1b = bytes32(uint256(0xdddd)); + bytes32 m2b = bytes32(uint256(0xeeee)); + bytes32 m3b = bytes32(uint256(0xffff)); + + vm.prank(oracle); + registry.updateRootWithMetadata(root1, bytes32(0), block.timestamp, 100, ipfsCid1, m1a, m2a, m3a); + vm.warp(block.timestamp + 1); + vm.prank(oracle); + registry.updateRootWithMetadata(root2, root1, block.timestamp, 200, ipfsCid2, m1b, m2b, m3b); + + // getRootDetailsByRoot exposes metadata + RegistryHelper.RootDetails memory byRoot = helper.getRootDetailsByRoot(CERTIFICATE_REGISTRY_ID, root1); + assertEq(byRoot.metadata1, m1a); + assertEq(byRoot.metadata2, m2a); + assertEq(byRoot.metadata3, m3a); + + // getRootDetailsByIndex exposes metadata + RegistryHelper.RootDetails memory byIndex = helper.getRootDetailsByIndex(CERTIFICATE_REGISTRY_ID, 2); + assertEq(byIndex.metadata1, m1b); + assertEq(byIndex.metadata2, m2b); + assertEq(byIndex.metadata3, m3b); + + // getLatestRootDetails exposes metadata + RegistryHelper.RootDetails memory latest = helper.getLatestRootDetails(CERTIFICATE_REGISTRY_ID); + assertEq(latest.metadata1, m1b); + assertEq(latest.metadata2, m2b); + assertEq(latest.metadata3, m3b); + + // getHistoricalRoots exposes metadata for each entry + (RegistryHelper.RootDetails[] memory page,) = helper.getHistoricalRoots(CERTIFICATE_REGISTRY_ID, 1, 10); + assertEq(page.length, 2); + assertEq(page[0].metadata1, m1a); + assertEq(page[0].metadata2, m2a); + assertEq(page[0].metadata3, m3a); + assertEq(page[1].metadata1, m1b); + assertEq(page[1].metadata2, m2b); + assertEq(page[1].metadata3, m3b); + } + function testIsRootValidAtTimestamp() public { // Set up registry with valid mock vm.prank(admin); diff --git a/packages/registry-explorer/app/certificates/diff/page.tsx b/packages/registry-explorer/app/certificates/diff/page.tsx index 64ff7bc99..01938c07f 100644 --- a/packages/registry-explorer/app/certificates/diff/page.tsx +++ b/packages/registry-explorer/app/certificates/diff/page.tsx @@ -4,50 +4,399 @@ import { Button } from "@/components/ui/button" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { LoadingAnimation } from "@/components/LoadingAnimation" import { Alert, AlertDescription } from "@/components/ui/alert" -import { ArrowLeft, AlertCircle, GitCompare, ArrowUpDown } from "lucide-react" +import { + ArrowLeft, + AlertCircle, + GitCompare, + ArrowUpDown, + ChevronDown, + ChevronUp, + ChevronLeft, + ChevronRight, +} from "lucide-react" import Link from "next/link" import { useSearchParams, useRouter } from "next/navigation" -import { useEffect, useState, Suspense } from "react" -import { PackagedCertificatesFile } from "@zkpassport/utils/types" -import { countryCodeAlpha3ToName, PackagedCertificate } from "@zkpassport/utils" -import { getCertificateUrl, getChainId } from "@/lib/certificate-url" +import { useEffect, useState, useMemo, Suspense } from "react" +import { + countryCodeAlpha3ToName, + PackagedCertificate, + PackagedCertificatesFile, + BRAINPOOL_CURVES_ABBR as BRAINPOOL_ABBR, +} from "@zkpassport/utils" +import { normalizeHash } from "@/lib/utils" +import { getCertificateUrl } from "@/lib/certificate-url" +import { useHistoricalCertificateRoots } from "@/hooks/useHistoricalCertificateRoots" +import { useNetwork } from "@/components/NetworkProvider" + +// ─── Types ──────────────────────────────────────────────────────────────────── interface DiffState { beforeData: PackagedCertificatesFile | null afterData: PackagedCertificatesFile | null + beforeRootHash: string | null + afterRootHash: string | null + beforeUrl: string | null + afterUrl: string | null isLoading: boolean error: string | null } +type ChangeCategory = + | "added" + | "removed" + | "trust_increased" + | "trust_decreased" + | "trust_changed" + | "other" + +interface FieldChange { + field: string + oldValue: string + newValue: string +} + interface CertificateChange { certificate: PackagedCertificate - changeType: "added" | "removed" | "modified" + changeType: ChangeCategory + beforeCertificate?: PackagedCertificate oldTags?: string[] newTags?: string[] - oldHashAlgorithm?: string - newHashAlgorithm?: string + fieldChanges?: FieldChange[] } interface CertificateDiff { - added: PackagedCertificate[] - removed: PackagedCertificate[] - modified: CertificateChange[] + added: CertificateChange[] + removed: CertificateChange[] + trustIncreased: CertificateChange[] + trustDecreased: CertificateChange[] + trustChanged: CertificateChange[] + other: CertificateChange[] +} + +// ─── Category display order & styling ───────────────────────────────────────── + +const CATEGORY_ORDER: ChangeCategory[] = [ + "added", + "removed", + "trust_increased", + "trust_decreased", + "trust_changed", + "other", +] + +const CATEGORY_CONFIG: Record< + ChangeCategory, + { + label: string + summarySign: string + icon: string + color: string + darkColor: string + bg: string + border: string + } +> = { + added: { + label: "Added", + summarySign: "+", + icon: "+", + color: "text-green-600", + darkColor: "dark:text-green-400", + bg: "bg-green-50 dark:bg-green-900/20", + border: "border-green-200 dark:border-green-800", + }, + removed: { + label: "Removed", + summarySign: "−", + icon: "−", + color: "text-red-600", + darkColor: "dark:text-red-400", + bg: "bg-red-50 dark:bg-red-900/20", + border: "border-red-200 dark:border-red-800", + }, + trust_increased: { + label: "Trust Increased", + summarySign: "↑", + icon: "↑", + color: "text-teal-600", + darkColor: "dark:text-teal-400", + bg: "bg-teal-50 dark:bg-teal-900/20", + border: "border-teal-200 dark:border-teal-800", + }, + trust_decreased: { + label: "Trust Decreased", + summarySign: "↓", + icon: "↓", + color: "text-amber-600", + darkColor: "dark:text-amber-400", + bg: "bg-amber-50 dark:bg-amber-900/20", + border: "border-amber-200 dark:border-amber-800", + }, + trust_changed: { + label: "Trust Changed", + summarySign: "~", + icon: "~", + color: "text-blue-600", + darkColor: "dark:text-blue-400", + bg: "bg-blue-50 dark:bg-blue-900/20", + border: "border-blue-200 dark:border-blue-800", + }, + other: { + label: "Other", + summarySign: "~", + icon: "?", + color: "text-purple-600", + darkColor: "dark:text-purple-400", + bg: "bg-purple-50 dark:bg-purple-900/20", + border: "border-purple-200 dark:border-purple-800", + }, +} + +// ─── Helpers ────────────────────────────────────────────────────────────────── + +/** Normalise legacy "ICAO" tag to "UN" */ +const normalizeTags = (tags?: string[]): string[] => + (tags || []).map((tag: string) => (tag === "ICAO" ? "UN" : tag)) + +// ─── Reusable masterlist tags component ────────────────────────────────────── + +/** Renders masterlist tags with color-coded diffs (added / removed / unchanged). */ +function MasterlistTags({ + oldTags, + newTags, + tags, + showLabel = false, + className = "", +}: { + /** Previous tags (for diff mode) */ + oldTags?: string[] + /** New tags (for diff mode) */ + newTags?: string[] + /** Plain tags when there is no diff */ + tags?: string[] + /** Whether to prefix with "Masterlists:" label */ + showLabel?: boolean + className?: string +}) { + // Diff mode: oldTags & newTags are both provided + if (oldTags && newTags) { + const removedTags = oldTags.filter((t) => !newTags.includes(t)) + const addedTags = newTags.filter((t) => !oldTags.includes(t)) + const unchangedTags = oldTags.filter((t) => newTags.includes(t)) + const allTags = [ + ...removedTags.map((tag) => ({ tag, type: "removed" as const })), + ...addedTags.map((tag) => ({ tag, type: "added" as const })), + ...unchangedTags.map((tag) => ({ tag, type: "unchanged" as const })), + ] + + if (allTags.length === 0) + return showLabel ? Masterlists: None : null + + return ( + + {showLabel && Masterlists: } + {allTags.map(({ tag, type }, i) => ( + + {type === "removed" && ( + {tag} + )} + {type === "added" && ( + {tag} + )} + {type === "unchanged" && {tag}} + {i < allTags.length - 1 && ", "} + + ))} + + ) + } + + // Plain mode: just show the tags + const normalised = normalizeTags(tags) + if (normalised.length === 0) return null + + return ( + + {showLabel && Masterlists: } + {normalised.join(", ")} + + ) +} + +/** Compare every field *except* tags & fingerprint between two certs */ +const detectFieldChanges = ( + before: PackagedCertificate, + after: PackagedCertificate, +): FieldChange[] => { + const changes: FieldChange[] = [] + const fmtDate = (ts: number) => new Date(ts * 1000).toLocaleDateString("en-GB") + + if (before.country !== after.country) { + changes.push({ field: "Country", oldValue: before.country, newValue: after.country }) + } + if (before.signature_algorithm !== after.signature_algorithm) { + changes.push({ + field: "Signature Algorithm", + oldValue: before.signature_algorithm, + newValue: after.signature_algorithm, + }) + } + if (JSON.stringify(before.public_key) !== JSON.stringify(after.public_key)) { + const describeKey = (pk: PackagedCertificate["public_key"]) => { + if (!pk) return "N/A" + if (pk.type === "RSA") return `RSA-${pk.key_size}` + if (pk.type === "EC") return `EC ${pk.curve}` + return "Unknown" + } + changes.push({ + field: "Public Key", + oldValue: describeKey(before.public_key), + newValue: describeKey(after.public_key), + }) + } + if (JSON.stringify(before.validity) !== JSON.stringify(after.validity)) { + changes.push({ + field: "Validity", + oldValue: `${fmtDate(before.validity.not_before)} – ${fmtDate(before.validity.not_after)}`, + newValue: `${fmtDate(after.validity.not_before)} – ${fmtDate(after.validity.not_after)}`, + }) + } + if (before.subject_key_identifier !== after.subject_key_identifier) { + changes.push({ + field: "Subject Key Identifier", + oldValue: before.subject_key_identifier || "N/A", + newValue: after.subject_key_identifier || "N/A", + }) + } + if (before.authority_key_identifier !== after.authority_key_identifier) { + changes.push({ + field: "Authority Key Identifier", + oldValue: before.authority_key_identifier || "N/A", + newValue: after.authority_key_identifier || "N/A", + }) + } + if (before.type !== after.type) { + changes.push({ field: "Type", oldValue: before.type || "N/A", newValue: after.type || "N/A" }) + } + if ( + JSON.stringify(before.private_key_usage_period) !== + JSON.stringify(after.private_key_usage_period) + ) { + changes.push({ + field: "Private Key Usage Period", + oldValue: JSON.stringify(before.private_key_usage_period ?? "N/A"), + newValue: JSON.stringify(after.private_key_usage_period ?? "N/A"), + }) + } + + return changes } +/** Look up changes array for a given category key */ +const getDiffCategory = (diff: CertificateDiff, category: ChangeCategory): CertificateChange[] => { + switch (category) { + case "added": + return diff.added + case "removed": + return diff.removed + case "trust_increased": + return diff.trustIncreased + case "trust_decreased": + return diff.trustDecreased + case "trust_changed": + return diff.trustChanged + case "other": + return diff.other + } +} + +const getTotalChanges = (diff: CertificateDiff): number => + CATEGORY_ORDER.reduce((sum, cat) => sum + getDiffCategory(diff, cat).length, 0) + +// ─── Main component ─────────────────────────────────────────────────────────── + function CertificateDiffContent() { const searchParams = useSearchParams() const router = useRouter() + const { chainId } = useNetwork() const beforeRoot = searchParams.get("before") const afterRoot = searchParams.get("after") const [diffState, setDiffState] = useState({ beforeData: null, afterData: null, + beforeRootHash: null, + afterRootHash: null, + beforeUrl: null, + afterUrl: null, isLoading: false, error: null, }) - // Fetch certificate data from root hashes + const [visibleTypes, setVisibleTypes] = useState>({ + added: true, + removed: true, + trust_increased: true, + trust_decreased: true, + trust_changed: true, + other: true, + }) + + const toggleVisibility = (type: ChangeCategory) => { + setVisibleTypes((prev) => ({ ...prev, [type]: !prev[type] })) + } + + const { roots: historicalRoots } = useHistoricalCertificateRoots() + + // Chronological order (oldest first) — the hook returns newest-first + const chronoRoots = useMemo(() => [...historicalRoots].reverse(), [historicalRoots]) + + const beforeIdx = chronoRoots.findIndex( + (r) => normalizeHash(r.root) === normalizeHash(beforeRoot || ""), + ) + const afterIdx = chronoRoots.findIndex( + (r) => normalizeHash(r.root) === normalizeHash(afterRoot || ""), + ) + + const canGoPrevious = beforeIdx > 0 + const canGoNext = afterIdx >= 0 && afterIdx < chronoRoots.length - 1 + + const navigateToPreviousDiff = () => { + if (canGoPrevious) { + const newBefore = chronoRoots[beforeIdx - 1].root + const newAfter = chronoRoots[beforeIdx].root + router.push( + `/certificates/diff?before=${encodeURIComponent(newBefore)}&after=${encodeURIComponent(newAfter)}`, + ) + } + } + + const navigateToNextDiff = () => { + if (canGoNext) { + const newBefore = chronoRoots[afterIdx].root + const newAfter = chronoRoots[afterIdx + 1].root + router.push( + `/certificates/diff?before=${encodeURIComponent(newBefore)}&after=${encodeURIComponent(newAfter)}`, + ) + } + } + + const [expandedCards, setExpandedCards] = useState>(new Set()) + + const toggleCard = (id: string) => { + setExpandedCards((prev) => { + const next = new Set(prev) + if (next.has(id)) { + next.delete(id) + } else { + next.add(id) + } + return next + }) + } + + // ── Fetch certificate data from root hashes ────────────────────────────── + useEffect(() => { const fetchCertificateData = async () => { if (!beforeRoot || !afterRoot) { @@ -60,8 +409,6 @@ function CertificateDiffContent() { setDiffState((prev) => ({ ...prev, isLoading: true, error: null })) - // Get chain ID and construct URLs from root hashes, local JSON files, or direct URLs - const chainId = getChainId() const beforeUrl = beforeRoot.startsWith("http") ? beforeRoot : beforeRoot.endsWith(".json") @@ -84,7 +431,6 @@ function CertificateDiffContent() { `Failed to fetch before data: ${beforeResponse.status} ${beforeResponse.statusText}`, ) } - if (!afterResponse.ok) { throw new Error( `Failed to fetch after data: ${afterResponse.status} ${afterResponse.statusText}`, @@ -95,10 +441,24 @@ function CertificateDiffContent() { beforeResponse.json(), afterResponse.json(), ]) + // Normalise fingerprints + for (const cert of beforeData.certificates) { + if (cert.fingerprint) cert.fingerprint = normalizeHash(cert.fingerprint) + } + for (const cert of afterData.certificates) { + if (cert.fingerprint) cert.fingerprint = normalizeHash(cert.fingerprint) + } + + const beforeRootHash = beforeRoot.startsWith("http") ? beforeData.root : beforeRoot + const afterRootHash = afterRoot.startsWith("http") ? afterData.root : afterRoot setDiffState({ beforeData, afterData, + beforeRootHash, + afterRootHash, + beforeUrl: beforeRoot.startsWith("http") ? beforeRoot : null, + afterUrl: afterRoot.startsWith("http") ? afterRoot : null, isLoading: false, error: null, }) @@ -112,12 +472,13 @@ function CertificateDiffContent() { } fetchCertificateData() - }, [beforeRoot, afterRoot]) + }, [beforeRoot, afterRoot, chainId]) - const formatRoot = (root: string) => { - if (root.endsWith(".json") || root.startsWith("http")) { - return root - } + // ── Utility ────────────────────────────────────────────────────────────── + + const formatRoot = (root: string | null): string => { + if (!root || typeof root !== "string") return "" + if (root.endsWith(".json") || root.startsWith("http")) return root return root.startsWith("0x") ? root : `0x${root}` } @@ -130,199 +491,312 @@ function CertificateDiffContent() { } } - // Function to generate unique certificate key - const getCertificateKey = (cert: PackagedCertificate): string => { - const publicKeyParts = [] - if (cert.public_key?.type === "RSA") { - publicKeyParts.push(cert.public_key.type, cert.public_key.modulus, cert.public_key.exponent) - } else if (cert.public_key?.type === "EC") { - publicKeyParts.push( - cert.public_key.type, - cert.public_key.curve, - cert.public_key.public_key_x, - cert.public_key.public_key_y, - ) - } - const parts = [cert.country, cert.signature_algorithm, cert.hash_algorithm, ...publicKeyParts] - return parts.join("|") - } + // ── Diff calculation (fingerprint-based) ───────────────────────────────── - // Function to calculate certificate differences const calculateCertificateDiff = ( beforeCerts: PackagedCertificate[], afterCerts: PackagedCertificate[], + // eslint-disable-next-line @typescript-eslint/no-unused-vars + afterTimestamp?: number, ): CertificateDiff => { const beforeMap = new Map() const afterMap = new Map() - // Create maps using the proper unique identifier + // Build maps keyed by fingerprint beforeCerts.forEach((cert) => { - const key = getCertificateKey(cert) - if (key) { - beforeMap.set(key, cert) - } + if (cert.fingerprint) beforeMap.set(cert.fingerprint, cert) }) - afterCerts.forEach((cert) => { - const key = getCertificateKey(cert) - if (key) { - afterMap.set(key, cert) - } + if (cert.fingerprint) afterMap.set(cert.fingerprint, cert) }) - const added: PackagedCertificate[] = [] - const removed: PackagedCertificate[] = [] - const modified: CertificateChange[] = [] + const diff: CertificateDiff = { + added: [], + removed: [], + trustIncreased: [], + trustDecreased: [], + trustChanged: [], + other: [], + } - // Find added certificates - afterMap.forEach((cert, id) => { - if (!beforeMap.has(id)) { - added.push(cert) + // Added: present in after but absent from before + afterMap.forEach((cert, fp) => { + if (!beforeMap.has(fp)) { + diff.added.push({ certificate: cert, changeType: "added" }) } }) - // Find removed certificates and modified certificates - beforeMap.forEach((beforeCert, id) => { - if (!afterMap.has(id)) { - removed.push(beforeCert) + // Removed / modified: iterate before list + beforeMap.forEach((beforeCert, fp) => { + if (!afterMap.has(fp)) { + // Fingerprint gone → removed + diff.removed.push({ certificate: beforeCert, changeType: "removed" }) } else { - const afterCert = afterMap.get(id)! - - // Compare tags and hash algorithm - const beforeTags = beforeCert.tags || [] - const afterTags = afterCert.tags || [] + // Present in both → check what changed + const afterCert = afterMap.get(fp)! + const beforeTags = normalizeTags(beforeCert.tags) + const afterTags = normalizeTags(afterCert.tags) const tagsChanged = beforeTags.length !== afterTags.length || - beforeTags.some((tag) => !afterTags.includes(tag)) || - afterTags.some((tag) => !beforeTags.includes(tag)) + beforeTags.some((t) => !afterTags.includes(t)) || + afterTags.some((t) => !beforeTags.includes(t)) - const hashAlgorithmChanged = beforeCert.hash_algorithm !== afterCert.hash_algorithm + const fieldChanges = detectFieldChanges(beforeCert, afterCert) - if (tagsChanged || hashAlgorithmChanged) { - modified.push({ + if (tagsChanged) { + const change: CertificateChange = { certificate: afterCert, - changeType: "modified", + changeType: "trust_changed", + beforeCertificate: beforeCert, oldTags: beforeTags, newTags: afterTags, - oldHashAlgorithm: hashAlgorithmChanged ? beforeCert.hash_algorithm : undefined, - newHashAlgorithm: hashAlgorithmChanged ? afterCert.hash_algorithm : undefined, + fieldChanges: fieldChanges.length > 0 ? fieldChanges : undefined, + } + + const addedTags = afterTags.filter((t) => !beforeTags.includes(t)) + const removedTags = beforeTags.filter((t) => !afterTags.includes(t)) + + if (addedTags.length > 0 && removedTags.length === 0) { + // Only new tags were added — pure trust increase + change.changeType = "trust_increased" + diff.trustIncreased.push(change) + } else if (removedTags.length > 0 && addedTags.length === 0) { + // Only existing tags were removed — pure trust decrease + change.changeType = "trust_decreased" + diff.trustDecreased.push(change) + } else { + diff.trustChanged.push(change) + } + } else if (fieldChanges.length > 0) { + diff.other.push({ + certificate: afterCert, + changeType: "other", + beforeCertificate: beforeCert, + fieldChanges, }) } } }) - return { added, removed, modified } + return diff } - const renderCertificateChange = ( - cert: PackagedCertificate, - changeType: "added" | "removed" | "modified", - oldTags?: string[], - newTags?: string[], - oldHashAlgorithm?: string, - newHashAlgorithm?: string, - ) => { - const getChangeTypeStyle = (type: "added" | "removed" | "modified") => { - switch (type) { - case "added": - return "border-green-200 bg-green-50 dark:border-green-800 dark:bg-green-900/20" - case "removed": - return "border-red-200 bg-red-50 dark:border-red-800 dark:bg-red-900/20" - case "modified": - return "border-blue-200 bg-blue-50 dark:border-blue-800 dark:bg-blue-900/20" - } - } + // ── Render a single certificate change card ────────────────────────────── - const getChangeTypeIcon = (type: "added" | "removed" | "modified") => { - switch (type) { - case "added": - return + - case "removed": - return - - case "modified": - return ~ + const renderCertificateChange = (change: CertificateChange) => { + const config = CATEGORY_CONFIG[change.changeType] + const cert = change.certificate + + // Stable unique ID for expand/collapse state + const cardId = cert.fingerprint + ? `${change.changeType}-${cert.fingerprint}` + : `${change.changeType}-${cert.country}-${cert.signature_algorithm}-${cert.validity?.not_before || ""}` + const isExpanded = expandedCards.has(cardId) + + // Concise algorithm + key description for summary line + const algoDesc = (() => { + const algo = cert.signature_algorithm || "" + if (cert.public_key?.type === "EC") { + const curve = cert.public_key.curve || "" + const displayCurve = BRAINPOOL_ABBR[curve as keyof typeof BRAINPOOL_ABBR] ?? curve + return `${algo} - ${displayCurve}`.trim() } - } + if (cert.public_key?.type === "RSA") return `${algo} ${cert.public_key.key_size || ""}`.trim() + return algo || "Unknown" + })() - return ( -
-
- {getChangeTypeIcon(changeType)} - {changeType} -
+ // Validity period for summary + const validityStr = + cert.validity?.not_before && cert.validity?.not_after + ? `${new Date(cert.validity.not_before * 1000).toLocaleDateString("en-GB")} to ${new Date(cert.validity.not_after * 1000).toLocaleDateString("en-GB")}` + : "" -
-
- {countryCodeAlpha3ToName(cert.country)} {" "} - ({cert.country}) -
-
- {cert.signature_algorithm} {cert.public_key?.key_size || "Unknown Key Size"} •{" "} - {oldHashAlgorithm && newHashAlgorithm ? ( - <> - - {oldHashAlgorithm} - {" "} - - {newHashAlgorithm} + const countryName = countryCodeAlpha3ToName(cert.country) + const showExpiredBadge = + cert.validity?.not_after != null && Date.now() > cert.validity.not_after * 1000 + // Compute effective old/new tags for the MasterlistTags component: + // - "added" certs: all tags are new (green) + // - "removed" certs: all tags are removed (red strikethrough) + // - trust changes: use the change's oldTags/newTags directly + const certTags = normalizeTags(cert.tags) + const effectiveOldTags = + change.oldTags ?? + (change.changeType === "added" ? [] : change.changeType === "removed" ? certTags : undefined) + const effectiveNewTags = + change.newTags ?? + (change.changeType === "added" ? certTags : change.changeType === "removed" ? [] : undefined) + + return ( +
+ {/* Header row — always visible, clickable to toggle */} +
- {cert.subject_key_identifier && ( -
- SKI: {cert.subject_key_identifier} -
+ {algoDesc && ( + + {" - "} + {algoDesc} + + )} + {validityStr && ( + + {" - "} + {validityStr} + + )} + {showExpiredBadge && ( + + Expired + + )} +
+ {/* Right-aligned masterlist tags with diff colors */} + + )} -
+ {isExpanded ? ( + + ) : ( + + )} + - {changeType === "modified" && oldTags && newTags ? ( -
- Tags:{" "} - {(() => { - const removedTags = oldTags.filter((tag) => !newTags.includes(tag)) - const addedTags = newTags.filter((tag) => !oldTags.includes(tag)) - const unchangedTags = oldTags.filter((tag) => newTags.includes(tag)) - - const allTags = [ - ...removedTags.map((tag) => ({ tag, type: "removed" })), - ...addedTags.map((tag) => ({ tag, type: "added" })), - ...unchangedTags.map((tag) => ({ tag, type: "unchanged" })), - ] - - if (allTags.length === 0) return "None" - - return allTags.map(({ tag, type }, index) => ( - - {type === "removed" && ( - {tag} + {/* Expanded details */} + {isExpanded && ( +
+
+ {/* Certificate core info */} +
+ {countryName} {" "} + ({cert.country}) +
+
+ {cert.signature_algorithm} {cert.public_key?.key_size || "Unknown Key Size"} +
+ {cert.validity?.not_before && cert.validity?.not_after && ( +
+ + Validity Period:{" "} + {new Date(cert.validity.not_before * 1000).toLocaleDateString("en-GB")} to{" "} + {new Date(cert.validity.not_after * 1000).toLocaleDateString("en-GB")} + + {showExpiredBadge && ( + + Expired + )} - {type === "added" && ( - {tag} +
+ )} + + {/* Public key details */} + {cert.public_key && ( +
+
+ {cert.public_key.type === "RSA" && "RSA Public Key"} + {cert.public_key.type === "EC" && + `EC Public Key (${cert.public_key.curve || "Unknown Curve"})`} +
+ {cert.public_key.type === "RSA" && ( + <> +
+ n: {cert.public_key.modulus} +
+
+ e: {cert.public_key.exponent} +
+ )} - {type === "unchanged" && {tag}} - {index < allTags.length - 1 && ", "} - - )) - })()} -
- ) : cert.tags && cert.tags.length > 0 ? ( -
- Tags: {cert.tags.join(", ")} + {cert.public_key.type === "EC" && ( + <> +
+ x: {cert.public_key.public_key_x} +
+
+ y: {cert.public_key.public_key_y} +
+ + )} +
+ )} + + {/* Identifiers */} + {cert.fingerprint && ( +
+ Fingerprint: {cert.fingerprint} +
+ )} + {cert.authority_key_identifier && ( +
+ AKI: {cert.authority_key_identifier} +
+ )} + {cert.subject_key_identifier && ( +
+ SKI: {cert.subject_key_identifier} +
+ )} + + {/* Tags diff for trust-related changes */} + {(effectiveOldTags && effectiveNewTags) || (cert.tags && cert.tags.length > 0) ? ( +
+ +
+ ) : null} + + {/* Field changes */} + {change.fieldChanges && change.fieldChanges.length > 0 && ( +
+ Field changes: + {change.fieldChanges.map((fc, i) => ( +
+ {fc.field}:{" "} + + {fc.oldValue} + + {" → "} + + {fc.newValue} + +
+ ))} +
+ )} +
- ) : null} + )}
) } + // ── Render change list ─────────────────────────────────────────────────── + const renderDiffList = (diff: CertificateDiff) => { - const totalChanges = diff.added.length + diff.removed.length + diff.modified.length + const totalChanges = getTotalChanges(diff) if (totalChanges === 0) { return ( @@ -332,35 +806,53 @@ function CertificateDiffContent() { ) } + const hasAnyVisible = CATEGORY_ORDER.some((cat) => visibleTypes[cat]) + if (!hasAnyVisible) { + return ( +
+ All change types are hidden. Click on the cards above to show changes. +
+ ) + } + + const visibleCount = CATEGORY_ORDER.reduce( + (sum, cat) => sum + (visibleTypes[cat] ? getDiffCategory(diff, cat).length : 0), + 0, + ) + return (
- {totalChanges} change{totalChanges !== 1 ? "s" : ""} found + {visibleCount !== totalChanges ? ( + <> + Showing {visibleCount} of {totalChanges} change + {totalChanges !== 1 ? "s" : ""} + + ) : ( + <> + {totalChanges} change{totalChanges !== 1 ? "s" : ""} found + + )}
- {diff.added.map((cert) => renderCertificateChange(cert, "added"))} - {diff.removed.map((cert) => renderCertificateChange(cert, "removed"))} - {diff.modified.map((change) => - renderCertificateChange( - change.certificate, - "modified", - change.oldTags, - change.newTags, - change.oldHashAlgorithm, - change.newHashAlgorithm, - ), + {CATEGORY_ORDER.map((cat) => + visibleTypes[cat] + ? getDiffCategory(diff, cat).map((change) => renderCertificateChange(change)) + : null, )}
) } + // ── Render summary cards ───────────────────────────────────────────────── + const renderDiffSummary = (diff: CertificateDiff) => { if (!diffState.beforeData || !diffState.afterData) return null const beforeCount = diffState.beforeData.certificates?.length || 0 const afterCount = diffState.afterData.certificates?.length || 0 - const totalChanges = diff.added.length + diff.removed.length + diff.modified.length + const totalChanges = getTotalChanges(diff) return ( @@ -372,31 +864,29 @@ function CertificateDiffContent() {
- {/* Change Cards First */} - {diff.added.length > 0 && ( -
-
- +{diff.added.length} -
-
Added
-
- )} - {diff.removed.length > 0 && ( -
-
- -{diff.removed.length} -
-
Removed
-
- )} - {diff.modified.length > 0 && ( -
-
- ~{diff.modified.length} -
-
Modified
-
- )} + {/* Category cards */} + {CATEGORY_ORDER.map((cat) => { + const items = getDiffCategory(diff, cat) + if (items.length === 0) return null + const config = CATEGORY_CONFIG[cat] + return ( + + ) + })} {totalChanges === 0 && (
0
@@ -404,14 +894,14 @@ function CertificateDiffContent() {
)} - {/* Context Cards at the End */} + {/* Context: before / after counts */}
{beforeCount}
Before
-
+
{afterCount}
@@ -423,15 +913,41 @@ function CertificateDiffContent() { ) } + // ── Page layout ────────────────────────────────────────────────────────── + return ( -
-
+
+
+ {chronoRoots.length > 0 && ( +
+ + +
+ )}
{diffState.error && ( @@ -453,6 +969,20 @@ function CertificateDiffContent() { <>

Comparing Certificate Roots

+ {diffState.afterData?.timestamp && ( +
+ Updated on {" "} + {new Date(diffState.afterData.timestamp * 1000).toLocaleString("en-US", { + year: "numeric", + month: "long", + day: "numeric", + hour: "2-digit", + minute: "2-digit", + second: "2-digit", + timeZoneName: "short", + })} +
+ )}
@@ -460,7 +990,23 @@ function CertificateDiffContent() { Before: - {formatRoot(beforeRoot)} + {diffState.beforeRootHash + ? formatRoot(diffState.beforeRootHash) + : formatRoot(beforeRoot)} + {diffState.beforeUrl && ( + + ( + + {diffState.beforeUrl} + + ) + + )}
@@ -468,7 +1014,23 @@ function CertificateDiffContent() { After: - {formatRoot(afterRoot)} + {diffState.afterRootHash + ? formatRoot(diffState.afterRootHash) + : formatRoot(afterRoot)} + {diffState.afterUrl && ( + + ( + + {diffState.afterUrl} + + ) + + )}
@@ -494,6 +1056,7 @@ function CertificateDiffContent() { const diff = calculateCertificateDiff( diffState.beforeData.certificates || [], diffState.afterData.certificates || [], + diffState.afterData.timestamp, ) return ( @@ -521,7 +1084,7 @@ export default function CertificateDiffPage() { return ( +
diff --git a/packages/registry-explorer/app/certificates/history/page.tsx b/packages/registry-explorer/app/certificates/history/page.tsx index ca57223a3..e252bf111 100644 --- a/packages/registry-explorer/app/certificates/history/page.tsx +++ b/packages/registry-explorer/app/certificates/history/page.tsx @@ -10,7 +10,7 @@ function HistoricalRootsContent() { if (error) { return ( -
+

Error Loading Roots

{error}
@@ -19,6 +19,11 @@ function HistoricalRootsContent() { return (
+

+ {isLoading && roots.length === 0 + ? "Browse all historical certificate roots stored in the registry" + : `${roots.length} historical certificate root${roots.length !== 1 ? "s" : ""} found`} +

{isLoading && roots.length === 0 ? (
@@ -46,15 +51,16 @@ export default function HistoricalRootsPage() { return (

Historical Certificate Roots

-

- Browse all historical certificate roots stored in the registry -

- - -
+ <> +

+ Browse all historical certificate roots stored in the registry +

+
+ +
+ } > diff --git a/packages/registry-explorer/app/certificates/page.tsx b/packages/registry-explorer/app/certificates/page.tsx index ea64cd89d..b22d94f88 100644 --- a/packages/registry-explorer/app/certificates/page.tsx +++ b/packages/registry-explorer/app/certificates/page.tsx @@ -3,7 +3,7 @@ import CertificateSearch from "@/components/CertificateSearch" export default function CertificatesPage() { return ( -
+

Certificate Registry Explorer

Loading...
}> diff --git a/packages/registry-explorer/app/layout.tsx b/packages/registry-explorer/app/layout.tsx index cf66dff72..c7e348f5c 100644 --- a/packages/registry-explorer/app/layout.tsx +++ b/packages/registry-explorer/app/layout.tsx @@ -1,4 +1,5 @@ import { DebugInitializer } from "@/components/DebugInitializer" +import { NetworkProvider } from "@/components/NetworkProvider" import { ThemeProvider } from "@/components/ThemeProvider" import type { Metadata } from "next" import localFont from "next/font/local" @@ -88,8 +89,10 @@ export default function RootLayout({ > - -
{children}
+ + +
{children}
+
diff --git a/packages/registry-explorer/app/map/page.tsx b/packages/registry-explorer/app/map/page.tsx index 7b6da66cd..bcadaa1ca 100644 --- a/packages/registry-explorer/app/map/page.tsx +++ b/packages/registry-explorer/app/map/page.tsx @@ -32,8 +32,6 @@ function MapPageContent() { useEffect(() => { const processCertificates = async () => { if (certificates && certificates.length > 0) { - console.log("Processing certificates:", certificates.length) - // Group certificates by country const certsByCountry: Record = {} certificates.forEach((cert) => { @@ -43,7 +41,6 @@ function MapPageContent() { certsByCountry[cert.country].push(cert) }) setCertificatesByCountry(certsByCountry) - console.log("Certificates by country:", Object.keys(certsByCountry).length, "countries") // Convert to Map for coverage calculation const certsByCountryMap = new Map(Object.entries(certsByCountry)) @@ -92,7 +89,6 @@ function MapPageContent() { } }) setCountryData(newCountryData) - console.log("Country data created with coverage:", newCountryData) } } diff --git a/packages/registry-explorer/app/page.tsx b/packages/registry-explorer/app/page.tsx index a5e0a6628..b36bb88c2 100644 --- a/packages/registry-explorer/app/page.tsx +++ b/packages/registry-explorer/app/page.tsx @@ -1,3 +1,5 @@ +"use client" + import { Button } from "@/components/ui/button" import { Card, diff --git a/packages/registry-explorer/components/CertificateRootCard.tsx b/packages/registry-explorer/components/CertificateRootCard.tsx index 464575ae8..cf03b8ed9 100644 --- a/packages/registry-explorer/components/CertificateRootCard.tsx +++ b/packages/registry-explorer/components/CertificateRootCard.tsx @@ -10,7 +10,7 @@ import { } from "@/components/ui/card" import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip" import { RootDetails } from "@zkpassport/registry" -import { Copy, GitCompare } from "lucide-react" +import { Copy, FileText, GitCompare } from "lucide-react" import Link from "next/link" import { useState } from "react" @@ -51,7 +51,7 @@ export function CertificateRootCard({ rootDetails, previousRoot }: CertificateRo
- {isLatest ? "Current Root" : "Historical Root"} + {isLatest ? "Current Root" : isGenesisRoot ? "Genesis Root" : "Historical Root"}
{revoked && Revoked} @@ -121,8 +121,11 @@ export function CertificateRootCard({ rootDetails, previousRoot }: CertificateRo
- {previousRoot && ( {isLatestRoot && ( - - Latest Root + + Latest )}
@@ -124,23 +133,27 @@ export default function CertificateSearch() {
{availableRoots.length > 0 && ( -
-
)}
@@ -167,172 +190,90 @@ export default function CertificateSearch() {
{/* Stats Cards */} -
-
-
-
-
- - - -
-
-
-
- Total Certificates -
-
-
- {certificates.length} -
-
-
-
+
+
+
+
+
+ Total Certificates +
+
+ {certificates.length} +
+
-
-
-
-
- - - -
-
-
-
- Countries -
-
-
- {uniqueCountries.length} -
-
-
-
+
+
+
+
+ Countries +
+
+ {uniqueCountries.length} +
+
-
-
-
-
- - - -
-
-
-
- RSA Certificates -
-
-
- {certificates.filter((cert) => isRSA(cert)).length} -
-
-
-
+
+
+
+
+ RSA Certificates +
+
+ {certificates.filter((cert) => isRSA(cert)).length} +
+
-
-
-
-
- - - -
-
-
-
- ECDSA Certificates -
-
-
- {certificates.filter((cert) => isECDSA(cert)).length} -
-
-
-
+
+
+
+
+ ECDSA Certificates +
+
+ {certificates.filter((cert) => isECDSA(cert)).length} +
+
{/* Search and Filter Section with Card UI */} -
-

- - - +
+

+ Filter Certificates

@@ -364,7 +305,8 @@ export default function CertificateSearch() { {filteredCertificates.length > 0 && (
Showing {filteredCertificates.length}{" "} - {filteredCertificates.length === 1 ? "certificate" : "certificates"} + {filteredCertificates.length === 1 ? "certificate" : "certificates"} across{" "} + {new Set(filteredCertificates.map((c) => c.country)).size} countries
)}
@@ -378,26 +320,28 @@ export default function CertificateSearch() {